{"version":3,"file":"assembled-to-message.cjs","names":["HumanMessage","SystemMessage","ToolMessage","AIMessageChunk","AIMessage"],"sources":["../../src/stream/assembled-to-message.ts"],"sourcesContent":["/**\n * Convert the protocol-native {@link AssembledMessage} (a namespace +\n * content-block bag) into a class instance from\n * `@langchain/core/messages`.\n *\n * The v2 messages channel carries `role` on the `message-start`\n * event, but `MessageAssembler` drops it by the time it produces an\n * `AssembledMessage`. The selector-side caller therefore captures the\n * role separately (via the assembler's per-update hook, see\n * `projections/messages.ts`) and passes it in.\n *\n * The conversion is intentionally lossless in the limit: when the\n * message finishes we emit the same BaseMessage shape that a\n * `values.messages` entry would round-trip to via\n * {@link tryCoerceMessageLikeToMessage}. Mid-stream, partial blocks\n * (e.g. tool_call_chunk) are folded into the same shape so the UI\n * can render an incrementally-completing message.\n */\nimport {\n  AIMessage,\n  AIMessageChunk,\n  HumanMessage,\n  SystemMessage,\n  ToolMessage,\n  type BaseMessage,\n  type UsageMetadata,\n} from \"@langchain/core/messages\";\nimport type { ContentBlock, MessageRole, UsageInfo } from \"@langchain/protocol\";\nimport type { AssembledMessage } from \"../client/stream/messages.js\";\n\nexport type ExtendedMessageRole = MessageRole | \"tool\";\n\nexport interface AssembledToMessageInput {\n  /** Stable message id (from `MessageStartData.id`). */\n  id?: string;\n  /** Author role captured from the `message-start` event. */\n  role: ExtendedMessageRole;\n  /** Content blocks assembled so far. */\n  blocks: ContentBlock[];\n  /** Namespace associated with the streamed message. */\n  namespace?: readonly string[];\n  /** Graph node associated with the streamed message. */\n  node?: string;\n  runId?: string;\n  /** Tool-call id a `role: \"tool\"` message is responding to, if any. */\n  toolCallId?: string;\n  /** Provider metadata (populated on `message-start`). */\n  metadata?: Readonly<Record<string, unknown>>;\n  /** Final-token usage (populated on `message-finish`). */\n  usage?: UsageInfo;\n  /** Response metadata (populated on `message-finish`). */\n  finishMetadata?: Readonly<Record<string, unknown>>;\n  /** Finish reason (populated on `message-finish`). */\n  finishReason?: string;\n}\n\n/**\n * Produce a `BaseMessage` class instance from an in-progress or\n * finished assembled message. Safe to call repeatedly across deltas —\n * each call returns a new instance whose content reflects the\n * currently-observed blocks.\n */\nexport function assembledToBaseMessage(\n  input: AssembledToMessageInput\n): BaseMessage {\n  const {\n    id,\n    role,\n    blocks,\n    namespace,\n    node,\n    runId,\n    toolCallId,\n    metadata,\n    usage,\n    finishMetadata,\n    finishReason,\n  } = input;\n  const textContent = extractContentString(blocks);\n  const toolCalls = extractToolCalls(blocks);\n  const toolCallChunks = extractToolCallChunks(blocks);\n  const additionalKwargs = {\n    ...(namespace != null ? { namespace } : {}),\n    ...(node != null ? { node } : {}),\n    ...(runId != null ? { run_id: runId } : {}),\n    ...(metadata != null ? { metadata } : {}),\n    ...(usage != null ? { usage } : {}),\n  };\n  const hasAdditionalKwargs = Object.keys(additionalKwargs).length > 0;\n  const responseMetadata = {\n    ...(finishReason != null ? { finish_reason: finishReason } : {}),\n    ...finishMetadata,\n  };\n\n  switch (role) {\n    case \"human\":\n      return new HumanMessage({\n        ...(id != null ? { id } : {}),\n        content: textContent,\n        ...(hasAdditionalKwargs ? { additional_kwargs: additionalKwargs } : {}),\n        ...(Object.keys(responseMetadata).length > 0\n          ? { response_metadata: responseMetadata }\n          : {}),\n      });\n    case \"system\":\n      return new SystemMessage({\n        ...(id != null ? { id } : {}),\n        content: textContent,\n        ...(hasAdditionalKwargs ? { additional_kwargs: additionalKwargs } : {}),\n        ...(Object.keys(responseMetadata).length > 0\n          ? { response_metadata: responseMetadata }\n          : {}),\n      });\n    case \"tool\":\n      return new ToolMessage({\n        ...(id != null ? { id } : {}),\n        content: textContent,\n        tool_call_id: toolCallId ?? \"\",\n        ...(hasAdditionalKwargs ? { additional_kwargs: additionalKwargs } : {}),\n        ...(Object.keys(responseMetadata).length > 0\n          ? { response_metadata: responseMetadata }\n          : {}),\n      });\n    case \"ai\":\n    default: {\n      // Use `AIMessageChunk` whenever tool_call_chunks are present —\n      // the concrete `AIMessage` class silently DROPS the\n      // `tool_call_chunks` field, which would leave mid-stream tool\n      // calls invisible to the UI (it sees an AI message with empty\n      // content and no tool calls, rendering a blank bubble until\n      // `content-block-finish` finally promotes the chunks to\n      // finalized `tool_calls`). The chunk class is assignment-compatible\n      // with `BaseMessage` and round-trips through the merge logic.\n      const payload = {\n        ...(id != null ? { id } : {}),\n        content: cloneContentBlocks(blocks),\n        ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n        ...(toolCallChunks.length > 0\n          ? { tool_call_chunks: toolCallChunks }\n          : {}),\n        ...(hasAdditionalKwargs ? { additional_kwargs: additionalKwargs } : {}),\n        usage_metadata: normalizeUsage(usage),\n        response_metadata: {\n          ...responseMetadata,\n          output_version: \"v1\" as const,\n        },\n      };\n      return toolCallChunks.length > 0\n        ? new AIMessageChunk(\n            payload as ConstructorParameters<typeof AIMessageChunk>[0]\n          )\n        : new AIMessage(payload as ConstructorParameters<typeof AIMessage>[0]);\n    }\n  }\n}\n\n/**\n * Convenience: given the raw assembled message + the role captured\n * from `message-start`, produce a `BaseMessage` with the same id.\n */\nexport function assembledMessageToBaseMessage(\n  assembled: AssembledMessage,\n  role: ExtendedMessageRole,\n  extras: { toolCallId?: string } = {}\n): BaseMessage {\n  return assembledToBaseMessage({\n    id: assembled.id,\n    role,\n    blocks: assembled.blocks,\n    namespace: assembled.namespace,\n    node: assembled.node,\n    runId: assembled.runId,\n    toolCallId: extras.toolCallId,\n    metadata: assembled.metadata,\n    usage: assembled.usage,\n    finishMetadata: assembled.finishMetadata,\n    finishReason: assembled.finishReason,\n  });\n}\n\n// ---------- helpers ----------\n\nfunction normalizeUsage(\n  usage: UsageInfo | undefined\n): UsageMetadata | undefined {\n  if (usage == null) return undefined;\n  return {\n    ...usage,\n    input_tokens: usage.input_tokens ?? 0,\n    output_tokens: usage.output_tokens ?? 0,\n    total_tokens: usage.total_tokens ?? 0,\n  };\n}\n\nfunction extractContentString(blocks: ContentBlock[]): string {\n  let out = \"\";\n  for (const block of blocks) {\n    if (\n      block.type === \"text\" &&\n      typeof (block as { text?: unknown }).text === \"string\"\n    ) {\n      out += (block as { text: string }).text;\n    }\n  }\n  return out;\n}\n\nfunction cloneContentBlocks(blocks: ContentBlock[]): ContentBlock[] {\n  return blocks.map((block) => structuredClone(block));\n}\n\ninterface LooseToolCall {\n  id: string;\n  name: string;\n  args: Record<string, unknown>;\n  type: \"tool_call\";\n}\n\nfunction extractToolCalls(blocks: ContentBlock[]): LooseToolCall[] {\n  const out: LooseToolCall[] = [];\n  for (const block of blocks) {\n    if (block.type !== \"tool_call\" && block.type !== \"tool_use\") continue;\n    const tc = block as ToolCallLikeBlock;\n    out.push({\n      id: tc.id ?? \"\",\n      name: tc.name ?? \"\",\n      args: normalizeToolCallArgs(tc.args ?? tc.input),\n      type: \"tool_call\",\n    });\n  }\n  return out;\n}\n\ninterface ToolCallLikeBlock {\n  id?: string;\n  name?: string;\n  args?: unknown;\n  input?: unknown;\n}\n\ninterface LooseToolCallChunk {\n  id?: string;\n  name?: string;\n  args?: string;\n  index?: number;\n  type: \"tool_call_chunk\";\n}\n\nfunction extractToolCallChunks(blocks: ContentBlock[]): LooseToolCallChunk[] {\n  const out: LooseToolCallChunk[] = [];\n  for (const block of blocks) {\n    if (block.type !== \"tool_call_chunk\") continue;\n    const tc = block as {\n      id?: string;\n      name?: string;\n      args?: string;\n      index?: number;\n    };\n    out.push({\n      id: tc.id,\n      name: tc.name,\n      args: tc.args,\n      index: tc.index,\n      type: \"tool_call_chunk\",\n    });\n  }\n  return out;\n}\n\nfunction normalizeToolCallArgs(value: unknown): Record<string, unknown> {\n  if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n    return value as Record<string, unknown>;\n  }\n  if (typeof value === \"string\" && value.length > 0) {\n    try {\n      const parsed = JSON.parse(value);\n      if (\n        parsed != null &&\n        typeof parsed === \"object\" &&\n        !Array.isArray(parsed)\n      ) {\n        return parsed as Record<string, unknown>;\n      }\n    } catch {\n      // Partial streaming input is represented via tool_call_chunks.\n    }\n  }\n  return {};\n}\n"],"mappings":"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"}