UNPKG

@tanstack/ai

Version:

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

100 lines (99 loc) 4.5 kB
import { EventType } from "../types.js"; import { isTanstackUsage, toSpecTokenUsage } from "./ag-ui-usage.js"; import { withTanstackMetadata } from "./merge-metadata.js"; import { reasoningEncryptedValue } from "./reasoning-encrypted-value.js"; import { specKeysFor } from "./spec-event-keys.js"; //#region src/utilities/normalize-stream-chunk.ts function stringField(value) { return typeof value === "string" && value !== "" ? value : void 0; } function encryptedValueExtras(chunk) { const extras = []; const timestamp = "timestamp" in chunk && typeof chunk.timestamp === "number" ? chunk.timestamp : void 0; if (typeof chunk.signature === "string" && chunk.signature !== "") { const source = chunk; const toolCallId = stringField(source.toolCallId); const entityId = stringField(chunk.stepId) ?? stringField(source.stepName) ?? stringField(source.messageId) ?? toolCallId; if (entityId !== void 0) extras.push(reasoningEncryptedValue({ subtype: toolCallId && !chunk.stepId ? "tool-call" : "message", entityId, encryptedValue: chunk.signature, timestamp })); } if (chunk.type === EventType.TOOL_CALL_START) { const thoughtSignature = stringField(chunk.metadata?.thoughtSignature); if (thoughtSignature !== void 0 && chunk.toolCallId) extras.push(reasoningEncryptedValue({ subtype: "tool-call", entityId: chunk.toolCallId, encryptedValue: thoughtSignature, timestamp })); } return extras; } function normalizeStreamChunk(chunk) { const specKeys = specKeysFor(chunk.type); const source = chunk; const specChunk = {}; for (const key of Object.keys(chunk)) if (specKeys.has(key)) specChunk[key] = source[key]; if (chunk.type === EventType.TOOL_CALL_START) { if (specChunk.toolCallName === void 0 && chunk.toolName) specChunk.toolCallName = chunk.toolName; } if (chunk.type === EventType.RUN_ERROR && chunk.error != null) { if (specChunk.message === void 0 && chunk.error.message) specChunk.message = chunk.error.message; if (specChunk.code === void 0 && chunk.error.code !== void 0) specChunk.code = chunk.error.code; } const tanstack = {}; if (chunk.model !== void 0 && chunk.type !== EventType.TEXT_MESSAGE_CONTENT && chunk.type !== EventType.TOOL_CALL_ARGS) tanstack.model = chunk.model; if (chunk.finishReason !== void 0) tanstack.finishReason = chunk.finishReason; const interruptErrors = chunk["tanstack:interruptErrors"]; if (interruptErrors !== void 0) tanstack.interruptErrors = interruptErrors; if (chunk.type === EventType.CUSTOM || chunk.type === EventType.RUN_ERROR) { if (chunk.threadId !== void 0) tanstack.threadId = chunk.threadId; if (chunk.runId !== void 0) tanstack.runId = chunk.runId; } const skipLeftover = /* @__PURE__ */ new Set([ "result", "error", "tanstack:interruptErrors" ]); if (chunk.type === EventType.TEXT_MESSAGE_CONTENT || chunk.type === EventType.TOOL_CALL_ARGS) { skipLeftover.add("model"); skipLeftover.add("content"); skipLeftover.add("args"); } if (chunk.type === EventType.TOOL_CALL_START) skipLeftover.add("toolName"); for (const key of Object.keys(chunk)) { if (specKeys.has(key) || skipLeftover.has(key)) continue; if (tanstack[key] !== void 0) continue; const value = source[key]; if (value !== void 0) tanstack[key] = value; } if ((chunk.type === EventType.RUN_FINISHED || chunk.type === EventType.RUN_ERROR) && isTanstackUsage(specChunk.usage)) { const { usage, leftover } = toSpecTokenUsage(specChunk.usage, { model: typeof chunk.model === "string" ? chunk.model : void 0 }); specChunk.usage = usage; if (leftover !== void 0) tanstack.usage = leftover; } const normalized = Object.keys(tanstack).length === 0 ? specChunk : withTanstackMetadata(specChunk, tanstack); const extras = encryptedValueExtras(chunk); const main = [normalized]; if (chunk.type === EventType.TOOL_CALL_END && chunk.result !== void 0) { const parentMessageId = source.parentMessageId; const resultChunk = { type: EventType.TOOL_CALL_RESULT, toolCallId: chunk.toolCallId, content: Array.isArray(chunk.result) ? JSON.stringify(chunk.result) : chunk.result, messageId: typeof parentMessageId === "string" && parentMessageId !== "" ? parentMessageId : chunk.toolCallId }; if (chunk.state === "output-error") main.push({ ...resultChunk, metadata: { tanstack: { state: chunk.state } } }); else main.push(resultChunk); } return [...main, ...extras]; } //#endregion export { normalizeStreamChunk }; //# sourceMappingURL=normalize-stream-chunk.js.map