@copilotkit/runtime 1.75.2 → 1.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/agent/converters/aisdk.cjs +21 -9
  2. package/dist/agent/converters/aisdk.cjs.map +1 -1
  3. package/dist/agent/converters/aisdk.d.cts.map +1 -1
  4. package/dist/agent/converters/aisdk.d.mts.map +1 -1
  5. package/dist/agent/converters/aisdk.mjs +21 -10
  6. package/dist/agent/converters/aisdk.mjs.map +1 -1
  7. package/dist/agent/converters/tanstack.cjs +8 -6
  8. package/dist/agent/converters/tanstack.cjs.map +1 -1
  9. package/dist/agent/converters/tanstack.d.cts.map +1 -1
  10. package/dist/agent/converters/tanstack.d.mts.map +1 -1
  11. package/dist/agent/converters/tanstack.mjs +9 -7
  12. package/dist/agent/converters/tanstack.mjs.map +1 -1
  13. package/dist/agent/converters/usage.cjs +8 -2
  14. package/dist/agent/converters/usage.cjs.map +1 -1
  15. package/dist/agent/converters/usage.d.cts +3 -1
  16. package/dist/agent/converters/usage.d.cts.map +1 -1
  17. package/dist/agent/converters/usage.d.mts +3 -1
  18. package/dist/agent/converters/usage.d.mts.map +1 -1
  19. package/dist/agent/converters/usage.mjs +8 -2
  20. package/dist/agent/converters/usage.mjs.map +1 -1
  21. package/dist/agent/index.cjs +127 -34
  22. package/dist/agent/index.cjs.map +1 -1
  23. package/dist/agent/index.d.cts +18 -6
  24. package/dist/agent/index.d.cts.map +1 -1
  25. package/dist/agent/index.d.mts +18 -6
  26. package/dist/agent/index.d.mts.map +1 -1
  27. package/dist/agent/index.mjs +129 -36
  28. package/dist/agent/index.mjs.map +1 -1
  29. package/dist/agent/mcp-tool-names.cjs +84 -0
  30. package/dist/agent/mcp-tool-names.cjs.map +1 -0
  31. package/dist/agent/mcp-tool-names.mjs +81 -0
  32. package/dist/agent/mcp-tool-names.mjs.map +1 -0
  33. package/dist/lib/runtime/copilot-runtime.cjs +20 -9
  34. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  35. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  36. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  37. package/dist/lib/runtime/copilot-runtime.mjs +20 -9
  38. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  39. package/dist/package.cjs +6 -7
  40. package/dist/package.mjs +6 -7
  41. package/dist/v2/runtime/handlers/intelligence/connect.cjs +1 -0
  42. package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
  43. package/dist/v2/runtime/handlers/intelligence/connect.mjs +1 -0
  44. package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -1
  45. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +90 -4
  46. package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
  47. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +90 -4
  48. package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
  49. package/dist/v2/runtime/runner/in-memory.cjs +16 -1
  50. package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
  51. package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
  52. package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
  53. package/dist/v2/runtime/runner/in-memory.mjs +16 -1
  54. package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
  55. package/dist/v2/runtime/runner/intelligence.cjs +5 -2
  56. package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
  57. package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
  58. package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
  59. package/dist/v2/runtime/runner/intelligence.mjs +6 -3
  60. package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
  61. package/package.json +7 -10
@@ -12,7 +12,7 @@ let _ag_ui_client = require("@ag-ui/client");
12
12
  */
13
13
  function getAISDKRunFinishedDetails(part, identity = {}) {
14
14
  const details = {};
15
- if (typeof part.finishReason === "string") details.finishReason = part.finishReason;
15
+ if (typeof part.finishReason === "string") details.metadata = { finishReason: part.finishReason };
16
16
  if (part.totalUsage === null || typeof part.totalUsage !== "object" || Array.isArray(part.totalUsage)) return details;
17
17
  const totalUsage = part.totalUsage;
18
18
  const counts = {};
@@ -39,6 +39,21 @@ function formatToolError(error) {
39
39
  }
40
40
  }
41
41
  /**
42
+ * Returns the AG-UI message id for an AI SDK `text-start` / `reasoning-start`
43
+ * part.
44
+ *
45
+ * Several providers number stream parts per response instead of giving them
46
+ * a unique id: @ai-sdk/anthropic and @ai-sdk/google use a block counter
47
+ * ("0", "1", ...) and @ai-sdk/openai-compatible always uses "txt-0" /
48
+ * "reasoning-0". Those ids repeat on every step and every run, so reusing
49
+ * them would append later replies to an earlier message. Only ids that look
50
+ * unique are kept.
51
+ */
52
+ function resolveStreamPartMessageId(providedId) {
53
+ if (typeof providedId !== "string" || providedId === "" || /^(\d+|(txt|reasoning|msg)-0)$/.test(providedId)) return (0, _copilotkit_shared.randomUUID)();
54
+ return providedId;
55
+ }
56
+ /**
42
57
  * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.
43
58
  *
44
59
  * This is a pure converter — it does NOT emit lifecycle events
@@ -96,9 +111,8 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
96
111
  if (p.type !== "reasoning-delta") yield* closeReasoningIfOpen();
97
112
  switch (p.type) {
98
113
  case "abort": return;
99
- case "reasoning-start": {
100
- const providedId = "id" in p ? p.id : void 0;
101
- reasoningMessageId = providedId && providedId !== "0" ? providedId : (0, _copilotkit_shared.randomUUID)();
114
+ case "reasoning-start":
115
+ reasoningMessageId = resolveStreamPartMessageId("id" in p ? p.id : void 0);
102
116
  yield {
103
117
  type: _ag_ui_client.EventType.REASONING_START,
104
118
  messageId: reasoningMessageId
@@ -110,7 +124,6 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
110
124
  };
111
125
  isInReasoning = true;
112
126
  break;
113
- }
114
127
  case "reasoning-delta": {
115
128
  const delta = p.text ?? "";
116
129
  if (!delta) break;
@@ -149,11 +162,9 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
149
162
  break;
150
163
  }
151
164
  case "tool-input-end": break;
152
- case "text-start": {
153
- const providedId = "id" in p ? p.id : void 0;
154
- messageId = providedId && providedId !== "0" ? providedId : (0, _copilotkit_shared.randomUUID)();
165
+ case "text-start":
166
+ messageId = resolveStreamPartMessageId("id" in p ? p.id : void 0);
155
167
  break;
156
- }
157
168
  case "text-delta": {
158
169
  const textDelta = "text" in p ? p.text : "";
159
170
  yield {
@@ -341,4 +352,5 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
341
352
  exports.convertAISDKStream = convertAISDKStream;
342
353
  exports.formatToolError = formatToolError;
343
354
  exports.getAISDKRunFinishedDetails = getAISDKRunFinishedDetails;
355
+ exports.resolveStreamPartMessageId = resolveStreamPartMessageId;
344
356
  //# sourceMappingURL=aisdk.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"aisdk.cjs","names":["tokenCountKeys","getTokenCount","createStateEventNormalizer","EventType"],"sources":["../../../src/agent/converters/aisdk.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n ReasoningEndEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningMessageStartEvent,\n ReasoningStartEvent,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport { aggregateRunUsage, getTokenCount, tokenCountKeys } from \"./usage\";\nimport type { AgentRunFinishedDetails, AgentRunUsage } from \"./usage\";\n\n/**\n * Reads aggregate usage from an AI SDK finish part without inventing values\n * when a provider omits a token count.\n */\nexport function getAISDKRunFinishedDetails(\n part: Record<string, unknown>,\n identity: { provider?: string; model?: string } = {},\n): AgentRunFinishedDetails {\n const details: AgentRunFinishedDetails = {};\n\n if (typeof part.finishReason === \"string\") {\n details.finishReason = part.finishReason;\n }\n\n if (\n part.totalUsage === null ||\n typeof part.totalUsage !== \"object\" ||\n Array.isArray(part.totalUsage)\n ) {\n return details;\n }\n\n const totalUsage = part.totalUsage as Record<string, unknown>;\n const counts: AgentRunUsage = {};\n\n for (const key of tokenCountKeys) {\n const value = getTokenCount(totalUsage[key]);\n if (value !== undefined) {\n counts[key] = value;\n }\n }\n\n aggregateRunUsage(details, [{ ...identity, ...counts }]);\n\n return details;\n}\n\nexport function formatToolError(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n if (typeof error === \"string\") return error;\n if (error === undefined || error === null) return \"Unknown tool error\";\n\n try {\n const serialized = JSON.stringify(error);\n return serialized === undefined ? String(error) : serialized;\n } catch {\n return String(error);\n }\n}\n\n/**\n * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * Terminal stream events (finish, error, abort) cause the generator to\n * return so the caller can handle lifecycle appropriately.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * AI SDK `tool-approval-request` part (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertAISDKStream(\n fullStream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n let messageId = randomUUID();\n let reasoningMessageId = randomUUID();\n let isInReasoning = false;\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n const toolCallStates = new Map<\n string,\n {\n started: boolean;\n hasArgsDelta: boolean;\n ended: boolean;\n toolName?: string;\n }\n >();\n\n const ensureToolCallState = (toolCallId: string) => {\n let state = toolCallStates.get(toolCallId);\n if (!state) {\n state = { started: false, hasArgsDelta: false, ended: false };\n toolCallStates.set(toolCallId, state);\n }\n return state;\n };\n\n /**\n * Auto-close an open reasoning lifecycle.\n * Some AI SDK providers (notably @ai-sdk/anthropic) never emit \"reasoning-end\",\n * which leaves downstream state machines stuck. This helper emits the\n * missing REASONING_MESSAGE_END + REASONING_END events so the stream\n * can transition to text, tool-call, or finish phases.\n */\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (!isInReasoning) return;\n isInReasoning = false;\n const reasoningMsgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield reasoningMsgEnd;\n const reasoningEnd: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield reasoningEnd;\n }\n\n try {\n const warnedUnknownPartTypes = new Set<string>();\n for await (const part of fullStream) {\n const p = part as Record<string, unknown>;\n\n // Close any open reasoning lifecycle on every event except\n // reasoning-delta, which arrives mid-block and must not interrupt it.\n if (p.type !== \"reasoning-delta\") {\n yield* closeReasoningIfOpen();\n }\n\n switch (p.type) {\n case \"abort\": {\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"reasoning-start\": {\n // Use SDK-provided id, or generate a fresh UUID if id is falsy/\"0\"\n // to prevent consecutive reasoning blocks from sharing a messageId\n const providedId = \"id\" in p ? p.id : undefined;\n reasoningMessageId =\n providedId && providedId !== \"0\"\n ? (providedId as string)\n : randomUUID();\n const reasoningStartEvent: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield reasoningStartEvent;\n const reasoningMessageStart: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield reasoningMessageStart;\n isInReasoning = true;\n break;\n }\n\n case \"reasoning-delta\": {\n const delta = (p.text as string) ?? \"\";\n if (!delta) break; // skip — @ag-ui/core schema requires delta to be non-empty\n const reasoningDeltaEvent: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta,\n };\n yield reasoningDeltaEvent;\n break;\n }\n\n case \"reasoning-end\": {\n // closeReasoningIfOpen() already called before the switch — no-op here\n // if the SDK never emits this event (e.g. @ai-sdk/anthropic).\n break;\n }\n\n case \"tool-input-start\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = p.toolName as string;\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n break;\n }\n\n case \"tool-input-delta\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.hasArgsDelta = true;\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: p.delta as string,\n };\n yield argsEvent;\n break;\n }\n\n case \"tool-input-end\": {\n // No direct event – the subsequent \"tool-call\" part marks completion.\n break;\n }\n\n case \"text-start\": {\n // New text message starting - use the SDK-provided id\n // Use randomUUID() if part.id is falsy or \"0\" to prevent message merging issues\n const providedId = \"id\" in p ? p.id : undefined;\n messageId =\n providedId && providedId !== \"0\"\n ? (providedId as string)\n : randomUUID();\n break;\n }\n\n case \"text-delta\": {\n // AI SDK text-delta events use 'text' (not 'delta')\n const textDelta = \"text\" in p ? (p.text as string) : \"\";\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: textDelta,\n };\n yield textEvent;\n break;\n }\n\n case \"tool-call\": {\n const toolCallId = p.toolCallId as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = (p.toolName as string) ?? state.toolName;\n\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n\n if (!state.hasArgsDelta && \"input\" in p && p.input !== undefined) {\n let serializedInput = \"\";\n if (typeof p.input === \"string\") {\n serializedInput = p.input;\n } else {\n try {\n serializedInput = JSON.stringify(p.input);\n } catch {\n serializedInput = String(p.input);\n }\n }\n\n if (serializedInput.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serializedInput,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n break;\n }\n\n case \"tool-approval-request\": {\n // AI SDK native human-in-the-loop: a tool declared `needsApproval`\n // was called. The preceding \"tool-call\" part already streamed the\n // tool name + args; this part carries the toolCallId to pause on.\n // (Some shapes nest the call under `toolCall` — read both.)\n const nested = (p.toolCall ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n };\n const toolCallId =\n (p.toolCallId as string | undefined) ?? nested.toolCallId;\n if (!toolCallId) {\n throw new Error(\n \"AI SDK tool-approval-request is missing toolCallId\",\n );\n }\n const state = ensureToolCallState(toolCallId);\n const toolName = state.toolName ?? nested.toolName;\n\n // Defensive: emit the tool-call lifecycle if the \"tool-call\" part\n // didn't precede this one, so the assistant tool-call is in history\n // for the resume run (which keys the injected result by toolCallId).\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: toolName ?? \"\",\n };\n yield startEvent;\n }\n if (!state.hasArgsDelta && nested.input !== undefined) {\n let serialized = \"\";\n try {\n serialized =\n typeof nested.input === \"string\"\n ? nested.input\n : JSON.stringify(nested.input);\n } catch {\n serialized = String(nested.input);\n }\n if (serialized.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serialized,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: toolName ? `Approve \"${toolName}\"?` : undefined,\n ...(toolName ? { metadata: { toolName } } : {}),\n });\n break;\n }\n\n case \"tool-error\": {\n const toolCallId = p.toolCallId as string | undefined;\n if (!toolCallId) {\n throw new Error(\"AI SDK tool-error is missing toolCallId\");\n }\n\n // Interrupt tools do not execute on the server. Their result is\n // supplied by the human on the resume run, so suppress this part.\n if (\n pendingInterrupts?.some(\n (interrupt) => interrupt.toolCallId === toolCallId,\n )\n ) {\n toolCallStates.delete(toolCallId);\n break;\n }\n\n toolCallStates.delete(toolCallId);\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n // A tool exception is a tool result from the model's perspective.\n // Keeping the Error prefix consistent with the core tool runner\n // lets both the client and the next model step see the failure.\n content: `Error: ${formatToolError(p.error)}`,\n };\n yield resultEvent;\n break;\n }\n\n case \"tool-result\": {\n // AI SDK tool-result uses \"output\"; older versions used \"result\" — check both\n const toolResult =\n \"output\" in p ? p.output : \"result\" in p ? p.result : null;\n const toolName = \"toolName\" in p ? (p.toolName as string) : \"\";\n toolCallStates.delete(p.toolCallId as string);\n\n // Check if this is a state update tool\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const snapshot = (toolResult as Record<string, unknown>).snapshot;\n if (snapshot !== undefined) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n } else if (\n toolName === \"AGUISendStateDelta\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const delta = (toolResult as { delta?: StateDeltaEvent[\"delta\"] })\n .delta;\n if (delta !== undefined) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n }\n\n // Always emit the tool result event for the LLM\n let serializedResult: string;\n try {\n serializedResult = JSON.stringify(toolResult);\n } catch {\n serializedResult = `[Unserializable tool result from ${toolName || \"unknown tool\"}]`;\n }\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId: p.toolCallId as string,\n content: serializedResult,\n };\n yield resultEvent;\n break;\n }\n\n case \"finish\": {\n if (runFinishedDetails) {\n Object.assign(runFinishedDetails, getAISDKRunFinishedDetails(p));\n }\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"error\": {\n if (abortSignal.aborted) {\n return;\n }\n // Re-throw so the caller can emit RUN_ERROR\n const err = p.error ?? p.message ?? p.cause;\n if (err instanceof Error) throw err;\n throw new Error(\n typeof err === \"string\"\n ? err\n : `AI SDK stream error: ${JSON.stringify(p)}`,\n );\n }\n\n // These AI SDK fullStream parts carry metadata that has no AG-UI event\n // equivalent. They are known and intentionally ignored; listing them\n // keeps the default's warning for genuinely new parts.\n case \"start\":\n case \"start-step\":\n case \"finish-step\":\n case \"text-end\":\n case \"source\":\n case \"file\":\n case \"tool-output-denied\":\n case \"raw\":\n break;\n\n default: {\n // Parts come from the caller's own `ai` install, which can be newer\n // than ours. Warn once per type and keep the run alive.\n const unknownType = String(p.type);\n if (!warnedUnknownPartTypes.has(unknownType)) {\n warnedUnknownPartTypes.add(unknownType);\n console.warn(\n `[convertAISDKStream] Ignoring unhandled AI SDK stream part: ${unknownType}`,\n );\n }\n break;\n }\n }\n }\n } finally {\n // Always close reasoning on exit (normal or exceptional)\n yield* closeReasoningIfOpen();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"aisdk.cjs","names":["tokenCountKeys","getTokenCount","createStateEventNormalizer","EventType"],"sources":["../../../src/agent/converters/aisdk.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n ReasoningEndEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningMessageStartEvent,\n ReasoningStartEvent,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport { aggregateRunUsage, getTokenCount, tokenCountKeys } from \"./usage\";\nimport type { AgentRunFinishedDetails, AgentRunUsage } from \"./usage\";\n\n/**\n * Reads aggregate usage from an AI SDK finish part without inventing values\n * when a provider omits a token count.\n */\nexport function getAISDKRunFinishedDetails(\n part: Record<string, unknown>,\n identity: { provider?: string; model?: string } = {},\n): AgentRunFinishedDetails {\n const details: AgentRunFinishedDetails = {};\n\n if (typeof part.finishReason === \"string\") {\n details.metadata = { finishReason: part.finishReason };\n }\n\n if (\n part.totalUsage === null ||\n typeof part.totalUsage !== \"object\" ||\n Array.isArray(part.totalUsage)\n ) {\n return details;\n }\n\n const totalUsage = part.totalUsage as Record<string, unknown>;\n const counts: AgentRunUsage = {};\n\n for (const key of tokenCountKeys) {\n const value = getTokenCount(totalUsage[key]);\n if (value !== undefined) {\n counts[key] = value;\n }\n }\n\n aggregateRunUsage(details, [{ ...identity, ...counts }]);\n\n return details;\n}\n\nexport function formatToolError(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n if (typeof error === \"string\") return error;\n if (error === undefined || error === null) return \"Unknown tool error\";\n\n try {\n const serialized = JSON.stringify(error);\n return serialized === undefined ? String(error) : serialized;\n } catch {\n return String(error);\n }\n}\n\n/**\n * Returns the AG-UI message id for an AI SDK `text-start` / `reasoning-start`\n * part.\n *\n * Several providers number stream parts per response instead of giving them\n * a unique id: @ai-sdk/anthropic and @ai-sdk/google use a block counter\n * (\"0\", \"1\", ...) and @ai-sdk/openai-compatible always uses \"txt-0\" /\n * \"reasoning-0\". Those ids repeat on every step and every run, so reusing\n * them would append later replies to an earlier message. Only ids that look\n * unique are kept.\n */\nexport function resolveStreamPartMessageId(providedId: unknown): string {\n if (\n typeof providedId !== \"string\" ||\n providedId === \"\" ||\n /^(\\d+|(txt|reasoning|msg)-0)$/.test(providedId)\n ) {\n return randomUUID();\n }\n return providedId;\n}\n\n/**\n * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * Terminal stream events (finish, error, abort) cause the generator to\n * return so the caller can handle lifecycle appropriately.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * AI SDK `tool-approval-request` part (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertAISDKStream(\n fullStream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n let messageId = randomUUID();\n let reasoningMessageId = randomUUID();\n let isInReasoning = false;\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n const toolCallStates = new Map<\n string,\n {\n started: boolean;\n hasArgsDelta: boolean;\n ended: boolean;\n toolName?: string;\n }\n >();\n\n const ensureToolCallState = (toolCallId: string) => {\n let state = toolCallStates.get(toolCallId);\n if (!state) {\n state = { started: false, hasArgsDelta: false, ended: false };\n toolCallStates.set(toolCallId, state);\n }\n return state;\n };\n\n /**\n * Auto-close an open reasoning lifecycle.\n * Some AI SDK providers (notably @ai-sdk/anthropic) never emit \"reasoning-end\",\n * which leaves downstream state machines stuck. This helper emits the\n * missing REASONING_MESSAGE_END + REASONING_END events so the stream\n * can transition to text, tool-call, or finish phases.\n */\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (!isInReasoning) return;\n isInReasoning = false;\n const reasoningMsgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield reasoningMsgEnd;\n const reasoningEnd: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield reasoningEnd;\n }\n\n try {\n const warnedUnknownPartTypes = new Set<string>();\n for await (const part of fullStream) {\n const p = part as Record<string, unknown>;\n\n // Close any open reasoning lifecycle on every event except\n // reasoning-delta, which arrives mid-block and must not interrupt it.\n if (p.type !== \"reasoning-delta\") {\n yield* closeReasoningIfOpen();\n }\n\n switch (p.type) {\n case \"abort\": {\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"reasoning-start\": {\n reasoningMessageId = resolveStreamPartMessageId(\n \"id\" in p ? p.id : undefined,\n );\n const reasoningStartEvent: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield reasoningStartEvent;\n const reasoningMessageStart: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield reasoningMessageStart;\n isInReasoning = true;\n break;\n }\n\n case \"reasoning-delta\": {\n const delta = (p.text as string) ?? \"\";\n if (!delta) break; // skip — @ag-ui/core schema requires delta to be non-empty\n const reasoningDeltaEvent: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta,\n };\n yield reasoningDeltaEvent;\n break;\n }\n\n case \"reasoning-end\": {\n // closeReasoningIfOpen() already called before the switch — no-op here\n // if the SDK never emits this event (e.g. @ai-sdk/anthropic).\n break;\n }\n\n case \"tool-input-start\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = p.toolName as string;\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n break;\n }\n\n case \"tool-input-delta\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.hasArgsDelta = true;\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: p.delta as string,\n };\n yield argsEvent;\n break;\n }\n\n case \"tool-input-end\": {\n // No direct event – the subsequent \"tool-call\" part marks completion.\n break;\n }\n\n case \"text-start\": {\n messageId = resolveStreamPartMessageId(\"id\" in p ? p.id : undefined);\n break;\n }\n\n case \"text-delta\": {\n // AI SDK text-delta events use 'text' (not 'delta')\n const textDelta = \"text\" in p ? (p.text as string) : \"\";\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: textDelta,\n };\n yield textEvent;\n break;\n }\n\n case \"tool-call\": {\n const toolCallId = p.toolCallId as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = (p.toolName as string) ?? state.toolName;\n\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n\n if (!state.hasArgsDelta && \"input\" in p && p.input !== undefined) {\n let serializedInput = \"\";\n if (typeof p.input === \"string\") {\n serializedInput = p.input;\n } else {\n try {\n serializedInput = JSON.stringify(p.input);\n } catch {\n serializedInput = String(p.input);\n }\n }\n\n if (serializedInput.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serializedInput,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n break;\n }\n\n case \"tool-approval-request\": {\n // AI SDK native human-in-the-loop: a tool declared `needsApproval`\n // was called. The preceding \"tool-call\" part already streamed the\n // tool name + args; this part carries the toolCallId to pause on.\n // (Some shapes nest the call under `toolCall` — read both.)\n const nested = (p.toolCall ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n };\n const toolCallId =\n (p.toolCallId as string | undefined) ?? nested.toolCallId;\n if (!toolCallId) {\n throw new Error(\n \"AI SDK tool-approval-request is missing toolCallId\",\n );\n }\n const state = ensureToolCallState(toolCallId);\n const toolName = state.toolName ?? nested.toolName;\n\n // Defensive: emit the tool-call lifecycle if the \"tool-call\" part\n // didn't precede this one, so the assistant tool-call is in history\n // for the resume run (which keys the injected result by toolCallId).\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: toolName ?? \"\",\n };\n yield startEvent;\n }\n if (!state.hasArgsDelta && nested.input !== undefined) {\n let serialized = \"\";\n try {\n serialized =\n typeof nested.input === \"string\"\n ? nested.input\n : JSON.stringify(nested.input);\n } catch {\n serialized = String(nested.input);\n }\n if (serialized.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serialized,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: toolName ? `Approve \"${toolName}\"?` : undefined,\n ...(toolName ? { metadata: { toolName } } : {}),\n });\n break;\n }\n\n case \"tool-error\": {\n const toolCallId = p.toolCallId as string | undefined;\n if (!toolCallId) {\n throw new Error(\"AI SDK tool-error is missing toolCallId\");\n }\n\n // Interrupt tools do not execute on the server. Their result is\n // supplied by the human on the resume run, so suppress this part.\n if (\n pendingInterrupts?.some(\n (interrupt) => interrupt.toolCallId === toolCallId,\n )\n ) {\n toolCallStates.delete(toolCallId);\n break;\n }\n\n toolCallStates.delete(toolCallId);\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n // A tool exception is a tool result from the model's perspective.\n // Keeping the Error prefix consistent with the core tool runner\n // lets both the client and the next model step see the failure.\n content: `Error: ${formatToolError(p.error)}`,\n };\n yield resultEvent;\n break;\n }\n\n case \"tool-result\": {\n // AI SDK tool-result uses \"output\"; older versions used \"result\" — check both\n const toolResult =\n \"output\" in p ? p.output : \"result\" in p ? p.result : null;\n const toolName = \"toolName\" in p ? (p.toolName as string) : \"\";\n toolCallStates.delete(p.toolCallId as string);\n\n // Check if this is a state update tool\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const snapshot = (toolResult as Record<string, unknown>).snapshot;\n if (snapshot !== undefined) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n } else if (\n toolName === \"AGUISendStateDelta\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const delta = (toolResult as { delta?: StateDeltaEvent[\"delta\"] })\n .delta;\n if (delta !== undefined) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n }\n\n // Always emit the tool result event for the LLM\n let serializedResult: string;\n try {\n serializedResult = JSON.stringify(toolResult);\n } catch {\n serializedResult = `[Unserializable tool result from ${toolName || \"unknown tool\"}]`;\n }\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId: p.toolCallId as string,\n content: serializedResult,\n };\n yield resultEvent;\n break;\n }\n\n case \"finish\": {\n if (runFinishedDetails) {\n Object.assign(runFinishedDetails, getAISDKRunFinishedDetails(p));\n }\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"error\": {\n if (abortSignal.aborted) {\n return;\n }\n // Re-throw so the caller can emit RUN_ERROR\n const err = p.error ?? p.message ?? p.cause;\n if (err instanceof Error) throw err;\n throw new Error(\n typeof err === \"string\"\n ? err\n : `AI SDK stream error: ${JSON.stringify(p)}`,\n );\n }\n\n // These AI SDK fullStream parts carry metadata that has no AG-UI event\n // equivalent. They are known and intentionally ignored; listing them\n // keeps the default's warning for genuinely new parts.\n case \"start\":\n case \"start-step\":\n case \"finish-step\":\n case \"text-end\":\n case \"source\":\n case \"file\":\n case \"tool-output-denied\":\n case \"raw\":\n break;\n\n default: {\n // Parts come from the caller's own `ai` install, which can be newer\n // than ours. Warn once per type and keep the run alive.\n const unknownType = String(p.type);\n if (!warnedUnknownPartTypes.has(unknownType)) {\n warnedUnknownPartTypes.add(unknownType);\n console.warn(\n `[convertAISDKStream] Ignoring unhandled AI SDK stream part: ${unknownType}`,\n );\n }\n break;\n }\n }\n }\n } finally {\n // Always close reasoning on exit (normal or exceptional)\n yield* closeReasoningIfOpen();\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"aisdk.d.cts","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBA8FuB,kBAAA,CACrB,UAAA,EAAY,aAAA,WACZ,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
1
+ {"version":3,"file":"aisdk.d.cts","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAoHuB,kBAAA,CACrB,UAAA,EAAY,aAAA,WACZ,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"aisdk.d.mts","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBA8FuB,kBAAA,CACrB,UAAA,EAAY,aAAA,WACZ,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
1
+ {"version":3,"file":"aisdk.d.mts","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAoHuB,kBAAA,CACrB,UAAA,EAAY,aAAA,WACZ,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
@@ -11,7 +11,7 @@ import { EventType } from "@ag-ui/client";
11
11
  */
12
12
  function getAISDKRunFinishedDetails(part, identity = {}) {
13
13
  const details = {};
14
- if (typeof part.finishReason === "string") details.finishReason = part.finishReason;
14
+ if (typeof part.finishReason === "string") details.metadata = { finishReason: part.finishReason };
15
15
  if (part.totalUsage === null || typeof part.totalUsage !== "object" || Array.isArray(part.totalUsage)) return details;
16
16
  const totalUsage = part.totalUsage;
17
17
  const counts = {};
@@ -38,6 +38,21 @@ function formatToolError(error) {
38
38
  }
39
39
  }
40
40
  /**
41
+ * Returns the AG-UI message id for an AI SDK `text-start` / `reasoning-start`
42
+ * part.
43
+ *
44
+ * Several providers number stream parts per response instead of giving them
45
+ * a unique id: @ai-sdk/anthropic and @ai-sdk/google use a block counter
46
+ * ("0", "1", ...) and @ai-sdk/openai-compatible always uses "txt-0" /
47
+ * "reasoning-0". Those ids repeat on every step and every run, so reusing
48
+ * them would append later replies to an earlier message. Only ids that look
49
+ * unique are kept.
50
+ */
51
+ function resolveStreamPartMessageId(providedId) {
52
+ if (typeof providedId !== "string" || providedId === "" || /^(\d+|(txt|reasoning|msg)-0)$/.test(providedId)) return randomUUID();
53
+ return providedId;
54
+ }
55
+ /**
41
56
  * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.
42
57
  *
43
58
  * This is a pure converter — it does NOT emit lifecycle events
@@ -95,9 +110,8 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
95
110
  if (p.type !== "reasoning-delta") yield* closeReasoningIfOpen();
96
111
  switch (p.type) {
97
112
  case "abort": return;
98
- case "reasoning-start": {
99
- const providedId = "id" in p ? p.id : void 0;
100
- reasoningMessageId = providedId && providedId !== "0" ? providedId : randomUUID();
113
+ case "reasoning-start":
114
+ reasoningMessageId = resolveStreamPartMessageId("id" in p ? p.id : void 0);
101
115
  yield {
102
116
  type: EventType.REASONING_START,
103
117
  messageId: reasoningMessageId
@@ -109,7 +123,6 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
109
123
  };
110
124
  isInReasoning = true;
111
125
  break;
112
- }
113
126
  case "reasoning-delta": {
114
127
  const delta = p.text ?? "";
115
128
  if (!delta) break;
@@ -148,11 +161,9 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
148
161
  break;
149
162
  }
150
163
  case "tool-input-end": break;
151
- case "text-start": {
152
- const providedId = "id" in p ? p.id : void 0;
153
- messageId = providedId && providedId !== "0" ? providedId : randomUUID();
164
+ case "text-start":
165
+ messageId = resolveStreamPartMessageId("id" in p ? p.id : void 0);
154
166
  break;
155
- }
156
167
  case "text-delta": {
157
168
  const textDelta = "text" in p ? p.text : "";
158
169
  yield {
@@ -337,5 +348,5 @@ async function* convertAISDKStream(fullStream, abortSignal, pendingInterrupts, i
337
348
  }
338
349
 
339
350
  //#endregion
340
- export { convertAISDKStream, formatToolError, getAISDKRunFinishedDetails };
351
+ export { convertAISDKStream, formatToolError, getAISDKRunFinishedDetails, resolveStreamPartMessageId };
341
352
  //# sourceMappingURL=aisdk.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"aisdk.mjs","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n ReasoningEndEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningMessageStartEvent,\n ReasoningStartEvent,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport { aggregateRunUsage, getTokenCount, tokenCountKeys } from \"./usage\";\nimport type { AgentRunFinishedDetails, AgentRunUsage } from \"./usage\";\n\n/**\n * Reads aggregate usage from an AI SDK finish part without inventing values\n * when a provider omits a token count.\n */\nexport function getAISDKRunFinishedDetails(\n part: Record<string, unknown>,\n identity: { provider?: string; model?: string } = {},\n): AgentRunFinishedDetails {\n const details: AgentRunFinishedDetails = {};\n\n if (typeof part.finishReason === \"string\") {\n details.finishReason = part.finishReason;\n }\n\n if (\n part.totalUsage === null ||\n typeof part.totalUsage !== \"object\" ||\n Array.isArray(part.totalUsage)\n ) {\n return details;\n }\n\n const totalUsage = part.totalUsage as Record<string, unknown>;\n const counts: AgentRunUsage = {};\n\n for (const key of tokenCountKeys) {\n const value = getTokenCount(totalUsage[key]);\n if (value !== undefined) {\n counts[key] = value;\n }\n }\n\n aggregateRunUsage(details, [{ ...identity, ...counts }]);\n\n return details;\n}\n\nexport function formatToolError(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n if (typeof error === \"string\") return error;\n if (error === undefined || error === null) return \"Unknown tool error\";\n\n try {\n const serialized = JSON.stringify(error);\n return serialized === undefined ? String(error) : serialized;\n } catch {\n return String(error);\n }\n}\n\n/**\n * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * Terminal stream events (finish, error, abort) cause the generator to\n * return so the caller can handle lifecycle appropriately.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * AI SDK `tool-approval-request` part (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertAISDKStream(\n fullStream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n let messageId = randomUUID();\n let reasoningMessageId = randomUUID();\n let isInReasoning = false;\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n const toolCallStates = new Map<\n string,\n {\n started: boolean;\n hasArgsDelta: boolean;\n ended: boolean;\n toolName?: string;\n }\n >();\n\n const ensureToolCallState = (toolCallId: string) => {\n let state = toolCallStates.get(toolCallId);\n if (!state) {\n state = { started: false, hasArgsDelta: false, ended: false };\n toolCallStates.set(toolCallId, state);\n }\n return state;\n };\n\n /**\n * Auto-close an open reasoning lifecycle.\n * Some AI SDK providers (notably @ai-sdk/anthropic) never emit \"reasoning-end\",\n * which leaves downstream state machines stuck. This helper emits the\n * missing REASONING_MESSAGE_END + REASONING_END events so the stream\n * can transition to text, tool-call, or finish phases.\n */\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (!isInReasoning) return;\n isInReasoning = false;\n const reasoningMsgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield reasoningMsgEnd;\n const reasoningEnd: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield reasoningEnd;\n }\n\n try {\n const warnedUnknownPartTypes = new Set<string>();\n for await (const part of fullStream) {\n const p = part as Record<string, unknown>;\n\n // Close any open reasoning lifecycle on every event except\n // reasoning-delta, which arrives mid-block and must not interrupt it.\n if (p.type !== \"reasoning-delta\") {\n yield* closeReasoningIfOpen();\n }\n\n switch (p.type) {\n case \"abort\": {\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"reasoning-start\": {\n // Use SDK-provided id, or generate a fresh UUID if id is falsy/\"0\"\n // to prevent consecutive reasoning blocks from sharing a messageId\n const providedId = \"id\" in p ? p.id : undefined;\n reasoningMessageId =\n providedId && providedId !== \"0\"\n ? (providedId as string)\n : randomUUID();\n const reasoningStartEvent: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield reasoningStartEvent;\n const reasoningMessageStart: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield reasoningMessageStart;\n isInReasoning = true;\n break;\n }\n\n case \"reasoning-delta\": {\n const delta = (p.text as string) ?? \"\";\n if (!delta) break; // skip — @ag-ui/core schema requires delta to be non-empty\n const reasoningDeltaEvent: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta,\n };\n yield reasoningDeltaEvent;\n break;\n }\n\n case \"reasoning-end\": {\n // closeReasoningIfOpen() already called before the switch — no-op here\n // if the SDK never emits this event (e.g. @ai-sdk/anthropic).\n break;\n }\n\n case \"tool-input-start\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = p.toolName as string;\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n break;\n }\n\n case \"tool-input-delta\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.hasArgsDelta = true;\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: p.delta as string,\n };\n yield argsEvent;\n break;\n }\n\n case \"tool-input-end\": {\n // No direct event – the subsequent \"tool-call\" part marks completion.\n break;\n }\n\n case \"text-start\": {\n // New text message starting - use the SDK-provided id\n // Use randomUUID() if part.id is falsy or \"0\" to prevent message merging issues\n const providedId = \"id\" in p ? p.id : undefined;\n messageId =\n providedId && providedId !== \"0\"\n ? (providedId as string)\n : randomUUID();\n break;\n }\n\n case \"text-delta\": {\n // AI SDK text-delta events use 'text' (not 'delta')\n const textDelta = \"text\" in p ? (p.text as string) : \"\";\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: textDelta,\n };\n yield textEvent;\n break;\n }\n\n case \"tool-call\": {\n const toolCallId = p.toolCallId as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = (p.toolName as string) ?? state.toolName;\n\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n\n if (!state.hasArgsDelta && \"input\" in p && p.input !== undefined) {\n let serializedInput = \"\";\n if (typeof p.input === \"string\") {\n serializedInput = p.input;\n } else {\n try {\n serializedInput = JSON.stringify(p.input);\n } catch {\n serializedInput = String(p.input);\n }\n }\n\n if (serializedInput.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serializedInput,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n break;\n }\n\n case \"tool-approval-request\": {\n // AI SDK native human-in-the-loop: a tool declared `needsApproval`\n // was called. The preceding \"tool-call\" part already streamed the\n // tool name + args; this part carries the toolCallId to pause on.\n // (Some shapes nest the call under `toolCall` — read both.)\n const nested = (p.toolCall ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n };\n const toolCallId =\n (p.toolCallId as string | undefined) ?? nested.toolCallId;\n if (!toolCallId) {\n throw new Error(\n \"AI SDK tool-approval-request is missing toolCallId\",\n );\n }\n const state = ensureToolCallState(toolCallId);\n const toolName = state.toolName ?? nested.toolName;\n\n // Defensive: emit the tool-call lifecycle if the \"tool-call\" part\n // didn't precede this one, so the assistant tool-call is in history\n // for the resume run (which keys the injected result by toolCallId).\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: toolName ?? \"\",\n };\n yield startEvent;\n }\n if (!state.hasArgsDelta && nested.input !== undefined) {\n let serialized = \"\";\n try {\n serialized =\n typeof nested.input === \"string\"\n ? nested.input\n : JSON.stringify(nested.input);\n } catch {\n serialized = String(nested.input);\n }\n if (serialized.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serialized,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: toolName ? `Approve \"${toolName}\"?` : undefined,\n ...(toolName ? { metadata: { toolName } } : {}),\n });\n break;\n }\n\n case \"tool-error\": {\n const toolCallId = p.toolCallId as string | undefined;\n if (!toolCallId) {\n throw new Error(\"AI SDK tool-error is missing toolCallId\");\n }\n\n // Interrupt tools do not execute on the server. Their result is\n // supplied by the human on the resume run, so suppress this part.\n if (\n pendingInterrupts?.some(\n (interrupt) => interrupt.toolCallId === toolCallId,\n )\n ) {\n toolCallStates.delete(toolCallId);\n break;\n }\n\n toolCallStates.delete(toolCallId);\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n // A tool exception is a tool result from the model's perspective.\n // Keeping the Error prefix consistent with the core tool runner\n // lets both the client and the next model step see the failure.\n content: `Error: ${formatToolError(p.error)}`,\n };\n yield resultEvent;\n break;\n }\n\n case \"tool-result\": {\n // AI SDK tool-result uses \"output\"; older versions used \"result\" — check both\n const toolResult =\n \"output\" in p ? p.output : \"result\" in p ? p.result : null;\n const toolName = \"toolName\" in p ? (p.toolName as string) : \"\";\n toolCallStates.delete(p.toolCallId as string);\n\n // Check if this is a state update tool\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const snapshot = (toolResult as Record<string, unknown>).snapshot;\n if (snapshot !== undefined) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n } else if (\n toolName === \"AGUISendStateDelta\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const delta = (toolResult as { delta?: StateDeltaEvent[\"delta\"] })\n .delta;\n if (delta !== undefined) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n }\n\n // Always emit the tool result event for the LLM\n let serializedResult: string;\n try {\n serializedResult = JSON.stringify(toolResult);\n } catch {\n serializedResult = `[Unserializable tool result from ${toolName || \"unknown tool\"}]`;\n }\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId: p.toolCallId as string,\n content: serializedResult,\n };\n yield resultEvent;\n break;\n }\n\n case \"finish\": {\n if (runFinishedDetails) {\n Object.assign(runFinishedDetails, getAISDKRunFinishedDetails(p));\n }\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"error\": {\n if (abortSignal.aborted) {\n return;\n }\n // Re-throw so the caller can emit RUN_ERROR\n const err = p.error ?? p.message ?? p.cause;\n if (err instanceof Error) throw err;\n throw new Error(\n typeof err === \"string\"\n ? err\n : `AI SDK stream error: ${JSON.stringify(p)}`,\n );\n }\n\n // These AI SDK fullStream parts carry metadata that has no AG-UI event\n // equivalent. They are known and intentionally ignored; listing them\n // keeps the default's warning for genuinely new parts.\n case \"start\":\n case \"start-step\":\n case \"finish-step\":\n case \"text-end\":\n case \"source\":\n case \"file\":\n case \"tool-output-denied\":\n case \"raw\":\n break;\n\n default: {\n // Parts come from the caller's own `ai` install, which can be newer\n // than ours. Warn once per type and keep the run alive.\n const unknownType = String(p.type);\n if (!warnedUnknownPartTypes.has(unknownType)) {\n warnedUnknownPartTypes.add(unknownType);\n console.warn(\n `[convertAISDKStream] Ignoring unhandled AI SDK stream part: ${unknownType}`,\n );\n }\n break;\n }\n }\n }\n } finally {\n // Always close reasoning on exit (normal or exceptional)\n yield* closeReasoningIfOpen();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"aisdk.mjs","names":[],"sources":["../../../src/agent/converters/aisdk.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n ReasoningEndEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningMessageStartEvent,\n ReasoningStartEvent,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport { aggregateRunUsage, getTokenCount, tokenCountKeys } from \"./usage\";\nimport type { AgentRunFinishedDetails, AgentRunUsage } from \"./usage\";\n\n/**\n * Reads aggregate usage from an AI SDK finish part without inventing values\n * when a provider omits a token count.\n */\nexport function getAISDKRunFinishedDetails(\n part: Record<string, unknown>,\n identity: { provider?: string; model?: string } = {},\n): AgentRunFinishedDetails {\n const details: AgentRunFinishedDetails = {};\n\n if (typeof part.finishReason === \"string\") {\n details.metadata = { finishReason: part.finishReason };\n }\n\n if (\n part.totalUsage === null ||\n typeof part.totalUsage !== \"object\" ||\n Array.isArray(part.totalUsage)\n ) {\n return details;\n }\n\n const totalUsage = part.totalUsage as Record<string, unknown>;\n const counts: AgentRunUsage = {};\n\n for (const key of tokenCountKeys) {\n const value = getTokenCount(totalUsage[key]);\n if (value !== undefined) {\n counts[key] = value;\n }\n }\n\n aggregateRunUsage(details, [{ ...identity, ...counts }]);\n\n return details;\n}\n\nexport function formatToolError(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n if (typeof error === \"string\") return error;\n if (error === undefined || error === null) return \"Unknown tool error\";\n\n try {\n const serialized = JSON.stringify(error);\n return serialized === undefined ? String(error) : serialized;\n } catch {\n return String(error);\n }\n}\n\n/**\n * Returns the AG-UI message id for an AI SDK `text-start` / `reasoning-start`\n * part.\n *\n * Several providers number stream parts per response instead of giving them\n * a unique id: @ai-sdk/anthropic and @ai-sdk/google use a block counter\n * (\"0\", \"1\", ...) and @ai-sdk/openai-compatible always uses \"txt-0\" /\n * \"reasoning-0\". Those ids repeat on every step and every run, so reusing\n * them would append later replies to an earlier message. Only ids that look\n * unique are kept.\n */\nexport function resolveStreamPartMessageId(providedId: unknown): string {\n if (\n typeof providedId !== \"string\" ||\n providedId === \"\" ||\n /^(\\d+|(txt|reasoning|msg)-0)$/.test(providedId)\n ) {\n return randomUUID();\n }\n return providedId;\n}\n\n/**\n * Converts an AI SDK `fullStream` into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * Terminal stream events (finish, error, abort) cause the generator to\n * return so the caller can handle lifecycle appropriately.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * AI SDK `tool-approval-request` part (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertAISDKStream(\n fullStream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n let messageId = randomUUID();\n let reasoningMessageId = randomUUID();\n let isInReasoning = false;\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n const toolCallStates = new Map<\n string,\n {\n started: boolean;\n hasArgsDelta: boolean;\n ended: boolean;\n toolName?: string;\n }\n >();\n\n const ensureToolCallState = (toolCallId: string) => {\n let state = toolCallStates.get(toolCallId);\n if (!state) {\n state = { started: false, hasArgsDelta: false, ended: false };\n toolCallStates.set(toolCallId, state);\n }\n return state;\n };\n\n /**\n * Auto-close an open reasoning lifecycle.\n * Some AI SDK providers (notably @ai-sdk/anthropic) never emit \"reasoning-end\",\n * which leaves downstream state machines stuck. This helper emits the\n * missing REASONING_MESSAGE_END + REASONING_END events so the stream\n * can transition to text, tool-call, or finish phases.\n */\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (!isInReasoning) return;\n isInReasoning = false;\n const reasoningMsgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield reasoningMsgEnd;\n const reasoningEnd: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield reasoningEnd;\n }\n\n try {\n const warnedUnknownPartTypes = new Set<string>();\n for await (const part of fullStream) {\n const p = part as Record<string, unknown>;\n\n // Close any open reasoning lifecycle on every event except\n // reasoning-delta, which arrives mid-block and must not interrupt it.\n if (p.type !== \"reasoning-delta\") {\n yield* closeReasoningIfOpen();\n }\n\n switch (p.type) {\n case \"abort\": {\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"reasoning-start\": {\n reasoningMessageId = resolveStreamPartMessageId(\n \"id\" in p ? p.id : undefined,\n );\n const reasoningStartEvent: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield reasoningStartEvent;\n const reasoningMessageStart: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield reasoningMessageStart;\n isInReasoning = true;\n break;\n }\n\n case \"reasoning-delta\": {\n const delta = (p.text as string) ?? \"\";\n if (!delta) break; // skip — @ag-ui/core schema requires delta to be non-empty\n const reasoningDeltaEvent: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta,\n };\n yield reasoningDeltaEvent;\n break;\n }\n\n case \"reasoning-end\": {\n // closeReasoningIfOpen() already called before the switch — no-op here\n // if the SDK never emits this event (e.g. @ai-sdk/anthropic).\n break;\n }\n\n case \"tool-input-start\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = p.toolName as string;\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n break;\n }\n\n case \"tool-input-delta\": {\n const toolCallId = p.id as string;\n const state = ensureToolCallState(toolCallId);\n state.hasArgsDelta = true;\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: p.delta as string,\n };\n yield argsEvent;\n break;\n }\n\n case \"tool-input-end\": {\n // No direct event – the subsequent \"tool-call\" part marks completion.\n break;\n }\n\n case \"text-start\": {\n messageId = resolveStreamPartMessageId(\"id\" in p ? p.id : undefined);\n break;\n }\n\n case \"text-delta\": {\n // AI SDK text-delta events use 'text' (not 'delta')\n const textDelta = \"text\" in p ? (p.text as string) : \"\";\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: textDelta,\n };\n yield textEvent;\n break;\n }\n\n case \"tool-call\": {\n const toolCallId = p.toolCallId as string;\n const state = ensureToolCallState(toolCallId);\n state.toolName = (p.toolName as string) ?? state.toolName;\n\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: p.toolName as string,\n };\n yield startEvent;\n }\n\n if (!state.hasArgsDelta && \"input\" in p && p.input !== undefined) {\n let serializedInput = \"\";\n if (typeof p.input === \"string\") {\n serializedInput = p.input;\n } else {\n try {\n serializedInput = JSON.stringify(p.input);\n } catch {\n serializedInput = String(p.input);\n }\n }\n\n if (serializedInput.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serializedInput,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n break;\n }\n\n case \"tool-approval-request\": {\n // AI SDK native human-in-the-loop: a tool declared `needsApproval`\n // was called. The preceding \"tool-call\" part already streamed the\n // tool name + args; this part carries the toolCallId to pause on.\n // (Some shapes nest the call under `toolCall` — read both.)\n const nested = (p.toolCall ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n };\n const toolCallId =\n (p.toolCallId as string | undefined) ?? nested.toolCallId;\n if (!toolCallId) {\n throw new Error(\n \"AI SDK tool-approval-request is missing toolCallId\",\n );\n }\n const state = ensureToolCallState(toolCallId);\n const toolName = state.toolName ?? nested.toolName;\n\n // Defensive: emit the tool-call lifecycle if the \"tool-call\" part\n // didn't precede this one, so the assistant tool-call is in history\n // for the resume run (which keys the injected result by toolCallId).\n if (!state.started) {\n state.started = true;\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: toolName ?? \"\",\n };\n yield startEvent;\n }\n if (!state.hasArgsDelta && nested.input !== undefined) {\n let serialized = \"\";\n try {\n serialized =\n typeof nested.input === \"string\"\n ? nested.input\n : JSON.stringify(nested.input);\n } catch {\n serialized = String(nested.input);\n }\n if (serialized.length > 0) {\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId,\n delta: serialized,\n };\n yield argsEvent;\n state.hasArgsDelta = true;\n }\n }\n if (!state.ended) {\n state.ended = true;\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n }\n\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: toolName ? `Approve \"${toolName}\"?` : undefined,\n ...(toolName ? { metadata: { toolName } } : {}),\n });\n break;\n }\n\n case \"tool-error\": {\n const toolCallId = p.toolCallId as string | undefined;\n if (!toolCallId) {\n throw new Error(\"AI SDK tool-error is missing toolCallId\");\n }\n\n // Interrupt tools do not execute on the server. Their result is\n // supplied by the human on the resume run, so suppress this part.\n if (\n pendingInterrupts?.some(\n (interrupt) => interrupt.toolCallId === toolCallId,\n )\n ) {\n toolCallStates.delete(toolCallId);\n break;\n }\n\n toolCallStates.delete(toolCallId);\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n // A tool exception is a tool result from the model's perspective.\n // Keeping the Error prefix consistent with the core tool runner\n // lets both the client and the next model step see the failure.\n content: `Error: ${formatToolError(p.error)}`,\n };\n yield resultEvent;\n break;\n }\n\n case \"tool-result\": {\n // AI SDK tool-result uses \"output\"; older versions used \"result\" — check both\n const toolResult =\n \"output\" in p ? p.output : \"result\" in p ? p.result : null;\n const toolName = \"toolName\" in p ? (p.toolName as string) : \"\";\n toolCallStates.delete(p.toolCallId as string);\n\n // Check if this is a state update tool\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const snapshot = (toolResult as Record<string, unknown>).snapshot;\n if (snapshot !== undefined) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n } else if (\n toolName === \"AGUISendStateDelta\" &&\n toolResult &&\n typeof toolResult === \"object\"\n ) {\n const delta = (toolResult as { delta?: StateDeltaEvent[\"delta\"] })\n .delta;\n if (delta !== undefined) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n }\n\n // Always emit the tool result event for the LLM\n let serializedResult: string;\n try {\n serializedResult = JSON.stringify(toolResult);\n } catch {\n serializedResult = `[Unserializable tool result from ${toolName || \"unknown tool\"}]`;\n }\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId: p.toolCallId as string,\n content: serializedResult,\n };\n yield resultEvent;\n break;\n }\n\n case \"finish\": {\n if (runFinishedDetails) {\n Object.assign(runFinishedDetails, getAISDKRunFinishedDetails(p));\n }\n // Terminal — let the caller handle lifecycle\n return;\n }\n\n case \"error\": {\n if (abortSignal.aborted) {\n return;\n }\n // Re-throw so the caller can emit RUN_ERROR\n const err = p.error ?? p.message ?? p.cause;\n if (err instanceof Error) throw err;\n throw new Error(\n typeof err === \"string\"\n ? err\n : `AI SDK stream error: ${JSON.stringify(p)}`,\n );\n }\n\n // These AI SDK fullStream parts carry metadata that has no AG-UI event\n // equivalent. They are known and intentionally ignored; listing them\n // keeps the default's warning for genuinely new parts.\n case \"start\":\n case \"start-step\":\n case \"finish-step\":\n case \"text-end\":\n case \"source\":\n case \"file\":\n case \"tool-output-denied\":\n case \"raw\":\n break;\n\n default: {\n // Parts come from the caller's own `ai` install, which can be newer\n // than ours. Warn once per type and keep the run alive.\n const unknownType = String(p.type);\n if (!warnedUnknownPartTypes.has(unknownType)) {\n warnedUnknownPartTypes.add(unknownType);\n console.warn(\n `[convertAISDKStream] Ignoring unhandled AI SDK stream part: ${unknownType}`,\n );\n }\n break;\n }\n }\n }\n } finally {\n // Always close reasoning on exit (normal or exceptional)\n yield* closeReasoningIfOpen();\n }\n}\n"],"mappings":"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"}
@@ -43,6 +43,7 @@ function convertUserContent(content) {
43
43
  mimeType: source.mimeType
44
44
  }
45
45
  });
46
+ else if (source.type === "file") console.warn(`[CopilotKit] Dropping a ${partType} part that references a provider file handle: it is not a URL or inline data, so it cannot be sent to the model here.`);
46
47
  else if (source.type === "url") parts.push({
47
48
  type: partType,
48
49
  source: {
@@ -133,7 +134,7 @@ function convertInputToTanStackAI(input) {
133
134
  const messages = input.messages.filter((m) => chatRoles.has(m.role)).map((m) => {
134
135
  const msg = {
135
136
  role: m.role,
136
- content: m.role === "user" ? convertUserContent(m.content) : typeof m.content === "string" ? m.content : null
137
+ content: m.role === "user" ? convertUserContent(m.content) : m.role === "tool" ? (0, _ag_ui_client.contentToText)(m.content) : typeof m.content === "string" ? m.content : null
137
138
  };
138
139
  if (m.role === "assistant" && "toolCalls" in m && m.toolCalls) msg.toolCalls = m.toolCalls.map((tc) => ({
139
140
  id: tc.id,
@@ -337,16 +338,17 @@ async function* convertTanStackStream(stream, abortSignal, pendingInterrupts, in
337
338
  /** Normalizes legacy and standard TanStack usage into AG-UI token usage. */
338
339
  function collectTanStackRunFinishedDetails(event, details) {
339
340
  if (!details) return;
340
- if (typeof event.finishReason === "string") details.finishReason = event.finishReason;
341
341
  const fallbackIdentity = {
342
342
  provider: require_usage.getNonEmptyString(event.provider),
343
343
  model: require_usage.getNonEmptyString(event.model)
344
344
  };
345
+ require_usage.collectStandardRunFinishedDetails(event, details, fallbackIdentity);
346
+ if (typeof event.finishReason === "string") details.metadata = {
347
+ ...details.metadata,
348
+ finishReason: event.finishReason
349
+ };
345
350
  const usage = event.usage;
346
- if (Array.isArray(usage)) {
347
- require_usage.collectStandardRunFinishedDetails(event, details, fallbackIdentity);
348
- return;
349
- }
351
+ if (Array.isArray(usage)) return;
350
352
  if (!require_usage.isRecord(usage)) return;
351
353
  const promptDetails = require_usage.isRecord(usage.promptTokensDetails) ? usage.promptTokensDetails : {};
352
354
  const completionDetails = require_usage.isRecord(usage.completionTokensDetails) ? usage.completionTokensDetails : {};
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.cjs","names":["createStateEventNormalizer","EventType","getNonEmptyString","isRecord","getTokenCount"],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n RunAgentInput,\n Message,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n ReasoningStartEvent,\n ReasoningMessageStartEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningEndEvent,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport {\n aggregateRunUsage,\n collectStandardRunFinishedDetails,\n getNonEmptyString,\n getTokenCount,\n isRecord,\n} from \"./usage\";\nimport type { AgentRunFinishedDetails } from \"./usage\";\n\ntype ContentPartSource =\n | { type: \"data\"; value: string; mimeType: string }\n | { type: \"url\"; value: string; mimeType?: string };\n\n/**\n * A TanStack AI content part (text, image, audio, video, or document).\n */\nexport type TanStackContentPart =\n | { type: \"text\"; content: string }\n | { type: \"image\"; source: ContentPartSource }\n | { type: \"audio\"; source: ContentPartSource }\n | { type: \"video\"; source: ContentPartSource }\n | { type: \"document\"; source: ContentPartSource };\n\n/**\n * Message format expected by TanStack AI's `chat()`.\n *\n * Content is typed as `any[]` for the multimodal case so messages are directly\n * passable to any adapter without casts — different adapters constrain which\n * modalities they accept (e.g. OpenAI only allows text + image).\n * Use `TanStackContentPart` to inspect individual parts if needed.\n */\nexport interface TanStackChatMessage {\n role: \"user\" | \"assistant\" | \"tool\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n content: string | null | any[];\n name?: string;\n toolCalls?: Array<{\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }>;\n toolCallId?: string;\n}\n\n/**\n * A TanStack AI client-side tool, derived from a frontend-provided AG-UI tool.\n *\n * Shaped to match `@tanstack/ai`'s `ClientTool` (`__toolSide: \"client\"`, no\n * `execute`): the model may CALL it, but TanStack does not run it — it pauses\n * the run and hands the call back to the AG-UI client (the CopilotKit frontend\n * / bot) to execute, mirroring CopilotKit's client-tool round-trip. `chat()`\n * accepts a JSON Schema directly as `inputSchema`, so the AG-UI tool's\n * `parameters` pass through unchanged.\n */\nexport interface TanStackClientTool {\n __toolSide: \"client\";\n name: string;\n description: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n inputSchema: any;\n}\n\n/**\n * Result of converting RunAgentInput to TanStack AI format.\n */\nexport interface TanStackInputResult {\n /** Chat messages (only user/assistant/tool roles; all others excluded) */\n messages: TanStackChatMessage[];\n /** System prompts extracted from system/developer messages, context, and state */\n systemPrompts: string[];\n /**\n * Client-side tools derived from `input.tools` (the frontend-provided tools\n * the CopilotKit client forwards on every run). Pass these into `chat()`\n * alongside any server/provider tools so the model can call the frontend's\n * generative-UI and human-in-the-loop tools; TanStack pauses the run on a\n * client-tool call and the client executes it.\n */\n tools: TanStackClientTool[];\n}\n\n/**\n * Converts AG-UI user message content to TanStack AI format.\n * Handles plain strings, multimodal parts (image/audio/video/document),\n * and legacy BinaryInputContent for backward compatibility.\n */\nfunction convertUserContent(\n content: unknown,\n): string | null | TanStackContentPart[] {\n if (!content) return null;\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return null;\n if (content.length === 0) return \"\";\n\n const parts: TanStackContentPart[] = [];\n\n for (const part of content) {\n if (!part || typeof part !== \"object\" || !(\"type\" in part)) continue;\n\n switch ((part as { type: string }).type) {\n case \"text\": {\n const text = (part as { text?: string }).text;\n if (text != null) parts.push({ type: \"text\", content: text });\n break;\n }\n\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\": {\n const source = (part as { source?: any }).source;\n if (!source) break;\n const partType = (part as { type: string }).type as\n | \"image\"\n | \"audio\"\n | \"video\"\n | \"document\";\n if (source.type === \"data\") {\n parts.push({\n type: partType,\n source: {\n type: \"data\",\n value: source.value,\n mimeType: source.mimeType,\n },\n });\n } else if (source.type === \"url\") {\n parts.push({\n type: partType,\n source: {\n type: \"url\",\n value: source.value,\n ...(source.mimeType ? { mimeType: source.mimeType } : {}),\n },\n });\n }\n break;\n }\n\n // Legacy BinaryInputContent backward compatibility\n case \"binary\": {\n const legacy = part as {\n mimeType?: string;\n data?: string;\n url?: string;\n };\n const mimeType = legacy.mimeType ?? \"application/octet-stream\";\n const isImage = mimeType.startsWith(\"image/\");\n\n if (legacy.data) {\n const partType = isImage ? \"image\" : \"document\";\n parts.push({\n type: partType,\n source: { type: \"data\", value: legacy.data, mimeType },\n });\n } else if (legacy.url) {\n const partType = isImage ? \"image\" : \"document\";\n parts.push({\n type: partType,\n source: { type: \"url\", value: legacy.url, mimeType },\n });\n }\n break;\n }\n }\n }\n\n return parts.length > 0 ? parts : \"\";\n}\n\n/**\n * Recursively normalizes a frontend tool's JSON Schema so OpenAI accepts it as\n * a function-tool schema.\n *\n * Frontend tools are often authored with permissive Zod (`z.any()`,\n * `z.record(...)`, `.passthrough()`), which serialize to open objects —\n * `additionalProperties: {}` (an empty sub-schema) or `additionalProperties:\n * true`. OpenAI rejects both: strict mode requires `additionalProperties:\n * false`, and an empty `{}` sub-schema fails base validation (\"schema must\n * have a 'type' key\"). The classic (Vercel AI SDK) path sanitized these\n * implicitly via a Zod round-trip; the TanStack path forwards the raw schema,\n * so we close open objects here to match. (Models can't supply free-form extra\n * keys either way — same as the classic path.)\n */\nfunction sanitizeClientToolSchema(schema: unknown): unknown {\n if (Array.isArray(schema)) {\n return schema.map(sanitizeClientToolSchema);\n }\n if (!schema || typeof schema !== \"object\") {\n return schema;\n }\n const node: Record<string, unknown> = {\n ...(schema as Record<string, unknown>),\n };\n\n // Any `additionalProperties` (empty `{}`, `true`, or a sub-schema) becomes\n // `false` — the only form OpenAI accepts for strict function tools.\n if (\"additionalProperties\" in node) {\n node.additionalProperties = false;\n }\n\n if (node.properties && typeof node.properties === \"object\") {\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n node.properties as Record<string, unknown>,\n )) {\n props[key] = sanitizeClientToolSchema(value);\n }\n node.properties = props;\n }\n\n if (\"items\" in node) {\n node.items = sanitizeClientToolSchema(node.items);\n }\n\n for (const combinator of [\"anyOf\", \"allOf\", \"oneOf\"] as const) {\n if (Array.isArray(node[combinator])) {\n node[combinator] = (node[combinator] as unknown[]).map(\n sanitizeClientToolSchema,\n );\n }\n }\n\n return node;\n}\n\n/**\n * Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.\n *\n * - Keeps only user/assistant/tool messages (activity, reasoning, and other roles are also excluded)\n * - Extracts system/developer messages into `systemPrompts`\n * - Appends context entries and application state to `systemPrompts`\n * - Preserves tool calls on assistant messages and toolCallId on tool messages\n */\nexport function convertInputToTanStackAI(\n input: RunAgentInput,\n): TanStackInputResult {\n // Allowlist: only pass user/assistant/tool messages to TanStack.\n // Other roles (system, developer, activity, reasoning) are either\n // extracted into systemPrompts or not applicable.\n const chatRoles = new Set([\"user\", \"assistant\", \"tool\"]);\n const messages: TanStackChatMessage[] = input.messages\n .filter((m: Message) => chatRoles.has(m.role))\n .map((m: Message): TanStackChatMessage => {\n const msg: TanStackChatMessage = {\n role: m.role as \"user\" | \"assistant\" | \"tool\",\n content:\n m.role === \"user\"\n ? convertUserContent(m.content)\n : typeof m.content === \"string\"\n ? m.content\n : null,\n };\n if (m.role === \"assistant\" && \"toolCalls\" in m && m.toolCalls) {\n msg.toolCalls = m.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n }));\n }\n if (m.role === \"tool\" && \"toolCallId\" in m) {\n msg.toolCallId = (m as Record<string, unknown>).toolCallId as string;\n }\n return msg;\n });\n\n const systemPrompts: string[] = [];\n for (const m of input.messages) {\n if ((m.role === \"system\" || m.role === \"developer\") && m.content) {\n systemPrompts.push(\n typeof m.content === \"string\" ? m.content : JSON.stringify(m.content),\n );\n }\n }\n\n if (input.context?.length) {\n for (const ctx of input.context) {\n systemPrompts.push(`${ctx.description}:\\n${ctx.value}`);\n }\n }\n\n if (\n input.state !== undefined &&\n input.state !== null &&\n typeof input.state === \"object\" &&\n Object.keys(input.state).length > 0\n ) {\n systemPrompts.push(\n `Application State:\\n\\`\\`\\`json\\n${JSON.stringify(input.state, null, 2)}\\n\\`\\`\\``,\n );\n }\n\n // Frontend-provided tools become client-side TanStack tools (no executor):\n // the model can call them, TanStack pauses the run, and the AG-UI client\n // executes them and resumes — the CopilotKit client-tool round-trip.\n const tools: TanStackClientTool[] = (input.tools ?? []).map((t) => ({\n __toolSide: \"client\",\n name: t.name,\n description: t.description,\n inputSchema: sanitizeClientToolSchema(t.parameters),\n }));\n\n return { messages, systemPrompts, tools };\n}\n\n/**\n * Converts a TanStack AI stream into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * CUSTOM \"approval-requested\" chunk (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n const messageId = randomUUID();\n const toolNamesById = new Map<string, string>();\n // Track the reasoning lifecycle at two granularities so closeReasoningIfOpen\n // emits exactly the events still owed. A single boolean conflates the run\n // (REASONING_START → REASONING_END) with the message\n // (REASONING_MESSAGE_START → REASONING_MESSAGE_END) and produces a duplicate\n // REASONING_MESSAGE_END when upstream emits MSG_END but not END before\n // text/tools resume.\n let reasoningRunOpen = false;\n let reasoningMessageOpen = false;\n let reasoningMessageId = randomUUID();\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (reasoningMessageOpen) {\n reasoningMessageOpen = false;\n const msgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield msgEnd;\n }\n if (reasoningRunOpen) {\n reasoningRunOpen = false;\n const end: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield end;\n }\n }\n\n // TanStack's chat() engine runs a multi-turn agent loop and emits a\n // RUN_STARTED / RUN_FINISHED pair PER model turn — not once for the whole\n // run. When it executes a tool itself (an MCP server tool or a provider tool\n // like web_search), it does so between turns and streams a TOOL_CALL_RESULT\n // followed by the next turn's text. The overall run lifecycle is owned by the\n // Agent wrapper (it emits exactly one outer RUN_STARTED / RUN_FINISHED), so\n // we drop TanStack's per-turn lifecycle markers and convert every content\n // event across all turns. (A previous version stopped converting at the first\n // RUN_FINISHED — that truncated the run at the first tool turn and silently\n // dropped both the tool result and the model's final answer.)\n //\n // chat() can re-announce a tool call when it re-prompts after executing it,\n // so START / END are de-duplicated by toolCallId to avoid emitting a pair\n // twice (which would violate the ag-ui verify middleware).\n const startedToolCalls = new Set<string>();\n const endedToolCalls = new Set<string>();\n\n for await (const chunk of stream) {\n if (abortSignal.aborted) break;\n\n const raw = chunk as Record<string, unknown>;\n const type = raw.type as string;\n\n // TanStack native human-in-the-loop: a tool declared `needsApproval: true`\n // emits a CUSTOM \"approval-requested\" chunk. These are built from the\n // finish event and can arrive around lifecycle markers, so handle them\n // before dropping TanStack's per-turn lifecycle events.\n // The tool-call lifecycle was already streamed in the model pass.\n if (type === \"CUSTOM\" && raw.name === \"approval-requested\") {\n const value = (raw.value ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n };\n const toolCallId = value.toolCallId;\n if (toolCallId) {\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: value.toolName ? `Approve \"${value.toolName}\"?` : undefined,\n ...(value.toolName ? { metadata: { toolName: value.toolName } } : {}),\n });\n }\n continue;\n }\n\n // Per-turn lifecycle markers are owned by the Agent wrapper, not forwarded.\n if (type === \"RUN_FINISHED\") {\n collectTanStackRunFinishedDetails(raw, runFinishedDetails);\n continue;\n }\n if (type === \"RUN_STARTED\") continue;\n\n // Surface engine errors instead of dropping them: throw so the Agent\n // wrapper emits a terminal RUN_ERROR. Without this a failed run (e.g. a\n // provider 4xx) would finish empty with no indication of what went wrong.\n if (type === \"RUN_ERROR\") {\n throw new Error(\n typeof raw.message === \"string\" ? raw.message : \"TanStack AI run error\",\n );\n }\n\n if (type === \"TEXT_MESSAGE_CONTENT\" && raw.delta != null) {\n yield* closeReasoningIfOpen();\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: raw.delta as string,\n };\n yield textEvent;\n } else if (type === \"TOOL_CALL_START\") {\n const toolCallId = raw.toolCallId as string;\n if (startedToolCalls.has(toolCallId)) continue;\n startedToolCalls.add(toolCallId);\n yield* closeReasoningIfOpen();\n toolNamesById.set(toolCallId, raw.toolCallName as string);\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: raw.toolCallName as string,\n };\n yield startEvent;\n } else if (type === \"TOOL_CALL_ARGS\") {\n // Drop args re-announced after the call has ended (the re-prompt pass);\n // forwarding them would corrupt the already-closed call's accumulated args.\n if (endedToolCalls.has(raw.toolCallId as string)) continue;\n yield* closeReasoningIfOpen();\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: raw.toolCallId as string,\n delta: raw.delta as string,\n };\n yield argsEvent;\n } else if (type === \"TOOL_CALL_END\") {\n const toolCallId = raw.toolCallId as string;\n if (endedToolCalls.has(toolCallId)) continue;\n endedToolCalls.add(toolCallId);\n yield* closeReasoningIfOpen();\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n } else if (type === \"TOOL_CALL_RESULT\") {\n yield* closeReasoningIfOpen();\n const toolCallId = raw.toolCallId as string;\n const toolName = toolNamesById.get(toolCallId);\n // Accept the payload from either `content` (canonical TanStack shape)\n // or `result` (alternate shape used by some adapters / tests). Both\n // state-tool detection and the final TOOL_CALL_RESULT serialization\n // must read the same field, otherwise STATE_SNAPSHOT/STATE_DELTA can\n // be silently dropped when upstream uses `result`.\n const rawPayload = raw.content ?? raw.result;\n\n const parsedContent =\n typeof rawPayload === \"string\" ? safeParse(rawPayload) : rawPayload;\n\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n parsedContent &&\n typeof parsedContent === \"object\" &&\n \"snapshot\" in parsedContent\n ) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot: (parsedContent as Record<string, unknown>).snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n\n if (\n toolName === \"AGUISendStateDelta\" &&\n parsedContent &&\n typeof parsedContent === \"object\" &&\n \"delta\" in parsedContent\n ) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta: (parsedContent as Record<string, unknown>).delta as never,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n\n let serializedContent: string;\n if (typeof rawPayload === \"string\") {\n serializedContent = rawPayload;\n } else {\n try {\n serializedContent = JSON.stringify(rawPayload ?? null);\n } catch {\n serializedContent = \"[Unserializable tool result]\";\n }\n }\n\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n content: serializedContent,\n };\n yield resultEvent;\n toolNamesById.delete(toolCallId);\n } else if (type === \"REASONING_START\") {\n // If a prior reasoning run is still open (no REASONING_END before this\n // new START), close it cleanly first so MSG_END / END pair correctly.\n yield* closeReasoningIfOpen();\n reasoningRunOpen = true;\n reasoningMessageId = (raw.messageId as string) ?? randomUUID();\n const startEvt: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield startEvt;\n } else if (type === \"REASONING_MESSAGE_START\") {\n reasoningMessageOpen = true;\n const evt: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield evt;\n } else if (type === \"REASONING_MESSAGE_CONTENT\") {\n const evt: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: raw.delta as string,\n };\n yield evt;\n } else if (type === \"REASONING_MESSAGE_END\") {\n reasoningMessageOpen = false;\n const evt: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield evt;\n } else if (type === \"REASONING_END\") {\n // If upstream sends REASONING_END while a message is still open, emit\n // the missing REASONING_MESSAGE_END FIRST so the closing pair stays in\n // order (MSG_END before END). Otherwise the next non-reasoning chunk\n // would trigger closeReasoningIfOpen and emit MSG_END after END.\n if (reasoningMessageOpen) {\n reasoningMessageOpen = false;\n const msgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield msgEnd;\n }\n reasoningRunOpen = false;\n const evt: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield evt;\n }\n }\n\n yield* closeReasoningIfOpen();\n}\n\n/** Normalizes legacy and standard TanStack usage into AG-UI token usage. */\nfunction collectTanStackRunFinishedDetails(\n event: Record<string, unknown>,\n details?: AgentRunFinishedDetails,\n): void {\n if (!details) return;\n\n if (typeof event.finishReason === \"string\") {\n details.finishReason = event.finishReason;\n }\n\n const fallbackIdentity = {\n provider: getNonEmptyString(event.provider),\n model: getNonEmptyString(event.model),\n };\n const usage = event.usage;\n\n if (Array.isArray(usage)) {\n collectStandardRunFinishedDetails(event, details, fallbackIdentity);\n return;\n }\n\n if (!isRecord(usage)) return;\n\n const promptDetails = isRecord(usage.promptTokensDetails)\n ? usage.promptTokensDetails\n : {};\n const completionDetails = isRecord(usage.completionTokensDetails)\n ? usage.completionTokensDetails\n : {};\n aggregateRunUsage(details, [\n {\n ...fallbackIdentity,\n inputTokens: getTokenCount(usage.promptTokens),\n outputTokens: getTokenCount(usage.completionTokens),\n totalTokens: getTokenCount(usage.totalTokens),\n reasoningTokens: getTokenCount(completionDetails.reasoningTokens),\n cachedInputTokens: getTokenCount(promptDetails.cachedTokens),\n },\n ]);\n}\n\nfunction safeParse(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tanstack.cjs","names":["createStateEventNormalizer","EventType","getNonEmptyString","isRecord","getTokenCount"],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import type {\n BaseEvent,\n Interrupt,\n RunAgentInput,\n Message,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCallResultEvent,\n StateSnapshotEvent,\n StateDeltaEvent,\n ReasoningStartEvent,\n ReasoningMessageStartEvent,\n ReasoningMessageContentEvent,\n ReasoningMessageEndEvent,\n ReasoningEndEvent,\n} from \"@ag-ui/client\";\nimport { contentToText, EventType } from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\nimport { createStateEventNormalizer } from \"../state-delta\";\nimport {\n aggregateRunUsage,\n collectStandardRunFinishedDetails,\n getNonEmptyString,\n getTokenCount,\n isRecord,\n} from \"./usage\";\nimport type { AgentRunFinishedDetails } from \"./usage\";\n\ntype ContentPartSource =\n | { type: \"data\"; value: string; mimeType: string }\n | { type: \"url\"; value: string; mimeType?: string };\n\n/**\n * A TanStack AI content part (text, image, audio, video, or document).\n */\nexport type TanStackContentPart =\n | { type: \"text\"; content: string }\n | { type: \"image\"; source: ContentPartSource }\n | { type: \"audio\"; source: ContentPartSource }\n | { type: \"video\"; source: ContentPartSource }\n | { type: \"document\"; source: ContentPartSource };\n\n/**\n * Message format expected by TanStack AI's `chat()`.\n *\n * Content is typed as `any[]` for the multimodal case so messages are directly\n * passable to any adapter without casts — different adapters constrain which\n * modalities they accept (e.g. OpenAI only allows text + image).\n * Use `TanStackContentPart` to inspect individual parts if needed.\n */\nexport interface TanStackChatMessage {\n role: \"user\" | \"assistant\" | \"tool\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n content: string | null | any[];\n name?: string;\n toolCalls?: Array<{\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }>;\n toolCallId?: string;\n}\n\n/**\n * A TanStack AI client-side tool, derived from a frontend-provided AG-UI tool.\n *\n * Shaped to match `@tanstack/ai`'s `ClientTool` (`__toolSide: \"client\"`, no\n * `execute`): the model may CALL it, but TanStack does not run it — it pauses\n * the run and hands the call back to the AG-UI client (the CopilotKit frontend\n * / bot) to execute, mirroring CopilotKit's client-tool round-trip. `chat()`\n * accepts a JSON Schema directly as `inputSchema`, so the AG-UI tool's\n * `parameters` pass through unchanged.\n */\nexport interface TanStackClientTool {\n __toolSide: \"client\";\n name: string;\n description: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n inputSchema: any;\n}\n\n/**\n * Result of converting RunAgentInput to TanStack AI format.\n */\nexport interface TanStackInputResult {\n /** Chat messages (only user/assistant/tool roles; all others excluded) */\n messages: TanStackChatMessage[];\n /** System prompts extracted from system/developer messages, context, and state */\n systemPrompts: string[];\n /**\n * Client-side tools derived from `input.tools` (the frontend-provided tools\n * the CopilotKit client forwards on every run). Pass these into `chat()`\n * alongside any server/provider tools so the model can call the frontend's\n * generative-UI and human-in-the-loop tools; TanStack pauses the run on a\n * client-tool call and the client executes it.\n */\n tools: TanStackClientTool[];\n}\n\n/**\n * Converts AG-UI user message content to TanStack AI format.\n * Handles plain strings, multimodal parts (image/audio/video/document),\n * and legacy BinaryInputContent for backward compatibility.\n */\nfunction convertUserContent(\n content: unknown,\n): string | null | TanStackContentPart[] {\n if (!content) return null;\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return null;\n if (content.length === 0) return \"\";\n\n const parts: TanStackContentPart[] = [];\n\n for (const part of content) {\n if (!part || typeof part !== \"object\" || !(\"type\" in part)) continue;\n\n switch ((part as { type: string }).type) {\n case \"text\": {\n const text = (part as { text?: string }).text;\n if (text != null) parts.push({ type: \"text\", content: text });\n break;\n }\n\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\": {\n const source = (part as { source?: any }).source;\n if (!source) break;\n const partType = (part as { type: string }).type as\n | \"image\"\n | \"audio\"\n | \"video\"\n | \"document\";\n if (source.type === \"data\") {\n parts.push({\n type: partType,\n source: {\n type: \"data\",\n value: source.value,\n mimeType: source.mimeType,\n },\n });\n } else if (source.type === \"file\") {\n // AG-UI 1.0 provider file handle: not a URL or inline data.\n console.warn(\n `[CopilotKit] Dropping a ${partType} part that references a provider file handle: it is not a URL or inline data, so it cannot be sent to the model here.`,\n );\n } else if (source.type === \"url\") {\n parts.push({\n type: partType,\n source: {\n type: \"url\",\n value: source.value,\n ...(source.mimeType ? { mimeType: source.mimeType } : {}),\n },\n });\n }\n break;\n }\n\n // Legacy BinaryInputContent backward compatibility\n case \"binary\": {\n const legacy = part as {\n mimeType?: string;\n data?: string;\n url?: string;\n };\n const mimeType = legacy.mimeType ?? \"application/octet-stream\";\n const isImage = mimeType.startsWith(\"image/\");\n\n if (legacy.data) {\n const partType = isImage ? \"image\" : \"document\";\n parts.push({\n type: partType,\n source: { type: \"data\", value: legacy.data, mimeType },\n });\n } else if (legacy.url) {\n const partType = isImage ? \"image\" : \"document\";\n parts.push({\n type: partType,\n source: { type: \"url\", value: legacy.url, mimeType },\n });\n }\n break;\n }\n }\n }\n\n return parts.length > 0 ? parts : \"\";\n}\n\n/**\n * Recursively normalizes a frontend tool's JSON Schema so OpenAI accepts it as\n * a function-tool schema.\n *\n * Frontend tools are often authored with permissive Zod (`z.any()`,\n * `z.record(...)`, `.passthrough()`), which serialize to open objects —\n * `additionalProperties: {}` (an empty sub-schema) or `additionalProperties:\n * true`. OpenAI rejects both: strict mode requires `additionalProperties:\n * false`, and an empty `{}` sub-schema fails base validation (\"schema must\n * have a 'type' key\"). The classic (Vercel AI SDK) path sanitized these\n * implicitly via a Zod round-trip; the TanStack path forwards the raw schema,\n * so we close open objects here to match. (Models can't supply free-form extra\n * keys either way — same as the classic path.)\n */\nfunction sanitizeClientToolSchema(schema: unknown): unknown {\n if (Array.isArray(schema)) {\n return schema.map(sanitizeClientToolSchema);\n }\n if (!schema || typeof schema !== \"object\") {\n return schema;\n }\n const node: Record<string, unknown> = {\n ...(schema as Record<string, unknown>),\n };\n\n // Any `additionalProperties` (empty `{}`, `true`, or a sub-schema) becomes\n // `false` — the only form OpenAI accepts for strict function tools.\n if (\"additionalProperties\" in node) {\n node.additionalProperties = false;\n }\n\n if (node.properties && typeof node.properties === \"object\") {\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n node.properties as Record<string, unknown>,\n )) {\n props[key] = sanitizeClientToolSchema(value);\n }\n node.properties = props;\n }\n\n if (\"items\" in node) {\n node.items = sanitizeClientToolSchema(node.items);\n }\n\n for (const combinator of [\"anyOf\", \"allOf\", \"oneOf\"] as const) {\n if (Array.isArray(node[combinator])) {\n node[combinator] = (node[combinator] as unknown[]).map(\n sanitizeClientToolSchema,\n );\n }\n }\n\n return node;\n}\n\n/**\n * Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.\n *\n * - Keeps only user/assistant/tool messages (activity, reasoning, and other roles are also excluded)\n * - Extracts system/developer messages into `systemPrompts`\n * - Appends context entries and application state to `systemPrompts`\n * - Preserves tool calls on assistant messages and toolCallId on tool messages\n */\nexport function convertInputToTanStackAI(\n input: RunAgentInput,\n): TanStackInputResult {\n // Allowlist: only pass user/assistant/tool messages to TanStack.\n // Other roles (system, developer, activity, reasoning) are either\n // extracted into systemPrompts or not applicable.\n const chatRoles = new Set([\"user\", \"assistant\", \"tool\"]);\n const messages: TanStackChatMessage[] = input.messages\n .filter((m: Message) => chatRoles.has(m.role))\n .map((m: Message): TanStackChatMessage => {\n const msg: TanStackChatMessage = {\n role: m.role as \"user\" | \"assistant\" | \"tool\",\n content:\n m.role === \"user\"\n ? convertUserContent(m.content)\n : m.role === \"tool\"\n ? // A tool result is a string or a list of parts; TanStack takes\n // text here, so the text parts are concatenated.\n contentToText(m.content)\n : typeof m.content === \"string\"\n ? m.content\n : null,\n };\n if (m.role === \"assistant\" && \"toolCalls\" in m && m.toolCalls) {\n msg.toolCalls = m.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n }));\n }\n if (m.role === \"tool\" && \"toolCallId\" in m) {\n msg.toolCallId = (m as Record<string, unknown>).toolCallId as string;\n }\n return msg;\n });\n\n const systemPrompts: string[] = [];\n for (const m of input.messages) {\n if ((m.role === \"system\" || m.role === \"developer\") && m.content) {\n systemPrompts.push(\n typeof m.content === \"string\" ? m.content : JSON.stringify(m.content),\n );\n }\n }\n\n if (input.context?.length) {\n for (const ctx of input.context) {\n systemPrompts.push(`${ctx.description}:\\n${ctx.value}`);\n }\n }\n\n if (\n input.state !== undefined &&\n input.state !== null &&\n typeof input.state === \"object\" &&\n Object.keys(input.state).length > 0\n ) {\n systemPrompts.push(\n `Application State:\\n\\`\\`\\`json\\n${JSON.stringify(input.state, null, 2)}\\n\\`\\`\\``,\n );\n }\n\n // Frontend-provided tools become client-side TanStack tools (no executor):\n // the model can call them, TanStack pauses the run, and the AG-UI client\n // executes them and resumes — the CopilotKit client-tool round-trip.\n const tools: TanStackClientTool[] = (input.tools ?? []).map((t) => ({\n __toolSide: \"client\",\n name: t.name,\n description: t.description,\n inputSchema: sanitizeClientToolSchema(t.parameters),\n }));\n\n return { messages, systemPrompts, tools };\n}\n\n/**\n * Converts a TanStack AI stream into AG-UI `BaseEvent` objects.\n *\n * This is a pure converter — it does NOT emit lifecycle events\n * (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)\n * is responsible for those.\n *\n * `pendingInterrupts`, when provided, is filled with one AG-UI Interrupt per\n * CUSTOM \"approval-requested\" chunk (a tool declared `needsApproval: true`).\n * The caller turns a non-empty array into a RUN_FINISHED `outcome:interrupt`.\n */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\n pendingInterrupts?: Interrupt[],\n initialState?: unknown,\n runFinishedDetails?: AgentRunFinishedDetails,\n): AsyncGenerator<BaseEvent> {\n const messageId = randomUUID();\n const toolNamesById = new Map<string, string>();\n // Track the reasoning lifecycle at two granularities so closeReasoningIfOpen\n // emits exactly the events still owed. A single boolean conflates the run\n // (REASONING_START → REASONING_END) with the message\n // (REASONING_MESSAGE_START → REASONING_MESSAGE_END) and produces a duplicate\n // REASONING_MESSAGE_END when upstream emits MSG_END but not END before\n // text/tools resume.\n let reasoningRunOpen = false;\n let reasoningMessageOpen = false;\n let reasoningMessageId = randomUUID();\n const normalizeStateEvent = createStateEventNormalizer(initialState);\n\n function* closeReasoningIfOpen(): Generator<BaseEvent> {\n if (reasoningMessageOpen) {\n reasoningMessageOpen = false;\n const msgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield msgEnd;\n }\n if (reasoningRunOpen) {\n reasoningRunOpen = false;\n const end: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield end;\n }\n }\n\n // TanStack's chat() engine runs a multi-turn agent loop and emits a\n // RUN_STARTED / RUN_FINISHED pair PER model turn — not once for the whole\n // run. When it executes a tool itself (an MCP server tool or a provider tool\n // like web_search), it does so between turns and streams a TOOL_CALL_RESULT\n // followed by the next turn's text. The overall run lifecycle is owned by the\n // Agent wrapper (it emits exactly one outer RUN_STARTED / RUN_FINISHED), so\n // we drop TanStack's per-turn lifecycle markers and convert every content\n // event across all turns. (A previous version stopped converting at the first\n // RUN_FINISHED — that truncated the run at the first tool turn and silently\n // dropped both the tool result and the model's final answer.)\n //\n // chat() can re-announce a tool call when it re-prompts after executing it,\n // so START / END are de-duplicated by toolCallId to avoid emitting a pair\n // twice (which would violate the ag-ui verify middleware).\n const startedToolCalls = new Set<string>();\n const endedToolCalls = new Set<string>();\n\n for await (const chunk of stream) {\n if (abortSignal.aborted) break;\n\n const raw = chunk as Record<string, unknown>;\n const type = raw.type as string;\n\n // TanStack native human-in-the-loop: a tool declared `needsApproval: true`\n // emits a CUSTOM \"approval-requested\" chunk. These are built from the\n // finish event and can arrive around lifecycle markers, so handle them\n // before dropping TanStack's per-turn lifecycle events.\n // The tool-call lifecycle was already streamed in the model pass.\n if (type === \"CUSTOM\" && raw.name === \"approval-requested\") {\n const value = (raw.value ?? {}) as {\n toolCallId?: string;\n toolName?: string;\n };\n const toolCallId = value.toolCallId;\n if (toolCallId) {\n pendingInterrupts?.push({\n id: toolCallId,\n toolCallId,\n reason: \"tool_approval\",\n message: value.toolName ? `Approve \"${value.toolName}\"?` : undefined,\n ...(value.toolName ? { metadata: { toolName: value.toolName } } : {}),\n });\n }\n continue;\n }\n\n // Per-turn lifecycle markers are owned by the Agent wrapper, not forwarded.\n if (type === \"RUN_FINISHED\") {\n collectTanStackRunFinishedDetails(raw, runFinishedDetails);\n continue;\n }\n if (type === \"RUN_STARTED\") continue;\n\n // Surface engine errors instead of dropping them: throw so the Agent\n // wrapper emits a terminal RUN_ERROR. Without this a failed run (e.g. a\n // provider 4xx) would finish empty with no indication of what went wrong.\n if (type === \"RUN_ERROR\") {\n throw new Error(\n typeof raw.message === \"string\" ? raw.message : \"TanStack AI run error\",\n );\n }\n\n if (type === \"TEXT_MESSAGE_CONTENT\" && raw.delta != null) {\n yield* closeReasoningIfOpen();\n const textEvent: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: raw.delta as string,\n };\n yield textEvent;\n } else if (type === \"TOOL_CALL_START\") {\n const toolCallId = raw.toolCallId as string;\n if (startedToolCalls.has(toolCallId)) continue;\n startedToolCalls.add(toolCallId);\n yield* closeReasoningIfOpen();\n toolNamesById.set(toolCallId, raw.toolCallName as string);\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId,\n toolCallName: raw.toolCallName as string,\n };\n yield startEvent;\n } else if (type === \"TOOL_CALL_ARGS\") {\n // Drop args re-announced after the call has ended (the re-prompt pass);\n // forwarding them would corrupt the already-closed call's accumulated args.\n if (endedToolCalls.has(raw.toolCallId as string)) continue;\n yield* closeReasoningIfOpen();\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: raw.toolCallId as string,\n delta: raw.delta as string,\n };\n yield argsEvent;\n } else if (type === \"TOOL_CALL_END\") {\n const toolCallId = raw.toolCallId as string;\n if (endedToolCalls.has(toolCallId)) continue;\n endedToolCalls.add(toolCallId);\n yield* closeReasoningIfOpen();\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId,\n };\n yield endEvent;\n } else if (type === \"TOOL_CALL_RESULT\") {\n yield* closeReasoningIfOpen();\n const toolCallId = raw.toolCallId as string;\n const toolName = toolNamesById.get(toolCallId);\n // Accept the payload from either `content` (canonical TanStack shape)\n // or `result` (alternate shape used by some adapters / tests). Both\n // state-tool detection and the final TOOL_CALL_RESULT serialization\n // must read the same field, otherwise STATE_SNAPSHOT/STATE_DELTA can\n // be silently dropped when upstream uses `result`.\n const rawPayload = raw.content ?? raw.result;\n\n const parsedContent =\n typeof rawPayload === \"string\" ? safeParse(rawPayload) : rawPayload;\n\n if (\n toolName === \"AGUISendStateSnapshot\" &&\n parsedContent &&\n typeof parsedContent === \"object\" &&\n \"snapshot\" in parsedContent\n ) {\n const stateSnapshotEvent: StateSnapshotEvent = {\n type: EventType.STATE_SNAPSHOT,\n snapshot: (parsedContent as Record<string, unknown>).snapshot,\n };\n for (const event of normalizeStateEvent(stateSnapshotEvent)) {\n yield event;\n }\n }\n\n if (\n toolName === \"AGUISendStateDelta\" &&\n parsedContent &&\n typeof parsedContent === \"object\" &&\n \"delta\" in parsedContent\n ) {\n const stateDeltaEvent: StateDeltaEvent = {\n type: EventType.STATE_DELTA,\n delta: (parsedContent as Record<string, unknown>).delta as never,\n };\n for (const event of normalizeStateEvent(stateDeltaEvent)) {\n yield event;\n }\n }\n\n let serializedContent: string;\n if (typeof rawPayload === \"string\") {\n serializedContent = rawPayload;\n } else {\n try {\n serializedContent = JSON.stringify(rawPayload ?? null);\n } catch {\n serializedContent = \"[Unserializable tool result]\";\n }\n }\n\n const resultEvent: ToolCallResultEvent = {\n type: EventType.TOOL_CALL_RESULT,\n role: \"tool\",\n messageId: randomUUID(),\n toolCallId,\n content: serializedContent,\n };\n yield resultEvent;\n toolNamesById.delete(toolCallId);\n } else if (type === \"REASONING_START\") {\n // If a prior reasoning run is still open (no REASONING_END before this\n // new START), close it cleanly first so MSG_END / END pair correctly.\n yield* closeReasoningIfOpen();\n reasoningRunOpen = true;\n reasoningMessageId = (raw.messageId as string) ?? randomUUID();\n const startEvt: ReasoningStartEvent = {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield startEvt;\n } else if (type === \"REASONING_MESSAGE_START\") {\n reasoningMessageOpen = true;\n const evt: ReasoningMessageStartEvent = {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n yield evt;\n } else if (type === \"REASONING_MESSAGE_CONTENT\") {\n const evt: ReasoningMessageContentEvent = {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: raw.delta as string,\n };\n yield evt;\n } else if (type === \"REASONING_MESSAGE_END\") {\n reasoningMessageOpen = false;\n const evt: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield evt;\n } else if (type === \"REASONING_END\") {\n // If upstream sends REASONING_END while a message is still open, emit\n // the missing REASONING_MESSAGE_END FIRST so the closing pair stays in\n // order (MSG_END before END). Otherwise the next non-reasoning chunk\n // would trigger closeReasoningIfOpen and emit MSG_END after END.\n if (reasoningMessageOpen) {\n reasoningMessageOpen = false;\n const msgEnd: ReasoningMessageEndEvent = {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n };\n yield msgEnd;\n }\n reasoningRunOpen = false;\n const evt: ReasoningEndEvent = {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n };\n yield evt;\n }\n }\n\n yield* closeReasoningIfOpen();\n}\n\n/** Normalizes legacy and standard TanStack usage into AG-UI token usage. */\nfunction collectTanStackRunFinishedDetails(\n event: Record<string, unknown>,\n details?: AgentRunFinishedDetails,\n): void {\n if (!details) return;\n\n const fallbackIdentity = {\n provider: getNonEmptyString(event.provider),\n model: getNonEmptyString(event.model),\n };\n collectStandardRunFinishedDetails(event, details, fallbackIdentity);\n\n // TanStack's native finish reason becomes AG-UI terminal metadata.\n if (typeof event.finishReason === \"string\") {\n details.metadata = {\n ...details.metadata,\n finishReason: event.finishReason,\n };\n }\n\n const usage = event.usage;\n\n if (Array.isArray(usage)) {\n return;\n }\n\n if (!isRecord(usage)) return;\n\n const promptDetails = isRecord(usage.promptTokensDetails)\n ? usage.promptTokensDetails\n : {};\n const completionDetails = isRecord(usage.completionTokensDetails)\n ? usage.completionTokensDetails\n : {};\n aggregateRunUsage(details, [\n {\n ...fallbackIdentity,\n inputTokens: getTokenCount(usage.promptTokens),\n outputTokens: getTokenCount(usage.completionTokens),\n totalTokens: getTokenCount(usage.totalTokens),\n reasoningTokens: getTokenCount(completionDetails.reasoningTokens),\n cachedInputTokens: getTokenCount(promptDetails.cachedTokens),\n },\n ]);\n}\n\nfunction safeParse(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.d.cts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;;AAsFA;;;;;;;UAlCiB,mBAAA;EACf,IAAA;EAEA,OAAA;EACA,IAAA;EACA,SAAA,GAAY,KAAA;IACV,EAAA;IACA,IAAA;IACA,QAAA;MAAY,IAAA;MAAc,SAAA;IAAA;EAAA;EAE5B,UAAA;AAAA;;;;;;;;;;;UAae,kBAAA;EACf,UAAA;EACA,IAAA;EACA,WAAA;EAEA,WAAA;AAAA;;;;UAMe,mBAAA;EAmQC;EAjQhB,QAAA,EAAU,mBAAA;EAiQe;EA/PzB,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBA4JO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;;;;;iBAmFoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
1
+ {"version":3,"file":"tanstack.d.cts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;;AAsFA;;;;;;;UAlCiB,mBAAA;EACf,IAAA;EAEA,OAAA;EACA,IAAA;EACA,SAAA,GAAY,KAAA;IACV,EAAA;IACA,IAAA;IACA,QAAA;MAAY,IAAA;MAAc,SAAA;IAAA;EAAA;EAE5B,UAAA;AAAA;;;;;;;;;;;UAae,kBAAA;EACf,UAAA;EACA,IAAA;EACA,WAAA;EAEA,WAAA;AAAA;;;;UAMe,mBAAA;EA4QC;EA1QhB,QAAA,EAAU,mBAAA;EA0Qe;EAxQzB,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBAiKO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;;;;;iBAuFoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.d.mts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;;AAsFA;;;;;;;UAlCiB,mBAAA;EACf,IAAA;EAEA,OAAA;EACA,IAAA;EACA,SAAA,GAAY,KAAA;IACV,EAAA;IACA,IAAA;IACA,QAAA;MAAY,IAAA;MAAc,SAAA;IAAA;EAAA;EAE5B,UAAA;AAAA;;;;;;;;;;;UAae,kBAAA;EACf,UAAA;EACA,IAAA;EACA,WAAA;EAEA,WAAA;AAAA;;;;UAMe,mBAAA;EAmQC;EAjQhB,QAAA,EAAU,mBAAA;EAiQe;EA/PzB,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBA4JO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;;;;;iBAmFoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}
1
+ {"version":3,"file":"tanstack.d.mts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;;AAsFA;;;;;;;UAlCiB,mBAAA;EACf,IAAA;EAEA,OAAA;EACA,IAAA;EACA,SAAA,GAAY,KAAA;IACV,EAAA;IACA,IAAA;IACA,QAAA;MAAY,IAAA;MAAc,SAAA;IAAA;EAAA;EAE5B,UAAA;AAAA;;;;;;;;;;;UAae,kBAAA;EACf,UAAA;EACA,IAAA;EACA,WAAA;EAEA,WAAA;AAAA;;;;UAMe,mBAAA;EA4QC;EA1QhB,QAAA,EAAU,mBAAA;EA0Qe;EAxQzB,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBAiKO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;;;;;iBAuFoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,EACb,iBAAA,GAAoB,SAAA,IACpB,YAAA,YACA,kBAAA,GAAqB,uBAAA,GACpB,cAAA,CAAe,SAAA"}