{"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} from \"@ag-ui/client\";\nimport { randomUUID } from \"@copilotkit/shared\";\n\n/**\n * A TanStack AI content part (text, image, audio, video, or document).\n */\nexport type TanStackContentPart =\n  | { type: \"text\"; content: string }\n  | {\n      type: \"image\" | \"audio\" | \"video\" | \"document\";\n      source:\n        | { type: \"data\"; value: string; mimeType: string }\n        | { type: \"url\"; value: string; mimeType?: string };\n    };\n\n/**\n * Message format expected by TanStack AI's `chat()`.\n */\nexport interface TanStackChatMessage {\n  role: \"user\" | \"assistant\" | \"tool\";\n  content: string | null | TanStackContentPart[];\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\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    if (type === \"TEXT_MESSAGE_CONTENT\" && raw.delta) {\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 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      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 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      let serializedContent: string;\n      if (typeof raw.content === \"string\") {\n        serializedContent = raw.content;\n      } else {\n        try {\n          serializedContent = JSON.stringify(raw.content ?? raw.result ?? null);\n        } catch {\n          serializedContent = \"[Unserializable tool result]\";\n        }\n      }\n      const resultEvent: ToolCallResultEvent = {\n        type: EventType.TOOL_CALL_RESULT,\n        role: \"tool\",\n        messageId: randomUUID(),\n        toolCallId: raw.toolCallId as string,\n        content: serializedContent,\n      };\n      yield resultEvent;\n    }\n    // Unhandled chunk types are silently ignored.\n    // Known gaps: STATE_SNAPSHOT, STATE_DELTA, and REASONING events are not\n    // converted from TanStack streams. Shared state and reasoning will not\n    // surface when using the TanStack backend. Use the AI SDK backend if these\n    // features are required.\n  }\n}\n"],"mappings":"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"}