Skip to content

Commit d4405a3

Browse files
committed
Ignore streaming AI SDK tool availability
1 parent 85bfd41 commit d4405a3

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

src/api/transform/__tests__/ai-sdk.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,25 @@ describe("AI SDK conversion utilities", () => {
484484
})
485485
})
486486

487+
it("uses args when tool-call input is an empty object", () => {
488+
const part = {
489+
type: "tool-call" as const,
490+
toolCallId: "call_1",
491+
toolName: "attempt_completion",
492+
input: {},
493+
args: { result: "done" },
494+
}
495+
const chunks = [...processAiSdkStreamPart(part as any)]
496+
497+
expect(chunks).toHaveLength(1)
498+
expect(chunks[0]).toEqual({
499+
type: "tool_call",
500+
id: "call_1",
501+
name: "attempt_completion",
502+
arguments: '{"result":"done"}',
503+
})
504+
})
505+
487506
it("processes complete tool-call chunks with arguments", () => {
488507
const part = {
489508
type: "tool-call" as const,
@@ -536,6 +555,43 @@ describe("AI SDK conversion utilities", () => {
536555
expect(seenStreamingToolCallIds.has("call_1")).toBe(false)
537556
})
538557

558+
it("ignores tool-input-available for calls that are still streaming input", () => {
559+
const seenStreamingToolCallIds = new Set<string>()
560+
const chunks = [
561+
...processAiSdkStreamPart(
562+
{ type: "tool-input-start" as const, id: "call_1", toolName: "attempt_completion" },
563+
seenStreamingToolCallIds,
564+
),
565+
...processAiSdkStreamPart(
566+
{
567+
type: "tool-input-available" as const,
568+
toolCallId: "call_1",
569+
toolName: "attempt_completion",
570+
input: {},
571+
},
572+
seenStreamingToolCallIds,
573+
),
574+
...processAiSdkStreamPart(
575+
{
576+
type: "tool-call" as const,
577+
toolCallId: "call_1",
578+
toolName: "attempt_completion",
579+
input: { result: "done" },
580+
},
581+
seenStreamingToolCallIds,
582+
),
583+
]
584+
585+
expect(chunks).toEqual([
586+
{
587+
type: "tool_call",
588+
id: "call_1",
589+
name: "attempt_completion",
590+
arguments: '{"result":"done"}',
591+
},
592+
])
593+
})
594+
539595
it("processes source chunks with URL", () => {
540596
const part = {
541597
type: "source" as const,

src/api/transform/ai-sdk.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ type ExtendedStreamPart =
191191

192192
function stringifyToolInput(part: Extract<TextStreamPart<any>, { type: "tool-call" }>) {
193193
const input =
194-
"input" in part && part.input !== undefined
194+
"input" in part && part.input !== undefined && !isEmptyObject(part.input)
195195
? part.input
196196
: "args" in part
197197
? (part as { args: unknown }).args
@@ -202,6 +202,10 @@ function stringifyToolInput(part: Extract<TextStreamPart<any>, { type: "tool-cal
202202
return typeof input === "string" ? input : JSON.stringify(input)
203203
}
204204

205+
function isEmptyObject(value: unknown) {
206+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0
207+
}
208+
205209
type ToolInputPart = {
206210
id?: string
207211
toolCallId?: string
@@ -249,6 +253,10 @@ export function* processAiSdkStreamPart(
249253
break
250254

251255
case "tool-input-available":
256+
if (seenStreamingToolCallIds?.has(getToolCallId(part))) {
257+
break
258+
}
259+
252260
yield {
253261
type: "tool_call",
254262
id: getToolCallId(part),

0 commit comments

Comments
 (0)