mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-12 10:12:11 +03:00
fix(command-code): include tool call arguments
This commit is contained in:
committed by
diegosouzapw
parent
918647af69
commit
9f8755a05b
@@ -56,4 +56,105 @@ describe("CommandCodeExecutor", () => {
|
||||
// Network error is expected in test environment
|
||||
}
|
||||
});
|
||||
|
||||
it("assistant tool-call conversion always emits a valid required arguments field (#regression input[N] missing required field arguments)", async () => {
|
||||
const calls: Array<{ url: string; init: RequestInit; body: unknown }> = [];
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
||||
calls.push({
|
||||
url: String(url),
|
||||
init: init || {},
|
||||
body: JSON.parse(String((init as RequestInit | undefined)?.body)),
|
||||
});
|
||||
return new Response("", { status: 200 });
|
||||
}) as typeof fetch;
|
||||
|
||||
const executor = new mod.CommandCodeExecutor();
|
||||
const pairedId = "call_paired";
|
||||
const body = {
|
||||
messages: [
|
||||
{ role: "user", content: "hi" },
|
||||
{
|
||||
role: "assistant",
|
||||
content: "",
|
||||
tool_calls: [
|
||||
// Missing arguments entirely -> must still get a valid arguments field
|
||||
{ id: "call_missing", type: "function", function: { name: "lookup" } },
|
||||
// Empty string arguments -> "{}"
|
||||
{
|
||||
id: "call_empty",
|
||||
type: "function",
|
||||
function: { name: "lookup", arguments: "" },
|
||||
},
|
||||
// Valid object arguments -> round-trips as JSON string
|
||||
{
|
||||
id: pairedId,
|
||||
type: "function",
|
||||
function: { name: "lookup", arguments: { q: "docs" } },
|
||||
},
|
||||
// Valid string arguments -> preserved as-is
|
||||
{
|
||||
id: "call_string",
|
||||
type: "function",
|
||||
function: { name: "lookup", arguments: '{"q":"string"}' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{ role: "tool", tool_call_id: "call_missing", content: "r1" },
|
||||
{ role: "tool", tool_call_id: "call_empty", content: "r2" },
|
||||
{ role: "tool", tool_call_id: pairedId, content: "r3" },
|
||||
{ role: "tool", tool_call_id: "call_string", content: "r4" },
|
||||
],
|
||||
};
|
||||
|
||||
try {
|
||||
await executor.execute({
|
||||
model: "test",
|
||||
body,
|
||||
stream: false,
|
||||
credentials: { apiKey: "fake-key" },
|
||||
signal: null,
|
||||
});
|
||||
assert.fail("Expected fetch to reject (no real network)");
|
||||
} catch {
|
||||
// Fetch rejection is expected; inspect the captured body
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
|
||||
assert.equal(calls.length, 1, "exactly one upstream call");
|
||||
const sentBody = calls[0].body as {
|
||||
params: { messages: Array<{ role: string; content: unknown }> };
|
||||
};
|
||||
const assistant = sentBody.params.messages.find((m) => m.role === "assistant");
|
||||
assert.ok(assistant, "assistant turn present");
|
||||
const parts = assistant.content as Array<Record<string, unknown>>;
|
||||
const toolCalls = parts.filter((p) => p.type === "tool-call");
|
||||
assert.equal(toolCalls.length, 4, "all four paired tool calls converted");
|
||||
|
||||
for (const call of toolCalls) {
|
||||
assert.equal(
|
||||
typeof call.arguments,
|
||||
"string",
|
||||
`tool-call ${String(call.toolCallId)} must carry a string arguments field`
|
||||
);
|
||||
const parsed = JSON.parse(call.arguments as string);
|
||||
assert.equal(typeof parsed, "object");
|
||||
assert.ok(!Array.isArray(parsed), "arguments must parse to a JSON object");
|
||||
}
|
||||
|
||||
const byId = new Map(toolCalls.map((c) => [String(c.toolCallId), c]));
|
||||
assert.equal(byId.get("call_missing").arguments, "{}", "missing arguments -> empty object");
|
||||
assert.equal(byId.get("call_empty").arguments, "{}", "empty string arguments -> empty object");
|
||||
assert.equal(
|
||||
byId.get(pairedId).arguments,
|
||||
'{"q":"docs"}',
|
||||
"object arguments round-trip as JSON string"
|
||||
);
|
||||
assert.equal(
|
||||
byId.get("call_string").arguments,
|
||||
'{"q":"string"}',
|
||||
"valid string arguments preserved as-is"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user