@langchain/langgraph-sdk 1.7.4 → 1.8.0
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.
- package/dist/react/stream.custom.cjs +21 -1
- package/dist/react/stream.custom.cjs.map +1 -1
- package/dist/react/stream.custom.js +21 -1
- package/dist/react/stream.custom.js.map +1 -1
- package/dist/react/stream.lgp.cjs +11 -1
- package/dist/react/stream.lgp.cjs.map +1 -1
- package/dist/react/stream.lgp.js +11 -1
- package/dist/react/stream.lgp.js.map +1 -1
- package/dist/ui/index.cjs +4 -0
- package/dist/ui/index.d.cts +3 -1
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +3 -1
- package/dist/ui/manager.cjs +181 -0
- package/dist/ui/manager.cjs.map +1 -1
- package/dist/ui/manager.d.cts +41 -0
- package/dist/ui/manager.d.cts.map +1 -1
- package/dist/ui/manager.d.ts +41 -0
- package/dist/ui/manager.d.ts.map +1 -1
- package/dist/ui/manager.js +181 -0
- package/dist/ui/manager.js.map +1 -1
- package/dist/ui/orchestrator-custom.cjs +372 -0
- package/dist/ui/orchestrator-custom.cjs.map +1 -0
- package/dist/ui/orchestrator-custom.d.cts +185 -0
- package/dist/ui/orchestrator-custom.d.cts.map +1 -0
- package/dist/ui/orchestrator-custom.d.ts +185 -0
- package/dist/ui/orchestrator-custom.d.ts.map +1 -0
- package/dist/ui/orchestrator-custom.js +372 -0
- package/dist/ui/orchestrator-custom.js.map +1 -0
- package/dist/ui/orchestrator.cjs +866 -0
- package/dist/ui/orchestrator.cjs.map +1 -0
- package/dist/ui/orchestrator.d.cts +366 -0
- package/dist/ui/orchestrator.d.cts.map +1 -0
- package/dist/ui/orchestrator.d.ts +366 -0
- package/dist/ui/orchestrator.d.ts.map +1 -0
- package/dist/ui/orchestrator.js +866 -0
- package/dist/ui/orchestrator.js.map +1 -0
- package/dist/ui/subagents.cjs +24 -1
- package/dist/ui/subagents.cjs.map +1 -1
- package/dist/ui/subagents.d.cts +13 -0
- package/dist/ui/subagents.d.cts.map +1 -1
- package/dist/ui/subagents.d.ts +13 -0
- package/dist/ui/subagents.d.ts.map +1 -1
- package/dist/ui/subagents.js +24 -1
- package/dist/ui/subagents.js.map +1 -1
- package/dist/ui/types.d.cts +3 -2
- package/dist/ui/types.d.cts.map +1 -1
- package/dist/ui/types.d.ts +3 -2
- package/dist/ui/types.d.ts.map +1 -1
- package/package.json +2 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","names":["#options","#accessors","#runMetadataStorage","#callbackStreamModes","#trackedStreamModes","#threadId","#history","#mutate","#streamUnsub","#notify","#queueUnsub","#listeners","#version","#disposed","#fetchHistoryForThread","#threadIdStreaming","#branch","#getMessages","#setMessages","#threadIdPromise","#setThreadIdFromSubmit","#submitting","#drainQueue"],"sources":["../../src/ui/orchestrator.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport { Client } from \"../client.js\";\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { StreamMode } from \"../types.stream.js\";\nimport type { StreamEvent } from \"../types.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 ensureHistoryMessageInstances,\n} from \"./messages.js\";\nimport { PendingRunsTracker } from \"./queue.js\";\nimport { getBranchContext, getMessagesMetadataMap } from \"./branching.js\";\nimport { StreamError } from \"./errors.js\";\nimport { extractInterrupts } from \"./interrupts.js\";\nimport { unique, filterStream } from \"./utils.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport type {\n UseStreamThread,\n AnyStreamOptions,\n SubmitOptions,\n RunCallbackMeta,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\ninterface RunMetadataStorage {\n getItem(key: `lg:stream:${string}`): string | null;\n setItem(key: `lg:stream:${string}`, value: string): void;\n removeItem(key: `lg:stream:${string}`): void;\n}\n\n/**\n * Fetch the history of a thread.\n * @param client - The client to use.\n * @param threadId - The ID of the thread to fetch the history of.\n * @param options - The options to use.\n * @returns The history of the thread.\n */\nfunction fetchHistory<StateType extends Record<string, unknown>>(\n client: Client,\n threadId: string,\n options?: { limit?: boolean | number }\n) {\n if (options?.limit === false) {\n return client.threads.getState<StateType>(threadId).then((state) => {\n if (state.checkpoint == null) return [];\n return [state];\n });\n }\n\n const limit = typeof options?.limit === \"number\" ? options.limit : 10;\n return client.threads.getHistory<StateType>(threadId, { limit });\n}\n\n/**\n * Resolve the run metadata storage.\n * @param reconnectOnMount - The reconnect on mount option.\n * @returns The run metadata storage.\n */\nfunction resolveRunMetadataStorage(\n reconnectOnMount: boolean | (() => RunMetadataStorage) | undefined\n): RunMetadataStorage | null {\n if (typeof globalThis.window === \"undefined\") return null;\n if (reconnectOnMount === true) return globalThis.window.sessionStorage;\n if (typeof reconnectOnMount === \"function\") return reconnectOnMount();\n return null;\n}\n\n/**\n * Resolve the callback stream modes.\n * @param options - The options to use.\n * @returns The callback stream modes.\n */\nfunction resolveCallbackStreamModes<\n S extends Record<string, unknown>,\n B extends BagTemplate\n>(options: AnyStreamOptions<S, B>): StreamMode[] {\n const modes: StreamMode[] = [];\n if (options.onUpdateEvent) modes.push(\"updates\");\n if (options.onCustomEvent) modes.push(\"custom\");\n if (options.onCheckpointEvent) modes.push(\"checkpoints\");\n if (options.onTaskEvent) modes.push(\"tasks\");\n if (\"onDebugEvent\" in options && options.onDebugEvent) modes.push(\"debug\");\n if (\"onLangChainEvent\" in options && options.onLangChainEvent)\n modes.push(\"events\");\n return modes;\n}\n\n/**\n * Callbacks for resolving dynamic/reactive option values.\n * Framework adapters provide implementations that unwrap reactive primitives.\n */\nexport interface OrchestratorAccessors {\n getClient(): Client;\n getAssistantId(): string;\n getMessagesKey(): string;\n}\n\n/**\n * Framework-agnostic orchestrator for LangGraph Platform streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular:\n * thread management, history fetching, stream lifecycle, queue management,\n * branching, subagent management, and auto-reconnect.\n *\n * Framework adapters subscribe to state changes via {@link subscribe} and\n * map the orchestrator's getters to framework-specific reactive primitives.\n */\nexport class StreamOrchestrator<\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 pendingRuns: PendingRunsTracker<\n StateType,\n SubmitOptions<StateType, GetConfigurableType<Bag>>\n >;\n\n readonly #options: AnyStreamOptions<StateType, Bag>;\n\n readonly #accessors: OrchestratorAccessors;\n\n readonly historyLimit: boolean | number;\n\n readonly #runMetadataStorage: RunMetadataStorage | null;\n\n readonly #callbackStreamModes: StreamMode[];\n\n readonly #trackedStreamModes: StreamMode[] = [];\n\n #threadId: string | undefined;\n\n #threadIdPromise: Promise<string> | null = null;\n\n #threadIdStreaming: string | null = null;\n\n #history: UseStreamThread<StateType>;\n\n #branch: string = \"\";\n\n #submitting = false;\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #queueUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n /**\n * Create a new StreamOrchestrator.\n *\n * @param options - Configuration options for the stream, including callbacks,\n * throttle settings, reconnect behaviour, and subagent filters.\n * @param accessors - Framework-specific accessors that resolve reactive\n * primitives (client, assistant ID, messages key) at call time.\n */\n constructor(\n options: AnyStreamOptions<StateType, Bag>,\n accessors: OrchestratorAccessors\n ) {\n this.#options = options;\n this.#accessors = accessors;\n\n this.#runMetadataStorage = resolveRunMetadataStorage(\n options.reconnectOnMount\n );\n this.#callbackStreamModes = resolveCallbackStreamModes(options);\n\n this.historyLimit =\n typeof options.fetchStateHistory === \"object\" &&\n options.fetchStateHistory != null\n ? options.fetchStateHistory.limit ?? false\n : options.fetchStateHistory ?? false;\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.pendingRuns = new PendingRunsTracker<\n StateType,\n SubmitOptions<StateType, GetConfigurableType<Bag>>\n >();\n\n this.#threadId = undefined;\n this.#history = {\n data: undefined,\n error: undefined,\n isLoading: false,\n mutate: this.#mutate,\n };\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#notify();\n });\n\n this.#queueUnsub = this.pendingRuns.subscribe(() => {\n this.#notify();\n });\n }\n\n /**\n * Register a listener that is called whenever the orchestrator's internal\n * state changes (stream updates, queue changes, history mutations, etc.).\n *\n * @param listener - Callback invoked on every 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 every state change.\n * Useful as a React `useSyncExternalStore` snapshot.\n *\n * @returns The current monotonically increasing version counter.\n */\n getSnapshot(): number {\n return this.#version;\n }\n\n /**\n * Increment the version counter and invoke all registered listeners.\n * No-op if the orchestrator has been disposed.\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 * The current thread ID, or `undefined` if no thread is active.\n */\n get threadId(): string | undefined {\n return this.#threadId;\n }\n\n /**\n * Update thread ID from an external source (e.g. reactive prop change).\n * Clears the current stream and triggers a history fetch.\n * @param newId - The new thread ID to set.\n * @returns The new thread ID.\n */\n setThreadId(newId: string | undefined): void {\n if (newId === this.#threadId) return;\n this.#threadId = newId;\n this.stream.clear();\n this.#fetchHistoryForThread(newId);\n this.#notify();\n }\n\n /**\n * Update the thread ID from within a submit flow. Sets both the\n * streaming and canonical thread IDs, fires the `onThreadId` callback,\n * and notifies listeners.\n *\n * @param newId - The newly created or resolved thread ID.\n */\n #setThreadIdFromSubmit(newId: string): void {\n this.#threadIdStreaming = newId;\n this.#threadId = newId;\n this.#options.onThreadId?.(newId);\n this.#notify();\n }\n\n #fetchHistoryForThread(threadId: string | undefined): void {\n if (\n this.#threadIdStreaming != null &&\n this.#threadIdStreaming === threadId\n ) {\n return;\n }\n\n if (threadId != null) {\n this.#history = {\n ...this.#history,\n isLoading: true,\n mutate: this.#mutate,\n };\n this.#notify();\n void this.#mutate(threadId);\n } else {\n this.#history = {\n data: undefined,\n error: undefined,\n isLoading: false,\n mutate: this.#mutate,\n };\n this.#notify();\n }\n }\n\n /**\n * The current thread history fetch state, including data, loading status,\n * error, and a {@link UseStreamThread.mutate | mutate} function to\n * manually re-fetch.\n */\n get historyData(): UseStreamThread<StateType> {\n return this.#history;\n }\n\n async #mutate(\n mutateId?: string\n ): Promise<ThreadState<StateType>[] | undefined> {\n const tid = mutateId ?? this.#threadId;\n if (!tid) return undefined;\n try {\n const data = await fetchHistory<StateType>(\n this.#accessors.getClient(),\n tid,\n { limit: this.historyLimit }\n );\n this.#history = {\n data,\n error: undefined,\n isLoading: false,\n mutate: this.#mutate,\n };\n this.#notify();\n return data;\n } catch (err) {\n this.#history = {\n ...this.#history,\n error: err,\n isLoading: false,\n };\n this.#notify();\n this.#options.onError?.(err, undefined);\n return undefined;\n }\n }\n\n /**\n * Trigger initial history fetch for the current thread ID.\n * Should be called once after construction when the initial threadId is known.\n */\n initThreadId(threadId: string | undefined): void {\n this.#threadId = threadId;\n this.#fetchHistoryForThread(threadId);\n }\n\n /**\n * The currently active branch identifier. An empty string represents\n * the main (default) branch.\n */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Set the active branch and notify listeners if the value changed.\n *\n * @param value - The branch identifier to switch to.\n */\n setBranch(value: string): void {\n if (value === this.#branch) return;\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * Derived branch context computed from the current branch and thread\n * history. Contains the thread head, branch tree, and checkpoint-to-branch\n * mapping for the active branch.\n */\n get branchContext() {\n return getBranchContext(this.#branch, this.#history.data ?? undefined);\n }\n\n #getMessages(value: StateType): Message[] {\n const messagesKey = this.#accessors.getMessagesKey();\n return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];\n }\n\n #setMessages(current: StateType, messages: Message[]): StateType {\n const messagesKey = this.#accessors.getMessagesKey();\n return { ...current, [messagesKey]: messages };\n }\n\n /**\n * The state values from the thread head of the current branch history,\n * falling back to {@link AnyStreamOptions.initialValues | initialValues}\n * or an empty object.\n */\n get historyValues(): StateType {\n return (\n this.branchContext.threadHead?.values ??\n this.#options.initialValues ??\n ({} as StateType)\n );\n }\n\n /**\n * The error from the last task in the thread head, if any.\n * Attempts to parse structured {@link StreamError} instances from JSON.\n */\n get historyError(): unknown {\n const error = this.branchContext.threadHead?.tasks?.at(-1)?.error;\n if (error == null) return undefined;\n try {\n const parsed = JSON.parse(error) as unknown;\n if (StreamError.isStructuredError(parsed)) return new StreamError(parsed);\n return parsed;\n } catch {\n // do nothing\n }\n return error;\n }\n\n /**\n * The latest state values received from the active stream, or `null` if\n * no stream is running or no values have been received yet.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /**\n * The error from the active stream, if one occurred during streaming.\n */\n get streamError(): unknown {\n return this.stream.error;\n }\n\n /**\n * The merged state values, preferring live stream values over history.\n * This is the primary way to read the current thread state.\n */\n get values(): StateType {\n return this.stream.values ?? this.historyValues;\n }\n\n /**\n * The first available error from the stream, history, or thread fetch.\n * Returns `undefined` when no error is present.\n */\n get error(): unknown {\n return this.stream.error ?? this.historyError ?? this.#history.error;\n }\n\n /**\n * Whether the stream is currently active and receiving events.\n */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /**\n * The messages array extracted from the current {@link values} using the\n * configured messages key.\n */\n get messages(): Message[] {\n return this.#getMessages(this.values);\n }\n\n /**\n * The current messages converted to LangChain {@link BaseMessage} instances.\n * Automatically tracks the `\"messages-tuple\"` stream mode.\n */\n get messageInstances(): BaseMessage[] {\n this.trackStreamMode(\"messages-tuple\");\n return ensureMessageInstances(this.messages) as BaseMessage[];\n }\n\n /**\n * All tool calls with their corresponding results extracted from\n * the current messages. Automatically tracks the `\"messages-tuple\"`\n * stream mode.\n */\n get toolCalls() {\n this.trackStreamMode(\"messages-tuple\");\n return getToolCallsWithResults(this.#getMessages(this.values));\n }\n\n /**\n * Get tool calls with results for a specific AI message.\n * Automatically tracks the `\"messages-tuple\"` stream mode.\n *\n * @param message - The AI message to extract tool calls from.\n * @returns Tool calls whose AI message ID matches the given message.\n */\n getToolCalls(message: Message) {\n this.trackStreamMode(\"messages-tuple\");\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts for the current thread state.\n * Returns an empty array when the stream is loading or no interrupts\n * are present. Falls back to a `{ when: \"breakpoint\" }` sentinel when\n * there are pending next nodes but no explicit interrupt data.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n const v = this.values;\n if (v != null && \"__interrupt__\" in v && Array.isArray(v.__interrupt__)) {\n const valueInterrupts = v.__interrupt__;\n if (valueInterrupts.length === 0) return [{ when: \"breakpoint\" }];\n return valueInterrupts;\n }\n\n if (this.isLoading) return [];\n\n const allTasks = this.branchContext.threadHead?.tasks ?? [];\n const allInterrupts = allTasks.flatMap((t) => t.interrupts ?? []);\n\n if (allInterrupts.length > 0) {\n return allInterrupts as Interrupt<GetInterruptType<Bag>>[];\n }\n\n const next = this.branchContext.threadHead?.next ?? [];\n if (!next.length || this.error != null) return [];\n return [{ when: \"breakpoint\" }];\n }\n\n /**\n * The single most relevant interrupt for the current thread state,\n * or `undefined` if no interrupt is active. Convenience accessor that\n * delegates to {@link extractInterrupts}.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.values, {\n isLoading: this.isLoading,\n threadState: this.branchContext.threadHead,\n error: this.error,\n });\n }\n\n /**\n * Flattened history messages as LangChain {@link BaseMessage} instances,\n * ordered chronologically across all branch checkpoints.\n *\n * @throws If `fetchStateHistory` was not enabled in the options.\n */\n get flatHistory() {\n if (this.historyLimit === false) {\n throw new Error(\n \"`fetchStateHistory` must be set to `true` to use `history`\"\n );\n }\n return ensureHistoryMessageInstances(\n this.branchContext.flatHistory,\n this.#accessors.getMessagesKey()\n );\n }\n\n /**\n * Whether the initial thread history is still being loaded and no data\n * is available yet. Returns `false` once the first fetch completes.\n */\n get isThreadLoading(): boolean {\n return this.#history.isLoading && this.#history.data == null;\n }\n\n /**\n * The full branch tree structure for the current thread history.\n *\n * @experimental This API may change in future releases.\n * @throws If `fetchStateHistory` was not enabled in the options.\n */\n get experimental_branchTree() {\n if (this.historyLimit === false) {\n throw new Error(\n \"`fetchStateHistory` must be set to `true` to use `experimental_branchTree`\"\n );\n }\n return this.branchContext.branchTree;\n }\n\n /**\n * A map of metadata entries for all messages, derived from history\n * and branch context. Used internally by {@link getMessagesMetadata}.\n */\n get messageMetadata() {\n return getMessagesMetadataMap({\n initialValues: this.#options.initialValues,\n history: this.#history.data,\n getMessages: (value: StateType) => this.#getMessages(value),\n branchContext: this.branchContext,\n });\n }\n\n /**\n * Look up metadata for a specific message, merging stream-time metadata\n * with history-derived metadata.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as a fallback identifier.\n * @returns The merged metadata, or `undefined` if none 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 const historyMetadata = this.messageMetadata?.find(\n (m) => m.messageId === (message.id ?? index)\n );\n\n if (streamMetadata != null || historyMetadata != null) {\n return {\n ...historyMetadata,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n\n return undefined;\n }\n\n /**\n * The list of pending run entries currently waiting in the queue.\n */\n get queueEntries() {\n return this.pendingRuns.entries;\n }\n\n /**\n * The number of pending runs in the queue.\n */\n get queueSize() {\n return this.pendingRuns.size;\n }\n\n /**\n * Cancel and remove a specific pending run from the queue.\n * If the run exists and a thread is active, the run is also cancelled\n * on the server.\n *\n * @param id - The run ID to cancel.\n * @returns `true` if the run was found and removed, `false` otherwise.\n */\n async cancelQueueItem(id: string): Promise<boolean> {\n const tid = this.#threadId;\n const removed = this.pendingRuns.remove(id);\n if (removed && tid) {\n await this.#accessors.getClient().runs.cancel(tid, id);\n }\n return removed;\n }\n\n /**\n * Remove all pending runs from the queue and cancel them on the server.\n */\n async clearQueue(): Promise<void> {\n const tid = this.#threadId;\n const removed = this.pendingRuns.removeAll();\n if (tid && removed.length > 0) {\n await Promise.all(\n removed.map((e) => this.#accessors.getClient().runs.cancel(tid, e.id))\n );\n }\n }\n\n /**\n * A map of all known subagent stream interfaces, keyed by tool call ID.\n */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /**\n * The subset of subagents that are currently active (streaming).\n */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Retrieve a specific subagent stream interface by its tool call ID.\n *\n * @param toolCallId - The tool call ID that spawned the subagent.\n * @returns The subagent interface, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent stream interfaces that match a given agent type.\n *\n * @param type - The agent type name to filter by.\n * @returns An array of matching subagent interfaces.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent stream interfaces associated with a specific\n * AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent interfaces spawned by that message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagents from history messages if applicable.\n * Call this when history finishes loading and the stream isn't active.\n * Returns an AbortController for cancelling the subagent history fetch,\n * or null if no reconstruction was needed.\n */\n reconstructSubagentsIfNeeded(): AbortController | null {\n const hvMessages = this.#getMessages(this.historyValues);\n const should =\n this.#options.filterSubagentMessages &&\n !this.isLoading &&\n !this.#history.isLoading &&\n hvMessages.length > 0;\n\n if (!should) return null;\n\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n\n const tid = this.#threadId;\n if (tid) {\n const controller = new AbortController();\n void this.stream.fetchSubagentHistory(\n this.#accessors.getClient().threads,\n tid,\n {\n messagesKey: this.#accessors.getMessagesKey(),\n signal: controller.signal,\n }\n );\n return controller;\n }\n\n return null;\n }\n\n /**\n * Register additional stream modes that should be included in future\n * stream requests. Modes are deduplicated automatically.\n *\n * @param modes - One or more stream modes to track.\n */\n trackStreamMode(...modes: StreamMode[]): void {\n for (const mode of modes) {\n if (!this.#trackedStreamModes.includes(mode)) {\n this.#trackedStreamModes.push(mode);\n }\n }\n }\n\n /**\n * Stop the currently active stream. If reconnect metadata storage is\n * configured, also cancels the run on the server and cleans up stored\n * run metadata.\n */\n stop(): void {\n void this.stream.stop(this.historyValues, {\n onStop: (args) => {\n if (this.#runMetadataStorage && this.#threadId) {\n const runId = this.#runMetadataStorage.getItem(\n `lg:stream:${this.#threadId}`\n );\n if (runId) {\n void this.#accessors.getClient().runs.cancel(this.#threadId, runId);\n }\n this.#runMetadataStorage.removeItem(`lg:stream:${this.#threadId}`);\n }\n this.#options.onStop?.(args);\n },\n });\n }\n\n /**\n * Join an existing run's event stream by run ID. Used for reconnecting\n * to in-progress runs or consuming queued runs.\n *\n * @param runId - The ID of the run to join.\n * @param lastEventId - The last event ID received, for resuming mid-stream.\n * Defaults to `\"-1\"` (start from the beginning).\n * @param joinOptions - Additional options for stream mode and event filtering.\n */\n async joinStream(\n runId: string,\n lastEventId?: string,\n joinOptions?: {\n streamMode?: StreamMode | StreamMode[];\n filter?: (event: {\n id?: string;\n event: StreamEvent;\n data: unknown;\n }) => boolean;\n }\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n // eslint-disable-next-line no-param-reassign\n lastEventId ??= \"-1\";\n const tid = this.#threadId;\n if (!tid) return;\n this.#threadIdStreaming = tid;\n\n const callbackMeta: RunCallbackMeta = {\n thread_id: tid,\n run_id: runId,\n };\n\n const client = this.#accessors.getClient();\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n const rawStream = client.runs.joinStream(tid, runId, {\n signal,\n lastEventId,\n streamMode: joinOptions?.streamMode,\n }) as AsyncGenerator<\n EventStreamEvent<StateType, UpdateType, CustomType>\n >;\n\n return joinOptions?.filter != null\n ? filterStream(rawStream, joinOptions.filter)\n : rawStream;\n },\n {\n getMessages: (value: StateType) => this.#getMessages(value),\n setMessages: (current: StateType, messages: Message[]) =>\n this.#setMessages(current, messages),\n initialValues: this.historyValues,\n callbacks: this.#options,\n onSuccess: async () => {\n this.#runMetadataStorage?.removeItem(`lg:stream:${tid}`);\n const newHistory = await this.#mutate(tid);\n const lastHead = newHistory?.at(0);\n if (lastHead) this.#options.onFinish?.(lastHead, callbackMeta);\n },\n onError: (error) => {\n this.#options.onError?.(error, callbackMeta);\n },\n onFinish: () => {\n this.#threadIdStreaming = null;\n },\n }\n );\n }\n\n /**\n * Submit input values directly to the LangGraph Platform, creating a new\n * thread if necessary. Starts a streaming run and processes events until\n * completion. Unlike {@link submit}, this does not handle queueing — if\n * a stream is already active, a concurrent run will be started.\n *\n * @param values - The state values to send as run input.\n * @param submitOptions - Optional configuration for the run (config,\n * checkpoint, multitask strategy, optimistic values, etc.).\n */\n submitDirect(\n values: StateType,\n submitOptions?: SubmitOptions<StateType, GetConfigurableType<Bag>>\n ) {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentBranchContext = this.branchContext;\n\n const checkpointId = submitOptions?.checkpoint?.checkpoint_id;\n this.#branch =\n checkpointId != null\n ? currentBranchContext.branchByCheckpoint[checkpointId]?.branch ?? \"\"\n : \"\";\n\n const includeImplicitBranch =\n this.historyLimit === true || typeof this.historyLimit === \"number\";\n\n const shouldRefetch =\n this.#options.onFinish != null || includeImplicitBranch;\n\n let checkpoint =\n submitOptions?.checkpoint ??\n (includeImplicitBranch\n ? currentBranchContext.threadHead?.checkpoint\n : undefined) ??\n undefined;\n\n if (submitOptions?.checkpoint === null) checkpoint = undefined;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n if (checkpoint != null) delete checkpoint.thread_id;\n\n let callbackMeta: RunCallbackMeta | undefined;\n let rejoinKey: `lg:stream:${string}` | undefined;\n let usableThreadId: string | undefined;\n\n const client = this.#accessors.getClient();\n const assistantId = this.#accessors.getAssistantId();\n\n return this.stream.start(\n async (signal) => {\n usableThreadId = this.#threadId;\n if (usableThreadId) {\n this.#threadIdStreaming = usableThreadId;\n }\n if (!usableThreadId) {\n const threadPromise = client.threads.create({\n threadId: submitOptions?.threadId,\n metadata: submitOptions?.metadata,\n });\n\n this.#threadIdPromise = threadPromise.then((t) => t.thread_id);\n\n const thread = await threadPromise;\n\n usableThreadId = thread.thread_id;\n this.#setThreadIdFromSubmit(usableThreadId);\n }\n\n const streamMode = unique([\n \"values\" as StreamMode,\n \"updates\" as StreamMode,\n ...(submitOptions?.streamMode ?? []),\n ...this.#trackedStreamModes,\n ...this.#callbackStreamModes,\n ]);\n\n this.stream.setStreamValues(() => {\n const prev = { ...this.historyValues, ...this.stream.values };\n\n if (submitOptions?.optimisticValues != null) {\n return {\n ...prev,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(prev)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...prev };\n });\n\n const streamResumable =\n submitOptions?.streamResumable ?? !!this.#runMetadataStorage;\n\n return client.runs.stream(usableThreadId!, assistantId, {\n input: values as Record<string, unknown>,\n config: submitOptions?.config,\n context: submitOptions?.context,\n command: submitOptions?.command,\n\n interruptBefore: submitOptions?.interruptBefore,\n interruptAfter: submitOptions?.interruptAfter,\n metadata: submitOptions?.metadata,\n multitaskStrategy: submitOptions?.multitaskStrategy,\n onCompletion: submitOptions?.onCompletion,\n onDisconnect:\n submitOptions?.onDisconnect ??\n (streamResumable ? \"continue\" : \"cancel\"),\n\n signal,\n\n checkpoint,\n streamMode,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n streamResumable,\n durability: submitOptions?.durability,\n onRunCreated: (params) => {\n callbackMeta = {\n run_id: params.run_id,\n thread_id: params.thread_id ?? usableThreadId!,\n };\n\n if (this.#runMetadataStorage) {\n rejoinKey = `lg:stream:${usableThreadId}`;\n this.#runMetadataStorage.setItem(rejoinKey, callbackMeta.run_id);\n }\n\n this.#options.onCreated?.(callbackMeta);\n },\n }) as AsyncGenerator<\n EventStreamEvent<StateType, UpdateType, CustomType>\n >;\n },\n {\n getMessages: (value: StateType) => this.#getMessages(value),\n setMessages: (current: StateType, messages: Message[]) =>\n this.#setMessages(current, messages),\n initialValues: this.historyValues,\n callbacks: this.#options,\n\n onSuccess: async () => {\n if (rejoinKey) this.#runMetadataStorage?.removeItem(rejoinKey);\n\n if (shouldRefetch && usableThreadId) {\n const newHistory = await this.#mutate(usableThreadId);\n const lastHead = newHistory?.at(0);\n if (lastHead) {\n this.#options.onFinish?.(lastHead, callbackMeta);\n return null;\n }\n }\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, callbackMeta);\n submitOptions?.onError?.(error, callbackMeta);\n },\n onFinish: () => {\n this.#threadIdStreaming = null;\n },\n }\n );\n }\n\n #drainQueue(): void {\n if (!this.isLoading && !this.#submitting && this.pendingRuns.size > 0) {\n const next = this.pendingRuns.shift();\n if (next) {\n this.#submitting = true;\n void this.joinStream(next.id).finally(() => {\n this.#submitting = false;\n this.#drainQueue();\n });\n }\n }\n }\n\n /**\n * Trigger queue draining. Framework adapters should call this\n * when isLoading or queue size changes.\n */\n drainQueue(): void {\n this.#drainQueue();\n }\n\n /**\n * Submit input values with automatic queue management. If a stream is\n * already active, the run is enqueued (unless the multitask strategy\n * is `\"interrupt\"` or `\"rollback\"`, in which case the current run is\n * replaced). Queued runs are drained sequentially via {@link drainQueue}.\n *\n * @param values - The state values to send as run input.\n * @param submitOptions - Optional configuration for the run.\n * @returns The result of {@link submitDirect} if the run was started\n * immediately, or `void` if the run was enqueued.\n */\n async submit(\n values: StateType,\n submitOptions?: SubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<ReturnType<typeof this.submitDirect> | void> {\n if (this.stream.isLoading || this.#submitting) {\n const shouldAbort =\n submitOptions?.multitaskStrategy === \"interrupt\" ||\n submitOptions?.multitaskStrategy === \"rollback\";\n\n if (shouldAbort) {\n this.#submitting = true;\n try {\n await this.submitDirect(values, submitOptions);\n } finally {\n this.#submitting = false;\n }\n return;\n }\n\n let usableThreadId: string | undefined = this.#threadId;\n if (!usableThreadId && this.#threadIdPromise) {\n usableThreadId = await this.#threadIdPromise;\n }\n if (usableThreadId) {\n const client = this.#accessors.getClient();\n const assistantId = this.#accessors.getAssistantId();\n try {\n const run = await client.runs.create(usableThreadId, assistantId, {\n input: values as Record<string, unknown>,\n config: submitOptions?.config,\n context: submitOptions?.context,\n command: submitOptions?.command,\n interruptBefore: submitOptions?.interruptBefore,\n interruptAfter: submitOptions?.interruptAfter,\n metadata: submitOptions?.metadata,\n multitaskStrategy: \"enqueue\",\n streamResumable: true,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n durability: submitOptions?.durability,\n });\n\n this.pendingRuns.add({\n id: run.run_id,\n values: values as Partial<StateType> | null | undefined,\n options: submitOptions,\n createdAt: new Date(run.created_at),\n });\n } catch (error) {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n }\n return;\n }\n }\n\n this.#submitting = true;\n const result = this.submitDirect(values, submitOptions);\n void Promise.resolve(result).finally(() => {\n this.#submitting = false;\n this.#drainQueue();\n });\n return result;\n }\n\n /**\n * Switch to a different thread (or clear the current thread).\n * Clears the active stream, cancels all queued runs on the previous\n * thread, fetches history for the new thread, and notifies the\n * {@link AnyStreamOptions.onThreadId | onThreadId} callback.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n const current = this.#threadId ?? null;\n if (newThreadId !== current) {\n const prevThreadId = this.#threadId;\n this.#threadId = newThreadId ?? undefined;\n this.stream.clear();\n\n const removed = this.pendingRuns.removeAll();\n if (prevThreadId && removed.length > 0) {\n const client = this.#accessors.getClient();\n void Promise.all(\n removed.map((e) => client.runs.cancel(prevThreadId, e.id))\n );\n }\n\n this.#fetchHistoryForThread(this.#threadId);\n\n if (newThreadId != null) {\n this.#options.onThreadId?.(newThreadId);\n }\n\n this.#notify();\n }\n }\n\n /**\n * Attempt to reconnect to a previously running stream.\n * Returns true if a reconnection was initiated.\n */\n tryReconnect(): boolean {\n if (this.#runMetadataStorage && this.#threadId) {\n const runId = this.#runMetadataStorage.getItem(\n `lg:stream:${this.#threadId}`\n );\n if (runId) {\n void this.joinStream(runId);\n return true;\n }\n }\n return false;\n }\n\n /**\n * Whether reconnect-on-mount behaviour is enabled (i.e. run metadata\n * storage is available).\n */\n get shouldReconnect(): boolean {\n return !!this.#runMetadataStorage;\n }\n\n /**\n * Tear down the orchestrator: stop the active stream, remove all\n * internal subscriptions, and mark the instance as disposed.\n * After calling this method, the orchestrator should not be reused.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#queueUnsub?.();\n this.#streamUnsub = null;\n this.#queueUnsub = null;\n void this.stop();\n }\n}\n"],"mappings":"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"}
|
package/dist/ui/subagents.cjs
CHANGED
|
@@ -231,7 +231,8 @@ var SubagentManager = class {
|
|
|
231
231
|
* Adds messages and derived properties.
|
|
232
232
|
*/
|
|
233
233
|
buildExecution(base) {
|
|
234
|
-
const
|
|
234
|
+
const streamingMessages = this.getMessagesForSubagent(base.id);
|
|
235
|
+
const messages = streamingMessages.length > 0 ? streamingMessages : base.messages;
|
|
235
236
|
return this.createSubagentStream({
|
|
236
237
|
...base,
|
|
237
238
|
messages
|
|
@@ -581,6 +582,28 @@ var SubagentManager = class {
|
|
|
581
582
|
if (hasChanges) this.onSubagentChange?.();
|
|
582
583
|
}
|
|
583
584
|
/**
|
|
585
|
+
* Update a reconstructed subagent's messages and values from its subgraph checkpoint state.
|
|
586
|
+
*
|
|
587
|
+
* This is called after fetching the subgraph's history to restore the internal
|
|
588
|
+
* conversation that was lost on page refresh. Only updates if messages are
|
|
589
|
+
* currently empty (does not overwrite live streaming data).
|
|
590
|
+
*
|
|
591
|
+
* @param toolCallId - The tool call ID identifying the subagent
|
|
592
|
+
* @param messages - Messages from the subgraph's latest checkpoint
|
|
593
|
+
* @param values - Full state values from the subgraph's latest checkpoint
|
|
594
|
+
* @returns true if the subagent was updated, false otherwise
|
|
595
|
+
*/
|
|
596
|
+
updateSubagentFromSubgraphState(toolCallId, messages, values) {
|
|
597
|
+
const subagent = this.subagents.get(toolCallId);
|
|
598
|
+
if (!subagent) return false;
|
|
599
|
+
if (subagent.messages.length > 0) return false;
|
|
600
|
+
if (messages.length === 0) return false;
|
|
601
|
+
subagent.messages = messages;
|
|
602
|
+
if (values != null) subagent.values = values;
|
|
603
|
+
this.onSubagentChange?.();
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
584
607
|
* Check if any subagents are currently tracked.
|
|
585
608
|
*/
|
|
586
609
|
hasSubagents() {
|
|
@@ -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 shown to the user.\n * Subagents are only shown once they've actually started running.\n *\n * This filters out:\n * - Pending subagents that haven't been matched to a namespace yet\n * - Streaming artifacts with partial/corrupted data\n *\n * The idea is: we register subagents internally when we see tool calls,\n * but we only show them to the user once LangGraph confirms they're\n * actually executing (via namespace events).\n */\n private isValidSubagent(subagent: SubagentStreamBase<ToolCall>): boolean {\n // Only show subagents that have started running or completed\n // This ensures we don't show partial/pending subagents\n return subagent.status === \"running\" || subagent.status === \"complete\";\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 manager\n const messages = this.getMessagesForSubagent(base.id);\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 content 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\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: [], // Internal messages are not available from history\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 * 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 * 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 shown to the user.\n * Subagents are only shown once they've actually started running.\n *\n * This filters out:\n * - Pending subagents that haven't been matched to a namespace yet\n * - Streaming artifacts with partial/corrupted data\n *\n * The idea is: we register subagents internally when we see tool calls,\n * but we only show them to the user once LangGraph confirms they're\n * actually executing (via namespace events).\n */\n private isValidSubagent(subagent: SubagentStreamBase<ToolCall>): boolean {\n // Only show subagents that have started running or completed\n // This ensures we don't show partial/pending subagents\n return subagent.status === \"running\" || subagent.status === \"complete\";\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":";;;;;;;AAmBA,MAAM,8BAA8B,CAAC,OAAO;;;;;;;;;;AAW5C,SAAgB,oBACd,WACS;AACT,KAAI,CAAC,UAAW,QAAO;AAGvB,KAAI,OAAO,cAAc,SACvB,QAAO,UAAU,SAAS,SAAS;AAIrC,QAAO,UAAU,MAAM,MAAM,EAAE,WAAW,SAAS,CAAC;;;;;;;;;;;AAYtD,SAAgB,+BACd,WACoB;AACpB,KAAI,CAAC,aAAa,UAAU,WAAW,EAAG,QAAO,KAAA;AAGjD,MAAK,MAAM,WAAW,UACpB,KAAI,QAAQ,WAAW,SAAS,CAC9B,QAAO,QAAQ,MAAM,EAAE;;;;;;;;;AAc7B,SAAgB,4BACd,WACQ;AACR,KAAI,CAAC,UAAW,QAAO;AACvB,QAAO,UAAU,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC,CAAC;;;;;;;;;;;AAYzD,SAAgB,6BACd,WACe;AACf,KAAI,CAAC,aAAa,UAAU,SAAS,EAAG,QAAO;CAE/C,MAAM,eAAe,UAAU,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;AACpE,KAAI,aAAa,SAAS,EAAG,QAAO;AAGpC,QAAO,aAAa,aAAa,SAAS,IAAI,MAAM,EAAE,IAAI;;;;;;;;AAqD5D,IAAa,kBAAb,MAAyD;CACvD,4BAAoB,IAAI,KAA2C;;;;;;CAOnE,wCAAgC,IAAI,KAAqB;;;;;CAMzD,iCAAyB,IAAI,KAAqB;;;;;;CAOlD,kCAA0B,IAAI,KAAkC;CAEhE;CAEA;CAEA;CAEA,YAAY,SAAkC;AAC5C,OAAK,oBAAoB,IAAI,IAC3B,SAAS,qBAAqB,4BAC/B;AACD,OAAK,mBAAmB,SAAS;AACjC,OAAK,YAAY,SAAS,aAAaA,iBAAAA;;;;;CAMzC,kBAA0B,YAAyC;EACjE,IAAI,UAAU,KAAK,gBAAgB,IAAI,WAAW;AAClD,MAAI,CAAC,SAAS;AACZ,aAAU,IAAIC,iBAAAA,qBAAqB;AACnC,QAAK,gBAAgB,IAAI,YAAY,QAAQ;;AAE/C,SAAO;;;;;;CAOT,uBAA+B,YAAyC;EACtE,MAAM,UAAU,KAAK,gBAAgB,IAAI,WAAW;AACpD,MAAI,CAAC,QAAS,QAAO,EAAE;EAEvB,MAAM,WAAgC,EAAE;AACxC,OAAK,MAAM,SAAS,OAAO,OAAO,QAAQ,OAAO,CAC/C,KAAI,MAAM,MACR,UAAS,KAAK,KAAK,UAAU,MAAM,MAAM,CAAsB;AAGnE,SAAO;;;;;;CAOT,qBACE,MAC4D;EAC5D,MAAM,EAAE,aAAa;EACrB,MAAM,eAAeC,cAAAA,wBAAkC,SAAS;AAEhE,SAAO;GACL,GAAG;GAEH,WAAW,KAAK,WAAW;GAG3B,WAAW;GAGX,eACE,YACmC;AACnC,WAAO,aAAa,QAAQ,OAAO,GAAG,UAAU,OAAO,QAAQ,GAAG;;GAIpE,WAAW,KAAA;GACX,YAAY,EAAE;GAGd,oBAAoB;GAGpB,2BAAW,IAAI,KAGZ;GACH,iBAAiB,EAAE;GACnB,mBAAmB,KAAA;GACnB,0BAA0B,EAAE;GAC5B,6BAA6B,EAAE;GAChC;;;;;;CAOH,2BAA2B,aAA6B;AACtD,SAAO,KAAK,sBAAsB,IAAI,YAAY,IAAI;;;;;;;;;;;;;;;CAgBxD,wBACE,aACA,aACoB;AAEpB,MAAI,KAAK,sBAAsB,IAAI,YAAY,CAC7C,QAAO,KAAK,sBAAsB,IAAI,YAAY;EAIpD,MAAM,oBAAoB,IAAI,IAAI,KAAK,sBAAsB,QAAQ,CAAC;EAGtE,MAAM,oBAAoB,eAA+B;AACvD,QAAK,sBAAsB,IAAI,aAAa,WAAW;GAEvD,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,OAAI,YAAY,SAAS,WAAW,WAAW;AAC7C,SAAK,UAAU,IAAI,YAAY;KAC7B,GAAG;KACH,QAAQ;KACR,WAAW,CAAC,YAAY;KACxB,2BAAW,IAAI,MAAM;KACtB,CAAC;AACF,SAAK,oBAAoB;;AAE3B,UAAO;;AAIT,OAAK,MAAM,CAAC,YAAY,aAAa,KAAK,UACxC,MACG,SAAS,WAAW,aAAa,SAAS,WAAW,cACtD,CAAC,kBAAkB,IAAI,WAAW,IAClC,SAAS,SAAS,KAAK,gBAAgB,YAEvC,QAAO,iBAAiB,WAAW;AAKvC,OAAK,MAAM,CAAC,YAAY,aAAa,KAAK,UACxC,MACG,SAAS,WAAW,aAAa,SAAS,WAAW,cACtD,CAAC,kBAAkB,IAAI,WAAW,EAClC;GACA,MAAM,eAAe,SAAS,SAAS,KAAK,eAAe;AAC3D,OACG,gBAAgB,YAAY,SAAS,aAAa,IAClD,gBAAgB,aAAa,SAAS,YAAY,EACnD;AAEA,QAAI,YAAY,SAAS,aAAa,OACpC,MAAK,UAAU,IAAI,YAAY;KAC7B,GAAG;KACH,UAAU;MACR,GAAG,SAAS;MACZ,MAAM;OACJ,GAAG,SAAS,SAAS;OACrB;OACD;MACF;KACF,CAAC;AAEJ,WAAO,iBAAiB,WAAW;;;AAMzC,MAAI,YACF,MAAK,eAAe,IAAI,aAAa,YAAY;;;;;CAQrD,mBAAmB,UAA2B;AAC5C,SAAO,KAAK,kBAAkB,IAAI,SAAS;;;;;;CAO7C,oBAA4B,MAAwB;AAElD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,QAAO;AAIT,MAAI,KAAK,SAAS,EAChB,QAAO;AAKT,MAAI,CAAC,2BAA2B,KAAK,KAAK,CACxC,QAAO;AAIT,MAAI,KAAK,SAAS,GAChB,QAAO;AAGT,SAAO;;;;;;;;;;;;;;CAeT,gBAAwB,UAAiD;AAGvE,SAAO,SAAS,WAAW,aAAa,SAAS,WAAW;;;;;;CAO9D,eACE,MAC4D;EAI5D,MAAM,oBAAoB,KAAK,uBAAuB,KAAK,GAAG;EAC9D,MAAM,WACJ,kBAAkB,SAAS,IAAI,oBAAoB,KAAK;AAC1D,SAAO,KAAK,qBAAqB;GAC/B,GAAG;GACH;GACD,CAAC;;;;;;CAOJ,eAGE;EACA,MAAM,yBAAS,IAAI,KAGhB;AACH,OAAK,MAAM,CAAC,IAAI,aAAa,KAAK,UAChC,KAAI,KAAK,gBAAgB,SAAS,CAChC,QAAO,IAAI,IAAI,KAAK,eAAe,SAAS,CAAC;AAGjD,SAAO;;;;;;CAOT,qBAGI;AACF,SAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CAAC,CAChC,QAAQ,MAAM,EAAE,WAAW,aAAa,KAAK,gBAAgB,EAAE,CAAC,CAChE,KAAK,MAAM,KAAK,eAAe,EAAE,CAAC;;;;;CAMvC,YACE,YACwE;EACxE,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,SAAO,WAAW,KAAK,eAAe,SAAS,GAAG,KAAA;;;;;CAMpD,mBACE,MAC8D;AAC9D,SAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CAAC,CAChC,QAAQ,MAAM,EAAE,SAAS,KAAK,kBAAkB,KAAK,CACrD,KAAK,MAAM,KAAK,eAAe,EAAE,CAAC;;;;;;;;CASvC,sBACE,WAC8D;AAC9D,SAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CAAC,CAChC,QAAQ,MAAM,EAAE,gBAAgB,aAAa,KAAK,gBAAgB,EAAE,CAAC,CACrE,KAAK,MAAM,KAAK,eAAe,EAAE,CAAC;;;;;;CAOvC,UACE,MACyB;AACzB,MAAI,CAAC,KAAM,QAAO,EAAE;AACpB,MAAI,OAAO,SAAS,SAClB,KAAI;AACF,UAAO,KAAK,MAAM,KAAK;UACjB;AACN,UAAO,EAAE;;AAGb,SAAO;;;;;;;;;;;CAYT,sBACE,WAKA,aACM;EACN,IAAI,aAAa;AAEjB,OAAK,MAAM,YAAY,WAAW;AAChC,OAAI,CAAC,SAAS,GAAI;AAClB,OAAI,CAAC,KAAK,mBAAmB,SAAS,KAAK,CAAE;GAG7C,MAAM,aAAa,KAAK,UAAU,SAAS,KAAK;GAIhD,MAAM,eAAe,KAAK,oBAAoB,WAAW,cAAc;GAGvE,MAAM,WAAW,KAAK,UAAU,IAAI,SAAS,GAAG;AAChD,OAAI,UAAU;IAEZ,MAAM,UAAW,WAAW,iBAA4B;IACxD,MAAM,UAAU,SAAS,SAAS,KAAK,iBAAiB;IACxD,MAAM,UAAW,WAAW,eAA0B;IACtD,MAAM,UAAU,SAAS,SAAS,KAAK,eAAe;IAItD,MAAM,mBADiB,KAAK,oBAAoB,QAAQ,IAEpC,QAAQ,SAAS,QAAQ;IAC7C,MAAM,mBAAmB,QAAQ,SAAS,QAAQ;IAIlD,MAAM,wBACJ,eAAe,QAAQ,gBAAgB,SAAS;AAElD,QAAI,oBAAoB,oBAAoB,uBAAuB;AACjE,UAAK,UAAU,IAAI,SAAS,IAAI;MAC9B,GAAG;MACH,GAAI,wBAAwB,EAAE,aAAa,GAAG,EAAE;MAChD,UAAU;OACR,GAAG,SAAS;OACZ,MAAM;QACJ,GAAG,SAAS,SAAS;QACrB,GAAG;QACH,aAAa,mBAAmB,UAAU;QAC1C,eAAe,mBAAmB,UAAU;QAC7C;OACF;MACF,CAAC;AACF,kBAAa;;AAEf;;AAKF,OAAI,CAAC,aACH;GAGF,MAAM,mBAAqC;IACzC,IAAI,SAAS;IACb,MAAM,SAAS;IACf,MAAM;KACJ,aAAa,WAAW;KACxB,eAAe,WAAW;KAC1B,GAAG;KACJ;IACF;GAED,MAAM,YAA0C;IAC9C,IAAI,SAAS;IACb,UAAU;IACV,QAAQ;IACR,QAAQ,EAAE;IACV,QAAQ;IACR,OAAO;IACP,WAAW,EAAE;IACb,UAAU,EAAE;IACZ,aAAa,eAAe;IAC5B,UAAU;IACV,OAAO;IACP,WAAW;IACX,aAAa;IACd;AAED,QAAK,UAAU,IAAI,SAAS,IAAI,UAAU;AAE1C,QAAK,kBAAkB,SAAS,GAAG;AACnC,gBAAa;;AAIf,MAAI,YAAY;AACd,QAAK,qBAAqB;AAC1B,QAAK,oBAAoB;;;;;;CAO7B,sBAAoC;AAClC,MAAI,KAAK,eAAe,SAAS,EAAG;AAGpC,OAAK,MAAM,CAAC,aAAa,gBAAgB,KAAK,gBAAgB;AAE5D,OAAI,KAAK,sBAAsB,IAAI,YAAY,EAAE;AAC/C,SAAK,eAAe,OAAO,YAAY;AACvC;;AAKF,OADgB,KAAK,wBAAwB,aAAa,YAAY,CAEpE,MAAK,eAAe,OAAO,YAAY;;;;;;;;;;;;CAc7C,YACE,YACA,SAGM;EACN,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,MAAI,CAAC,SAAU;EAEf,MAAM,YAAY,SAAS,aAAa,SAAS;AAEjD,OAAK,UAAU,IAAI,YAAY;GAC7B,GAAG;GACH,QAAQ;GACR;GACA,UACE,SAAS,YAAY,6BAA6B,UAAU,IAAI;GAClE,OAAO,SAAS,SAAS,4BAA4B,UAAU;GAC/D,WAAW,SAAS,6BAAa,IAAI,MAAM;GAC5C,CAAC;AAEF,OAAK,oBAAoB;;;;;;;;;CAU3B,yBAAyB,aAAqB,WAA4B;EACxE,MAAM,aAAa,KAAK,2BAA2B,YAAY;AAC/D,OAAK,YAAY,YAAY,EAAE,WAAW,CAAC;;;;;;;;;;;;;CAc7C,qBACE,aACA,YACA,UACM;AAGN,MAAI,WAAW,SAAS,WAAW,OAAO,WAAW,YAAY,SAC/D,MAAK,wBAAwB,aAAa,WAAW,QAAQ;EAI/D,MAAM,aAAa,KAAK,2BAA2B,YAAY;EAC/D,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAM/C,MAAI,CAAC,SACH;AAQF,MAHgB,KAAK,kBAAkB,WAAW,CACxB,IAAI,YAAY,SAAS,CAIjD,KAAI,WAAW,SAAS,KACtB,MAAK,UAAU,IAAI,YAAY;GAC7B,GAAG;GACH,QAAQ;GACR,WAAW,SAAS,6BAAa,IAAI,MAAM;GAE3C,UAAU,KAAK,uBAAuB,WAAW;GAClD,CAAC;MAGF,MAAK,UAAU,IAAI,YAAY;GAC7B,GAAG;GACH,UAAU,KAAK,uBAAuB,WAAW;GAClD,CAAC;AAIN,OAAK,oBAAoB;;;;;;;;;;;;CAa3B,qBACE,aACA,QACM;EAEN,MAAM,aAAa,KAAK,2BAA2B,YAAY;EAC/D,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAE/C,MAAI,CAAC,SACH;AAGF,OAAK,UAAU,IAAI,YAAY;GAC7B,GAAG;GACH;GACA,QAAQ,SAAS,WAAW,YAAY,YAAY,SAAS;GAC7D,WAAW,SAAS,6BAAa,IAAI,MAAM;GAC5C,CAAC;AAEF,OAAK,oBAAoB;;;;;;;;;;;CAY3B,SACE,YACA,QACA,SAA+B,YACzB;EACN,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,MAAI,CAAC,SAAU;AAEf,OAAK,UAAU,IAAI,YAAY;GAC7B,GAAG;GACH;GACA,QAAQ,WAAW,aAAa,SAAS;GACzC,OAAO,WAAW,UAAU,SAAS;GACrC,6BAAa,IAAI,MAAM;GACxB,CAAC;AAEF,OAAK,oBAAoB;;;;;CAM3B,QAAc;AACZ,OAAK,UAAU,OAAO;AACtB,OAAK,sBAAsB,OAAO;AAClC,OAAK,gBAAgB,OAAO;AAC5B,OAAK,eAAe,OAAO;AAC3B,OAAK,oBAAoB;;;;;;;;;CAU3B,mBACE,YACA,SACA,SAA8B,WACxB;AAEN,MAAI,CADa,KAAK,UAAU,IAAI,WAAW,CAChC;AAEf,OAAK,SACH,YACA,SACA,WAAW,YAAY,aAAa,QACrC;;;;;;;;;;;;;;;;;;;;;;;;CAyBH,wBACE,UACA,SACM;AAEN,MAAI,SAAS,mBAAmB,KAAK,UAAU,OAAO,EACpD;EAIF,MAAM,8BAAc,IAAI,KAGrB;AAEH,OAAK,MAAM,WAAW,SACpB,KAAI,QAAQ,SAAS,UAAU,kBAAkB,SAAS;GACxD,MAAM,aAAa,QAAQ;GAC3B,MAAM,UACJ,OAAO,QAAQ,YAAY,WACvB,QAAQ,UACR,KAAK,UAAU,QAAQ,QAAQ;GACrC,MAAM,SACJ,YAAY,WAAW,QAAQ,WAAW,UACtC,UACA;AACN,eAAY,IAAI,YAAY;IAAE;IAAS;IAAQ,CAAC;;EAKpD,IAAI,aAAa;AAEjB,OAAK,MAAM,WAAW,UAAU;AAC9B,OACE,QAAQ,SAAS,QACjB,EAAE,gBAAgB,YAClB,CAAC,MAAM,QAAQ,QAAQ,WAAW,CAElC;AAGF,QAAK,MAAM,YAAY,QAAQ,YAAY;AACzC,QAAI,CAAC,SAAS,GAAI;AAClB,QAAI,CAAC,KAAK,mBAAmB,SAAS,KAAK,CAAE;AAG7C,QAAI,KAAK,UAAU,IAAI,SAAS,GAAG,CAAE;IAGrC,MAAM,aAAa,KAAK,UAAU,SAAS,KAAK;AAGhD,QAAI,CAAC,KAAK,oBAAoB,WAAW,cAAc,CAAE;IAGzD,MAAM,mBAAqC;KACzC,IAAI,SAAS;KACb,MAAM,SAAS;KACf,MAAM;MACJ,aAAa,WAAW;MACxB,eAAe,WAAW;MAC1B,GAAG;MACJ;KACF;IAGD,MAAM,aAAa,YAAY,IAAI,SAAS,GAAG;IAC/C,MAAM,aAAa,CAAC,CAAC;IAErB,MAAM,SAAyB,aAC3B,WAAW,WAAW,UACpB,UACA,aACF;IAKJ,MAAM,YAA0C;KAC9C,IAAI,SAAS;KACb,UAAU;KACV;KACA,QAAQ,EAAE;KACV,QACE,cAAc,WAAW,aAAa,WAAW,UAAU;KAC7D,OAAO,cAAc,WAAW,UAAU,WAAW,UAAU;KAC/D,WAAW,EAAE;KACb,UAAU,EAAE;KACZ,aAAc,QAAQ,MAAiB;KACvC,UAAU;KACV,OAAO;KACP,WAAW;KACX,aAAa,6BAAa,IAAI,MAAM,GAAG;KACxC;AAED,SAAK,UAAU,IAAI,SAAS,IAAI,UAAU;AAC1C,iBAAa;;;AAIjB,MAAI,WACF,MAAK,oBAAoB;;;;;;;;;;;;;;CAgB7B,gCACE,YACA,UACA,QACS;EACT,MAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AACzC,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,WAAS,WAAW;AACpB,MAAI,UAAU,KAAM,UAAS,SAAS;AAEtC,OAAK,oBAAoB;AACzB,SAAO;;;;;CAMT,eAAwB;AACtB,SAAO,KAAK,UAAU,OAAO"}
|
package/dist/ui/subagents.d.cts
CHANGED
|
@@ -287,6 +287,19 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
|
|
|
287
287
|
reconstructFromMessages(messages: Message<DefaultToolCall>[], options?: {
|
|
288
288
|
skipIfPopulated?: boolean;
|
|
289
289
|
}): void;
|
|
290
|
+
/**
|
|
291
|
+
* Update a reconstructed subagent's messages and values from its subgraph checkpoint state.
|
|
292
|
+
*
|
|
293
|
+
* This is called after fetching the subgraph's history to restore the internal
|
|
294
|
+
* conversation that was lost on page refresh. Only updates if messages are
|
|
295
|
+
* currently empty (does not overwrite live streaming data).
|
|
296
|
+
*
|
|
297
|
+
* @param toolCallId - The tool call ID identifying the subagent
|
|
298
|
+
* @param messages - Messages from the subgraph's latest checkpoint
|
|
299
|
+
* @param values - Full state values from the subgraph's latest checkpoint
|
|
300
|
+
* @returns true if the subagent was updated, false otherwise
|
|
301
|
+
*/
|
|
302
|
+
updateSubagentFromSubgraphState(toolCallId: string, messages: Message[], values?: Record<string, unknown>): boolean;
|
|
290
303
|
/**
|
|
291
304
|
* Check if any subagents are currently tracked.
|
|
292
305
|
*/
|
|
@@ -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;
|
|
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;EAsUgB;;;EAjUhB,gBAAA;EAmW2B;;;;EA7V3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EA2mBE;;;;;EAAA,QApmBF,qBAAA;EAo0BS;;;;EAAA,QA9zBT,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;EA0MA;;;;EAAA,QAzLA,oBAAA;EAwNkB;;;;EA5K1B,0BAAA,CAA2B,WAAA;EAgMzB;;;;;;;;;;;;;EA/KF,uBAAA,CACE,WAAA,UACA,WAAA;EAiNyB;;;EApI3B,kBAAA,CAAmB,QAAA;EAsKN;;;;EAAA,QA9JL,mBAAA;EA8JN;;;;;;;;;;;;EAAA,QAzHM,eAAA;EAiTc;;;;EAAA,QAvSd,cAAA;EAkWN;;;;EA/UF,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA6WjD;;;;EA3VF,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EA8XA;;;EApXF,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAsZhC;;;EA9YpB,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAigBpD;;;;;;EArfA,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwgBxC;;;;EAAA,QA9fJ,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"}
|
package/dist/ui/subagents.d.ts
CHANGED
|
@@ -287,6 +287,19 @@ declare class SubagentManager<ToolCall = DefaultToolCall> {
|
|
|
287
287
|
reconstructFromMessages(messages: Message<DefaultToolCall>[], options?: {
|
|
288
288
|
skipIfPopulated?: boolean;
|
|
289
289
|
}): void;
|
|
290
|
+
/**
|
|
291
|
+
* Update a reconstructed subagent's messages and values from its subgraph checkpoint state.
|
|
292
|
+
*
|
|
293
|
+
* This is called after fetching the subgraph's history to restore the internal
|
|
294
|
+
* conversation that was lost on page refresh. Only updates if messages are
|
|
295
|
+
* currently empty (does not overwrite live streaming data).
|
|
296
|
+
*
|
|
297
|
+
* @param toolCallId - The tool call ID identifying the subagent
|
|
298
|
+
* @param messages - Messages from the subgraph's latest checkpoint
|
|
299
|
+
* @param values - Full state values from the subgraph's latest checkpoint
|
|
300
|
+
* @returns true if the subagent was updated, false otherwise
|
|
301
|
+
*/
|
|
302
|
+
updateSubagentFromSubgraphState(toolCallId: string, messages: Message[], values?: Record<string, unknown>): boolean;
|
|
290
303
|
/**
|
|
291
304
|
* Check if any subagents are currently tracked.
|
|
292
305
|
*/
|
|
@@ -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;
|
|
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;EAsUgB;;;EAjUhB,gBAAA;EAmW2B;;;;EA7V3B,SAAA,IAAa,KAAA,EAAO,WAAA,KAAgB,OAAA,GAAU,WAAA;AAAA;;;;;;;cA+BnC,eAAA,YAA2B,eAAA;EAAA,QAC9B,SAAA;EA2mBE;;;;;EAAA,QApmBF,qBAAA;EAo0BS;;;;EAAA,QA9zBT,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;EA0MA;;;;EAAA,QAzLA,oBAAA;EAwNkB;;;;EA5K1B,0BAAA,CAA2B,WAAA;EAgMzB;;;;;;;;;;;;;EA/KF,uBAAA,CACE,WAAA,UACA,WAAA;EAiNyB;;;EApI3B,kBAAA,CAAmB,QAAA;EAsKN;;;;EAAA,QA9JL,mBAAA;EA8JN;;;;;;;;;;;;EAAA,QAzHM,eAAA;EAiTc;;;;EAAA,QAvSd,cAAA;EAkWN;;;;EA/UF,YAAA,CAAA,GAAgB,GAAA,SAEd,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EA6WjD;;;;EA3VF,kBAAA,CAAA,GAAsB,uBAAA,CACpB,MAAA,mBACA,QAAA;EA8XA;;;EApXF,WAAA,CACE,UAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAsZhC;;;EA9YpB,kBAAA,CACE,IAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAigBpD;;;;;;EArfA,qBAAA,CACE,SAAA,WACC,uBAAA,CAAwB,MAAA,mBAAyB,QAAA;EAwgBxC;;;;EAAA,QA9fJ,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"}
|
package/dist/ui/subagents.js
CHANGED
|
@@ -231,7 +231,8 @@ var SubagentManager = class {
|
|
|
231
231
|
* Adds messages and derived properties.
|
|
232
232
|
*/
|
|
233
233
|
buildExecution(base) {
|
|
234
|
-
const
|
|
234
|
+
const streamingMessages = this.getMessagesForSubagent(base.id);
|
|
235
|
+
const messages = streamingMessages.length > 0 ? streamingMessages : base.messages;
|
|
235
236
|
return this.createSubagentStream({
|
|
236
237
|
...base,
|
|
237
238
|
messages
|
|
@@ -581,6 +582,28 @@ var SubagentManager = class {
|
|
|
581
582
|
if (hasChanges) this.onSubagentChange?.();
|
|
582
583
|
}
|
|
583
584
|
/**
|
|
585
|
+
* Update a reconstructed subagent's messages and values from its subgraph checkpoint state.
|
|
586
|
+
*
|
|
587
|
+
* This is called after fetching the subgraph's history to restore the internal
|
|
588
|
+
* conversation that was lost on page refresh. Only updates if messages are
|
|
589
|
+
* currently empty (does not overwrite live streaming data).
|
|
590
|
+
*
|
|
591
|
+
* @param toolCallId - The tool call ID identifying the subagent
|
|
592
|
+
* @param messages - Messages from the subgraph's latest checkpoint
|
|
593
|
+
* @param values - Full state values from the subgraph's latest checkpoint
|
|
594
|
+
* @returns true if the subagent was updated, false otherwise
|
|
595
|
+
*/
|
|
596
|
+
updateSubagentFromSubgraphState(toolCallId, messages, values) {
|
|
597
|
+
const subagent = this.subagents.get(toolCallId);
|
|
598
|
+
if (!subagent) return false;
|
|
599
|
+
if (subagent.messages.length > 0) return false;
|
|
600
|
+
if (messages.length === 0) return false;
|
|
601
|
+
subagent.messages = messages;
|
|
602
|
+
if (values != null) subagent.values = values;
|
|
603
|
+
this.onSubagentChange?.();
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
584
607
|
* Check if any subagents are currently tracked.
|
|
585
608
|
*/
|
|
586
609
|
hasSubagents() {
|