Skip to content

Commit a0be545

Browse files
committed
feat(runtime): emit STATE_DELTA on AGUISendStateDelta in TanStack converter
1 parent 5f233a1 commit a0be545

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

packages/runtime/src/agent/__tests__/converter-tanstack.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,4 +340,25 @@ describe("TanStack AI converter — state tools", () => {
340340
snapshot,
341341
);
342342
});
343+
344+
it("emits STATE_DELTA before TOOL_CALL_RESULT for AGUISendStateDelta", async () => {
345+
const delta = [{ op: "replace", path: "/counter", value: 7 }];
346+
const agent = createAgent("tanstack", [
347+
tanstackToolCallStart("call1", "AGUISendStateDelta"),
348+
tanstackToolCallEnd("call1"),
349+
tanstackToolCallResult("call1", { success: true, delta }),
350+
]);
351+
const events = await collectEvents(agent.run(createDefaultInput()));
352+
353+
expectLifecycleWrapped(events);
354+
355+
const deltaIdx = events.findIndex((e) => e.type === EventType.STATE_DELTA);
356+
const resultIdx = events.findIndex(
357+
(e) => e.type === EventType.TOOL_CALL_RESULT,
358+
);
359+
360+
expect(deltaIdx).toBeGreaterThanOrEqual(0);
361+
expect(deltaIdx).toBeLessThan(resultIdx);
362+
expect(eventField<unknown>(events[deltaIdx], "delta")).toEqual(delta);
363+
});
343364
});

packages/runtime/src/agent/converters/tanstack.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,19 @@ export async function* convertTanStackStream(
290290
yield stateSnapshotEvent;
291291
}
292292

293+
if (
294+
toolName === "AGUISendStateDelta" &&
295+
parsedContent &&
296+
typeof parsedContent === "object" &&
297+
"delta" in parsedContent
298+
) {
299+
const stateDeltaEvent: StateDeltaEvent = {
300+
type: EventType.STATE_DELTA,
301+
delta: (parsedContent as Record<string, unknown>).delta as never,
302+
};
303+
yield stateDeltaEvent;
304+
}
305+
293306
let serializedContent: string;
294307
if (typeof rawContent === "string") {
295308
serializedContent = rawContent;
@@ -312,10 +325,9 @@ export async function* convertTanStackStream(
312325
toolNamesById.delete(toolCallId);
313326
}
314327
// Unhandled chunk types are silently ignored.
315-
// Known gaps: STATE_DELTA and REASONING events are not yet converted from
316-
// TanStack streams. Shared state (STATE_SNAPSHOT) is now supported.
328+
// Known gap: REASONING events are not yet converted from TanStack streams.
317329
// Reasoning will not surface when using the TanStack backend.
318-
// Use the AI SDK backend if these features are required.
330+
// Use the AI SDK backend if reasoning is required.
319331
}
320332
}
321333

0 commit comments

Comments
 (0)