UNPKG

assistant-cloud

Version:

Cloud integration for assistant-ui

146 lines (145 loc) • 5.55 kB
import { createRunTelemetryToolCall, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "../runTelemetry.js"; // src/ai-sdk/index.ts /** The stored form of an AI SDK message: the message without its id. */ const aiSDKV6FormatAdapter = { format: "ai-sdk/v6", encode: ({ message: { id: _id, ...message } }) => message, decode: (stored) => ({ parentId: stored.parent_id, message: { id: stored.id, ...stored.content } }), getId: (message) => message.id }; function isRecord(value) { return value !== null && typeof value === "object"; } function isPart(value) { return isRecord(value) && typeof value.type === "string"; } /** * The AI SDK's own tool part rules, kept here so the entry loads without the * `ai` runtime: a static tool part is `tool-<name>`, a dynamic one is * `dynamic-tool` with its name in `toolName`. */ function toolCallOf(part) { if (typeof part.toolCallId !== "string") return void 0; const isStatic = part.type.startsWith("tool-"); if (!isStatic && part.type !== "dynamic-tool") return void 0; const toolName = isStatic ? part.type.slice(5) : typeof part.toolName === "string" ? part.toolName : void 0; if (!toolName) return void 0; return createRunTelemetryToolCall({ toolName, toolCallId: part.toolCallId, args: part.input ?? part.args, result: part.output ?? part.result, toolSource: isStatic ? "frontend" : "mcp" }); } function attachSamplingCalls(toolCalls, metadata) { const samplingCalls = isRecord(metadata?.samplingCalls) ? metadata.samplingCalls : void 0; if (!samplingCalls) return; for (const toolCall of toolCalls) { const calls = samplingCalls[toolCall.tool_call_id]; if (Array.isArray(calls) && calls.length > 0) toolCall.sampling_calls = calls; } } function stepUsages(metadata) { const steps = metadata?.steps; if (!Array.isArray(steps)) return []; return steps.map((step) => isRecord(step) && isRecord(step.usage) ? step.usage : void 0); } function sumUsage(usages) { const total = {}; for (const usage of usages) { if (usage.inputTokens != null) total.inputTokens = (total.inputTokens ?? 0) + usage.inputTokens; if (usage.outputTokens != null) total.outputTokens = (total.outputTokens ?? 0) + usage.outputTokens; if (usage.reasoningTokens != null) total.reasoningTokens = (total.reasoningTokens ?? 0) + usage.reasoningTokens; if (usage.cachedInputTokens != null) total.cachedInputTokens = (total.cachedInputTokens ?? 0) + usage.cachedInputTokens; } return total; } /** * The usage a message reports: `metadata.usage` when the integration copied * the run total there, else the sum over `metadata.steps[].usage`. */ function messageUsage(metadata) { const total = isRecord(metadata?.usage) ? normalizeRunTelemetryUsage(metadata.usage) : void 0; if (total) return total; const perStep = stepUsages(metadata).flatMap((usage) => { const normalized = usage ? normalizeRunTelemetryUsage(usage) : void 0; return normalized ? [normalized] : []; }); return perStep.length > 0 ? sumUsage(perStep) : void 0; } /** * Reads the run report fields out of the assistant messages of one run. A run * the AI SDK streamed as one message is one element; a run the cloud stored as * several assistant rows is aggregated, step by step, in order. Returns null * when no assistant message is present. Status reads completed when the run * produced text or tool calls, as a live finish with reason `tool-calls` does; * an integration that observed the finish event overrides it. */ function extractAISDKRunTelemetry(messages) { const textParts = []; const toolCalls = []; const steps = []; const usages = []; let assistant; for (const message of messages) { if (message.role !== "assistant") continue; assistant = message; const metadata = isRecord(message.metadata) ? message.metadata : void 0; const usagePerStep = stepUsages(metadata); const messageToolCalls = []; let step; let stepIndex = -1; for (const part of message.parts) { if (!isPart(part)) continue; if (part.type === "step-start") { stepIndex += 1; const usage = usagePerStep[stepIndex]; step = usage ? { usage } : {}; steps.push(step); continue; } if (part.type === "text" && typeof part.text === "string" && part.text) { textParts.push(part.text); continue; } const toolCall = toolCallOf(part); if (!toolCall) continue; toolCalls.push(toolCall); messageToolCalls.push(toolCall); if (step) { step.toolCalls = [...step.toolCalls ?? [], toolCall]; step.finishReason = "tool-calls"; } } attachSamplingCalls(messageToolCalls, metadata); const usage = messageUsage(metadata); if (usage) usages.push(usage); } if (!assistant) return null; const metadata = isRecord(assistant.metadata) ? assistant.metadata : void 0; const usage = usages.length > 0 ? sumUsage(usages) : void 0; const modelId = extractRunTelemetryModelId(metadata); const completed = textParts.length > 0 || toolCalls.length > 0; return { ...assistant.id !== void 0 ? { assistantMessageId: assistant.id } : void 0, status: completed ? "completed" : "incomplete", ...toolCalls.length > 0 ? { toolCalls } : void 0, ...steps.length > 0 ? { steps, totalSteps: steps.length } : void 0, ...textParts.length > 0 ? { outputText: truncateRunTelemetryText(textParts.join("")) } : void 0, ...usage ? { usage } : void 0, ...modelId ? { modelId } : void 0, ...metadata ? { metadata } : void 0 }; } export { aiSDKV6FormatAdapter, extractAISDKRunTelemetry }; //# sourceMappingURL=index.js.map