UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

93 lines (92 loc) 2.95 kB
//#region src/utilities/ag-ui-wire.ts /** * Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages` * wire shape. Each anchor (system/user/assistant) carries the canonical * `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`) * so AG-UI Zod parsing succeeds. Tool results and thinking parts on * assistant messages are additionally emitted as fan-out * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict * AG-UI server consumers. */ function uiMessagesToWire(messages) { const wire = []; for (const msg of messages) { const parts = msg.parts ?? []; if (msg.role === "system") { wire.push({ ...msg, content: parts.length > 0 ? collectText(parts) : msg.content ?? "" }); continue; } if (msg.role === "user") { wire.push({ ...msg, content: parts.length > 0 ? collectUserContent(parts) : msg.content ?? "" }); continue; } for (const part of parts) if (part.type === "thinking") wire.push({ role: "reasoning", id: deriveReasoningId(msg.id, part), content: part.content }); const text = collectText(parts); const toolCalls = collectToolCalls(parts); wire.push({ ...msg, ...text !== "" && { content: text }, ...toolCalls && { toolCalls } }); for (const part of parts) if (part.type === "tool-result") wire.push({ role: "tool", id: deriveToolMessageId(part.toolCallId), toolCallId: part.toolCallId, content: typeof part.content === "string" ? part.content : JSON.stringify(part.content), ...part.error !== void 0 && { error: part.error } }); } return wire; } function collectText(parts) { const out = []; for (const p of parts) if (p.type === "text") out.push(p.content); else if (p.type === "structured-output" && p.status === "complete" && p.raw !== "") out.push(p.raw); return out.join(""); } function collectUserContent(parts) { if (!parts.some((p) => p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document")) return collectText(parts); const out = []; for (const p of parts) if (p.type === "text") out.push({ type: "text", text: p.content }); else if (p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document") out.push(p); return out; } function collectToolCalls(parts) { const calls = []; for (const p of parts) if (p.type === "tool-call") calls.push({ id: p.id, type: "function", function: { name: p.name, arguments: p.arguments } }); return calls.length > 0 ? calls : void 0; } function deriveReasoningId(messageId, part) { return `${messageId}-reasoning-${part.id ?? hashContent(part.content)}`; } function deriveToolMessageId(toolCallId) { return `tool-${toolCallId}`; } function hashContent(s) { let h = 0; for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) | 0; return Math.abs(h).toString(36); } //#endregion export { uiMessagesToWire }; //# sourceMappingURL=ag-ui-wire.js.map