@copilotkit/runtime 1.61.0 → 1.61.1
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.
- package/dist/agent/converters/tanstack.cjs +53 -10
- package/dist/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts +24 -0
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts +24 -0
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs +53 -10
- package/dist/agent/converters/tanstack.mjs.map +1 -1
- package/dist/package.cjs +3 -3
- package/dist/package.mjs +3 -3
- package/dist/v2/index.cjs +1 -0
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/fetch-handler.cjs +5 -4
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +5 -4
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +3 -3
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +7 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +7 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +3 -3
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.cjs +14 -1
- package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.mjs +14 -1
- package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/threads.cjs +6 -6
- package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/threads.mjs +6 -6
- package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -1
- package/dist/v2/runtime/runner/agent-runner.cjs +4 -0
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts +21 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts +21 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.mjs +4 -1
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.cjs +4 -0
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.cts +1 -0
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.mts +1 -0
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.mjs +4 -0
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
- package/dist/v2/runtime/runner/index.d.cts +1 -1
- package/dist/v2/runtime/runner/index.d.mts +1 -1
- package/dist/v2/runtime/runner/index.mjs +1 -1
- package/package.json +4 -4
|
@@ -83,6 +83,38 @@ function convertUserContent(content) {
|
|
|
83
83
|
return parts.length > 0 ? parts : "";
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
+
* Recursively normalizes a frontend tool's JSON Schema so OpenAI accepts it as
|
|
87
|
+
* a function-tool schema.
|
|
88
|
+
*
|
|
89
|
+
* Frontend tools are often authored with permissive Zod (`z.any()`,
|
|
90
|
+
* `z.record(...)`, `.passthrough()`), which serialize to open objects —
|
|
91
|
+
* `additionalProperties: {}` (an empty sub-schema) or `additionalProperties:
|
|
92
|
+
* true`. OpenAI rejects both: strict mode requires `additionalProperties:
|
|
93
|
+
* false`, and an empty `{}` sub-schema fails base validation ("schema must
|
|
94
|
+
* have a 'type' key"). The classic (Vercel AI SDK) path sanitized these
|
|
95
|
+
* implicitly via a Zod round-trip; the TanStack path forwards the raw schema,
|
|
96
|
+
* so we close open objects here to match. (Models can't supply free-form extra
|
|
97
|
+
* keys either way — same as the classic path.)
|
|
98
|
+
*/
|
|
99
|
+
function sanitizeClientToolSchema(schema) {
|
|
100
|
+
if (Array.isArray(schema)) return schema.map(sanitizeClientToolSchema);
|
|
101
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
102
|
+
const node = { ...schema };
|
|
103
|
+
if ("additionalProperties" in node) node.additionalProperties = false;
|
|
104
|
+
if (node.properties && typeof node.properties === "object") {
|
|
105
|
+
const props = {};
|
|
106
|
+
for (const [key, value] of Object.entries(node.properties)) props[key] = sanitizeClientToolSchema(value);
|
|
107
|
+
node.properties = props;
|
|
108
|
+
}
|
|
109
|
+
if ("items" in node) node.items = sanitizeClientToolSchema(node.items);
|
|
110
|
+
for (const combinator of [
|
|
111
|
+
"anyOf",
|
|
112
|
+
"allOf",
|
|
113
|
+
"oneOf"
|
|
114
|
+
]) if (Array.isArray(node[combinator])) node[combinator] = node[combinator].map(sanitizeClientToolSchema);
|
|
115
|
+
return node;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
86
118
|
* Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.
|
|
87
119
|
*
|
|
88
120
|
* - Keeps only user/assistant/tool messages (activity, reasoning, and other roles are also excluded)
|
|
@@ -118,7 +150,13 @@ function convertInputToTanStackAI(input) {
|
|
|
118
150
|
if (input.state !== void 0 && input.state !== null && typeof input.state === "object" && Object.keys(input.state).length > 0) systemPrompts.push(`Application State:\n\`\`\`json\n${JSON.stringify(input.state, null, 2)}\n\`\`\``);
|
|
119
151
|
return {
|
|
120
152
|
messages,
|
|
121
|
-
systemPrompts
|
|
153
|
+
systemPrompts,
|
|
154
|
+
tools: (input.tools ?? []).map((t) => ({
|
|
155
|
+
__toolSide: "client",
|
|
156
|
+
name: t.name,
|
|
157
|
+
description: t.description,
|
|
158
|
+
inputSchema: sanitizeClientToolSchema(t.parameters)
|
|
159
|
+
}))
|
|
122
160
|
};
|
|
123
161
|
}
|
|
124
162
|
/**
|
|
@@ -150,16 +188,14 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
150
188
|
};
|
|
151
189
|
}
|
|
152
190
|
}
|
|
153
|
-
|
|
191
|
+
const startedToolCalls = /* @__PURE__ */ new Set();
|
|
192
|
+
const endedToolCalls = /* @__PURE__ */ new Set();
|
|
154
193
|
for await (const chunk of stream) {
|
|
155
194
|
if (abortSignal.aborted) break;
|
|
156
195
|
const raw = chunk;
|
|
157
196
|
const type = raw.type;
|
|
158
|
-
if (type === "RUN_FINISHED")
|
|
159
|
-
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
if (runFinished) continue;
|
|
197
|
+
if (type === "RUN_STARTED" || type === "RUN_FINISHED") continue;
|
|
198
|
+
if (type === "RUN_ERROR") throw new Error(typeof raw.message === "string" ? raw.message : "TanStack AI run error");
|
|
163
199
|
if (type === "TEXT_MESSAGE_CONTENT" && raw.delta != null) {
|
|
164
200
|
yield* closeReasoningIfOpen();
|
|
165
201
|
yield {
|
|
@@ -169,15 +205,19 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
169
205
|
delta: raw.delta
|
|
170
206
|
};
|
|
171
207
|
} else if (type === "TOOL_CALL_START") {
|
|
208
|
+
const toolCallId = raw.toolCallId;
|
|
209
|
+
if (startedToolCalls.has(toolCallId)) continue;
|
|
210
|
+
startedToolCalls.add(toolCallId);
|
|
172
211
|
yield* closeReasoningIfOpen();
|
|
173
|
-
toolNamesById.set(
|
|
212
|
+
toolNamesById.set(toolCallId, raw.toolCallName);
|
|
174
213
|
yield {
|
|
175
214
|
type: _ag_ui_client.EventType.TOOL_CALL_START,
|
|
176
215
|
parentMessageId: messageId,
|
|
177
|
-
toolCallId
|
|
216
|
+
toolCallId,
|
|
178
217
|
toolCallName: raw.toolCallName
|
|
179
218
|
};
|
|
180
219
|
} else if (type === "TOOL_CALL_ARGS") {
|
|
220
|
+
if (endedToolCalls.has(raw.toolCallId)) continue;
|
|
181
221
|
yield* closeReasoningIfOpen();
|
|
182
222
|
yield {
|
|
183
223
|
type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
|
|
@@ -185,10 +225,13 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
185
225
|
delta: raw.delta
|
|
186
226
|
};
|
|
187
227
|
} else if (type === "TOOL_CALL_END") {
|
|
228
|
+
const toolCallId = raw.toolCallId;
|
|
229
|
+
if (endedToolCalls.has(toolCallId)) continue;
|
|
230
|
+
endedToolCalls.add(toolCallId);
|
|
188
231
|
yield* closeReasoningIfOpen();
|
|
189
232
|
yield {
|
|
190
233
|
type: _ag_ui_client.EventType.TOOL_CALL_END,
|
|
191
|
-
toolCallId
|
|
234
|
+
toolCallId
|
|
192
235
|
};
|
|
193
236
|
} else if (type === "TOOL_CALL_RESULT") {
|
|
194
237
|
yield* closeReasoningIfOpen();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack.cjs","names":["EventType"],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import {\n BaseEvent,\n EventType,\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 { randomUUID } from \"@copilotkit/shared\";\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 * 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\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 * 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 return { messages, systemPrompts };\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 */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\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\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: after the model\n // returns tool calls, the engine tries to execute them and re-prompt. This\n // produces a second round of TOOL_CALL_START / TOOL_CALL_END events that\n // duplicate the ones from the first streaming pass. The CopilotKit runtime\n // handles tool execution externally (via the frontend SDK), so we must stop\n // converting events once the TanStack adapter signals the first turn is\n // complete with RUN_FINISHED.\n let runFinished = false;\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 // Stop converting after the first RUN_FINISHED — any subsequent events\n // come from TanStack's internal tool-execution loop and would produce\n // duplicate TOOL_CALL_END events that violate the ag-ui verify middleware.\n if (type === \"RUN_FINISHED\") {\n runFinished = true;\n continue;\n }\n if (runFinished) continue;\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 yield* closeReasoningIfOpen();\n toolNamesById.set(raw.toolCallId as string, raw.toolCallName as string);\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId: raw.toolCallId as string,\n toolCallName: raw.toolCallName as string,\n };\n yield startEvent;\n } else if (type === \"TOOL_CALL_ARGS\") {\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 yield* closeReasoningIfOpen();\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId: raw.toolCallId as string,\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 yield stateSnapshotEvent;\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 yield stateDeltaEvent;\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\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":["EventType"],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import type {\n BaseEvent,\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\";\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 */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\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\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 // Per-turn lifecycle markers are owned by the Agent wrapper, not forwarded.\n if (type === \"RUN_STARTED\" || type === \"RUN_FINISHED\") {\n continue;\n }\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 yield stateSnapshotEvent;\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 yield stateDeltaEvent;\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\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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"}
|
|
@@ -24,6 +24,22 @@ interface TanStackChatMessage {
|
|
|
24
24
|
}>;
|
|
25
25
|
toolCallId?: string;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A TanStack AI client-side tool, derived from a frontend-provided AG-UI tool.
|
|
29
|
+
*
|
|
30
|
+
* Shaped to match `@tanstack/ai`'s `ClientTool` (`__toolSide: "client"`, no
|
|
31
|
+
* `execute`): the model may CALL it, but TanStack does not run it — it pauses
|
|
32
|
+
* the run and hands the call back to the AG-UI client (the CopilotKit frontend
|
|
33
|
+
* / bot) to execute, mirroring CopilotKit's client-tool round-trip. `chat()`
|
|
34
|
+
* accepts a JSON Schema directly as `inputSchema`, so the AG-UI tool's
|
|
35
|
+
* `parameters` pass through unchanged.
|
|
36
|
+
*/
|
|
37
|
+
interface TanStackClientTool {
|
|
38
|
+
__toolSide: "client";
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
inputSchema: any;
|
|
42
|
+
}
|
|
27
43
|
/**
|
|
28
44
|
* Result of converting RunAgentInput to TanStack AI format.
|
|
29
45
|
*/
|
|
@@ -32,6 +48,14 @@ interface TanStackInputResult {
|
|
|
32
48
|
messages: TanStackChatMessage[];
|
|
33
49
|
/** System prompts extracted from system/developer messages, context, and state */
|
|
34
50
|
systemPrompts: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Client-side tools derived from `input.tools` (the frontend-provided tools
|
|
53
|
+
* the CopilotKit client forwards on every run). Pass these into `chat()`
|
|
54
|
+
* alongside any server/provider tools so the model can call the frontend's
|
|
55
|
+
* generative-UI and human-in-the-loop tools; TanStack pauses the run on a
|
|
56
|
+
* client-tool call and the client executes it.
|
|
57
|
+
*/
|
|
58
|
+
tools: TanStackClientTool[];
|
|
35
59
|
}
|
|
36
60
|
/**
|
|
37
61
|
* Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack.d.cts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tanstack.d.cts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;AA4EA;;;;;;;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;;EAEf,QAAA,EAAU,mBAAA;;EAEV,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBA4JO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;iBA+EoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,GACZ,cAAA,CAAe,SAAA"}
|
|
@@ -24,6 +24,22 @@ interface TanStackChatMessage {
|
|
|
24
24
|
}>;
|
|
25
25
|
toolCallId?: string;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A TanStack AI client-side tool, derived from a frontend-provided AG-UI tool.
|
|
29
|
+
*
|
|
30
|
+
* Shaped to match `@tanstack/ai`'s `ClientTool` (`__toolSide: "client"`, no
|
|
31
|
+
* `execute`): the model may CALL it, but TanStack does not run it — it pauses
|
|
32
|
+
* the run and hands the call back to the AG-UI client (the CopilotKit frontend
|
|
33
|
+
* / bot) to execute, mirroring CopilotKit's client-tool round-trip. `chat()`
|
|
34
|
+
* accepts a JSON Schema directly as `inputSchema`, so the AG-UI tool's
|
|
35
|
+
* `parameters` pass through unchanged.
|
|
36
|
+
*/
|
|
37
|
+
interface TanStackClientTool {
|
|
38
|
+
__toolSide: "client";
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
inputSchema: any;
|
|
42
|
+
}
|
|
27
43
|
/**
|
|
28
44
|
* Result of converting RunAgentInput to TanStack AI format.
|
|
29
45
|
*/
|
|
@@ -32,6 +48,14 @@ interface TanStackInputResult {
|
|
|
32
48
|
messages: TanStackChatMessage[];
|
|
33
49
|
/** System prompts extracted from system/developer messages, context, and state */
|
|
34
50
|
systemPrompts: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Client-side tools derived from `input.tools` (the frontend-provided tools
|
|
53
|
+
* the CopilotKit client forwards on every run). Pass these into `chat()`
|
|
54
|
+
* alongside any server/provider tools so the model can call the frontend's
|
|
55
|
+
* generative-UI and human-in-the-loop tools; TanStack pauses the run on a
|
|
56
|
+
* client-tool call and the client executes it.
|
|
57
|
+
*/
|
|
58
|
+
tools: TanStackClientTool[];
|
|
35
59
|
}
|
|
36
60
|
/**
|
|
37
61
|
* Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack.d.mts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tanstack.d.mts","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"mappings":";;;;;AA4EA;;;;;;;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;;EAEf,QAAA,EAAU,mBAAA;;EAEV,aAAA;;;;;;;;EAQA,KAAA,EAAO,kBAAA;AAAA;;;;;;;;;iBA4JO,wBAAA,CACd,KAAA,EAAO,aAAA,GACN,mBAAA;;;;;;;;iBA+EoB,qBAAA,CACrB,MAAA,EAAQ,aAAA,WACR,WAAA,EAAa,WAAA,GACZ,cAAA,CAAe,SAAA"}
|
|
@@ -82,6 +82,38 @@ function convertUserContent(content) {
|
|
|
82
82
|
return parts.length > 0 ? parts : "";
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
+
* Recursively normalizes a frontend tool's JSON Schema so OpenAI accepts it as
|
|
86
|
+
* a function-tool schema.
|
|
87
|
+
*
|
|
88
|
+
* Frontend tools are often authored with permissive Zod (`z.any()`,
|
|
89
|
+
* `z.record(...)`, `.passthrough()`), which serialize to open objects —
|
|
90
|
+
* `additionalProperties: {}` (an empty sub-schema) or `additionalProperties:
|
|
91
|
+
* true`. OpenAI rejects both: strict mode requires `additionalProperties:
|
|
92
|
+
* false`, and an empty `{}` sub-schema fails base validation ("schema must
|
|
93
|
+
* have a 'type' key"). The classic (Vercel AI SDK) path sanitized these
|
|
94
|
+
* implicitly via a Zod round-trip; the TanStack path forwards the raw schema,
|
|
95
|
+
* so we close open objects here to match. (Models can't supply free-form extra
|
|
96
|
+
* keys either way — same as the classic path.)
|
|
97
|
+
*/
|
|
98
|
+
function sanitizeClientToolSchema(schema) {
|
|
99
|
+
if (Array.isArray(schema)) return schema.map(sanitizeClientToolSchema);
|
|
100
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
101
|
+
const node = { ...schema };
|
|
102
|
+
if ("additionalProperties" in node) node.additionalProperties = false;
|
|
103
|
+
if (node.properties && typeof node.properties === "object") {
|
|
104
|
+
const props = {};
|
|
105
|
+
for (const [key, value] of Object.entries(node.properties)) props[key] = sanitizeClientToolSchema(value);
|
|
106
|
+
node.properties = props;
|
|
107
|
+
}
|
|
108
|
+
if ("items" in node) node.items = sanitizeClientToolSchema(node.items);
|
|
109
|
+
for (const combinator of [
|
|
110
|
+
"anyOf",
|
|
111
|
+
"allOf",
|
|
112
|
+
"oneOf"
|
|
113
|
+
]) if (Array.isArray(node[combinator])) node[combinator] = node[combinator].map(sanitizeClientToolSchema);
|
|
114
|
+
return node;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
85
117
|
* Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.
|
|
86
118
|
*
|
|
87
119
|
* - Keeps only user/assistant/tool messages (activity, reasoning, and other roles are also excluded)
|
|
@@ -117,7 +149,13 @@ function convertInputToTanStackAI(input) {
|
|
|
117
149
|
if (input.state !== void 0 && input.state !== null && typeof input.state === "object" && Object.keys(input.state).length > 0) systemPrompts.push(`Application State:\n\`\`\`json\n${JSON.stringify(input.state, null, 2)}\n\`\`\``);
|
|
118
150
|
return {
|
|
119
151
|
messages,
|
|
120
|
-
systemPrompts
|
|
152
|
+
systemPrompts,
|
|
153
|
+
tools: (input.tools ?? []).map((t) => ({
|
|
154
|
+
__toolSide: "client",
|
|
155
|
+
name: t.name,
|
|
156
|
+
description: t.description,
|
|
157
|
+
inputSchema: sanitizeClientToolSchema(t.parameters)
|
|
158
|
+
}))
|
|
121
159
|
};
|
|
122
160
|
}
|
|
123
161
|
/**
|
|
@@ -149,16 +187,14 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
149
187
|
};
|
|
150
188
|
}
|
|
151
189
|
}
|
|
152
|
-
|
|
190
|
+
const startedToolCalls = /* @__PURE__ */ new Set();
|
|
191
|
+
const endedToolCalls = /* @__PURE__ */ new Set();
|
|
153
192
|
for await (const chunk of stream) {
|
|
154
193
|
if (abortSignal.aborted) break;
|
|
155
194
|
const raw = chunk;
|
|
156
195
|
const type = raw.type;
|
|
157
|
-
if (type === "RUN_FINISHED")
|
|
158
|
-
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if (runFinished) continue;
|
|
196
|
+
if (type === "RUN_STARTED" || type === "RUN_FINISHED") continue;
|
|
197
|
+
if (type === "RUN_ERROR") throw new Error(typeof raw.message === "string" ? raw.message : "TanStack AI run error");
|
|
162
198
|
if (type === "TEXT_MESSAGE_CONTENT" && raw.delta != null) {
|
|
163
199
|
yield* closeReasoningIfOpen();
|
|
164
200
|
yield {
|
|
@@ -168,15 +204,19 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
168
204
|
delta: raw.delta
|
|
169
205
|
};
|
|
170
206
|
} else if (type === "TOOL_CALL_START") {
|
|
207
|
+
const toolCallId = raw.toolCallId;
|
|
208
|
+
if (startedToolCalls.has(toolCallId)) continue;
|
|
209
|
+
startedToolCalls.add(toolCallId);
|
|
171
210
|
yield* closeReasoningIfOpen();
|
|
172
|
-
toolNamesById.set(
|
|
211
|
+
toolNamesById.set(toolCallId, raw.toolCallName);
|
|
173
212
|
yield {
|
|
174
213
|
type: EventType.TOOL_CALL_START,
|
|
175
214
|
parentMessageId: messageId,
|
|
176
|
-
toolCallId
|
|
215
|
+
toolCallId,
|
|
177
216
|
toolCallName: raw.toolCallName
|
|
178
217
|
};
|
|
179
218
|
} else if (type === "TOOL_CALL_ARGS") {
|
|
219
|
+
if (endedToolCalls.has(raw.toolCallId)) continue;
|
|
180
220
|
yield* closeReasoningIfOpen();
|
|
181
221
|
yield {
|
|
182
222
|
type: EventType.TOOL_CALL_ARGS,
|
|
@@ -184,10 +224,13 @@ async function* convertTanStackStream(stream, abortSignal) {
|
|
|
184
224
|
delta: raw.delta
|
|
185
225
|
};
|
|
186
226
|
} else if (type === "TOOL_CALL_END") {
|
|
227
|
+
const toolCallId = raw.toolCallId;
|
|
228
|
+
if (endedToolCalls.has(toolCallId)) continue;
|
|
229
|
+
endedToolCalls.add(toolCallId);
|
|
187
230
|
yield* closeReasoningIfOpen();
|
|
188
231
|
yield {
|
|
189
232
|
type: EventType.TOOL_CALL_END,
|
|
190
|
-
toolCallId
|
|
233
|
+
toolCallId
|
|
191
234
|
};
|
|
192
235
|
} else if (type === "TOOL_CALL_RESULT") {
|
|
193
236
|
yield* closeReasoningIfOpen();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack.mjs","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import {\n BaseEvent,\n EventType,\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 { randomUUID } from \"@copilotkit/shared\";\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 * 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\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 * 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 return { messages, systemPrompts };\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 */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\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\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: after the model\n // returns tool calls, the engine tries to execute them and re-prompt. This\n // produces a second round of TOOL_CALL_START / TOOL_CALL_END events that\n // duplicate the ones from the first streaming pass. The CopilotKit runtime\n // handles tool execution externally (via the frontend SDK), so we must stop\n // converting events once the TanStack adapter signals the first turn is\n // complete with RUN_FINISHED.\n let runFinished = false;\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 // Stop converting after the first RUN_FINISHED — any subsequent events\n // come from TanStack's internal tool-execution loop and would produce\n // duplicate TOOL_CALL_END events that violate the ag-ui verify middleware.\n if (type === \"RUN_FINISHED\") {\n runFinished = true;\n continue;\n }\n if (runFinished) continue;\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 yield* closeReasoningIfOpen();\n toolNamesById.set(raw.toolCallId as string, raw.toolCallName as string);\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId: raw.toolCallId as string,\n toolCallName: raw.toolCallName as string,\n };\n yield startEvent;\n } else if (type === \"TOOL_CALL_ARGS\") {\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 yield* closeReasoningIfOpen();\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId: raw.toolCallId as string,\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 yield stateSnapshotEvent;\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 yield stateDeltaEvent;\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\nfunction safeParse(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n"],"mappings":";;;;;;;;;;AAsEA,SAAS,mBACP,SACuC;AACvC,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,OAAO,YAAY,SAAU,QAAO;AACxC,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;AACpC,KAAI,QAAQ,WAAW,EAAG,QAAO;CAEjC,MAAM,QAA+B,EAAE;AAEvC,MAAK,MAAM,QAAQ,SAAS;AAC1B,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,MAAO;AAE5D,UAAS,KAA0B,MAAnC;GACE,KAAK,QAAQ;IACX,MAAM,OAAQ,KAA2B;AACzC,QAAI,QAAQ,KAAM,OAAM,KAAK;KAAE,MAAM;KAAQ,SAAS;KAAM,CAAC;AAC7D;;GAGF,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,YAAY;IACf,MAAM,SAAU,KAA0B;AAC1C,QAAI,CAAC,OAAQ;IACb,MAAM,WAAY,KAA0B;AAK5C,QAAI,OAAO,SAAS,OAClB,OAAM,KAAK;KACT,MAAM;KACN,QAAQ;MACN,MAAM;MACN,OAAO,OAAO;MACd,UAAU,OAAO;MAClB;KACF,CAAC;aACO,OAAO,SAAS,MACzB,OAAM,KAAK;KACT,MAAM;KACN,QAAQ;MACN,MAAM;MACN,OAAO,OAAO;MACd,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,UAAU,GAAG,EAAE;MACzD;KACF,CAAC;AAEJ;;GAIF,KAAK,UAAU;IACb,MAAM,SAAS;IAKf,MAAM,WAAW,OAAO,YAAY;IACpC,MAAM,UAAU,SAAS,WAAW,SAAS;AAE7C,QAAI,OAAO,MAAM;KACf,MAAM,WAAW,UAAU,UAAU;AACrC,WAAM,KAAK;MACT,MAAM;MACN,QAAQ;OAAE,MAAM;OAAQ,OAAO,OAAO;OAAM;OAAU;MACvD,CAAC;eACO,OAAO,KAAK;KACrB,MAAM,WAAW,UAAU,UAAU;AACrC,WAAM,KAAK;MACT,MAAM;MACN,QAAQ;OAAE,MAAM;OAAO,OAAO,OAAO;OAAK;OAAU;MACrD,CAAC;;AAEJ;;;;AAKN,QAAO,MAAM,SAAS,IAAI,QAAQ;;;;;;;;;;AAWpC,SAAgB,yBACd,OACqB;CAIrB,MAAM,YAAY,IAAI,IAAI;EAAC;EAAQ;EAAa;EAAO,CAAC;CACxD,MAAM,WAAkC,MAAM,SAC3C,QAAQ,MAAe,UAAU,IAAI,EAAE,KAAK,CAAC,CAC7C,KAAK,MAAoC;EACxC,MAAM,MAA2B;GAC/B,MAAM,EAAE;GACR,SACE,EAAE,SAAS,SACP,mBAAmB,EAAE,QAAQ,GAC7B,OAAO,EAAE,YAAY,WACnB,EAAE,UACF;GACT;AACD,MAAI,EAAE,SAAS,eAAe,eAAe,KAAK,EAAE,UAClD,KAAI,YAAY,EAAE,UAAU,KAAK,QAAQ;GACvC,IAAI,GAAG;GACP,MAAM;GACN,UAAU;IACR,MAAM,GAAG,SAAS;IAClB,WAAW,GAAG,SAAS;IACxB;GACF,EAAE;AAEL,MAAI,EAAE,SAAS,UAAU,gBAAgB,EACvC,KAAI,aAAc,EAA8B;AAElD,SAAO;GACP;CAEJ,MAAM,gBAA0B,EAAE;AAClC,MAAK,MAAM,KAAK,MAAM,SACpB,MAAK,EAAE,SAAS,YAAY,EAAE,SAAS,gBAAgB,EAAE,QACvD,eAAc,KACZ,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAK,UAAU,EAAE,QAAQ,CACtE;AAIL,KAAI,MAAM,SAAS,OACjB,MAAK,MAAM,OAAO,MAAM,QACtB,eAAc,KAAK,GAAG,IAAI,YAAY,KAAK,IAAI,QAAQ;AAI3D,KACE,MAAM,UAAU,UAChB,MAAM,UAAU,QAChB,OAAO,MAAM,UAAU,YACvB,OAAO,KAAK,MAAM,MAAM,CAAC,SAAS,EAElC,eAAc,KACZ,mCAAmC,KAAK,UAAU,MAAM,OAAO,MAAM,EAAE,CAAC,UACzE;AAGH,QAAO;EAAE;EAAU;EAAe;;;;;;;;;AAUpC,gBAAuB,sBACrB,QACA,aAC2B;CAC3B,MAAM,YAAY,YAAY;CAC9B,MAAM,gCAAgB,IAAI,KAAqB;CAO/C,IAAI,mBAAmB;CACvB,IAAI,uBAAuB;CAC3B,IAAI,qBAAqB,YAAY;CAErC,UAAU,uBAA6C;AACrD,MAAI,sBAAsB;AACxB,0BAAuB;AAKvB,SAJyC;IACvC,MAAM,UAAU;IAChB,WAAW;IACZ;;AAGH,MAAI,kBAAkB;AACpB,sBAAmB;AAKnB,SAJ+B;IAC7B,MAAM,UAAU;IAChB,WAAW;IACZ;;;CAYL,IAAI,cAAc;AAElB,YAAW,MAAM,SAAS,QAAQ;AAChC,MAAI,YAAY,QAAS;EAEzB,MAAM,MAAM;EACZ,MAAM,OAAO,IAAI;AAKjB,MAAI,SAAS,gBAAgB;AAC3B,iBAAc;AACd;;AAEF,MAAI,YAAa;AAEjB,MAAI,SAAS,0BAA0B,IAAI,SAAS,MAAM;AACxD,UAAO,sBAAsB;AAO7B,SANyC;IACvC,MAAM,UAAU;IAChB,MAAM;IACN;IACA,OAAO,IAAI;IACZ;aAEQ,SAAS,mBAAmB;AACrC,UAAO,sBAAsB;AAC7B,iBAAc,IAAI,IAAI,YAAsB,IAAI,aAAuB;AAOvE,SANuC;IACrC,MAAM,UAAU;IAChB,iBAAiB;IACjB,YAAY,IAAI;IAChB,cAAc,IAAI;IACnB;aAEQ,SAAS,kBAAkB;AACpC,UAAO,sBAAsB;AAM7B,SALqC;IACnC,MAAM,UAAU;IAChB,YAAY,IAAI;IAChB,OAAO,IAAI;IACZ;aAEQ,SAAS,iBAAiB;AACnC,UAAO,sBAAsB;AAK7B,SAJmC;IACjC,MAAM,UAAU;IAChB,YAAY,IAAI;IACjB;aAEQ,SAAS,oBAAoB;AACtC,UAAO,sBAAsB;GAC7B,MAAM,aAAa,IAAI;GACvB,MAAM,WAAW,cAAc,IAAI,WAAW;GAM9C,MAAM,aAAa,IAAI,WAAW,IAAI;GAEtC,MAAM,gBACJ,OAAO,eAAe,WAAW,UAAU,WAAW,GAAG;AAE3D,OACE,aAAa,2BACb,iBACA,OAAO,kBAAkB,YACzB,cAAc,cAMd,OAJ+C;IAC7C,MAAM,UAAU;IAChB,UAAW,cAA0C;IACtD;AAIH,OACE,aAAa,wBACb,iBACA,OAAO,kBAAkB,YACzB,WAAW,cAMX,OAJyC;IACvC,MAAM,UAAU;IAChB,OAAQ,cAA0C;IACnD;GAIH,IAAI;AACJ,OAAI,OAAO,eAAe,SACxB,qBAAoB;OAEpB,KAAI;AACF,wBAAoB,KAAK,UAAU,cAAc,KAAK;WAChD;AACN,wBAAoB;;AAWxB,SAPyC;IACvC,MAAM,UAAU;IAChB,MAAM;IACN,WAAW,YAAY;IACvB;IACA,SAAS;IACV;AAED,iBAAc,OAAO,WAAW;aACvB,SAAS,mBAAmB;AAGrC,UAAO,sBAAsB;AAC7B,sBAAmB;AACnB,wBAAsB,IAAI,aAAwB,YAAY;AAK9D,SAJsC;IACpC,MAAM,UAAU;IAChB,WAAW;IACZ;aAEQ,SAAS,2BAA2B;AAC7C,0BAAuB;AAMvB,SALwC;IACtC,MAAM,UAAU;IAChB,WAAW;IACX,MAAM;IACP;aAEQ,SAAS,4BAMlB,OAL0C;GACxC,MAAM,UAAU;GAChB,WAAW;GACX,OAAO,IAAI;GACZ;WAEQ,SAAS,yBAAyB;AAC3C,0BAAuB;AAKvB,SAJsC;IACpC,MAAM,UAAU;IAChB,WAAW;IACZ;aAEQ,SAAS,iBAAiB;AAKnC,OAAI,sBAAsB;AACxB,2BAAuB;AAKvB,UAJyC;KACvC,MAAM,UAAU;KAChB,WAAW;KACZ;;AAGH,sBAAmB;AAKnB,SAJ+B;IAC7B,MAAM,UAAU;IAChB,WAAW;IACZ;;;AAKL,QAAO,sBAAsB;;AAG/B,SAAS,UAAU,OAAwB;AACzC,KAAI;AACF,SAAO,KAAK,MAAM,MAAM;SAClB;AACN,SAAO"}
|
|
1
|
+
{"version":3,"file":"tanstack.mjs","names":[],"sources":["../../../src/agent/converters/tanstack.ts"],"sourcesContent":["import type {\n BaseEvent,\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\";\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 */\nexport async function* convertTanStackStream(\n stream: AsyncIterable<unknown>,\n abortSignal: AbortSignal,\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\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 // Per-turn lifecycle markers are owned by the Agent wrapper, not forwarded.\n if (type === \"RUN_STARTED\" || type === \"RUN_FINISHED\") {\n continue;\n }\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 yield stateSnapshotEvent;\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 yield stateDeltaEvent;\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\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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"}
|
package/dist/package.cjs
CHANGED
|
@@ -5,7 +5,7 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
|
5
5
|
var require_package = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.61.
|
|
8
|
+
"version": "1.61.1",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
|
@@ -77,11 +77,11 @@ var require_package = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, m
|
|
|
77
77
|
"attw": "attw --pack . --profile node16"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@ag-ui/a2ui-middleware": "0.0.
|
|
80
|
+
"@ag-ui/a2ui-middleware": "0.0.10",
|
|
81
81
|
"@ag-ui/client": "0.0.57",
|
|
82
82
|
"@ag-ui/core": "0.0.57",
|
|
83
83
|
"@ag-ui/encoder": "0.0.57",
|
|
84
|
-
"@ag-ui/langgraph": "0.0.
|
|
84
|
+
"@ag-ui/langgraph": "0.0.42",
|
|
85
85
|
"@ag-ui/mcp-apps-middleware": "0.0.3",
|
|
86
86
|
"@ag-ui/mcp-middleware": "0.0.1",
|
|
87
87
|
"@ai-sdk/anthropic": "^3.0.49",
|
package/dist/package.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { __commonJSMin } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
5
5
|
var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.61.
|
|
8
|
+
"version": "1.61.1",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
|
@@ -77,11 +77,11 @@ var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
77
77
|
"attw": "attw --pack . --profile node16"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@ag-ui/a2ui-middleware": "0.0.
|
|
80
|
+
"@ag-ui/a2ui-middleware": "0.0.10",
|
|
81
81
|
"@ag-ui/client": "0.0.57",
|
|
82
82
|
"@ag-ui/core": "0.0.57",
|
|
83
83
|
"@ag-ui/encoder": "0.0.57",
|
|
84
|
-
"@ag-ui/langgraph": "0.0.
|
|
84
|
+
"@ag-ui/langgraph": "0.0.42",
|
|
85
85
|
"@ag-ui/mcp-apps-middleware": "0.0.3",
|
|
86
86
|
"@ag-ui/mcp-middleware": "0.0.1",
|
|
87
87
|
"@ai-sdk/anthropic": "^3.0.49",
|
package/dist/v2/index.cjs
CHANGED
|
@@ -53,4 +53,5 @@ exports.isA2UIEnabled = require_runtime$1.isA2UIEnabled;
|
|
|
53
53
|
exports.isIntelligenceRuntime = require_runtime$1.isIntelligenceRuntime;
|
|
54
54
|
exports.resolveAgents = require_runtime$1.resolveAgents;
|
|
55
55
|
exports.resolveModel = require_index.resolveModel;
|
|
56
|
+
exports.supportsLocalThreadEndpoints = require_agent_runner.supportsLocalThreadEndpoints;
|
|
56
57
|
exports.toFetchCorsConfig = require_hono.toFetchCorsConfig;
|
package/dist/v2/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { TranscribeFileOptions, TranscriptionService } from "./runtime/transcription-service/transcription-service.cjs";
|
|
3
|
-
import { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest } from "./runtime/runner/agent-runner.cjs";
|
|
3
|
+
import { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest, LocalThreadEndpointRecord, LocalThreadEndpointRunner, supportsLocalThreadEndpoints } from "./runtime/runner/agent-runner.cjs";
|
|
4
4
|
import { CopilotKitIntelligence, CopilotKitIntelligenceConfig, CreateThreadRequest, ListThreadsResponse, SubscribeToThreadsRequest, SubscribeToThreadsResponse, ThreadSummary, UpdateThreadRequest } from "./runtime/intelligence-platform/client.cjs";
|
|
5
5
|
import { AgentFactoryContext, AgentsConfig, AgentsFactory, CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotRuntime, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, IdentifyUserCallback, McpAppsConfig, McpAppsServerConfig, OpenGenerativeUIConfig, OpenGenerativeUIOptions, VERSION, isA2UIEnabled, isIntelligenceRuntime, resolveAgents } from "./runtime/core/runtime.cjs";
|
|
6
6
|
import { CopilotCorsConfig } from "./runtime/core/fetch-cors.cjs";
|
|
@@ -17,4 +17,4 @@ import { CopilotKitRequestHandler, MCPClient, MCPTransport } from "./runtime/ind
|
|
|
17
17
|
import { convertAISDKStream } from "../agent/converters/aisdk.cjs";
|
|
18
18
|
import { TanStackChatMessage, TanStackInputResult, convertInputToTanStackAI, convertTanStackStream } from "../agent/converters/tanstack.cjs";
|
|
19
19
|
import { BasicAgent, BasicAgentConfiguration, BuiltInAgent, BuiltInAgentAISDKFactoryConfig, BuiltInAgentClassicConfig, BuiltInAgentConfiguration, BuiltInAgentCustomFactoryConfig, BuiltInAgentFactoryConfig, BuiltInAgentModel, BuiltInAgentTanStackFactoryConfig, MCPClientConfig, MCPClientConfigHTTP, MCPClientConfigSSE, MCPClientProvider, MessageConversionOptions, ModelSpecifier, OverridableProperty, ToolDefinition, convertJsonSchemaToZodSchema, convertMessagesToVercelAISDKMessages, convertToolDefinitionsToVercelAITools, convertToolsToVercelAITools, defineTool, resolveModel } from "../agent/index.cjs";
|
|
20
|
-
export { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest, AgentsConfig, AgentsFactory, BasicAgent, BasicAgentConfiguration, BuiltInAgent, BuiltInAgentAISDKFactoryConfig, BuiltInAgentClassicConfig, BuiltInAgentConfiguration, BuiltInAgentCustomFactoryConfig, BuiltInAgentFactoryConfig, BuiltInAgentModel, BuiltInAgentTanStackFactoryConfig, CopilotCorsConfig, CopilotEndpointCorsConfig, CopilotExpressEndpointParams, CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotKitIntelligence, CopilotKitIntelligenceConfig, CopilotKitRequestHandler, CopilotRuntime, CopilotRuntimeFetchHandler, CopilotRuntimeHandlerOptions, CopilotRuntimeHooks, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, CreateThreadRequest, ErrorHookContext, HandlerHookContext, HookContext, IdentifyUserCallback, InMemoryAgentRunner, InMemoryThread, IntelligenceAgentRunner, IntelligenceAgentRunnerOptions, ListThreadsResponse, MCPClient, MCPClientConfig, MCPClientConfigHTTP, MCPClientConfigSSE, MCPClientProvider, MCPTransport, McpAppsConfig, McpAppsServerConfig, MessageConversionOptions, ModelSpecifier, OpenGenerativeUIConfig, OpenGenerativeUIOptions, OverridableProperty, ResponseHookContext, RouteInfo, RunnerStartupBoundary, SubscribeToThreadsRequest, SubscribeToThreadsResponse, TanStackChatMessage, TanStackInputResult, ThreadSummary, ToolDefinition, TranscribeFileOptions, TranscriptionService, UpdateThreadRequest, VERSION, convertAISDKStream, convertInputToTanStackAI, convertJsonSchemaToZodSchema, convertMessagesToVercelAISDKMessages, convertTanStackStream, convertToolDefinitionsToVercelAITools, convertToolsToVercelAITools, createCopilotEndpoint, createCopilotExpressHandler as createCopilotEndpointExpress, createCopilotExpressHandler, createCopilotEndpointSingleRoute, createCopilotEndpointSingleRouteExpress, createCopilotHonoHandler, createCopilotRuntimeHandler, defineTool, finalizeRunEvents, isA2UIEnabled, isIntelligenceRuntime, resolveAgents, resolveModel, toFetchCorsConfig };
|
|
20
|
+
export { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest, AgentsConfig, AgentsFactory, BasicAgent, BasicAgentConfiguration, BuiltInAgent, BuiltInAgentAISDKFactoryConfig, BuiltInAgentClassicConfig, BuiltInAgentConfiguration, BuiltInAgentCustomFactoryConfig, BuiltInAgentFactoryConfig, BuiltInAgentModel, BuiltInAgentTanStackFactoryConfig, CopilotCorsConfig, CopilotEndpointCorsConfig, CopilotExpressEndpointParams, CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotKitIntelligence, CopilotKitIntelligenceConfig, CopilotKitRequestHandler, CopilotRuntime, CopilotRuntimeFetchHandler, CopilotRuntimeHandlerOptions, CopilotRuntimeHooks, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, CreateThreadRequest, ErrorHookContext, HandlerHookContext, HookContext, IdentifyUserCallback, InMemoryAgentRunner, InMemoryThread, IntelligenceAgentRunner, IntelligenceAgentRunnerOptions, ListThreadsResponse, LocalThreadEndpointRecord, LocalThreadEndpointRunner, MCPClient, MCPClientConfig, MCPClientConfigHTTP, MCPClientConfigSSE, MCPClientProvider, MCPTransport, McpAppsConfig, McpAppsServerConfig, MessageConversionOptions, ModelSpecifier, OpenGenerativeUIConfig, OpenGenerativeUIOptions, OverridableProperty, ResponseHookContext, RouteInfo, RunnerStartupBoundary, SubscribeToThreadsRequest, SubscribeToThreadsResponse, TanStackChatMessage, TanStackInputResult, ThreadSummary, ToolDefinition, TranscribeFileOptions, TranscriptionService, UpdateThreadRequest, VERSION, convertAISDKStream, convertInputToTanStackAI, convertJsonSchemaToZodSchema, convertMessagesToVercelAISDKMessages, convertTanStackStream, convertToolDefinitionsToVercelAITools, convertToolsToVercelAITools, createCopilotEndpoint, createCopilotExpressHandler as createCopilotEndpointExpress, createCopilotExpressHandler, createCopilotEndpointSingleRoute, createCopilotEndpointSingleRouteExpress, createCopilotHonoHandler, createCopilotRuntimeHandler, defineTool, finalizeRunEvents, isA2UIEnabled, isIntelligenceRuntime, resolveAgents, resolveModel, supportsLocalThreadEndpoints, toFetchCorsConfig };
|