@copilotkit/runtime
Version:
<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />
276 lines (274 loc) • 8.64 kB
JavaScript
require("reflect-metadata");
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
let _copilotkit_shared = require("@copilotkit/shared");
let _ag_ui_client = require("@ag-ui/client");
//#region src/agent/converters/tanstack.ts
/**
* Converts AG-UI user message content to TanStack AI format.
* Handles plain strings, multimodal parts (image/audio/video/document),
* and legacy BinaryInputContent for backward compatibility.
*/
function convertUserContent(content) {
if (!content) return null;
if (typeof content === "string") return content;
if (!Array.isArray(content)) return null;
if (content.length === 0) return "";
const parts = [];
for (const part of content) {
if (!part || typeof part !== "object" || !("type" in part)) continue;
switch (part.type) {
case "text": {
const text = part.text;
if (text != null) parts.push({
type: "text",
content: text
});
break;
}
case "image":
case "audio":
case "video":
case "document": {
const source = part.source;
if (!source) break;
const partType = part.type;
if (source.type === "data") parts.push({
type: partType,
source: {
type: "data",
value: source.value,
mimeType: source.mimeType
}
});
else if (source.type === "url") parts.push({
type: partType,
source: {
type: "url",
value: source.value,
...source.mimeType ? { mimeType: source.mimeType } : {}
}
});
break;
}
case "binary": {
const legacy = part;
const mimeType = legacy.mimeType ?? "application/octet-stream";
const isImage = mimeType.startsWith("image/");
if (legacy.data) {
const partType = isImage ? "image" : "document";
parts.push({
type: partType,
source: {
type: "data",
value: legacy.data,
mimeType
}
});
} else if (legacy.url) {
const partType = isImage ? "image" : "document";
parts.push({
type: partType,
source: {
type: "url",
value: legacy.url,
mimeType
}
});
}
break;
}
}
}
return parts.length > 0 ? parts : "";
}
/**
* Converts a RunAgentInput into the format expected by TanStack AI's `chat()`.
*
* - Keeps only user/assistant/tool messages (activity, reasoning, and other roles are also excluded)
* - Extracts system/developer messages into `systemPrompts`
* - Appends context entries and application state to `systemPrompts`
* - Preserves tool calls on assistant messages and toolCallId on tool messages
*/
function convertInputToTanStackAI(input) {
const chatRoles = new Set([
"user",
"assistant",
"tool"
]);
const messages = input.messages.filter((m) => chatRoles.has(m.role)).map((m) => {
const msg = {
role: m.role,
content: m.role === "user" ? convertUserContent(m.content) : typeof m.content === "string" ? m.content : null
};
if (m.role === "assistant" && "toolCalls" in m && m.toolCalls) msg.toolCalls = m.toolCalls.map((tc) => ({
id: tc.id,
type: "function",
function: {
name: tc.function.name,
arguments: tc.function.arguments
}
}));
if (m.role === "tool" && "toolCallId" in m) msg.toolCallId = m.toolCallId;
return msg;
});
const systemPrompts = [];
for (const m of input.messages) if ((m.role === "system" || m.role === "developer") && m.content) systemPrompts.push(typeof m.content === "string" ? m.content : JSON.stringify(m.content));
if (input.context?.length) for (const ctx of input.context) systemPrompts.push(`${ctx.description}:\n${ctx.value}`);
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\`\`\``);
return {
messages,
systemPrompts
};
}
/**
* Converts a TanStack AI stream into AG-UI `BaseEvent` objects.
*
* This is a pure converter — it does NOT emit lifecycle events
* (RUN_STARTED / RUN_FINISHED / RUN_ERROR). The caller (Agent class)
* is responsible for those.
*/
async function* convertTanStackStream(stream, abortSignal) {
const messageId = (0, _copilotkit_shared.randomUUID)();
const toolNamesById = /* @__PURE__ */ new Map();
let reasoningRunOpen = false;
let reasoningMessageOpen = false;
let reasoningMessageId = (0, _copilotkit_shared.randomUUID)();
function* closeReasoningIfOpen() {
if (reasoningMessageOpen) {
reasoningMessageOpen = false;
yield {
type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
messageId: reasoningMessageId
};
}
if (reasoningRunOpen) {
reasoningRunOpen = false;
yield {
type: _ag_ui_client.EventType.REASONING_END,
messageId: reasoningMessageId
};
}
}
let runFinished = false;
for await (const chunk of stream) {
if (abortSignal.aborted) break;
const raw = chunk;
const type = raw.type;
if (type === "RUN_FINISHED") {
runFinished = true;
continue;
}
if (runFinished) continue;
if (type === "TEXT_MESSAGE_CONTENT" && raw.delta != null) {
yield* closeReasoningIfOpen();
yield {
type: _ag_ui_client.EventType.TEXT_MESSAGE_CHUNK,
role: "assistant",
messageId,
delta: raw.delta
};
} else if (type === "TOOL_CALL_START") {
yield* closeReasoningIfOpen();
toolNamesById.set(raw.toolCallId, raw.toolCallName);
yield {
type: _ag_ui_client.EventType.TOOL_CALL_START,
parentMessageId: messageId,
toolCallId: raw.toolCallId,
toolCallName: raw.toolCallName
};
} else if (type === "TOOL_CALL_ARGS") {
yield* closeReasoningIfOpen();
yield {
type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
toolCallId: raw.toolCallId,
delta: raw.delta
};
} else if (type === "TOOL_CALL_END") {
yield* closeReasoningIfOpen();
yield {
type: _ag_ui_client.EventType.TOOL_CALL_END,
toolCallId: raw.toolCallId
};
} else if (type === "TOOL_CALL_RESULT") {
yield* closeReasoningIfOpen();
const toolCallId = raw.toolCallId;
const toolName = toolNamesById.get(toolCallId);
const rawPayload = raw.content ?? raw.result;
const parsedContent = typeof rawPayload === "string" ? safeParse(rawPayload) : rawPayload;
if (toolName === "AGUISendStateSnapshot" && parsedContent && typeof parsedContent === "object" && "snapshot" in parsedContent) yield {
type: _ag_ui_client.EventType.STATE_SNAPSHOT,
snapshot: parsedContent.snapshot
};
if (toolName === "AGUISendStateDelta" && parsedContent && typeof parsedContent === "object" && "delta" in parsedContent) yield {
type: _ag_ui_client.EventType.STATE_DELTA,
delta: parsedContent.delta
};
let serializedContent;
if (typeof rawPayload === "string") serializedContent = rawPayload;
else try {
serializedContent = JSON.stringify(rawPayload ?? null);
} catch {
serializedContent = "[Unserializable tool result]";
}
yield {
type: _ag_ui_client.EventType.TOOL_CALL_RESULT,
role: "tool",
messageId: (0, _copilotkit_shared.randomUUID)(),
toolCallId,
content: serializedContent
};
toolNamesById.delete(toolCallId);
} else if (type === "REASONING_START") {
yield* closeReasoningIfOpen();
reasoningRunOpen = true;
reasoningMessageId = raw.messageId ?? (0, _copilotkit_shared.randomUUID)();
yield {
type: _ag_ui_client.EventType.REASONING_START,
messageId: reasoningMessageId
};
} else if (type === "REASONING_MESSAGE_START") {
reasoningMessageOpen = true;
yield {
type: _ag_ui_client.EventType.REASONING_MESSAGE_START,
messageId: reasoningMessageId,
role: "reasoning"
};
} else if (type === "REASONING_MESSAGE_CONTENT") yield {
type: _ag_ui_client.EventType.REASONING_MESSAGE_CONTENT,
messageId: reasoningMessageId,
delta: raw.delta
};
else if (type === "REASONING_MESSAGE_END") {
reasoningMessageOpen = false;
yield {
type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
messageId: reasoningMessageId
};
} else if (type === "REASONING_END") {
if (reasoningMessageOpen) {
reasoningMessageOpen = false;
yield {
type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
messageId: reasoningMessageId
};
}
reasoningRunOpen = false;
yield {
type: _ag_ui_client.EventType.REASONING_END,
messageId: reasoningMessageId
};
}
}
yield* closeReasoningIfOpen();
}
function safeParse(value) {
try {
return JSON.parse(value);
} catch {
return value;
}
}
//#endregion
exports.convertInputToTanStackAI = convertInputToTanStackAI;
exports.convertTanStackStream = convertTanStackStream;
//# sourceMappingURL=tanstack.cjs.map