Files
diegosouzapw--omniroute/tests/unit/responses-namespace-flatten.test.ts
2026-07-13 13:39:12 +08:00

73 lines
2.7 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
// Regression for port-from-9router#1534: when a Codex CLI client routes a
// Responses-API request to a non-Codex backend (e.g. kr/claude-opus-4.7), MCP
// servers are declared as `namespace` tools — { type:"namespace", name, tools:[...] }.
// The Responses→Chat translator had no namespace branch, so each namespace
// collapsed into a single empty-schema function named `mcp__<server>__`, dropping
// every sub-tool. Any MCP call then failed with `unsupported call: mcp__<server>__`.
const { openaiResponsesToOpenAIRequest } = await import(
"../../open-sse/translator/request/openai-responses.ts"
);
test("#1534: namespace MCP tools flatten into one Chat function per sub-tool", () => {
const body = {
input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "hi" }] }],
tools: [
{
type: "namespace",
name: "mcp__ctx7__",
tools: [
{
name: "mcp__ctx7__get_docs",
description: "Get library docs",
parameters: {
type: "object",
properties: { id: { type: "string" } },
required: ["id"],
},
},
{
name: "mcp__ctx7__search",
description: "Search docs",
parameters: { type: "object", properties: { q: { type: "string" } } },
},
],
},
],
};
const out = openaiResponsesToOpenAIRequest("kr/claude-opus-4.7", body, false, {}) as {
tools: { type: string; function: { name: string; parameters?: unknown } }[];
};
const names = out.tools.map((t) => t.function?.name).sort();
assert.deepEqual(names, ["mcp__ctx7__get_docs", "mcp__ctx7__search"]);
// The empty namespace placeholder must NOT survive.
assert.equal(
out.tools.some((t) => t.function?.name === "mcp__ctx7__"),
false,
"the empty `mcp__ctx7__` namespace placeholder must not be emitted"
);
// Each flattened function keeps its own parameters.
const getDocs = out.tools.find((t) => t.function.name === "mcp__ctx7__get_docs");
assert.ok(getDocs?.function.parameters, "sub-tool parameters must be preserved");
assert.deepEqual((getDocs!.function.parameters as { required?: string[] }).required, ["id"]);
});
test("#1534: an empty namespace (no sub-tools) is dropped, not turned into a broken function", () => {
const body = {
input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "hi" }] }],
tools: [{ type: "namespace", name: "mcp__empty__", tools: [] }],
};
const out = openaiResponsesToOpenAIRequest("kr/claude-opus-4.7", body, false, {}) as {
tools: unknown[];
};
assert.equal(out.tools.length, 0, "an empty namespace yields no tools");
});