{"version":3,"file":"root-message-projection.cjs","names":["#messagesKey","#store","MessageAssembler","#roles","#indexById","#toolCallIdByNamespace","#assembler","#valuesMessageIds","#pendingMessages","#pendingValues","#flushScheduled","namespaceKey","assembledMessageToBaseMessage","messagesEqual","#scheduleFlush","reconcileMessagesFromValues","shouldPreferValuesMessageForToolCalls","buildMessageIndex","#flushPending"],"sources":["../../src/stream/root-message-projection.ts"],"sourcesContent":["/**\n * Root-namespace message projection.\n *\n * # What this module is\n *\n * The {@link RootMessageProjection} is the piece of the\n * {@link StreamController} that owns \"what messages does the root\n * namespace currently contain?\". It assembles streamed message deltas\n * via {@link MessageAssembler}, reconciles them against authoritative\n * `values.messages` snapshots from the server, and writes the merged\n * list back into the controller's root snapshot store.\n *\n * # Two streams of truth\n *\n * Root messages arrive on two channels and need to merge cleanly:\n *\n *   - **`messages` channel.** Token-level deltas that build messages\n *     incrementally. The {@link MessageAssembler} keeps partial\n *     messages by id and emits an updated `BaseMessage` per delta.\n *   - **`values` channel.** Periodic full-state snapshots that include\n *     the authoritative messages array. Used for ordering, removals,\n *     and forks (where the streamed messages may pre-date the new\n *     timeline).\n *\n * The reconciliation rules (delegated to\n * {@link reconcileMessagesFromValues}) preserve in-flight streamed\n * content while letting values dictate ordering and removals.\n *\n * # Tool-message namespace correlation\n *\n * Tool messages arrive on `messages-start` events with `role: \"tool\"`\n * but the start event doesn't always include a `tool_call_id`. We\n * recover it via three fallbacks:\n *\n *   1. The start event itself, when the server includes it.\n *   2. The legacy `<id>-tool-<call_id>` message id format.\n *   3. The most recent `tool-started` event recorded under the same\n *      namespace via {@link recordToolCallNamespace}.\n *\n * Without this correlation, tool messages render with empty\n * `tool_call_id` and downstream UIs can't pair them with the\n * originating tool call.\n *\n * # Store-write batching\n *\n * Every {@link handleMessage} / {@link applyValues} call updates the\n * in-projection bookkeeping (assembler state, id index, role cache)\n * synchronously, then stages the new `messages` / `values` into a\n * pending buffer and schedules a `setTimeout(0)` flush. A single\n * coalesced `store.setState` runs at the next macrotask boundary.\n *\n * The motivation is the long-replay freeze: a thread with hundreds\n * of messages replays through the `messages` channel on refresh or\n * mid-run join. Those events drain through the controller's\n * `for await` pump as a long microtask chain. Per-event\n * `store.setState` notifies `useSyncExternalStore` per event, and\n * after enough notifications React's `nestedUpdateCount` guard trips\n * with \"Maximum update depth exceeded\", permanently freezing the UI\n * on the first few messages. Coalescing to one notification per\n * macrotask lets React's scheduler commit between flushes.\n *\n * # Lifecycle\n *\n *   - `handleMessage(event)`              — apply a `messages` event delta.\n *   - `applyValues(values, msgs)`         — merge a `values` snapshot.\n *   - `recordToolCallNamespace(ns, id)`   — capture `namespace → tool_call_id`\n *     so subsequent tool message starts can recover the id.\n *   - `reset()`                           — clear all state on thread rebind.\n */\nimport type {\n  MessagesEvent,\n  MessageRole,\n  MessageStartData,\n} from \"@langchain/protocol\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport { MessageAssembler } from \"../client/stream/messages.js\";\nimport {\n  assembledMessageToBaseMessage,\n  type ExtendedMessageRole,\n} from \"./assembled-to-message.js\";\nimport type { StreamStore } from \"./store.js\";\nimport type { RootSnapshot } from \"./types.js\";\nimport { namespaceKey } from \"./namespace.js\";\nimport {\n  buildMessageIndex,\n  messagesEqual,\n  reconcileMessagesFromValues,\n  shouldPreferValuesMessageForToolCalls,\n} from \"./message-reconciliation.js\";\n\n/**\n * Root-namespace message projection. Owns the merge between the\n * `messages` (streamed deltas) and `values` (authoritative\n * snapshots) channels for the root namespace.\n *\n * @typeParam StateType     - Root state shape; the messages array is read\n *   from `values[messagesKey]`.\n * @typeParam InterruptType - Shape of root protocol interrupts (forwarded\n *   into `RootSnapshot` updates).\n */\nexport class RootMessageProjection<\n  StateType extends object,\n  InterruptType = unknown,\n> {\n  /**\n   * Key inside `values` that holds the message array. Defaults to\n   * `\"messages\"` in the controller; configurable for state graphs\n   * that surface messages under a different slot.\n   */\n  readonly #messagesKey: string;\n\n  /** Root snapshot store written to on every merge. */\n  readonly #store: StreamStore<RootSnapshot<StateType, InterruptType>>;\n\n  /**\n   * Stateful chunk assembler for in-flight messages. Reset (via a\n   * fresh instance) on every {@link reset} so a new thread starts\n   * with no half-built messages from the previous one.\n   */\n  #assembler = new MessageAssembler();\n\n  /**\n   * `messageId → role/toolCallId` captured from `message-start` events.\n   * The assembler's intermediate output drops these fields, so we cache\n   * them at start-time and reapply when projecting to a `BaseMessage`.\n   */\n  readonly #roles = new Map<\n    string,\n    { role: ExtendedMessageRole; toolCallId?: string }\n  >();\n\n  /**\n   * `messageId → position in #store.messages` for fast in-place\n   * updates as deltas arrive. Rebuilt on every full reconciliation\n   * driven by a `values` event.\n   */\n  readonly #indexById = new Map<string, number>();\n\n  /**\n   * Ids observed in the most recent `values.messages` snapshot.\n   * Reconciliation uses this to detect server-side removals: a\n   * previously-seen id missing from the next snapshot means it was\n   * removed by the server (and should drop from the projection).\n   */\n  #valuesMessageIds = new Set<string>();\n\n  /**\n   * `namespaceKey → tool_call_id` captured from root `tool-started`\n   * events. Used as a fallback when a tool-role `message-start` is\n   * missing its `tool_call_id` field.\n   */\n  readonly #toolCallIdByNamespace = new Map<string, string>();\n\n  /**\n   * Coalescing buffer for store writes. {@link handleMessage} and\n   * {@link applyValues} stage their computed `messages` / `values`\n   * here instead of calling `store.setState` per event. A single\n   * `setTimeout(0)` flush commits them in one `setState`, so a\n   * burst of SSE events draining as a microtask chain becomes one\n   * store notification at the next macrotask boundary.\n   *\n   * `null` means \"no staged write\" — once a flush settles, the\n   * slots are cleared so the next call starts from the latest\n   * committed store snapshot.\n   */\n  #pendingMessages: BaseMessage[] | null = null;\n  #pendingValues: StateType | null = null;\n  #flushScheduled = false;\n\n  /**\n   * @param params.messagesKey - Key inside `values` that holds the\n   *   message array.\n   * @param params.store       - Root snapshot store to mutate.\n   */\n  constructor(params: {\n    messagesKey: string;\n    store: StreamStore<RootSnapshot<StateType, InterruptType>>;\n  }) {\n    this.#messagesKey = params.messagesKey;\n    this.#store = params.store;\n  }\n\n  /**\n   * Drop all per-thread state. Called by the controller on thread\n   * rebind / dispose so a swap doesn't surface stale messages.\n   */\n  reset(): void {\n    this.#assembler = new MessageAssembler();\n    this.#roles.clear();\n    this.#indexById.clear();\n    this.#valuesMessageIds = new Set();\n    this.#toolCallIdByNamespace.clear();\n    // Drop any unflushed pending writes — they were computed against\n    // the previous thread's baseline and committing them after a\n    // rebind would bleed stale messages into the new thread.\n    this.#pendingMessages = null;\n    this.#pendingValues = null;\n    this.#flushScheduled = false;\n  }\n\n  /**\n   * Record a `namespace → tool_call_id` mapping captured from a root\n   * `tool-started` event.\n   *\n   * The companion tool-role `message-start` event may not carry a\n   * `tool_call_id`, so we fall back to the most recent value recorded\n   * here for the same namespace.\n   *\n   * @param namespace  - Event namespace from the `tool-started` event.\n   * @param toolCallId - Tool call id from the same event.\n   */\n  recordToolCallNamespace(\n    namespace: readonly string[],\n    toolCallId: string\n  ): void {\n    this.#toolCallIdByNamespace.set(namespaceKey(namespace), toolCallId);\n  }\n\n  /**\n   * Apply a `messages` channel event to the projection.\n   *\n   * Captures role/tool metadata on `message-start`, feeds the chunk\n   * to the assembler, projects the assembled output to a\n   * {@link BaseMessage}, and either appends or in-place updates the\n   * pending messages buffer based on whether the id was seen before.\n   *\n   * @param event - The `messages` channel event to consume.\n   */\n  handleMessage(event: MessagesEvent): void {\n    const data = event.params.data;\n    if (data.event === \"message-start\") {\n      const startData = data as MessageStartData;\n      const role = (startData.role ?? \"ai\") as MessageRole;\n      const extendedRole =\n        (startData as { role?: ExtendedMessageRole }).role ?? role;\n      let toolCallId = (startData as { tool_call_id?: string }).tool_call_id;\n      // Tool messages need a tool_call_id to render. Fall back through:\n      //   1. legacy `<id>-tool-<call_id>` message id format\n      //   2. namespace-recorded tool_call_id (from #recordToolCallNamespace)\n      if (extendedRole === \"tool\" && toolCallId == null) {\n        const messageId = startData.id;\n        if (messageId != null) {\n          const match = /-tool-(.+)$/.exec(messageId);\n          if (match != null) toolCallId = match[1];\n        }\n        if (toolCallId == null) {\n          toolCallId = this.#toolCallIdByNamespace.get(\n            namespaceKey(event.params.namespace)\n          );\n        }\n      }\n      if (startData.id != null) {\n        this.#roles.set(startData.id, {\n          role: extendedRole,\n          toolCallId,\n        });\n      }\n    }\n\n    const update = this.#assembler.consume(event);\n    if (update == null) return;\n    const id = update.message.id;\n    if (id == null) return;\n    const captured = this.#roles.get(id) ?? { role: \"ai\" as const };\n    const base = assembledMessageToBaseMessage(update.message, captured.role, {\n      toolCallId: captured.toolCallId,\n    });\n\n    // Compute against the pending baseline if we have one (so an\n    // earlier handleMessage in the same tick is the input to this\n    // one), else against the latest committed store snapshot.\n    // `#indexById` is the synchronous source of truth for \"where is\n    // each id in the current messages list\" — every code path below\n    // keeps it in sync before returning.\n    const baselineMessages =\n      this.#pendingMessages ?? this.#store.getSnapshot().messages;\n    const existingIdx = this.#indexById.get(id);\n    let messages: BaseMessage[];\n    if (existingIdx == null) {\n      this.#indexById.set(id, baselineMessages.length);\n      messages = [...baselineMessages, base];\n    } else if (messagesEqual(baselineMessages[existingIdx], base)) {\n      // Identical re-emission — skip the store write to keep\n      // snapshot identity stable.\n      return;\n    } else {\n      messages = baselineMessages.slice();\n      messages[existingIdx] = base;\n    }\n\n    // Mirror the new messages list into `values[messagesKey]` so\n    // direct `values` reads (used by some hooks and by the eventual\n    // `values` reconciliation) stay in sync.\n    const baselineValues =\n      this.#pendingValues ?? this.#store.getSnapshot().values;\n    const values = syncMessagesIntoValues(\n      baselineValues,\n      this.#messagesKey,\n      messages\n    );\n    this.#pendingMessages = messages;\n    if (values !== baselineValues) this.#pendingValues = values;\n    this.#scheduleFlush();\n  }\n\n  /**\n   * Reconcile a full `values` snapshot into the projection.\n   *\n   * Delegates the merge to {@link reconcileMessagesFromValues}:\n   * values stays authoritative for ordering and removals, while\n   * streamed in-flight messages keep their content until the server\n   * echoes them back. Empty messages just refresh the values blob.\n   *\n   * Rebuilds {@link #indexById} after the merge so subsequent delta\n   * applications target the new positions.\n   *\n   * @param nextValues   - Full values snapshot from the `values` event.\n   * @param nextMessages - The messages array extracted from\n   *   `values[messagesKey]` and coerced to `BaseMessage` instances.\n   */\n  applyValues(nextValues: StateType, nextMessages: BaseMessage[]): void {\n    const baselineSnapshot = this.#store.getSnapshot();\n    const baselineMessages = this.#pendingMessages ?? baselineSnapshot.messages;\n    const baselineValues = this.#pendingValues ?? baselineSnapshot.values;\n\n    if (nextMessages.length === 0) {\n      if (\n        stateValuesShallowEqual(baselineValues, nextValues, this.#messagesKey)\n      ) {\n        return;\n      }\n      // Mirror the current `messages` list back into the values slot\n      // so the staged snapshot stays consistent with the (separately\n      // tracked) messages array.\n      this.#pendingValues = syncMessagesIntoValues(\n        nextValues,\n        this.#messagesKey,\n        baselineMessages\n      );\n      this.#scheduleFlush();\n      return;\n    }\n\n    const reconciliation = reconcileMessagesFromValues({\n      valueMessages: nextMessages,\n      currentMessages: baselineMessages,\n      currentIndexById: this.#indexById,\n      previousValueMessageIds: this.#valuesMessageIds,\n      preferValuesMessage: shouldPreferValuesMessageForToolCalls,\n    });\n    this.#valuesMessageIds = reconciliation.valueMessageIds;\n    const messages = reconciliation.messages as BaseMessage[];\n    const values = {\n      ...(nextValues as Record<string, unknown>),\n      [this.#messagesKey]: messages,\n    } as StateType;\n    if (\n      messages === baselineMessages &&\n      stateValuesShallowEqual(baselineValues, values, this.#messagesKey)\n    ) {\n      return;\n    }\n\n    // Reconciliation may reorder, drop, or substitute messages, so\n    // rebuild the id → index map to match the new array.\n    this.#indexById.clear();\n    for (const [id, idx] of buildMessageIndex(messages)) {\n      this.#indexById.set(id, idx);\n    }\n    this.#pendingMessages = messages;\n    this.#pendingValues = values;\n    this.#scheduleFlush();\n  }\n\n  /**\n   * Schedule a coalesced flush on the next macrotask. Idempotent\n   * within a tick — multiple `handleMessage` / `applyValues` calls\n   * before the flush fires collapse into one store write.\n   *\n   * `setTimeout(0)` is a macrotask: it runs after the current\n   * microtask chain drains, so a burst of SSE events processed by\n   * the controller's `for await` pump becomes one `store.setState`\n   * (and therefore one `useSyncExternalStore` notification).\n   */\n  #scheduleFlush = (): void => {\n    if (this.#flushScheduled) return;\n    this.#flushScheduled = true;\n    setTimeout(this.#flushPending, 0);\n  };\n\n  /**\n   * Drain `#pendingMessages` / `#pendingValues` to the store in a\n   * single `setState` call.\n   */\n  #flushPending = (): void => {\n    this.#flushScheduled = false;\n    const messages = this.#pendingMessages;\n    const values = this.#pendingValues;\n    this.#pendingMessages = null;\n    this.#pendingValues = null;\n    if (messages == null && values == null) return;\n    this.#store.setState((s) => {\n      // Other rootStore mutators (controller-driven `isLoading`,\n      // `interrupts`, `toolCalls`, etc.) do not touch `s.messages`\n      // / `s.values`, so a last-write-wins commit on those two\n      // fields is safe.\n      if (messages == null) {\n        return values == null ? s : { ...s, values };\n      }\n      if (values == null) return { ...s, messages };\n      return { ...s, messages, values };\n    });\n  };\n}\n\n/**\n * Mirror a freshly-updated message list into `values[messagesKey]`.\n *\n * Returns the same `values` reference when the list is already\n * equal-by-content so the caller can keep the existing snapshot\n * identity (and avoid spurious `setSnapshot` notifications).\n */\nfunction syncMessagesIntoValues<StateType extends object>(\n  values: StateType,\n  messagesKey: string,\n  messages: BaseMessage[]\n): StateType {\n  const record = values as Record<string, unknown>;\n  const current = record[messagesKey];\n  if (Array.isArray(current) && messagesEqualList(current, messages)) {\n    return values;\n  }\n  return {\n    ...record,\n    [messagesKey]: messages,\n  } as StateType;\n}\n\n/**\n * True when two `BaseMessage` arrays carry the same per-message\n * content (using {@link messagesEqual}).\n */\nfunction messagesEqualList(\n  previous: readonly BaseMessage[],\n  next: readonly BaseMessage[]\n): boolean {\n  if (previous === next) return true;\n  if (previous.length !== next.length) return false;\n  for (let i = 0; i < previous.length; i += 1) {\n    if (!messagesEqual(previous[i], next[i])) return false;\n  }\n  return true;\n}\n\n/**\n * Shallow-equal for `values` objects, *ignoring* the messages slot.\n *\n * The messages array is compared separately by the caller (via\n * {@link messagesEqualList}) because both arrays contain class\n * instances whose JSON representation is not stable across reads.\n */\nfunction stateValuesShallowEqual(\n  previous: object,\n  next: object,\n  messagesKey: string\n): boolean {\n  if (previous === next) return true;\n  const previousRecord = previous as Record<string, unknown>;\n  const nextRecord = next as Record<string, unknown>;\n  const previousKeys = Object.keys(previousRecord);\n  const nextKeys = Object.keys(nextRecord);\n  if (previousKeys.length !== nextKeys.length) return false;\n  for (const key of previousKeys) {\n    if (!Object.prototype.hasOwnProperty.call(nextRecord, key)) return false;\n    const previousValue = previousRecord[key];\n    const nextValue = nextRecord[key];\n    if (\n      key === messagesKey &&\n      Array.isArray(previousValue) &&\n      Array.isArray(nextValue)\n    ) {\n      continue;\n    }\n    if (!Object.is(previousValue, nextValue)) return false;\n  }\n  return true;\n}\n"],"mappings":"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"}