From 092b95d4730b6c028898fdcc74927ec87e692141 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sun, 5 Jul 2026 15:57:24 +0200 Subject: [PATCH] test(ai): validated parallel tool call argument routing and chunk handling - Added a test case to ensure brace-prefixed chunks remain with their original sibling tool call. - Validated that parallel function call arguments are correctly routed to their respective tool call blocks. --- ...enai-responses-parallel-tool-calls.test.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/ai/test/openai-responses-parallel-tool-calls.test.ts b/packages/ai/test/openai-responses-parallel-tool-calls.test.ts index c1a580d6f..a01a0eaea 100644 --- a/packages/ai/test/openai-responses-parallel-tool-calls.test.ts +++ b/packages/ai/test/openai-responses-parallel-tool-calls.test.ts @@ -456,6 +456,54 @@ describe("processResponsesStream: parallel function_call items", () => { expect(deltas.map(delta => delta.contentIndex)).toEqual([0, 0]); }); + test("keeps brace-prefixed identifierless chunks on the current sibling when concatenation stays valid", async () => { + const output = makeOutput(); + const emitted: EmittedEvent[] = []; + const stream = { push: (e: unknown) => emitted.push(e as EmittedEvent), end: () => {} } as never; + + await processResponsesStream( + makeStream([ + { + type: "response.output_item.added", + item: { type: "function_call", id: "fc_a", call_id: "call_a", name: "bash", arguments: "" }, + }, + { + type: "response.output_item.added", + item: { type: "function_call", id: "fc_b", call_id: "call_b", name: "bash", arguments: "" }, + }, + { type: "response.function_call_arguments.delta", delta: '{"command":"echo ' }, + { type: "response.function_call_arguments.delta", delta: '{1..3}"}' }, + { type: "response.function_call_arguments.delta", delta: '{"command":"echo goodbye"}' }, + { + type: "response.output_item.done", + item: { type: "function_call", id: "fc_a", call_id: "call_a", name: "bash", arguments: "" }, + }, + { + type: "response.output_item.done", + item: { type: "function_call", id: "fc_b", call_id: "call_b", name: "bash", arguments: "" }, + }, + ]), + output, + stream, + makeModel(), + ); + + const [blockA, blockB] = output.content; + if (blockA?.type !== "toolCall" || blockB?.type !== "toolCall") throw new Error("expected toolCalls"); + expect(blockA.arguments).toEqual({ command: "echo {1..3}" }); + expect(blockB.arguments).toEqual({ command: "echo goodbye" }); + + const deltas = emitted.filter(e => e.type === "toolcall_delta") as Array<{ + delta: string; + contentIndex: number; + }>; + expect(deltas.map(delta => ({ delta: delta.delta, contentIndex: delta.contentIndex }))).toEqual([ + { delta: '{"command":"echo ', contentIndex: 0 }, + { delta: '{1..3}"}', contentIndex: 0 }, + { delta: '{"command":"echo goodbye"}', contentIndex: 1 }, + ]); + }); + test("routes deltas by item.call_id when llama.cpp omits item.id and output_index (issue #2015)", async () => { // llama.cpp's `to_json_oaicompat_resp` (tools/server/server-task.cpp) emits a // function_call's `output_item.added` with only `item.call_id` — no `item.id`,