@langchain/langgraph-sdk 1.8.6 → 1.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.d.ts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;AA2DA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA4B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAqGnC;;;;;;EA/DpB,SAAA,GAAS,QAAA;EAoIoC;;;;;;EAvH7C,WAAA;EAuJmB;;;;;;;EAtInB,YAAA,CAAa,KAAA;EA8KkB;;;;EAAA,IArJ3B,MAAA,CAAA,GAAU,SAAA;EA+JyB;;;;EAAA,IAvJnC,YAAA,CAAA,GAAgB,SAAA;EAkNiD;EAAA,IA7MjE,KAAA,CAAA;EA6Mc;EAAA,IAxMd,SAAA,CAAA;EAkSoB;EAAA,IA7RpB,MAAA,CAAA;EA6RM;;;;;EApRV,SAAA,CAAU,KAAA;EAsRA;;;;;EAAA,IA5QN,QAAA,CAAA,GAAY,WAAA;EArKJ;;;;EAAA,IAgLR,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EAnKI;;;;;;EAyL/B,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA7J0B;;;;;EAAA,IA0KnD,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAtGhC;;;;EAAA,IAuHT,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAjFxC;;;;;;;;EA6FJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EAxDN;EAAA,IAuET,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA5DP;EAAA,IAiElB,eAAA,CAAA,GAAmB,uBAAA;EAjEM;;;;;;EA2E7B,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cb;;;;;;EAuDjB,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAxC5B;;;;;;EAkDH,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBvC;;;;;EA6BA,4BAAA,CAAA;EAnBmB;;;;EAkCnB,IAAA,CAAA;EAxBsB;;;;;;EAoCtB,YAAA,CAAa,WAAA;EAAA;;;;;;;;;;;;EAqBP,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyFO;;;;;;;;;;EADJ,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EASI;;;;;EAAP,OAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"orchestrator-custom.d.ts","names":[],"sources":["../../src/ui/orchestrator-custom.ts"],"mappings":";;;;;;;;;;;;AA4DA;;;;cAAa,wBAAA,mBACO,MAAA,oBAA0B,MAAA,+BAChC,WAAA,GAAc,WAAA;EAAA;WAEjB,MAAA,EAAQ,aAAA,CAAc,SAAA,EAAW,GAAA;EAAA,SAEjC,cAAA,EAAgB,mBAAA;EAFiB;;;;;;EA4B1C,WAAA,CAAY,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,GAAA;EAoGzC;;;;;;EA9Dd,SAAA,GAAS,QAAA;EA8HoB;;;;;;EAjH7B,WAAA;EA4JW;;;;;EArJX,eAAA,CAAA,GAAmB,MAAA,EAAQ,UAAA;EAqLG;;;;;;;EApK9B,YAAA,CAAa,KAAA;EAwL0B;;;;EAAA,IA/JnC,MAAA,CAAA,GAAU,SAAA;EA0NuD;;;;EAAA,IAlNjE,YAAA,CAAA,GAAgB,SAAA;EA4SS;EAAA,IAvSzB,KAAA,CAAA;EAwSkC;EAAA,IAnSlC,SAAA,CAAA;EAmS6C;EAAA,IA9R7C,MAAA,CAAA;EA+RD;;;;;EAtRH,SAAA,CAAU,KAAA;EAlKV;;;;;EAAA,IA4KI,QAAA,CAAA,GAAY,WAAA;EA1Ke;;;;EAAA,IAqL3B,SAAA,CAAA,GAAS,kBAAA,CAXc,eAAA;EA9IN;;;;;;EAoKrB,YAAA,CAAa,OAAA,EAAS,OAAA,GAAO,kBAAA,CAAA,eAAA;EA1G7B;;;;;EAAA,IAuHI,UAAA,CAAA,GAAc,SAAA,CAAU,gBAAA,CAAiB,GAAA;EA7E/B;;;;EAAA,IA8FV,SAAA,CAAA,GAAa,SAAA,CAAU,gBAAA,CAAiB,GAAA;EAvExC;;;;;;;;EAmFJ,mBAAA,CACE,OAAA,EAAS,OAAA,EACT,KAAA,YACC,eAAA,CAAgB,SAAA;EA7CG;EAAA,IA4DlB,SAAA,CAAA,GAAa,GAAA,SAAY,uBAAA;EA5DA;EAAA,IAiEzB,eAAA,CAAA,GAAmB,uBAAA;EApDnB;;;;;;EA8DJ,WAAA,CAAY,UAAA,WAAkB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EA7Cc;;;;;;EAuD5C,kBAAA,CAAmB,IAAA,WAAY,uBAAA,CAAA,MAAA,mBAAA,eAAA;EAzB3B;;;;;;EAmCJ,qBAAA,CAAsB,SAAA,WAAiB,uBAAA,CAAA,MAAA,mBAAA,eAAA;EApBT;;;;;EA6B9B,4BAAA,CAAA;EAnB+B;;;;EAkC/B,IAAA,CAAA;EAxBuC;;;;;;EAoCvC,YAAA,CAAa,WAAA;EAsBH;;;;;;;;;;;;EADJ,YAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;EAyF0B;;;;;;;;;;EADvB,MAAA,CACJ,MAAA,EAAQ,aAAA,CAAc,GAAA,EAAK,SAAA,sBAC3B,aAAA,GAAgB,mBAAA,CAAoB,SAAA,EAAW,mBAAA,CAAoB,GAAA,KAClE,OAAA;;;;;;EASH,OAAA,CAAA;AAAA"}
@@ -87,6 +87,12 @@ var CustomStreamOrchestrator = class {
87
87
  * @returns The current version counter.
88
88
  */
89
89
  getSnapshot = () => this.#version;
90
+ /**
91
+ * Custom transports do not negotiate stream modes with the server the way
92
+ * LangGraph Platform streams do, but framework adapters call this method on
93
+ * both orchestrator variants. Keep the API surface aligned as a no-op.
94
+ */
95
+ trackStreamMode(..._modes) {}
90
96
  #notify() {
91
97
  if (this.#disposed) return;
92
98
  this.#version += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-custom.js","names":["#options","#historyValues","#threadId","#streamUnsub","#flushPendingHeadlessToolInterrupts","#notify","#getMessages","#listeners","#version","#disposed","#handledHeadlessToolInterruptIds","#branch","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport {\n extractInterrupts,\n userFacingInterruptsFromValuesArray,\n} from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { flushPendingHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n #handledHeadlessToolInterruptIds = new Set<string>();\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#flushPendingHeadlessToolInterrupts();\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n return userFacingInterruptsFromValuesArray<GetInterruptType<Bag>>(\n this.stream.values.__interrupt__ as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n #flushPendingHeadlessToolInterrupts(): void {\n flushPendingHeadlessToolInterrupts(\n this.stream.values as Record<string, unknown> | null,\n this.#options.tools,\n this.#handledHeadlessToolInterruptIds,\n {\n onTool: this.#options.onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n this.submit(null, {\n command,\n }),\n }\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator-custom.js","names":["#options","#historyValues","#threadId","#streamUnsub","#flushPendingHeadlessToolInterrupts","#notify","#getMessages","#listeners","#version","#disposed","#handledHeadlessToolInterruptIds","#branch","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { StreamMode } from \"../types.stream.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport {\n extractInterrupts,\n userFacingInterruptsFromValuesArray,\n} from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { flushPendingHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n #handledHeadlessToolInterruptIds = new Set<string>();\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#flushPendingHeadlessToolInterrupts();\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n /**\n * Custom transports do not negotiate stream modes with the server the way\n * LangGraph Platform streams do, but framework adapters call this method on\n * both orchestrator variants. Keep the API surface aligned as a no-op.\n */\n trackStreamMode(..._modes: StreamMode[]): void {}\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n return userFacingInterruptsFromValuesArray<GetInterruptType<Bag>>(\n this.stream.values.__interrupt__ as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n #flushPendingHeadlessToolInterrupts(): void {\n flushPendingHeadlessToolInterrupts(\n this.stream.values as Record<string, unknown> | null,\n this.#options.tools,\n this.#handledHeadlessToolInterruptIds,\n {\n onTool: this.#options.onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n this.submit(null, {\n command,\n }),\n }\n );\n }\n}\n"],"mappings":"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"}
@@ -79,6 +79,12 @@ var SubagentManager = class {
79
79
  */
80
80
  pendingMatches = /* @__PURE__ */ new Map();
81
81
  /**
82
+ * Messages received before we can map a subgraph namespace to the public
83
+ * subagent tool-call ID. Once the mapping is established, these messages are
84
+ * replayed so early tool calls are not lost.
85
+ */
86
+ pendingMessages = /* @__PURE__ */ new Map();
87
+ /**
82
88
  * Message managers for each subagent.
83
89
  * Uses the same MessageTupleManager as the main stream for proper
84
90
  * message chunk concatenation.
@@ -115,6 +121,28 @@ var SubagentManager = class {
115
121
  return messages;
116
122
  }
117
123
  /**
124
+ * Buffer a subagent message until we can resolve its namespace to a tool call.
125
+ */
126
+ queuePendingMessage(namespaceId, serialized, metadata) {
127
+ const pending = this.pendingMessages.get(namespaceId) ?? [];
128
+ pending.push({
129
+ serialized,
130
+ metadata
131
+ });
132
+ this.pendingMessages.set(namespaceId, pending);
133
+ }
134
+ /**
135
+ * Replay any buffered messages once a namespace has been mapped.
136
+ */
137
+ flushPendingMessages(namespaceId) {
138
+ const pending = this.pendingMessages.get(namespaceId);
139
+ if (!pending?.length) return;
140
+ this.pendingMessages.delete(namespaceId);
141
+ pending.forEach(({ serialized, metadata }) => {
142
+ this.addMessageToSubagent(namespaceId, serialized, metadata);
143
+ });
144
+ }
145
+ /**
118
146
  * Create a complete SubagentStream object with all derived properties.
119
147
  * This ensures consistency with UseStream interface.
120
148
  */
@@ -173,6 +201,7 @@ var SubagentManager = class {
173
201
  });
174
202
  this.onSubagentChange?.();
175
203
  }
204
+ this.flushPendingMessages(namespaceId);
176
205
  return toolCallId;
177
206
  };
178
207
  for (const [toolCallId, subagent] of this.subagents) if ((subagent.status === "pending" || subagent.status === "running") && !mappedToolCallIds.has(toolCallId) && subagent.toolCall.args.description === description) return establishMapping(toolCallId);
@@ -356,6 +385,7 @@ var SubagentManager = class {
356
385
  };
357
386
  this.subagents.set(toolCall.id, execution);
358
387
  this.getMessageManager(toolCall.id);
388
+ this.flushPendingMessages(toolCall.id);
359
389
  hasChanges = true;
360
390
  }
361
391
  if (hasChanges) {
@@ -425,7 +455,10 @@ var SubagentManager = class {
425
455
  if (serialized.type === "human" && typeof serialized.content === "string") this.matchSubgraphToSubagent(namespaceId, serialized.content);
426
456
  const toolCallId = this.getToolCallIdFromNamespace(namespaceId);
427
457
  const existing = this.subagents.get(toolCallId);
428
- if (!existing) return;
458
+ if (!existing) {
459
+ this.queuePendingMessage(namespaceId, serialized, metadata);
460
+ return;
461
+ }
429
462
  if (this.getMessageManager(toolCallId).add(serialized, metadata)) if (serialized.type === "ai") this.subagents.set(toolCallId, {
430
463
  ...existing,
431
464
  status: "running",
@@ -489,6 +522,7 @@ var SubagentManager = class {
489
522
  this.namespaceToToolCallId.clear();
490
523
  this.messageManagers.clear();
491
524
  this.pendingMatches.clear();
525
+ this.pendingMessages.clear();
492
526
  this.onSubagentChange?.();
493
527
  }
494
528
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"subagents.cjs","names":["toMessageDict","MessageTupleManager","getToolCallsWithResults"],"sources":["../../src/ui/subagents.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n Message,\n DefaultToolCall,\n AIMessage,\n ToolCallWithResult,\n} from \"../types.messages.js\";\nimport type {\n SubagentStreamInterface,\n SubagentToolCall,\n SubagentStatus,\n} from \"./types.js\";\nimport { MessageTupleManager, toMessageDict } from \"./messages.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\n\n/**\n * Default tool names that indicate subagent invocation.\n * Can be customized via SubagentManager options.\n */\nconst DEFAULT_SUBAGENT_TOOL_NAMES = [\"task\"];\n\n/**\n * Checks if a namespace indicates a subagent/subgraph message.\n *\n * Subagent namespaces contain a \"tools:\" segment indicating they\n * originate from a tool call that spawned a subgraph.\n *\n * @param namespace - The namespace array from stream events (or checkpoint_ns string)\n * @returns True if this is a subagent namespace\n */\nexport function isSubagentNamespace(\n namespace: string[] | string | undefined\n): boolean {\n if (!namespace) return false;\n\n // Handle string namespace (from checkpoint_ns)\n if (typeof namespace === \"string\") {\n return namespace.includes(\"tools:\");\n }\n\n // Handle array namespace\n return namespace.some((s) => s.startsWith(\"tools:\"));\n}\n\n/**\n * Extracts the tool call ID from a namespace path.\n *\n * Namespaces follow the pattern: [\"tools:call_abc123\", \"model_request:xyz\", ...]\n * This function extracts \"call_abc123\" from the first \"tools:\" segment.\n *\n * @param namespace - The namespace array from stream events\n * @returns The tool call ID, or undefined if not found\n */\nexport function extractToolCallIdFromNamespace(\n namespace: string[] | undefined\n): string | undefined {\n if (!namespace || namespace.length === 0) return undefined;\n\n // Find the first namespace segment that starts with \"tools:\"\n for (const segment of namespace) {\n if (segment.startsWith(\"tools:\")) {\n return segment.slice(6); // Remove \"tools:\" prefix\n }\n }\n\n return undefined;\n}\n\n/**\n * Calculates the depth of a subagent based on its namespace.\n * Counts the number of \"tools:\" segments in the namespace.\n *\n * @param namespace - The namespace array\n * @returns The depth (0 for main agent, 1+ for subagents)\n */\nexport function calculateDepthFromNamespace(\n namespace: string[] | undefined\n): number {\n if (!namespace) return 0;\n return namespace.filter((s) => s.startsWith(\"tools:\")).length;\n}\n\n/**\n * Extracts the parent tool call ID from a namespace.\n *\n * For nested subagents, the namespace looks like:\n * [\"tools:parent_id\", \"tools:child_id\", ...]\n *\n * @param namespace - The namespace array\n * @returns The parent tool call ID, or null if this is a top-level subagent\n */\nexport function extractParentIdFromNamespace(\n namespace: string[] | undefined\n): string | null {\n if (!namespace || namespace.length < 2) return null;\n\n const toolSegments = namespace.filter((s) => s.startsWith(\"tools:\"));\n if (toolSegments.length < 2) return null;\n\n // The second-to-last \"tools:\" segment is the parent\n return toolSegments[toolSegments.length - 2]?.slice(6) ?? null;\n}\n\n/**\n * Options for SubagentManager.\n */\nexport interface SubagentManagerOptions {\n /**\n * Tool names that indicate subagent invocation.\n * Defaults to [\"task\"].\n */\n subagentToolNames?: string[];\n\n /**\n * Callback when subagent state changes.\n */\n onSubagentChange?: () => void;\n\n /**\n * Converts a @langchain/core BaseMessage to the desired output format.\n * Defaults to `toMessageDict` which produces plain Message objects.\n */\n toMessage?: (chunk: BaseMessage) => Message | BaseMessage;\n}\n\n/**\n * Internal base type for SubagentStream storage.\n * Excludes derived properties that are computed on retrieval.\n */\ntype SubagentStreamBase<ToolCall> = Omit<\n SubagentStreamInterface<Record<string, unknown>, ToolCall>,\n | \"isLoading\"\n | \"toolCalls\"\n | \"getToolCalls\"\n | \"interrupt\"\n | \"interrupts\"\n | \"switchThread\"\n | \"subagents\"\n | \"activeSubagents\"\n | \"getSubagent\"\n | \"getSubagentsByType\"\n | \"getSubagentsByMessage\"\n> & {\n /** Internal: ID of the AI message that triggered this subagent */\n aiMessageId: string | null;\n};\n\n/**\n * Manages subagent execution state.\n *\n * Tracks subagents from the moment they are invoked (AI message with tool calls)\n * through streaming to completion (tool message result).\n */\nexport class SubagentManager<ToolCall = DefaultToolCall> {\n private subagents = new Map<string, SubagentStreamBase<ToolCall>>();\n\n /**\n * Maps namespace IDs (pregel task IDs) to tool call IDs.\n * LangGraph subgraphs use internal pregel task IDs in their namespace,\n * which are different from the tool_call_id used to invoke them.\n */\n private namespaceToToolCallId = new Map<string, string>();\n\n /**\n * Pending namespace matches that couldn't be resolved immediately.\n * These are retried when new tool calls are registered.\n */\n private pendingMatches = new Map<string, string>(); // namespaceId -> description\n\n /**\n * Message managers for each subagent.\n * Uses the same MessageTupleManager as the main stream for proper\n * message chunk concatenation.\n */\n private messageManagers = new Map<string, MessageTupleManager>();\n\n private subagentToolNames: Set<string>;\n\n private onSubagentChange?: () => void;\n\n private toMessage: (chunk: BaseMessage) => Message | BaseMessage;\n\n constructor(options?: SubagentManagerOptions) {\n this.subagentToolNames = new Set(\n options?.subagentToolNames ?? DEFAULT_SUBAGENT_TOOL_NAMES\n );\n this.onSubagentChange = options?.onSubagentChange;\n this.toMessage = options?.toMessage ?? toMessageDict;\n }\n\n /**\n * Get or create a MessageTupleManager for a subagent.\n */\n private getMessageManager(toolCallId: string): MessageTupleManager {\n let manager = this.messageManagers.get(toolCallId);\n if (!manager) {\n manager = new MessageTupleManager();\n this.messageManagers.set(toolCallId, manager);\n }\n return manager;\n }\n\n /**\n * Get messages for a subagent with proper chunk concatenation.\n * This mirrors how the main stream handles messages.\n */\n private getMessagesForSubagent(toolCallId: string): Message<ToolCall>[] {\n const manager = this.messageManagers.get(toolCallId);\n if (!manager) return [];\n\n const messages: Message<ToolCall>[] = [];\n for (const entry of Object.values(manager.chunks)) {\n if (entry.chunk) {\n messages.push(this.toMessage(entry.chunk) as Message<ToolCall>);\n }\n }\n return messages;\n }\n\n /**\n * Create a complete SubagentStream object with all derived properties.\n * This ensures consistency with UseStream interface.\n */\n private createSubagentStream(\n base: SubagentStreamBase<ToolCall>\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> {\n const { messages } = base;\n const allToolCalls = getToolCallsWithResults<ToolCall>(messages);\n\n return {\n ...base,\n // Derived from status for UseStream consistency\n isLoading: base.status === \"running\",\n\n // Tool calls derived from messages\n toolCalls: allToolCalls,\n\n // Method to get tool calls for a specific message\n getToolCalls: (\n message: AIMessage<ToolCall>\n ): ToolCallWithResult<ToolCall>[] => {\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n },\n\n // Subagents don't have interrupts yet (future enhancement)\n interrupt: undefined,\n interrupts: [],\n\n // Subagents don't support thread switching\n switchThread: () => {},\n\n // Nested subagent tracking (empty for now, future enhancement)\n subagents: new Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n >(),\n activeSubagents: [],\n getSubagent: () => undefined,\n getSubagentsByType: () => [],\n getSubagentsByMessage: () => [],\n };\n }\n\n /**\n * Get the tool call ID for a given namespace ID.\n * Returns the namespace ID itself if no mapping exists.\n */\n getToolCallIdFromNamespace(namespaceId: string): string {\n return this.namespaceToToolCallId.get(namespaceId) ?? namespaceId;\n }\n\n /**\n * Try to match a subgraph to a pending subagent by description.\n * Creates a mapping from namespace ID to tool call ID if a match is found.\n *\n * Uses a multi-pass matching strategy:\n * 1. Exact description match\n * 2. Description contains/partial match\n * 3. Any unmapped pending subagent (fallback)\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the subgraph\n * @param description - The description from the subgraph's initial message\n * @returns The matched tool call ID, or undefined if no match\n */\n matchSubgraphToSubagent(\n namespaceId: string,\n description: string\n ): string | undefined {\n // Skip if we already have a mapping\n if (this.namespaceToToolCallId.has(namespaceId)) {\n return this.namespaceToToolCallId.get(namespaceId);\n }\n\n // Get all already-mapped tool call IDs\n const mappedToolCallIds = new Set(this.namespaceToToolCallId.values());\n\n // Helper to establish mapping and mark as running\n const establishMapping = (toolCallId: string): string => {\n this.namespaceToToolCallId.set(namespaceId, toolCallId);\n // Also mark the subagent as running since we now have its namespace\n const subagent = this.subagents.get(toolCallId);\n if (subagent && subagent.status === \"pending\") {\n this.subagents.set(toolCallId, {\n ...subagent,\n status: \"running\",\n namespace: [namespaceId],\n startedAt: new Date(),\n });\n this.onSubagentChange?.();\n }\n return toolCallId;\n };\n\n // Pass 1: Find a pending subagent with exact description match\n for (const [toolCallId, subagent] of this.subagents) {\n if (\n (subagent.status === \"pending\" || subagent.status === \"running\") &&\n !mappedToolCallIds.has(toolCallId) &&\n subagent.toolCall.args.description === description\n ) {\n return establishMapping(toolCallId);\n }\n }\n\n // Pass 2: Find a pending subagent where description contains or is contained\n for (const [toolCallId, subagent] of this.subagents) {\n if (\n (subagent.status === \"pending\" || subagent.status === \"running\") &&\n !mappedToolCallIds.has(toolCallId)\n ) {\n const subagentDesc = subagent.toolCall.args.description || \"\";\n if (\n (subagentDesc && description.includes(subagentDesc)) ||\n (subagentDesc && subagentDesc.includes(description))\n ) {\n // Update the description if the new one is longer\n if (description.length > subagentDesc.length) {\n this.subagents.set(toolCallId, {\n ...subagent,\n toolCall: {\n ...subagent.toolCall,\n args: {\n ...subagent.toolCall.args,\n description,\n },\n },\n });\n }\n return establishMapping(toolCallId);\n }\n }\n }\n\n // No match found - store for retry when more tool calls are registered\n if (description) {\n this.pendingMatches.set(namespaceId, description);\n }\n return undefined;\n }\n\n /**\n * Check if a tool call is a subagent invocation.\n */\n isSubagentToolCall(toolName: string): boolean {\n return this.subagentToolNames.has(toolName);\n }\n\n /**\n * Check if a subagent_type value is valid.\n * Valid types are proper identifiers like \"weather-scout\", \"experience-curator\".\n */\n private isValidSubagentType(type: unknown): boolean {\n // Must be a non-empty string\n if (!type || typeof type !== \"string\") {\n return false;\n }\n\n // Must be at least 3 characters (avoids partial streaming like \"ex\")\n if (type.length < 3) {\n return false;\n }\n\n // Must look like a valid identifier (letters, numbers, hyphens, underscores)\n // Examples: \"weather-scout\", \"experience_curator\", \"budget-optimizer\"\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(type)) {\n return false;\n }\n\n // Must not be unreasonably long (corruption indicator)\n if (type.length > 50) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Check if a subagent should be exposed through the public API.\n *\n * We expose subagents as soon as their parent AI message emits a complete\n * subagent tool call, which means pending subagents should be visible.\n *\n * This still filters out corrupted or partial streaming artifacts by\n * requiring a valid-looking `subagent_type`.\n */\n private isValidSubagent(subagent: SubagentStreamBase<ToolCall>): boolean {\n return this.isValidSubagentType(subagent.toolCall.args.subagent_type);\n }\n\n /**\n * Build a complete SubagentStream from internal state.\n * Adds messages and derived properties.\n */\n private buildExecution(\n base: SubagentStreamBase<ToolCall>\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> {\n // Get fresh messages from the streaming manager (populated during live streaming).\n // Fall back to base.messages, which is populated by updateSubagentFromSubgraphState\n // when restoring history after page reload.\n const streamingMessages = this.getMessagesForSubagent(base.id);\n const messages =\n streamingMessages.length > 0 ? streamingMessages : base.messages;\n return this.createSubagentStream({\n ...base,\n messages,\n });\n }\n\n /**\n * Get all subagents as a Map.\n * Filters out incomplete/phantom subagents that lack subagent_type.\n */\n getSubagents(): Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n > {\n const result = new Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n >();\n for (const [id, subagent] of this.subagents) {\n if (this.isValidSubagent(subagent)) {\n result.set(id, this.buildExecution(subagent));\n }\n }\n return result;\n }\n\n /**\n * Get all currently running subagents.\n * Filters out incomplete/phantom subagents.\n */\n getActiveSubagents(): SubagentStreamInterface<\n Record<string, unknown>,\n ToolCall\n >[] {\n return [...this.subagents.values()]\n .filter((s) => s.status === \"running\" && this.isValidSubagent(s))\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Get a specific subagent by tool call ID.\n */\n getSubagent(\n toolCallId: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> | undefined {\n const subagent = this.subagents.get(toolCallId);\n return subagent ? this.buildExecution(subagent) : undefined;\n }\n\n /**\n * Get all subagents of a specific type.\n */\n getSubagentsByType(\n type: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall>[] {\n return [...this.subagents.values()]\n .filter((s) => s.toolCall.args.subagent_type === type)\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Get all subagents triggered by a specific AI message.\n *\n * @param messageId - The ID of the AI message.\n * @returns Array of subagent streams triggered by that message.\n */\n getSubagentsByMessage(\n messageId: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall>[] {\n return [...this.subagents.values()]\n .filter((s) => s.aiMessageId === messageId && this.isValidSubagent(s))\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Parse tool call args, handling both object and string formats.\n * During streaming, args might come as a string that needs parsing.\n */\n private parseArgs(\n args: Record<string, unknown> | string | undefined\n ): Record<string, unknown> {\n if (!args) return {};\n if (typeof args === \"string\") {\n try {\n return JSON.parse(args);\n } catch {\n return {};\n }\n }\n return args;\n }\n\n /**\n * Register new subagent(s) from AI message tool calls.\n *\n * Called when an AI message is received with tool calls.\n * Creates pending subagent entries for each subagent tool call.\n *\n * @param toolCalls - The tool calls from an AI message\n * @param aiMessageId - The ID of the AI message that triggered the tool calls\n */\n registerFromToolCalls(\n toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown> | string;\n }>,\n aiMessageId?: string | null\n ): void {\n let hasChanges = false;\n\n for (const toolCall of toolCalls) {\n if (!toolCall.id) continue;\n if (!this.isSubagentToolCall(toolCall.name)) continue;\n\n // Parse args (may be string during streaming)\n const parsedArgs = this.parseArgs(toolCall.args);\n\n // Skip tool calls that have no meaningful info (likely streaming artifacts)\n // We require a valid subagent_type that looks like a proper identifier\n const hasValidType = this.isValidSubagentType(parsedArgs.subagent_type);\n\n // If we already have this subagent, update the args if they're now more complete\n const existing = this.subagents.get(toolCall.id);\n if (existing) {\n // Only update if new values are valid AND longer (more complete)\n const newType = (parsedArgs.subagent_type as string) || \"\";\n const oldType = existing.toolCall.args.subagent_type || \"\";\n const newDesc = (parsedArgs.description as string) || \"\";\n const oldDesc = existing.toolCall.args.description || \"\";\n\n // Only accept new type if it's valid (not corrupted)\n const newTypeIsValid = this.isValidSubagentType(newType);\n const shouldUpdateType =\n newTypeIsValid && newType.length > oldType.length;\n const shouldUpdateDesc = newDesc.length > oldDesc.length;\n\n // Update aiMessageId when the provider replaces it (e.g. OpenAI\n // changes streaming \"lc_run--...\" IDs to final \"resp_...\" IDs).\n const shouldUpdateMessageId =\n aiMessageId != null && aiMessageId !== existing.aiMessageId;\n\n if (shouldUpdateType || shouldUpdateDesc || shouldUpdateMessageId) {\n this.subagents.set(toolCall.id, {\n ...existing,\n ...(shouldUpdateMessageId ? { aiMessageId } : {}),\n toolCall: {\n ...existing.toolCall,\n args: {\n ...existing.toolCall.args,\n ...parsedArgs,\n description: shouldUpdateDesc ? newDesc : oldDesc,\n subagent_type: shouldUpdateType ? newType : oldType,\n },\n },\n });\n hasChanges = true;\n }\n continue;\n }\n\n // Don't register subagents without at least a valid-looking subagent_type\n // Partial streaming is OK - we filter by status when displaying\n if (!hasValidType) {\n continue;\n }\n\n const subagentToolCall: SubagentToolCall = {\n id: toolCall.id,\n name: toolCall.name,\n args: {\n description: parsedArgs.description as string | undefined,\n subagent_type: parsedArgs.subagent_type as string | undefined,\n ...parsedArgs,\n },\n };\n\n const execution: SubagentStreamBase<ToolCall> = {\n id: toolCall.id,\n toolCall: subagentToolCall,\n status: \"pending\",\n values: {},\n result: null,\n error: null,\n namespace: [],\n messages: [],\n aiMessageId: aiMessageId ?? null,\n parentId: null,\n depth: 0,\n startedAt: null,\n completedAt: null,\n };\n\n this.subagents.set(toolCall.id, execution);\n // Create a message manager for this subagent\n this.getMessageManager(toolCall.id);\n hasChanges = true;\n }\n\n // Retry any pending matches now that we have new/updated tool calls\n if (hasChanges) {\n this.retryPendingMatches();\n this.onSubagentChange?.();\n }\n }\n\n /**\n * Retry matching pending namespaces to newly registered tool calls.\n */\n private retryPendingMatches(): void {\n if (this.pendingMatches.size === 0) return;\n\n // Try to match each pending namespace\n for (const [namespaceId, description] of this.pendingMatches) {\n // Skip if already matched\n if (this.namespaceToToolCallId.has(namespaceId)) {\n this.pendingMatches.delete(namespaceId);\n continue;\n }\n\n // Try to match - this will establish mapping if successful\n const matched = this.matchSubgraphToSubagent(namespaceId, description);\n if (matched) {\n this.pendingMatches.delete(namespaceId);\n }\n }\n }\n\n /**\n * Mark a subagent as running and update its namespace.\n *\n * Called when update events are received with a namespace indicating\n * which subagent is streaming.\n *\n * @param toolCallId - The tool call ID of the subagent\n * @param options - Additional update options\n */\n markRunning(\n toolCallId: string,\n options?: {\n namespace?: string[];\n }\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n const namespace = options?.namespace ?? existing.namespace;\n\n this.subagents.set(toolCallId, {\n ...existing,\n status: \"running\",\n namespace,\n parentId:\n existing.parentId ?? extractParentIdFromNamespace(namespace) ?? null,\n depth: existing.depth || calculateDepthFromNamespace(namespace),\n startedAt: existing.startedAt ?? new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Mark a subagent as running using a namespace ID.\n * Resolves the namespace ID to the actual tool call ID via the mapping.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the subgraph\n * @param namespace - The full namespace array\n */\n markRunningFromNamespace(namespaceId: string, namespace?: string[]): void {\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n this.markRunning(toolCallId, { namespace });\n }\n\n /**\n * Add a serialized message to a subagent from stream events.\n *\n * This method handles the raw serialized message data from SSE events.\n * Uses MessageTupleManager for proper chunk concatenation, matching\n * how the main stream handles messages.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the stream\n * @param serialized - The serialized message from the stream\n * @param metadata - Optional metadata from the stream event\n */\n addMessageToSubagent(\n namespaceId: string,\n serialized: Message<DefaultToolCall>,\n metadata?: Record<string, unknown>\n ): void {\n // First, try to match this namespace to an existing subagent\n // For human messages (which contain the description), try to establish the mapping\n if (serialized.type === \"human\" && typeof serialized.content === \"string\") {\n this.matchSubgraphToSubagent(namespaceId, serialized.content);\n }\n\n // Resolve the actual tool call ID from the namespace mapping\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n const existing = this.subagents.get(toolCallId);\n\n // If we still don't have a match, the mapping hasn't been established yet.\n // Don't create a placeholder - just skip this message.\n // The values event will establish the mapping, and subsequent messages\n // will be routed correctly.\n if (!existing) {\n return;\n }\n\n // Use MessageTupleManager for proper chunk concatenation\n // This is the same approach used by the main stream\n const manager = this.getMessageManager(toolCallId);\n const messageId = manager.add(serialized, metadata);\n\n if (messageId) {\n // Update the subagent status if this is an AI message with content\n if (serialized.type === \"ai\") {\n this.subagents.set(toolCallId, {\n ...existing,\n status: \"running\",\n startedAt: existing.startedAt ?? new Date(),\n // Messages are derived from the manager, so we update them here\n messages: this.getMessagesForSubagent(toolCallId),\n });\n } else {\n // For other message types, just update the messages\n this.subagents.set(toolCallId, {\n ...existing,\n messages: this.getMessagesForSubagent(toolCallId),\n });\n }\n }\n\n this.onSubagentChange?.();\n }\n\n /**\n * Update subagent values from a values stream event.\n *\n * Called when a values event is received from a subagent's namespace.\n * This populates the subagent's state values, making them accessible\n * via the `values` property.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the stream\n * @param values - The state values from the stream event\n */\n updateSubagentValues(\n namespaceId: string,\n values: Record<string, unknown>\n ): void {\n // Resolve the actual tool call ID from the namespace mapping\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n const existing = this.subagents.get(toolCallId);\n\n if (!existing) {\n return;\n }\n\n this.subagents.set(toolCallId, {\n ...existing,\n values,\n status: existing.status === \"pending\" ? \"running\" : existing.status,\n startedAt: existing.startedAt ?? new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Complete a subagent with a result.\n *\n * Called when a tool message is received for the subagent.\n *\n * @param toolCallId - The tool call ID of the subagent\n * @param result - The result content\n * @param status - The final status (complete or error)\n */\n complete(\n toolCallId: string,\n result: string,\n status: \"complete\" | \"error\" = \"complete\"\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n this.subagents.set(toolCallId, {\n ...existing,\n status,\n result: status === \"complete\" ? result : null,\n error: status === \"error\" ? result : null,\n completedAt: new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Clear all subagent state.\n */\n clear(): void {\n this.subagents.clear();\n this.namespaceToToolCallId.clear();\n this.messageManagers.clear();\n this.pendingMatches.clear();\n this.onSubagentChange?.();\n }\n\n /**\n * Process a tool message to complete a subagent.\n *\n * @param toolCallId - The tool call ID from the tool message\n * @param content - The result content\n * @param status - Whether the tool execution was successful\n */\n processToolMessage(\n toolCallId: string,\n content: string,\n status: \"success\" | \"error\" = \"success\"\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n this.complete(\n toolCallId,\n content,\n status === \"success\" ? \"complete\" : \"error\"\n );\n }\n\n /**\n * Reconstruct subagent state from historical messages.\n *\n * This method parses an array of messages (typically from thread history)\n * to identify subagent executions and their results. It's used to restore\n * subagent state after:\n * - Page refresh (when stream has already completed)\n * - Loading thread history\n * - Navigating between threads\n *\n * The reconstruction process:\n * 1. Find AI messages with tool calls matching subagent tool names\n * 2. Find corresponding tool messages with results\n * 3. Create SubagentStream entries with \"complete\" status\n *\n * Note: Internal subagent messages (their streaming conversation) are not\n * reconstructed since they are not persisted in the main thread state.\n *\n * @param messages - Array of messages from thread history\n * @param options - Optional configuration\n * @param options.skipIfPopulated - If true, skip reconstruction if subagents already exist\n */\n reconstructFromMessages(\n messages: Message<DefaultToolCall>[],\n options?: { skipIfPopulated?: boolean }\n ): void {\n // Skip if we already have subagents (from active streaming)\n if (options?.skipIfPopulated && this.subagents.size > 0) {\n return;\n }\n\n // Build a map of tool_call_id -> tool message data for quick lookup\n const toolResults = new Map<\n string,\n { content: string; status: \"success\" | \"error\" }\n >();\n\n for (const message of messages) {\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n const toolCallId = message.tool_call_id as string;\n const content =\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content);\n const status =\n \"status\" in message && message.status === \"error\"\n ? \"error\"\n : \"success\";\n toolResults.set(toolCallId, { content, status });\n }\n }\n\n // Find AI messages with subagent tool calls\n let hasChanges = false;\n\n for (const message of messages) {\n if (\n message.type !== \"ai\" ||\n !(\"tool_calls\" in message) ||\n !Array.isArray(message.tool_calls)\n ) {\n continue;\n }\n\n for (const toolCall of message.tool_calls) {\n if (!toolCall.id) continue;\n if (!this.isSubagentToolCall(toolCall.name)) continue;\n\n // Skip if we already have this subagent\n if (this.subagents.has(toolCall.id)) continue;\n\n // Parse args\n const parsedArgs = this.parseArgs(toolCall.args);\n\n // Skip if no valid subagent_type\n if (!this.isValidSubagentType(parsedArgs.subagent_type)) continue;\n\n // Create the subagent tool call\n const subagentToolCall: SubagentToolCall = {\n id: toolCall.id,\n name: toolCall.name,\n args: {\n description: parsedArgs.description as string | undefined,\n subagent_type: parsedArgs.subagent_type as string | undefined,\n ...parsedArgs,\n },\n };\n\n // Check if we have a result for this tool call\n const toolResult = toolResults.get(toolCall.id);\n const isComplete = !!toolResult;\n // eslint-disable-next-line no-nested-ternary\n const status: SubagentStatus = isComplete\n ? toolResult.status === \"error\"\n ? \"error\"\n : \"complete\"\n : \"running\";\n\n // Create the subagent execution stub. Messages and namespace are empty\n // here; fetchSubagentHistory will derive the subgraph checkpoint_ns by\n // inspecting intermediate history tasks and populate messages async.\n const execution: SubagentStreamBase<ToolCall> = {\n id: toolCall.id,\n toolCall: subagentToolCall,\n status,\n values: {}, // Values not available from history\n result:\n isComplete && status === \"complete\" ? toolResult.content : null,\n error: isComplete && status === \"error\" ? toolResult.content : null,\n namespace: [],\n messages: [], // Restored asynchronously via fetchSubagentHistory\n aiMessageId: (message.id as string) ?? null,\n parentId: null,\n depth: 0,\n startedAt: null,\n completedAt: isComplete ? new Date() : null,\n };\n\n this.subagents.set(toolCall.id, execution);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n this.onSubagentChange?.();\n }\n }\n\n /**\n * Update a reconstructed subagent's messages and values from its subgraph checkpoint state.\n *\n * This is called after fetching the subgraph's history to restore the internal\n * conversation that was lost on page refresh. Only updates if messages are\n * currently empty (does not overwrite live streaming data).\n *\n * @param toolCallId - The tool call ID identifying the subagent\n * @param messages - Messages from the subgraph's latest checkpoint\n * @param values - Full state values from the subgraph's latest checkpoint\n * @returns true if the subagent was updated, false otherwise\n */\n updateSubagentFromSubgraphState(\n toolCallId: string,\n messages: Message[],\n values?: Record<string, unknown>\n ): boolean {\n const subagent = this.subagents.get(toolCallId);\n if (!subagent) return false;\n // Don't overwrite messages from active streaming\n if (subagent.messages.length > 0) return false;\n if (messages.length === 0) return false;\n\n subagent.messages = messages as Message<ToolCall>[];\n if (values != null) subagent.values = values;\n\n this.onSubagentChange?.();\n return true;\n }\n\n /**\n * Check if any subagents are currently tracked.\n */\n hasSubagents(): boolean {\n return this.subagents.size > 0;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"subagents.cjs","names":["toMessageDict","MessageTupleManager","getToolCallsWithResults"],"sources":["../../src/ui/subagents.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n Message,\n DefaultToolCall,\n AIMessage,\n ToolCallWithResult,\n} from \"../types.messages.js\";\nimport type {\n SubagentStreamInterface,\n SubagentToolCall,\n SubagentStatus,\n} from \"./types.js\";\nimport { MessageTupleManager, toMessageDict } from \"./messages.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\n\n/**\n * Default tool names that indicate subagent invocation.\n * Can be customized via SubagentManager options.\n */\nconst DEFAULT_SUBAGENT_TOOL_NAMES = [\"task\"];\n\n/**\n * Checks if a namespace indicates a subagent/subgraph message.\n *\n * Subagent namespaces contain a \"tools:\" segment indicating they\n * originate from a tool call that spawned a subgraph.\n *\n * @param namespace - The namespace array from stream events (or checkpoint_ns string)\n * @returns True if this is a subagent namespace\n */\nexport function isSubagentNamespace(\n namespace: string[] | string | undefined\n): boolean {\n if (!namespace) return false;\n\n // Handle string namespace (from checkpoint_ns)\n if (typeof namespace === \"string\") {\n return namespace.includes(\"tools:\");\n }\n\n // Handle array namespace\n return namespace.some((s) => s.startsWith(\"tools:\"));\n}\n\n/**\n * Extracts the tool call ID from a namespace path.\n *\n * Namespaces follow the pattern: [\"tools:call_abc123\", \"model_request:xyz\", ...]\n * This function extracts \"call_abc123\" from the first \"tools:\" segment.\n *\n * @param namespace - The namespace array from stream events\n * @returns The tool call ID, or undefined if not found\n */\nexport function extractToolCallIdFromNamespace(\n namespace: string[] | undefined\n): string | undefined {\n if (!namespace || namespace.length === 0) return undefined;\n\n // Find the first namespace segment that starts with \"tools:\"\n for (const segment of namespace) {\n if (segment.startsWith(\"tools:\")) {\n return segment.slice(6); // Remove \"tools:\" prefix\n }\n }\n\n return undefined;\n}\n\n/**\n * Calculates the depth of a subagent based on its namespace.\n * Counts the number of \"tools:\" segments in the namespace.\n *\n * @param namespace - The namespace array\n * @returns The depth (0 for main agent, 1+ for subagents)\n */\nexport function calculateDepthFromNamespace(\n namespace: string[] | undefined\n): number {\n if (!namespace) return 0;\n return namespace.filter((s) => s.startsWith(\"tools:\")).length;\n}\n\n/**\n * Extracts the parent tool call ID from a namespace.\n *\n * For nested subagents, the namespace looks like:\n * [\"tools:parent_id\", \"tools:child_id\", ...]\n *\n * @param namespace - The namespace array\n * @returns The parent tool call ID, or null if this is a top-level subagent\n */\nexport function extractParentIdFromNamespace(\n namespace: string[] | undefined\n): string | null {\n if (!namespace || namespace.length < 2) return null;\n\n const toolSegments = namespace.filter((s) => s.startsWith(\"tools:\"));\n if (toolSegments.length < 2) return null;\n\n // The second-to-last \"tools:\" segment is the parent\n return toolSegments[toolSegments.length - 2]?.slice(6) ?? null;\n}\n\n/**\n * Options for SubagentManager.\n */\nexport interface SubagentManagerOptions {\n /**\n * Tool names that indicate subagent invocation.\n * Defaults to [\"task\"].\n */\n subagentToolNames?: string[];\n\n /**\n * Callback when subagent state changes.\n */\n onSubagentChange?: () => void;\n\n /**\n * Converts a @langchain/core BaseMessage to the desired output format.\n * Defaults to `toMessageDict` which produces plain Message objects.\n */\n toMessage?: (chunk: BaseMessage) => Message | BaseMessage;\n}\n\n/**\n * Internal base type for SubagentStream storage.\n * Excludes derived properties that are computed on retrieval.\n */\ntype SubagentStreamBase<ToolCall> = Omit<\n SubagentStreamInterface<Record<string, unknown>, ToolCall>,\n | \"isLoading\"\n | \"toolCalls\"\n | \"getToolCalls\"\n | \"interrupt\"\n | \"interrupts\"\n | \"switchThread\"\n | \"subagents\"\n | \"activeSubagents\"\n | \"getSubagent\"\n | \"getSubagentsByType\"\n | \"getSubagentsByMessage\"\n> & {\n /** Internal: ID of the AI message that triggered this subagent */\n aiMessageId: string | null;\n};\n\n/**\n * Manages subagent execution state.\n *\n * Tracks subagents from the moment they are invoked (AI message with tool calls)\n * through streaming to completion (tool message result).\n */\nexport class SubagentManager<ToolCall = DefaultToolCall> {\n private subagents = new Map<string, SubagentStreamBase<ToolCall>>();\n\n /**\n * Maps namespace IDs (pregel task IDs) to tool call IDs.\n * LangGraph subgraphs use internal pregel task IDs in their namespace,\n * which are different from the tool_call_id used to invoke them.\n */\n private namespaceToToolCallId = new Map<string, string>();\n\n /**\n * Pending namespace matches that couldn't be resolved immediately.\n * These are retried when new tool calls are registered.\n */\n private pendingMatches = new Map<string, string>(); // namespaceId -> description\n\n /**\n * Messages received before we can map a subgraph namespace to the public\n * subagent tool-call ID. Once the mapping is established, these messages are\n * replayed so early tool calls are not lost.\n */\n private pendingMessages = new Map<\n string,\n Array<{\n serialized: Message<DefaultToolCall>;\n metadata?: Record<string, unknown>;\n }>\n >();\n\n /**\n * Message managers for each subagent.\n * Uses the same MessageTupleManager as the main stream for proper\n * message chunk concatenation.\n */\n private messageManagers = new Map<string, MessageTupleManager>();\n\n private subagentToolNames: Set<string>;\n\n private onSubagentChange?: () => void;\n\n private toMessage: (chunk: BaseMessage) => Message | BaseMessage;\n\n constructor(options?: SubagentManagerOptions) {\n this.subagentToolNames = new Set(\n options?.subagentToolNames ?? DEFAULT_SUBAGENT_TOOL_NAMES\n );\n this.onSubagentChange = options?.onSubagentChange;\n this.toMessage = options?.toMessage ?? toMessageDict;\n }\n\n /**\n * Get or create a MessageTupleManager for a subagent.\n */\n private getMessageManager(toolCallId: string): MessageTupleManager {\n let manager = this.messageManagers.get(toolCallId);\n if (!manager) {\n manager = new MessageTupleManager();\n this.messageManagers.set(toolCallId, manager);\n }\n return manager;\n }\n\n /**\n * Get messages for a subagent with proper chunk concatenation.\n * This mirrors how the main stream handles messages.\n */\n private getMessagesForSubagent(toolCallId: string): Message<ToolCall>[] {\n const manager = this.messageManagers.get(toolCallId);\n if (!manager) return [];\n\n const messages: Message<ToolCall>[] = [];\n for (const entry of Object.values(manager.chunks)) {\n if (entry.chunk) {\n messages.push(this.toMessage(entry.chunk) as Message<ToolCall>);\n }\n }\n return messages;\n }\n\n /**\n * Buffer a subagent message until we can resolve its namespace to a tool call.\n */\n private queuePendingMessage(\n namespaceId: string,\n serialized: Message<DefaultToolCall>,\n metadata?: Record<string, unknown>\n ) {\n const pending = this.pendingMessages.get(namespaceId) ?? [];\n pending.push({ serialized, metadata });\n this.pendingMessages.set(namespaceId, pending);\n }\n\n /**\n * Replay any buffered messages once a namespace has been mapped.\n */\n private flushPendingMessages(namespaceId: string) {\n const pending = this.pendingMessages.get(namespaceId);\n if (!pending?.length) return;\n\n this.pendingMessages.delete(namespaceId);\n pending.forEach(({ serialized, metadata }) => {\n this.addMessageToSubagent(namespaceId, serialized, metadata);\n });\n }\n\n /**\n * Create a complete SubagentStream object with all derived properties.\n * This ensures consistency with UseStream interface.\n */\n private createSubagentStream(\n base: SubagentStreamBase<ToolCall>\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> {\n const { messages } = base;\n const allToolCalls = getToolCallsWithResults<ToolCall>(messages);\n\n return {\n ...base,\n // Derived from status for UseStream consistency\n isLoading: base.status === \"running\",\n\n // Tool calls derived from messages\n toolCalls: allToolCalls,\n\n // Method to get tool calls for a specific message\n getToolCalls: (\n message: AIMessage<ToolCall>\n ): ToolCallWithResult<ToolCall>[] => {\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n },\n\n // Subagents don't have interrupts yet (future enhancement)\n interrupt: undefined,\n interrupts: [],\n\n // Subagents don't support thread switching\n switchThread: () => {},\n\n // Nested subagent tracking (empty for now, future enhancement)\n subagents: new Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n >(),\n activeSubagents: [],\n getSubagent: () => undefined,\n getSubagentsByType: () => [],\n getSubagentsByMessage: () => [],\n };\n }\n\n /**\n * Get the tool call ID for a given namespace ID.\n * Returns the namespace ID itself if no mapping exists.\n */\n getToolCallIdFromNamespace(namespaceId: string): string {\n return this.namespaceToToolCallId.get(namespaceId) ?? namespaceId;\n }\n\n /**\n * Try to match a subgraph to a pending subagent by description.\n * Creates a mapping from namespace ID to tool call ID if a match is found.\n *\n * Uses a multi-pass matching strategy:\n * 1. Exact description match\n * 2. Description contains/partial match\n * 3. Any unmapped pending subagent (fallback)\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the subgraph\n * @param description - The description from the subgraph's initial message\n * @returns The matched tool call ID, or undefined if no match\n */\n matchSubgraphToSubagent(\n namespaceId: string,\n description: string\n ): string | undefined {\n // Skip if we already have a mapping\n if (this.namespaceToToolCallId.has(namespaceId)) {\n return this.namespaceToToolCallId.get(namespaceId);\n }\n\n // Get all already-mapped tool call IDs\n const mappedToolCallIds = new Set(this.namespaceToToolCallId.values());\n\n // Helper to establish mapping and mark as running\n const establishMapping = (toolCallId: string): string => {\n this.namespaceToToolCallId.set(namespaceId, toolCallId);\n // Also mark the subagent as running since we now have its namespace\n const subagent = this.subagents.get(toolCallId);\n if (subagent && subagent.status === \"pending\") {\n this.subagents.set(toolCallId, {\n ...subagent,\n status: \"running\",\n namespace: [namespaceId],\n startedAt: new Date(),\n });\n this.onSubagentChange?.();\n }\n this.flushPendingMessages(namespaceId);\n return toolCallId;\n };\n\n // Pass 1: Find a pending subagent with exact description match\n for (const [toolCallId, subagent] of this.subagents) {\n if (\n (subagent.status === \"pending\" || subagent.status === \"running\") &&\n !mappedToolCallIds.has(toolCallId) &&\n subagent.toolCall.args.description === description\n ) {\n return establishMapping(toolCallId);\n }\n }\n\n // Pass 2: Find a pending subagent where description contains or is contained\n for (const [toolCallId, subagent] of this.subagents) {\n if (\n (subagent.status === \"pending\" || subagent.status === \"running\") &&\n !mappedToolCallIds.has(toolCallId)\n ) {\n const subagentDesc = subagent.toolCall.args.description || \"\";\n if (\n (subagentDesc && description.includes(subagentDesc)) ||\n (subagentDesc && subagentDesc.includes(description))\n ) {\n // Update the description if the new one is longer\n if (description.length > subagentDesc.length) {\n this.subagents.set(toolCallId, {\n ...subagent,\n toolCall: {\n ...subagent.toolCall,\n args: {\n ...subagent.toolCall.args,\n description,\n },\n },\n });\n }\n return establishMapping(toolCallId);\n }\n }\n }\n\n // No match found - store for retry when more tool calls are registered\n if (description) {\n this.pendingMatches.set(namespaceId, description);\n }\n return undefined;\n }\n\n /**\n * Check if a tool call is a subagent invocation.\n */\n isSubagentToolCall(toolName: string): boolean {\n return this.subagentToolNames.has(toolName);\n }\n\n /**\n * Check if a subagent_type value is valid.\n * Valid types are proper identifiers like \"weather-scout\", \"experience-curator\".\n */\n private isValidSubagentType(type: unknown): boolean {\n // Must be a non-empty string\n if (!type || typeof type !== \"string\") {\n return false;\n }\n\n // Must be at least 3 characters (avoids partial streaming like \"ex\")\n if (type.length < 3) {\n return false;\n }\n\n // Must look like a valid identifier (letters, numbers, hyphens, underscores)\n // Examples: \"weather-scout\", \"experience_curator\", \"budget-optimizer\"\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(type)) {\n return false;\n }\n\n // Must not be unreasonably long (corruption indicator)\n if (type.length > 50) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Check if a subagent should be exposed through the public API.\n *\n * We expose subagents as soon as their parent AI message emits a complete\n * subagent tool call, which means pending subagents should be visible.\n *\n * This still filters out corrupted or partial streaming artifacts by\n * requiring a valid-looking `subagent_type`.\n */\n private isValidSubagent(subagent: SubagentStreamBase<ToolCall>): boolean {\n return this.isValidSubagentType(subagent.toolCall.args.subagent_type);\n }\n\n /**\n * Build a complete SubagentStream from internal state.\n * Adds messages and derived properties.\n */\n private buildExecution(\n base: SubagentStreamBase<ToolCall>\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> {\n // Get fresh messages from the streaming manager (populated during live streaming).\n // Fall back to base.messages, which is populated by updateSubagentFromSubgraphState\n // when restoring history after page reload.\n const streamingMessages = this.getMessagesForSubagent(base.id);\n const messages =\n streamingMessages.length > 0 ? streamingMessages : base.messages;\n return this.createSubagentStream({\n ...base,\n messages,\n });\n }\n\n /**\n * Get all subagents as a Map.\n * Filters out incomplete/phantom subagents that lack subagent_type.\n */\n getSubagents(): Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n > {\n const result = new Map<\n string,\n SubagentStreamInterface<Record<string, unknown>, ToolCall>\n >();\n for (const [id, subagent] of this.subagents) {\n if (this.isValidSubagent(subagent)) {\n result.set(id, this.buildExecution(subagent));\n }\n }\n return result;\n }\n\n /**\n * Get all currently running subagents.\n * Filters out incomplete/phantom subagents.\n */\n getActiveSubagents(): SubagentStreamInterface<\n Record<string, unknown>,\n ToolCall\n >[] {\n return [...this.subagents.values()]\n .filter((s) => s.status === \"running\" && this.isValidSubagent(s))\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Get a specific subagent by tool call ID.\n */\n getSubagent(\n toolCallId: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall> | undefined {\n const subagent = this.subagents.get(toolCallId);\n return subagent ? this.buildExecution(subagent) : undefined;\n }\n\n /**\n * Get all subagents of a specific type.\n */\n getSubagentsByType(\n type: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall>[] {\n return [...this.subagents.values()]\n .filter((s) => s.toolCall.args.subagent_type === type)\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Get all subagents triggered by a specific AI message.\n *\n * @param messageId - The ID of the AI message.\n * @returns Array of subagent streams triggered by that message.\n */\n getSubagentsByMessage(\n messageId: string\n ): SubagentStreamInterface<Record<string, unknown>, ToolCall>[] {\n return [...this.subagents.values()]\n .filter((s) => s.aiMessageId === messageId && this.isValidSubagent(s))\n .map((s) => this.buildExecution(s));\n }\n\n /**\n * Parse tool call args, handling both object and string formats.\n * During streaming, args might come as a string that needs parsing.\n */\n private parseArgs(\n args: Record<string, unknown> | string | undefined\n ): Record<string, unknown> {\n if (!args) return {};\n if (typeof args === \"string\") {\n try {\n return JSON.parse(args);\n } catch {\n return {};\n }\n }\n return args;\n }\n\n /**\n * Register new subagent(s) from AI message tool calls.\n *\n * Called when an AI message is received with tool calls.\n * Creates pending subagent entries for each subagent tool call.\n *\n * @param toolCalls - The tool calls from an AI message\n * @param aiMessageId - The ID of the AI message that triggered the tool calls\n */\n registerFromToolCalls(\n toolCalls: Array<{\n id?: string;\n name: string;\n args: Record<string, unknown> | string;\n }>,\n aiMessageId?: string | null\n ): void {\n let hasChanges = false;\n\n for (const toolCall of toolCalls) {\n if (!toolCall.id) continue;\n if (!this.isSubagentToolCall(toolCall.name)) continue;\n\n // Parse args (may be string during streaming)\n const parsedArgs = this.parseArgs(toolCall.args);\n\n // Skip tool calls that have no meaningful info (likely streaming artifacts)\n // We require a valid subagent_type that looks like a proper identifier\n const hasValidType = this.isValidSubagentType(parsedArgs.subagent_type);\n\n // If we already have this subagent, update the args if they're now more complete\n const existing = this.subagents.get(toolCall.id);\n if (existing) {\n // Only update if new values are valid AND longer (more complete)\n const newType = (parsedArgs.subagent_type as string) || \"\";\n const oldType = existing.toolCall.args.subagent_type || \"\";\n const newDesc = (parsedArgs.description as string) || \"\";\n const oldDesc = existing.toolCall.args.description || \"\";\n\n // Only accept new type if it's valid (not corrupted)\n const newTypeIsValid = this.isValidSubagentType(newType);\n const shouldUpdateType =\n newTypeIsValid && newType.length > oldType.length;\n const shouldUpdateDesc = newDesc.length > oldDesc.length;\n\n // Update aiMessageId when the provider replaces it (e.g. OpenAI\n // changes streaming \"lc_run--...\" IDs to final \"resp_...\" IDs).\n const shouldUpdateMessageId =\n aiMessageId != null && aiMessageId !== existing.aiMessageId;\n\n if (shouldUpdateType || shouldUpdateDesc || shouldUpdateMessageId) {\n this.subagents.set(toolCall.id, {\n ...existing,\n ...(shouldUpdateMessageId ? { aiMessageId } : {}),\n toolCall: {\n ...existing.toolCall,\n args: {\n ...existing.toolCall.args,\n ...parsedArgs,\n description: shouldUpdateDesc ? newDesc : oldDesc,\n subagent_type: shouldUpdateType ? newType : oldType,\n },\n },\n });\n hasChanges = true;\n }\n continue;\n }\n\n // Don't register subagents without at least a valid-looking subagent_type\n // Partial streaming is OK - we filter by status when displaying\n if (!hasValidType) {\n continue;\n }\n\n const subagentToolCall: SubagentToolCall = {\n id: toolCall.id,\n name: toolCall.name,\n args: {\n description: parsedArgs.description as string | undefined,\n subagent_type: parsedArgs.subagent_type as string | undefined,\n ...parsedArgs,\n },\n };\n\n const execution: SubagentStreamBase<ToolCall> = {\n id: toolCall.id,\n toolCall: subagentToolCall,\n status: \"pending\",\n values: {},\n result: null,\n error: null,\n namespace: [],\n messages: [],\n aiMessageId: aiMessageId ?? null,\n parentId: null,\n depth: 0,\n startedAt: null,\n completedAt: null,\n };\n\n this.subagents.set(toolCall.id, execution);\n // Create a message manager for this subagent\n this.getMessageManager(toolCall.id);\n this.flushPendingMessages(toolCall.id);\n hasChanges = true;\n }\n\n // Retry any pending matches now that we have new/updated tool calls\n if (hasChanges) {\n this.retryPendingMatches();\n this.onSubagentChange?.();\n }\n }\n\n /**\n * Retry matching pending namespaces to newly registered tool calls.\n */\n private retryPendingMatches(): void {\n if (this.pendingMatches.size === 0) return;\n\n // Try to match each pending namespace\n for (const [namespaceId, description] of this.pendingMatches) {\n // Skip if already matched\n if (this.namespaceToToolCallId.has(namespaceId)) {\n this.pendingMatches.delete(namespaceId);\n continue;\n }\n\n // Try to match - this will establish mapping if successful\n const matched = this.matchSubgraphToSubagent(namespaceId, description);\n if (matched) {\n this.pendingMatches.delete(namespaceId);\n }\n }\n }\n\n /**\n * Mark a subagent as running and update its namespace.\n *\n * Called when update events are received with a namespace indicating\n * which subagent is streaming.\n *\n * @param toolCallId - The tool call ID of the subagent\n * @param options - Additional update options\n */\n markRunning(\n toolCallId: string,\n options?: {\n namespace?: string[];\n }\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n const namespace = options?.namespace ?? existing.namespace;\n\n this.subagents.set(toolCallId, {\n ...existing,\n status: \"running\",\n namespace,\n parentId:\n existing.parentId ?? extractParentIdFromNamespace(namespace) ?? null,\n depth: existing.depth || calculateDepthFromNamespace(namespace),\n startedAt: existing.startedAt ?? new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Mark a subagent as running using a namespace ID.\n * Resolves the namespace ID to the actual tool call ID via the mapping.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the subgraph\n * @param namespace - The full namespace array\n */\n markRunningFromNamespace(namespaceId: string, namespace?: string[]): void {\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n this.markRunning(toolCallId, { namespace });\n }\n\n /**\n * Add a serialized message to a subagent from stream events.\n *\n * This method handles the raw serialized message data from SSE events.\n * Uses MessageTupleManager for proper chunk concatenation, matching\n * how the main stream handles messages.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the stream\n * @param serialized - The serialized message from the stream\n * @param metadata - Optional metadata from the stream event\n */\n addMessageToSubagent(\n namespaceId: string,\n serialized: Message<DefaultToolCall>,\n metadata?: Record<string, unknown>\n ): void {\n // First, try to match this namespace to an existing subagent\n // For human messages (which contain the description), try to establish the mapping\n if (serialized.type === \"human\" && typeof serialized.content === \"string\") {\n this.matchSubgraphToSubagent(namespaceId, serialized.content);\n }\n\n // Resolve the actual tool call ID from the namespace mapping\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n const existing = this.subagents.get(toolCallId);\n\n // If we still don't have a match, the mapping hasn't been established yet.\n // Buffer the message so early AI/tool-call chunks are replayed once the\n // values event or a later human message establishes the mapping.\n if (!existing) {\n this.queuePendingMessage(namespaceId, serialized, metadata);\n return;\n }\n\n // Use MessageTupleManager for proper chunk concatenation\n // This is the same approach used by the main stream\n const manager = this.getMessageManager(toolCallId);\n const messageId = manager.add(serialized, metadata);\n\n if (messageId) {\n // Update the subagent status if this is an AI message with content\n if (serialized.type === \"ai\") {\n this.subagents.set(toolCallId, {\n ...existing,\n status: \"running\",\n startedAt: existing.startedAt ?? new Date(),\n // Messages are derived from the manager, so we update them here\n messages: this.getMessagesForSubagent(toolCallId),\n });\n } else {\n // For other message types, just update the messages\n this.subagents.set(toolCallId, {\n ...existing,\n messages: this.getMessagesForSubagent(toolCallId),\n });\n }\n }\n\n this.onSubagentChange?.();\n }\n\n /**\n * Update subagent values from a values stream event.\n *\n * Called when a values event is received from a subagent's namespace.\n * This populates the subagent's state values, making them accessible\n * via the `values` property.\n *\n * @param namespaceId - The namespace ID (pregel task ID) from the stream\n * @param values - The state values from the stream event\n */\n updateSubagentValues(\n namespaceId: string,\n values: Record<string, unknown>\n ): void {\n // Resolve the actual tool call ID from the namespace mapping\n const toolCallId = this.getToolCallIdFromNamespace(namespaceId);\n const existing = this.subagents.get(toolCallId);\n\n if (!existing) {\n return;\n }\n\n this.subagents.set(toolCallId, {\n ...existing,\n values,\n status: existing.status === \"pending\" ? \"running\" : existing.status,\n startedAt: existing.startedAt ?? new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Complete a subagent with a result.\n *\n * Called when a tool message is received for the subagent.\n *\n * @param toolCallId - The tool call ID of the subagent\n * @param result - The result content\n * @param status - The final status (complete or error)\n */\n complete(\n toolCallId: string,\n result: string,\n status: \"complete\" | \"error\" = \"complete\"\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n this.subagents.set(toolCallId, {\n ...existing,\n status,\n result: status === \"complete\" ? result : null,\n error: status === \"error\" ? result : null,\n completedAt: new Date(),\n });\n\n this.onSubagentChange?.();\n }\n\n /**\n * Clear all subagent state.\n */\n clear(): void {\n this.subagents.clear();\n this.namespaceToToolCallId.clear();\n this.messageManagers.clear();\n this.pendingMatches.clear();\n this.pendingMessages.clear();\n this.onSubagentChange?.();\n }\n\n /**\n * Process a tool message to complete a subagent.\n *\n * @param toolCallId - The tool call ID from the tool message\n * @param content - The result content\n * @param status - Whether the tool execution was successful\n */\n processToolMessage(\n toolCallId: string,\n content: string,\n status: \"success\" | \"error\" = \"success\"\n ): void {\n const existing = this.subagents.get(toolCallId);\n if (!existing) return;\n\n this.complete(\n toolCallId,\n content,\n status === \"success\" ? \"complete\" : \"error\"\n );\n }\n\n /**\n * Reconstruct subagent state from historical messages.\n *\n * This method parses an array of messages (typically from thread history)\n * to identify subagent executions and their results. It's used to restore\n * subagent state after:\n * - Page refresh (when stream has already completed)\n * - Loading thread history\n * - Navigating between threads\n *\n * The reconstruction process:\n * 1. Find AI messages with tool calls matching subagent tool names\n * 2. Find corresponding tool messages with results\n * 3. Create SubagentStream entries with \"complete\" status\n *\n * Note: Internal subagent messages (their streaming conversation) are not\n * reconstructed since they are not persisted in the main thread state.\n *\n * @param messages - Array of messages from thread history\n * @param options - Optional configuration\n * @param options.skipIfPopulated - If true, skip reconstruction if subagents already exist\n */\n reconstructFromMessages(\n messages: Message<DefaultToolCall>[],\n options?: { skipIfPopulated?: boolean }\n ): void {\n // Skip if we already have subagents (from active streaming)\n if (options?.skipIfPopulated && this.subagents.size > 0) {\n return;\n }\n\n // Build a map of tool_call_id -> tool message data for quick lookup\n const toolResults = new Map<\n string,\n { content: string; status: \"success\" | \"error\" }\n >();\n\n for (const message of messages) {\n if (message.type === \"tool\" && \"tool_call_id\" in message) {\n const toolCallId = message.tool_call_id as string;\n const content =\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content);\n const status =\n \"status\" in message && message.status === \"error\"\n ? \"error\"\n : \"success\";\n toolResults.set(toolCallId, { content, status });\n }\n }\n\n // Find AI messages with subagent tool calls\n let hasChanges = false;\n\n for (const message of messages) {\n if (\n message.type !== \"ai\" ||\n !(\"tool_calls\" in message) ||\n !Array.isArray(message.tool_calls)\n ) {\n continue;\n }\n\n for (const toolCall of message.tool_calls) {\n if (!toolCall.id) continue;\n if (!this.isSubagentToolCall(toolCall.name)) continue;\n\n // Skip if we already have this subagent\n if (this.subagents.has(toolCall.id)) continue;\n\n // Parse args\n const parsedArgs = this.parseArgs(toolCall.args);\n\n // Skip if no valid subagent_type\n if (!this.isValidSubagentType(parsedArgs.subagent_type)) continue;\n\n // Create the subagent tool call\n const subagentToolCall: SubagentToolCall = {\n id: toolCall.id,\n name: toolCall.name,\n args: {\n description: parsedArgs.description as string | undefined,\n subagent_type: parsedArgs.subagent_type as string | undefined,\n ...parsedArgs,\n },\n };\n\n // Check if we have a result for this tool call\n const toolResult = toolResults.get(toolCall.id);\n const isComplete = !!toolResult;\n // eslint-disable-next-line no-nested-ternary\n const status: SubagentStatus = isComplete\n ? toolResult.status === \"error\"\n ? \"error\"\n : \"complete\"\n : \"running\";\n\n // Create the subagent execution stub. Messages and namespace are empty\n // here; fetchSubagentHistory will derive the subgraph checkpoint_ns by\n // inspecting intermediate history tasks and populate messages async.\n const execution: SubagentStreamBase<ToolCall> = {\n id: toolCall.id,\n toolCall: subagentToolCall,\n status,\n values: {}, // Values not available from history\n result:\n isComplete && status === \"complete\" ? toolResult.content : null,\n error: isComplete && status === \"error\" ? toolResult.content : null,\n namespace: [],\n messages: [], // Restored asynchronously via fetchSubagentHistory\n aiMessageId: (message.id as string) ?? null,\n parentId: null,\n depth: 0,\n startedAt: null,\n completedAt: isComplete ? new Date() : null,\n };\n\n this.subagents.set(toolCall.id, execution);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n this.onSubagentChange?.();\n }\n }\n\n /**\n * Update a reconstructed subagent's messages and values from its subgraph checkpoint state.\n *\n * This is called after fetching the subgraph's history to restore the internal\n * conversation that was lost on page refresh. Only updates if messages are\n * currently empty (does not overwrite live streaming data).\n *\n * @param toolCallId - The tool call ID identifying the subagent\n * @param messages - Messages from the subgraph's latest checkpoint\n * @param values - Full state values from the subgraph's latest checkpoint\n * @returns true if the subagent was updated, false otherwise\n */\n updateSubagentFromSubgraphState(\n toolCallId: string,\n messages: Message[],\n values?: Record<string, unknown>\n ): boolean {\n const subagent = this.subagents.get(toolCallId);\n if (!subagent) return false;\n // Don't overwrite messages from active streaming\n if (subagent.messages.length > 0) return false;\n if (messages.length === 0) return false;\n\n subagent.messages = messages as Message<ToolCall>[];\n if (values != null) subagent.values = values;\n\n this.onSubagentChange?.();\n return true;\n }\n\n /**\n * Check if any subagents are currently tracked.\n */\n hasSubagents(): boolean {\n return this.subagents.size > 0;\n }\n}\n"],"mappings":"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"}
@@ -79,6 +79,12 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
79
79
  * These are retried when new tool calls are registered.
80
80
  */
81
81
  private pendingMatches;
82
+ /**
83
+ * Messages received before we can map a subgraph namespace to the public
84
+ * subagent tool-call ID. Once the mapping is established, these messages are
85
+ * replayed so early tool calls are not lost.
86
+ */
87
+ private pendingMessages;
82
88
  /**
83
89
  * Message managers for each subagent.
84
90
  * Uses the same MessageTupleManager as the main stream for proper
@@ -98,6 +104,14 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
98
104
  * This mirrors how the main stream handles messages.
99
105
  */
100
106
  private getMessagesForSubagent;
107
+ /**
108
+ * Buffer a subagent message until we can resolve its namespace to a tool call.
109
+ */
110
+ private queuePendingMessage;
111
+ /**
112
+ * Replay any buffered messages once a namespace has been mapped.
113
+ */
114
+ private flushPendingMessages;
101
115
  /**
102
116
  * Create a complete SubagentStream object with all derived properties.
103
117
  * This ensures consistency with UseStream interface.
@@ -1 +1 @@
1
- {"version":3,"file":"subagents.d.cts","names":[],"sources":["../../src/ui/subagents.ts"],"mappings":";;;;;;;AA8BA;;;;;AAuBA;;iBAvBgB,mBAAA,CACd,SAAA;;;AA4CF;;;;;AAgBA;;iBAtCgB,8BAAA,CACd,SAAA;;;AAoDF;;;;;iBA/BgB,2BAAA,CACd,SAAA;;;;;;;;;;iBAec,4BAAA,CACd,SAAA;;AA6DF;;UA/CiB,sBAAA;EA+CuB;;;;EA1CtC,iBAAA;EAiUgB;;;EA5ThB,gBAAA;EA8V2B;;;;EAxV3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EAsmBE;;;;;EAAA,QA/lBF,qBAAA;EA+zBS;;;;EAAA,QAzzBT,cAAA;EAAA;;;;;EAAA,QAOA,eAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,gBAAA;EAAA,QAEA,SAAA;EAER,WAAA,CAAY,OAAA,GAAU,sBAAA;EAyCd;;;EAAA,QA9BA,iBAAA;EA4FN;;;;EAAA,QA/EM,sBAAA;EAuMA;;;;EAAA,QAtLA,oBAAA;EAmNkB;;;;EAvK1B,0BAAA,CAA2B,WAAA;EA2LzB;;;;;;;;;;;;;EA1KF,uBAAA,CACE,WAAA,UACA,WAAA;EA4MyB;;;EA/H3B,kBAAA,CAAmB,QAAA;EAiKN;;;;EAAA,QAzJL,mBAAA;EAyJN;;;;;;;;;EAAA,QAvHM,eAAA;EA6SR;;;;EAAA,QArSQ,cAAA;EAwSK;;;;EArRb,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA8UjD;;;;EA5TF,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EA6WF;;;EAnWA,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAmXlD;;;EA3WF,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA4YlD;;;;;;EAhYF,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAsfzC;;;;EAAA,QA5eH,SAAA;;;;;;;;;;EAuBR,qBAAA,CACE,SAAA,EAAW,KAAA;IACT,EAAA;IACA,IAAA;IACA,IAAA,EAAM,MAAA;EAAA,IAER,WAAA;;;;UAsGM,mBAAA;;;;;;;;;;EA4BR,WAAA,CACE,UAAA,UACA,OAAA;IACE,SAAA;EAAA;;;;;;;;EA4BJ,wBAAA,CAAyB,WAAA,UAAqB,SAAA;;;;;;;;;;;;EAgB9C,oBAAA,CACE,WAAA,UACA,UAAA,EAAY,OAAA,CAAQ,eAAA,GACpB,QAAA,GAAW,MAAA;;;;;;;;;;;EAyDb,oBAAA,CACE,WAAA,UACA,MAAA,EAAQ,MAAA;;;;;;;;;;EA6BV,QAAA,CACE,UAAA,UACA,MAAA,UACA,MAAA;;;;EAmBF,KAAA,CAAA;;;;;;;;EAeA,kBAAA,CACE,UAAA,UACA,OAAA,UACA,MAAA;;;;;;;;;;;;;;;;;;;;;;;EAkCF,uBAAA,CACE,QAAA,EAAU,OAAA,CAAQ,eAAA,KAClB,OAAA;IAAY,eAAA;EAAA;;;;;;;;;;;;;EAoHd,+BAAA,CACE,UAAA,UACA,QAAA,EAAU,OAAA,IACV,MAAA,GAAS,MAAA;;;;EAkBX,YAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"subagents.d.cts","names":[],"sources":["../../src/ui/subagents.ts"],"mappings":";;;;;;;AA8BA;;;;;AAuBA;;iBAvBgB,mBAAA,CACd,SAAA;;;AA4CF;;;;;AAgBA;;iBAtCgB,8BAAA,CACd,SAAA;;;AAoDF;;;;;iBA/BgB,2BAAA,CACd,SAAA;;;;;;;;;;iBAec,4BAAA,CACd,SAAA;;AA6DF;;UA/CiB,sBAAA;EA+CuB;;;;EA1CtC,iBAAA;EAyWgB;;;EApWhB,gBAAA;EAsY2B;;;;EAhY3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EA+oBE;;;;;EAAA,QAxoBF,qBAAA;EAy2BS;;;;EAAA,QAn2BT,cAAA;EAAA;;;;;EAAA,QAOA,eAAA;EAqBR;;;;;EAAA,QARQ,eAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,gBAAA;EAAA,QAEA,SAAA;EAER,WAAA,CAAY,OAAA,GAAU,sBAAA;EAgItB;;;EAAA,QArHQ,iBAAA;EAqMW;;;;EAAA,QAxLX,sBAAA;EA6PQ;;;EAAA,QA7OR,mBAAA;EAiQR;;;EAAA,QApPQ,oBAAA;EAgQR;;;;EAAA,QAlPQ,oBAAA;EA4PR;;;;EAhNA,0BAAA,CAA2B,WAAA;EA8N3B;;;;;;;;;;;;;EA7MA,uBAAA,CACE,WAAA,UACA,WAAA;EA2VM;;;EA7QR,kBAAA,CAAmB,QAAA;EA2SjB;;;;EAAA,QAnSM,mBAAA;EAiVN;;;;;;;;;EAAA,QA/SM,eAAA;EAyYR;;;;EAAA,QAjYQ,cAAA;EAuaR;;;;EApZA,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwbvC;;;;EAtaZ,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EAyhBF;;;EA/gBA,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAghBzC;;;EAxgBX,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwhBxC;;;;;;EA5gBZ,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;;;;;UAU5C,SAAA;;;;;;;;;;EAuBR,qBAAA,CACE,SAAA,EAAW,KAAA;IACT,EAAA;IACA,IAAA;IACA,IAAA,EAAM,MAAA;EAAA,IAER,WAAA;;;;UAuGM,mBAAA;;;;;;;;;;EA4BR,WAAA,CACE,UAAA,UACA,OAAA;IACE,SAAA;EAAA;;;;;;;;EA4BJ,wBAAA,CAAyB,WAAA,UAAqB,SAAA;;;;;;;;;;;;EAgB9C,oBAAA,CACE,WAAA,UACA,UAAA,EAAY,OAAA,CAAQ,eAAA,GACpB,QAAA,GAAW,MAAA;;;;;;;;;;;EAyDb,oBAAA,CACE,WAAA,UACA,MAAA,EAAQ,MAAA;;;;;;;;;;EA6BV,QAAA,CACE,UAAA,UACA,MAAA,UACA,MAAA;;;;EAmBF,KAAA,CAAA;;;;;;;;EAgBA,kBAAA,CACE,UAAA,UACA,OAAA,UACA,MAAA;;;;;;;;;;;;;;;;;;;;;;;EAkCF,uBAAA,CACE,QAAA,EAAU,OAAA,CAAQ,eAAA,KAClB,OAAA;IAAY,eAAA;EAAA;;;;;;;;;;;;;EAoHd,+BAAA,CACE,UAAA,UACA,QAAA,EAAU,OAAA,IACV,MAAA,GAAS,MAAA;;;;EAkBX,YAAA,CAAA;AAAA"}
@@ -79,6 +79,12 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
79
79
  * These are retried when new tool calls are registered.
80
80
  */
81
81
  private pendingMatches;
82
+ /**
83
+ * Messages received before we can map a subgraph namespace to the public
84
+ * subagent tool-call ID. Once the mapping is established, these messages are
85
+ * replayed so early tool calls are not lost.
86
+ */
87
+ private pendingMessages;
82
88
  /**
83
89
  * Message managers for each subagent.
84
90
  * Uses the same MessageTupleManager as the main stream for proper
@@ -98,6 +104,14 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
98
104
  * This mirrors how the main stream handles messages.
99
105
  */
100
106
  private getMessagesForSubagent;
107
+ /**
108
+ * Buffer a subagent message until we can resolve its namespace to a tool call.
109
+ */
110
+ private queuePendingMessage;
111
+ /**
112
+ * Replay any buffered messages once a namespace has been mapped.
113
+ */
114
+ private flushPendingMessages;
101
115
  /**
102
116
  * Create a complete SubagentStream object with all derived properties.
103
117
  * This ensures consistency with UseStream interface.
@@ -1 +1 @@
1
- {"version":3,"file":"subagents.d.ts","names":[],"sources":["../../src/ui/subagents.ts"],"mappings":";;;;;;;AA8BA;;;;;AAuBA;;iBAvBgB,mBAAA,CACd,SAAA;;;AA4CF;;;;;AAgBA;;iBAtCgB,8BAAA,CACd,SAAA;;;AAoDF;;;;;iBA/BgB,2BAAA,CACd,SAAA;;;;;;;;;;iBAec,4BAAA,CACd,SAAA;;AA6DF;;UA/CiB,sBAAA;EA+CuB;;;;EA1CtC,iBAAA;EAiUgB;;;EA5ThB,gBAAA;EA8V2B;;;;EAxV3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EAsmBE;;;;;EAAA,QA/lBF,qBAAA;EA+zBS;;;;EAAA,QAzzBT,cAAA;EAAA;;;;;EAAA,QAOA,eAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,gBAAA;EAAA,QAEA,SAAA;EAER,WAAA,CAAY,OAAA,GAAU,sBAAA;EAyCd;;;EAAA,QA9BA,iBAAA;EA4FN;;;;EAAA,QA/EM,sBAAA;EAuMA;;;;EAAA,QAtLA,oBAAA;EAmNkB;;;;EAvK1B,0BAAA,CAA2B,WAAA;EA2LzB;;;;;;;;;;;;;EA1KF,uBAAA,CACE,WAAA,UACA,WAAA;EA4MyB;;;EA/H3B,kBAAA,CAAmB,QAAA;EAiKN;;;;EAAA,QAzJL,mBAAA;EAyJN;;;;;;;;;EAAA,QAvHM,eAAA;EA6SR;;;;EAAA,QArSQ,cAAA;EAwSK;;;;EArRb,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA8UjD;;;;EA5TF,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EA6WF;;;EAnWA,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAmXlD;;;EA3WF,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA4YlD;;;;;;EAhYF,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAsfzC;;;;EAAA,QA5eH,SAAA;;;;;;;;;;EAuBR,qBAAA,CACE,SAAA,EAAW,KAAA;IACT,EAAA;IACA,IAAA;IACA,IAAA,EAAM,MAAA;EAAA,IAER,WAAA;;;;UAsGM,mBAAA;;;;;;;;;;EA4BR,WAAA,CACE,UAAA,UACA,OAAA;IACE,SAAA;EAAA;;;;;;;;EA4BJ,wBAAA,CAAyB,WAAA,UAAqB,SAAA;;;;;;;;;;;;EAgB9C,oBAAA,CACE,WAAA,UACA,UAAA,EAAY,OAAA,CAAQ,eAAA,GACpB,QAAA,GAAW,MAAA;;;;;;;;;;;EAyDb,oBAAA,CACE,WAAA,UACA,MAAA,EAAQ,MAAA;;;;;;;;;;EA6BV,QAAA,CACE,UAAA,UACA,MAAA,UACA,MAAA;;;;EAmBF,KAAA,CAAA;;;;;;;;EAeA,kBAAA,CACE,UAAA,UACA,OAAA,UACA,MAAA;;;;;;;;;;;;;;;;;;;;;;;EAkCF,uBAAA,CACE,QAAA,EAAU,OAAA,CAAQ,eAAA,KAClB,OAAA;IAAY,eAAA;EAAA;;;;;;;;;;;;;EAoHd,+BAAA,CACE,UAAA,UACA,QAAA,EAAU,OAAA,IACV,MAAA,GAAS,MAAA;;;;EAkBX,YAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"subagents.d.ts","names":[],"sources":["../../src/ui/subagents.ts"],"mappings":";;;;;;;AA8BA;;;;;AAuBA;;iBAvBgB,mBAAA,CACd,SAAA;;;AA4CF;;;;;AAgBA;;iBAtCgB,8BAAA,CACd,SAAA;;;AAoDF;;;;;iBA/BgB,2BAAA,CACd,SAAA;;;;;;;;;;iBAec,4BAAA,CACd,SAAA;;AA6DF;;UA/CiB,sBAAA;EA+CuB;;;;EA1CtC,iBAAA;EAyWgB;;;EApWhB,gBAAA;EAsY2B;;;;EAhY3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EA+oBE;;;;;EAAA,QAxoBF,qBAAA;EAy2BS;;;;EAAA,QAn2BT,cAAA;EAAA;;;;;EAAA,QAOA,eAAA;EAqBR;;;;;EAAA,QARQ,eAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,gBAAA;EAAA,QAEA,SAAA;EAER,WAAA,CAAY,OAAA,GAAU,sBAAA;EAgItB;;;EAAA,QArHQ,iBAAA;EAqMW;;;;EAAA,QAxLX,sBAAA;EA6PQ;;;EAAA,QA7OR,mBAAA;EAiQR;;;EAAA,QApPQ,oBAAA;EAgQR;;;;EAAA,QAlPQ,oBAAA;EA4PR;;;;EAhNA,0BAAA,CAA2B,WAAA;EA8N3B;;;;;;;;;;;;;EA7MA,uBAAA,CACE,WAAA,UACA,WAAA;EA2VM;;;EA7QR,kBAAA,CAAmB,QAAA;EA2SjB;;;;EAAA,QAnSM,mBAAA;EAiVN;;;;;;;;;EAAA,QA/SM,eAAA;EAyYR;;;;EAAA,QAjYQ,cAAA;EAuaR;;;;EApZA,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwbvC;;;;EAtaZ,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EAyhBF;;;EA/gBA,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAghBzC;;;EAxgBX,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwhBxC;;;;;;EA5gBZ,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;;;;;UAU5C,SAAA;;;;;;;;;;EAuBR,qBAAA,CACE,SAAA,EAAW,KAAA;IACT,EAAA;IACA,IAAA;IACA,IAAA,EAAM,MAAA;EAAA,IAER,WAAA;;;;UAuGM,mBAAA;;;;;;;;;;EA4BR,WAAA,CACE,UAAA,UACA,OAAA;IACE,SAAA;EAAA;;;;;;;;EA4BJ,wBAAA,CAAyB,WAAA,UAAqB,SAAA;;;;;;;;;;;;EAgB9C,oBAAA,CACE,WAAA,UACA,UAAA,EAAY,OAAA,CAAQ,eAAA,GACpB,QAAA,GAAW,MAAA;;;;;;;;;;;EAyDb,oBAAA,CACE,WAAA,UACA,MAAA,EAAQ,MAAA;;;;;;;;;;EA6BV,QAAA,CACE,UAAA,UACA,MAAA,UACA,MAAA;;;;EAmBF,KAAA,CAAA;;;;;;;;EAgBA,kBAAA,CACE,UAAA,UACA,OAAA,UACA,MAAA;;;;;;;;;;;;;;;;;;;;;;;EAkCF,uBAAA,CACE,QAAA,EAAU,OAAA,CAAQ,eAAA,KAClB,OAAA;IAAY,eAAA;EAAA;;;;;;;;;;;;;EAoHd,+BAAA,CACE,UAAA,UACA,QAAA,EAAU,OAAA,IACV,MAAA,GAAS,MAAA;;;;EAkBX,YAAA,CAAA;AAAA"}
@@ -79,6 +79,12 @@ var SubagentManager = class {
79
79
  */
80
80
  pendingMatches = /* @__PURE__ */ new Map();
81
81
  /**
82
+ * Messages received before we can map a subgraph namespace to the public
83
+ * subagent tool-call ID. Once the mapping is established, these messages are
84
+ * replayed so early tool calls are not lost.
85
+ */
86
+ pendingMessages = /* @__PURE__ */ new Map();
87
+ /**
82
88
  * Message managers for each subagent.
83
89
  * Uses the same MessageTupleManager as the main stream for proper
84
90
  * message chunk concatenation.
@@ -115,6 +121,28 @@ var SubagentManager = class {
115
121
  return messages;
116
122
  }
117
123
  /**
124
+ * Buffer a subagent message until we can resolve its namespace to a tool call.
125
+ */
126
+ queuePendingMessage(namespaceId, serialized, metadata) {
127
+ const pending = this.pendingMessages.get(namespaceId) ?? [];
128
+ pending.push({
129
+ serialized,
130
+ metadata
131
+ });
132
+ this.pendingMessages.set(namespaceId, pending);
133
+ }
134
+ /**
135
+ * Replay any buffered messages once a namespace has been mapped.
136
+ */
137
+ flushPendingMessages(namespaceId) {
138
+ const pending = this.pendingMessages.get(namespaceId);
139
+ if (!pending?.length) return;
140
+ this.pendingMessages.delete(namespaceId);
141
+ pending.forEach(({ serialized, metadata }) => {
142
+ this.addMessageToSubagent(namespaceId, serialized, metadata);
143
+ });
144
+ }
145
+ /**
118
146
  * Create a complete SubagentStream object with all derived properties.
119
147
  * This ensures consistency with UseStream interface.
120
148
  */
@@ -173,6 +201,7 @@ var SubagentManager = class {
173
201
  });
174
202
  this.onSubagentChange?.();
175
203
  }
204
+ this.flushPendingMessages(namespaceId);
176
205
  return toolCallId;
177
206
  };
178
207
  for (const [toolCallId, subagent] of this.subagents) if ((subagent.status === "pending" || subagent.status === "running") && !mappedToolCallIds.has(toolCallId) && subagent.toolCall.args.description === description) return establishMapping(toolCallId);
@@ -356,6 +385,7 @@ var SubagentManager = class {
356
385
  };
357
386
  this.subagents.set(toolCall.id, execution);
358
387
  this.getMessageManager(toolCall.id);
388
+ this.flushPendingMessages(toolCall.id);
359
389
  hasChanges = true;
360
390
  }
361
391
  if (hasChanges) {
@@ -425,7 +455,10 @@ var SubagentManager = class {
425
455
  if (serialized.type === "human" && typeof serialized.content === "string") this.matchSubgraphToSubagent(namespaceId, serialized.content);
426
456
  const toolCallId = this.getToolCallIdFromNamespace(namespaceId);
427
457
  const existing = this.subagents.get(toolCallId);
428
- if (!existing) return;
458
+ if (!existing) {
459
+ this.queuePendingMessage(namespaceId, serialized, metadata);
460
+ return;
461
+ }
429
462
  if (this.getMessageManager(toolCallId).add(serialized, metadata)) if (serialized.type === "ai") this.subagents.set(toolCallId, {
430
463
  ...existing,
431
464
  status: "running",
@@ -489,6 +522,7 @@ var SubagentManager = class {
489
522
  this.namespaceToToolCallId.clear();
490
523
  this.messageManagers.clear();
491
524
  this.pendingMatches.clear();
525
+ this.pendingMessages.clear();
492
526
  this.onSubagentChange?.();
493
527
  }
494
528
  /**