@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.
Files changed (49) hide show
  1. package/dist/react/stream.custom.cjs +21 -1
  2. package/dist/react/stream.custom.cjs.map +1 -1
  3. package/dist/react/stream.custom.js +21 -1
  4. package/dist/react/stream.custom.js.map +1 -1
  5. package/dist/react/stream.lgp.cjs +11 -1
  6. package/dist/react/stream.lgp.cjs.map +1 -1
  7. package/dist/react/stream.lgp.js +11 -1
  8. package/dist/react/stream.lgp.js.map +1 -1
  9. package/dist/ui/index.cjs +4 -0
  10. package/dist/ui/index.d.cts +3 -1
  11. package/dist/ui/index.d.ts +3 -1
  12. package/dist/ui/index.js +3 -1
  13. package/dist/ui/manager.cjs +181 -0
  14. package/dist/ui/manager.cjs.map +1 -1
  15. package/dist/ui/manager.d.cts +41 -0
  16. package/dist/ui/manager.d.cts.map +1 -1
  17. package/dist/ui/manager.d.ts +41 -0
  18. package/dist/ui/manager.d.ts.map +1 -1
  19. package/dist/ui/manager.js +181 -0
  20. package/dist/ui/manager.js.map +1 -1
  21. package/dist/ui/orchestrator-custom.cjs +372 -0
  22. package/dist/ui/orchestrator-custom.cjs.map +1 -0
  23. package/dist/ui/orchestrator-custom.d.cts +185 -0
  24. package/dist/ui/orchestrator-custom.d.cts.map +1 -0
  25. package/dist/ui/orchestrator-custom.d.ts +185 -0
  26. package/dist/ui/orchestrator-custom.d.ts.map +1 -0
  27. package/dist/ui/orchestrator-custom.js +372 -0
  28. package/dist/ui/orchestrator-custom.js.map +1 -0
  29. package/dist/ui/orchestrator.cjs +866 -0
  30. package/dist/ui/orchestrator.cjs.map +1 -0
  31. package/dist/ui/orchestrator.d.cts +366 -0
  32. package/dist/ui/orchestrator.d.cts.map +1 -0
  33. package/dist/ui/orchestrator.d.ts +366 -0
  34. package/dist/ui/orchestrator.d.ts.map +1 -0
  35. package/dist/ui/orchestrator.js +866 -0
  36. package/dist/ui/orchestrator.js.map +1 -0
  37. package/dist/ui/subagents.cjs +24 -1
  38. package/dist/ui/subagents.cjs.map +1 -1
  39. package/dist/ui/subagents.d.cts +13 -0
  40. package/dist/ui/subagents.d.cts.map +1 -1
  41. package/dist/ui/subagents.d.ts +13 -0
  42. package/dist/ui/subagents.d.ts.map +1 -1
  43. package/dist/ui/subagents.js +24 -1
  44. package/dist/ui/subagents.js.map +1 -1
  45. package/dist/ui/types.d.cts +3 -2
  46. package/dist/ui/types.d.cts.map +1 -1
  47. package/dist/ui/types.d.ts +3 -2
  48. package/dist/ui/types.d.ts.map +1 -1
  49. package/package.json +2 -6
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","names":[],"sources":["../../src/ui/manager.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type {\n CheckpointsStreamEvent,\n CustomStreamEvent,\n DebugStreamEvent,\n ErrorStreamEvent,\n EventsStreamEvent,\n FeedbackStreamEvent,\n MessagesTupleStreamEvent,\n MetadataStreamEvent,\n TasksStreamEvent,\n ToolsStreamEvent,\n UpdatesStreamEvent,\n ValuesStreamEvent,\n} from \"../types.stream.js\";\nimport { MessageTupleManager, toMessageDict } from \"./messages.js\";\nimport { StreamError } from \"./errors.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport {\n SubagentManager,\n extractToolCallIdFromNamespace,\n isSubagentNamespace,\n} from \"./subagents.js\";\nimport type { SubagentStreamInterface } from \"./types.js\";\n\n/**\n * Special ID used by LangGraph's messagesStateReducer to signal\n * that all messages should be removed from the state.\n */\nexport const REMOVE_ALL_MESSAGES = \"__remove_all__\";\n\ntype GetUpdateType<\n Bag extends BagTemplate,\n StateType extends Record<string, unknown>\n> = Bag extends { UpdateType: unknown }\n ? Bag[\"UpdateType\"]\n : Partial<StateType>;\n\ntype GetCustomEventType<Bag extends BagTemplate> = Bag extends {\n CustomEventType: unknown;\n}\n ? Bag[\"CustomEventType\"]\n : unknown;\n\ntype EventStreamMap<StateType, UpdateType, CustomType> = {\n values: ValuesStreamEvent<StateType>;\n updates: UpdatesStreamEvent<UpdateType>;\n custom: CustomStreamEvent<CustomType>;\n debug: DebugStreamEvent;\n messages: MessagesTupleStreamEvent;\n events: EventsStreamEvent;\n metadata: MetadataStreamEvent;\n checkpoints: CheckpointsStreamEvent<StateType>;\n tasks: TasksStreamEvent<StateType, UpdateType>;\n error: ErrorStreamEvent;\n feedback: FeedbackStreamEvent;\n tools: ToolsStreamEvent;\n};\n\nexport type EventStreamEvent<StateType, UpdateType, CustomType> =\n EventStreamMap<StateType, UpdateType, CustomType>[keyof EventStreamMap<\n StateType,\n UpdateType,\n CustomType\n >];\n\ninterface StreamManagerEventCallbacks<\n StateType extends Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> {\n onUpdateEvent?: (\n data: UpdatesStreamEvent<GetUpdateType<Bag, StateType>>[\"data\"],\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n onCustomEvent?: (\n data: GetCustomEventType<Bag>,\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n onMetadataEvent?: (data: MetadataStreamEvent[\"data\"]) => void;\n onLangChainEvent?: (data: EventsStreamEvent[\"data\"]) => void;\n onDebugEvent?: (\n data: DebugStreamEvent[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onCheckpointEvent?: (\n data: CheckpointsStreamEvent<StateType>[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onTaskEvent?: (\n data: TasksStreamEvent<StateType, GetUpdateType<Bag, StateType>>[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onToolEvent?: (\n data: ToolsStreamEvent[\"data\"],\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n}\n\n/**\n * Options for StreamManager constructor.\n */\nexport interface StreamManagerOptions {\n /**\n * Throttle the stream updates.\n * If a number is provided, updates are throttled to the given milliseconds.\n * If `true`, updates are batched in a single macrotask.\n * If `false`, updates are not throttled.\n */\n throttle: number | boolean;\n\n /**\n * Tool names that indicate subagent invocation.\n *\n * When an AI message contains tool calls with these names, they are\n * automatically tracked as subagent executions. This enables the\n * `subagents`, `activeSubagents`, `getSubagent()`, and `getSubagentsByType()`\n * properties on the stream.\n *\n * @default [\"task\"]\n *\n * @example\n * ```typescript\n * // Track both \"task\" and \"delegate\" as subagent tools\n * subagentToolNames: [\"task\", \"delegate\", \"spawn_agent\"]\n * ```\n */\n subagentToolNames?: string[];\n\n /**\n * Filter out messages from subagent streams in the main messages array.\n *\n * When enabled, messages from subagraph executions (those with a `tools:` namespace)\n * are excluded from `stream.messages`. Instead, these messages are tracked\n * per-subagent and accessible via `stream.subagents.get(id).messages`.\n *\n * This is useful for deep agent architectures where you want to display\n * the main conversation separately from subagent activity.\n *\n * @default false\n *\n * @example\n * ```typescript\n * const stream = useStream({\n * assistantId: \"my-agent\",\n * filterSubagentMessages: true,\n * });\n *\n * // Main thread messages only (no subagent messages)\n * stream.messages\n *\n * // Access subagent messages individually\n * stream.subagents.get(\"call_xyz\").messages\n * ```\n */\n filterSubagentMessages?: boolean;\n\n /**\n * Converts a @langchain/core BaseMessage to the desired output format.\n *\n * Defaults to `toMessageDict` which produces plain Message objects.\n * Framework SDKs pass `toMessageClass` (identity) to keep class instances.\n */\n toMessage?: (chunk: BaseMessage) => Message | BaseMessage;\n}\n\nexport class StreamManager<\n StateType extends Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> {\n private abortRef = new AbortController();\n\n private messages: MessageTupleManager;\n\n private subagentManager: SubagentManager;\n\n private listeners = new Set<() => void>();\n\n private throttle: number | boolean;\n\n private filterSubagentMessages: boolean;\n\n private toMessage: (chunk: BaseMessage) => Message | BaseMessage;\n\n private queue: Promise<unknown> = Promise.resolve();\n\n private queueSize: number = 0;\n\n private state: {\n isLoading: boolean;\n values: [values: StateType, kind: \"stream\" | \"stop\"] | null;\n error: unknown;\n /** Version counter to force React re-renders on subagent changes */\n version: number;\n };\n\n constructor(messages: MessageTupleManager, options: StreamManagerOptions) {\n this.messages = messages;\n this.state = {\n isLoading: false,\n values: null,\n error: undefined,\n version: 0,\n };\n this.throttle = options.throttle;\n this.filterSubagentMessages = options.filterSubagentMessages ?? false;\n this.toMessage = options.toMessage ?? toMessageDict;\n this.subagentManager = new SubagentManager({\n subagentToolNames: options.subagentToolNames,\n onSubagentChange: () => this.bumpVersion(),\n toMessage: this.toMessage,\n });\n }\n\n /**\n * Increment version counter to trigger React re-renders.\n * Called when subagent state changes.\n */\n private bumpVersion = () => {\n this.state = { ...this.state, version: this.state.version + 1 };\n this.notifyListeners();\n };\n\n /**\n * Get all subagents as a Map.\n */\n getSubagents(): Map<string, SubagentStreamInterface> {\n return this.subagentManager.getSubagents();\n }\n\n /**\n * Get all currently running subagents.\n */\n getActiveSubagents(): SubagentStreamInterface[] {\n return this.subagentManager.getActiveSubagents();\n }\n\n /**\n * Get a specific subagent by tool call ID.\n */\n getSubagent(toolCallId: string): SubagentStreamInterface | undefined {\n return this.subagentManager.getSubagent(toolCallId);\n }\n\n /**\n * Get all subagents of a specific type.\n */\n getSubagentsByType(type: string): SubagentStreamInterface[] {\n return this.subagentManager.getSubagentsByType(type);\n }\n\n /**\n * Get all subagents triggered by a specific AI message.\n */\n getSubagentsByMessage(messageId: string): SubagentStreamInterface[] {\n return this.subagentManager.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent state from historical messages.\n *\n * This method should be called when loading thread history to restore\n * subagent visualization after:\n * - Page refresh (when stream has already completed)\n * - Loading thread history\n * - Navigating between threads\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 reconstructSubagents(\n messages: Message[],\n options?: { skipIfPopulated?: boolean }\n ): void {\n this.subagentManager.reconstructFromMessages(messages, options);\n }\n\n /**\n * Check if any subagents are currently tracked.\n */\n hasSubagents(): boolean {\n return this.subagentManager.hasSubagents();\n }\n\n private setState = (newState: Partial<typeof this.state>) => {\n this.state = { ...this.state, ...newState };\n this.notifyListeners();\n };\n\n private notifyListeners = () => {\n this.listeners.forEach((listener) => listener());\n };\n\n subscribe = (listener: () => void): (() => void) => {\n if (this.throttle === false) {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n const timeoutMs = this.throttle === true ? 0 : this.throttle;\n let timeoutId: NodeJS.Timeout | number | undefined;\n\n const throttledListener = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n clearTimeout(timeoutId);\n listener();\n }, timeoutMs);\n };\n\n this.listeners.add(throttledListener);\n return () => {\n clearTimeout(timeoutId);\n this.listeners.delete(throttledListener);\n };\n };\n\n getSnapshot = () => this.state;\n\n get isLoading() {\n return this.state.isLoading;\n }\n\n get values() {\n return this.state.values?.[0] ?? null;\n }\n\n get error() {\n return this.state.error;\n }\n\n setStreamValues = (\n values:\n | (StateType | null)\n | ((prev: StateType | null, kind: \"stream\" | \"stop\") => StateType | null),\n kind: \"stream\" | \"stop\" = \"stream\"\n ) => {\n if (typeof values === \"function\") {\n const [prevValues, prevKind] = this.state.values ?? [null, \"stream\"];\n const nextValues = values(prevValues, prevKind);\n this.setState({ values: nextValues != null ? [nextValues, kind] : null });\n } else {\n const nextValues = values != null ? [values, kind] : null;\n this.setState({ values: nextValues as [StateType, \"stream\" | \"stop\"] });\n }\n };\n\n private getMutateFn = (kind: \"stream\" | \"stop\", historyValues: StateType) => {\n return (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => {\n const stateValues = (this.state.values ?? [null, \"stream\"])[0];\n const prev = {\n ...historyValues,\n ...stateValues,\n };\n const next = typeof update === \"function\" ? update(prev) : update;\n this.setStreamValues({ ...prev, ...next }, kind);\n };\n };\n\n private matchEventType = <\n T extends keyof EventStreamMap<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >(\n expected: T,\n actual: EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[\"event\"],\n _data: EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[\"data\"]\n ): _data is EventStreamMap<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[T][\"data\"] => {\n return expected === actual || actual.startsWith(`${expected}|`);\n };\n\n protected enqueue = async (\n action: (\n signal: AbortSignal\n ) => Promise<\n AsyncGenerator<\n EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >\n >,\n options: {\n getMessages: (values: StateType) => Message[];\n\n setMessages: (current: StateType, messages: Message[]) => StateType;\n\n initialValues: StateType;\n\n callbacks: StreamManagerEventCallbacks<StateType, Bag>;\n\n onSuccess: () =>\n | StateType\n | null\n | undefined\n | void\n | Promise<StateType | null | undefined | void>;\n\n onError: (error: unknown) => void | Promise<void>;\n\n onFinish?: () => void;\n }\n ) => {\n try {\n this.queueSize = Math.max(0, this.queueSize - 1);\n this.setState({ isLoading: true, error: undefined });\n this.abortRef = new AbortController();\n\n const run = await action(this.abortRef.signal);\n\n let streamError: StreamError | undefined;\n for await (const { event, data } of run) {\n if (event === \"error\") {\n streamError = new StreamError(data);\n break;\n }\n\n const namespace = event.includes(\"|\")\n ? event.split(\"|\").slice(1)\n : undefined;\n\n const mutate = this.getMutateFn(\"stream\", options.initialValues);\n\n if (event === \"metadata\") options.callbacks.onMetadataEvent?.(data);\n if (event === \"events\") options.callbacks.onLangChainEvent?.(data);\n\n if (this.matchEventType(\"updates\", event, data)) {\n options.callbacks.onUpdateEvent?.(data, { namespace, mutate });\n\n // Track subagent streaming updates from subgraph namespaces\n // Mark the subagent as running when we receive updates\n // The actual message content is handled via addMessageToSubagent\n if (namespace && isSubagentNamespace(namespace)) {\n const namespaceId = extractToolCallIdFromNamespace(namespace);\n if (namespaceId && this.filterSubagentMessages) {\n this.subagentManager.markRunningFromNamespace(\n namespaceId,\n namespace\n );\n }\n }\n\n // Also register subagents from main agent updates (tool_calls in messages)\n // AND process tool results to complete subagents\n // This is needed because tool_calls often appear complete in updates\n // before they appear in the messages stream\n if (!namespace || !isSubagentNamespace(namespace)) {\n const updateData = data as Record<string, unknown>;\n for (const nodeData of Object.values(updateData)) {\n if (\n nodeData &&\n typeof nodeData === \"object\" &&\n \"messages\" in nodeData\n ) {\n const { messages } = nodeData as { messages: unknown[] };\n if (Array.isArray(messages)) {\n for (const msg of messages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n\n // Register subagents from AI messages with tool_calls\n if (\n msgObj.type === \"ai\" &&\n \"tool_calls\" in msgObj &&\n Array.isArray(msgObj.tool_calls)\n ) {\n this.subagentManager.registerFromToolCalls(\n msgObj.tool_calls as Array<{\n id?: string;\n name: string;\n args: Record<string, unknown> | string;\n }>,\n msgObj.id as string | undefined\n );\n }\n\n // Complete subagents from tool messages (task results)\n if (\n msgObj.type === \"tool\" &&\n \"tool_call_id\" in msgObj &&\n typeof msgObj.tool_call_id === \"string\"\n ) {\n const content =\n typeof msgObj.content === \"string\"\n ? msgObj.content\n : JSON.stringify(msgObj.content);\n const status =\n \"status\" in msgObj && msgObj.status === \"error\"\n ? \"error\"\n : \"success\";\n this.subagentManager.processToolMessage(\n msgObj.tool_call_id,\n content,\n status\n );\n }\n }\n }\n }\n }\n }\n }\n\n if (this.matchEventType(\"custom\", event, data)) {\n options.callbacks.onCustomEvent?.(data, { namespace, mutate });\n }\n\n if (this.matchEventType(\"checkpoints\", event, data)) {\n options.callbacks.onCheckpointEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"tasks\", event, data)) {\n options.callbacks.onTaskEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"debug\", event, data)) {\n options.callbacks.onDebugEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"tools\", event, data)) {\n options.callbacks.onToolEvent?.(data, { namespace, mutate });\n }\n\n // Handle values events - use startsWith to match both \"values\" and \"values|tools:xxx\"\n if (event === \"values\" || event.startsWith(\"values|\")) {\n // Check if this is a subgraph values event (for namespace mapping and values)\n if (namespace && isSubagentNamespace(namespace)) {\n const namespaceId = extractToolCallIdFromNamespace(namespace);\n if (namespaceId && this.filterSubagentMessages) {\n const valuesData = data as Record<string, unknown>;\n\n // Try to establish namespace mapping from the initial human message\n const messages = valuesData.messages as unknown[];\n if (Array.isArray(messages) && messages.length > 0) {\n const firstMsg = messages[0] as Record<string, unknown>;\n if (\n firstMsg?.type === \"human\" &&\n typeof firstMsg?.content === \"string\"\n ) {\n this.subagentManager.matchSubgraphToSubagent(\n namespaceId,\n firstMsg.content\n );\n }\n }\n\n // Update the subagent's values with the full state\n this.subagentManager.updateSubagentValues(\n namespaceId,\n valuesData\n );\n }\n } else if (\n data &&\n typeof data === \"object\" &&\n \"__interrupt__\" in data\n ) {\n const interruptData = data as Partial<StateType>;\n this.setStreamValues(\n (prev) => ({ ...prev, ...interruptData } as StateType)\n );\n } else {\n this.setStreamValues(data as StateType);\n }\n }\n\n if (this.matchEventType(\"messages\", event, data)) {\n const [serialized, metadata] = data;\n\n // Check if this message is from a subagent namespace\n const rawCheckpointNs =\n (metadata?.langgraph_checkpoint_ns as string | undefined) ||\n (metadata?.checkpoint_ns as string | undefined);\n const checkpointNs: string | undefined =\n typeof rawCheckpointNs === \"string\" ? rawCheckpointNs : undefined;\n const isFromSubagent = isSubagentNamespace(checkpointNs);\n const toolCallId = isFromSubagent\n ? extractToolCallIdFromNamespace(checkpointNs?.split(\"|\"))\n : undefined;\n\n // If filtering is enabled and this is a subagent message,\n // add it to the subagent's messages instead of the main stream\n if (this.filterSubagentMessages && isFromSubagent && toolCallId) {\n // Add to subagent's message list\n this.subagentManager.addMessageToSubagent(\n toolCallId,\n serialized,\n metadata\n );\n continue;\n }\n\n const messageId = this.messages.add(serialized, metadata);\n if (!messageId) {\n console.warn(\n \"Failed to add message to manager, no message ID found\"\n );\n continue;\n }\n\n this.setStreamValues((streamValues) => {\n const values = {\n ...options.initialValues,\n ...streamValues,\n };\n\n // Assumption: we're concatenating the message\n let messages = options.getMessages(values).slice();\n const { chunk, index } =\n this.messages.get(messageId, messages.length) ?? {};\n\n if (!chunk || index == null) return values;\n if (chunk.getType() === \"remove\") {\n // Check for special REMOVE_ALL_MESSAGES sentinel\n if (chunk.id === REMOVE_ALL_MESSAGES) {\n // Clear all messages when __remove_all__ is received\n messages = [];\n } else {\n messages.splice(index, 1);\n }\n } else {\n const msgDict = this.toMessage(chunk) as Message;\n messages[index] = msgDict;\n\n // Track subagents from AI messages with tool calls (main agent only)\n if (\n !isFromSubagent &&\n msgDict.type === \"ai\" &&\n \"tool_calls\" in msgDict &&\n Array.isArray(msgDict.tool_calls)\n ) {\n this.subagentManager.registerFromToolCalls(\n msgDict.tool_calls,\n msgDict.id as string | undefined\n );\n }\n\n // Complete subagents when tool messages arrive (main agent only)\n if (\n !isFromSubagent &&\n msgDict.type === \"tool\" &&\n \"tool_call_id\" in msgDict\n ) {\n const tcId = msgDict.tool_call_id as string;\n const content =\n typeof msgDict.content === \"string\"\n ? msgDict.content\n : JSON.stringify(msgDict.content);\n const status =\n \"status\" in msgDict && msgDict.status === \"error\"\n ? \"error\"\n : \"success\";\n this.subagentManager.processToolMessage(tcId, content, status);\n }\n }\n\n return options.setMessages(values, messages);\n });\n }\n }\n\n if (streamError != null) throw streamError;\n\n // Skip onSuccess when the stream was aborted (e.g., by multitask interrupt).\n // This avoids unnecessary HTTP calls (like history fetching) that would\n // delay the next queued stream from starting.\n if (!this.abortRef.signal.aborted) {\n const values = await options.onSuccess?.();\n if (typeof values !== \"undefined\" && this.queueSize === 0) {\n this.setStreamValues(values);\n }\n }\n } catch (error) {\n if (\n !(\n error instanceof Error && // eslint-disable-line no-instanceof/no-instanceof\n (error.name === \"AbortError\" || error.name === \"TimeoutError\")\n )\n ) {\n console.error(error);\n this.setState({ error });\n await options.onError?.(error);\n }\n } finally {\n this.setState({ isLoading: false });\n this.abortRef = new AbortController();\n options.onFinish?.();\n }\n };\n\n start = async (\n action: (\n signal: AbortSignal\n ) => Promise<\n AsyncGenerator<\n EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >\n >,\n options: {\n getMessages: (values: StateType) => Message[];\n\n setMessages: (current: StateType, messages: Message[]) => StateType;\n\n initialValues: StateType;\n\n callbacks: StreamManagerEventCallbacks<StateType, Bag>;\n\n onSuccess: () =>\n | StateType\n | null\n | undefined\n | void\n | Promise<StateType | null | undefined | void>;\n\n onError: (error: unknown) => void | Promise<void>;\n\n onFinish?: () => void;\n },\n startOptions?: {\n /**\n * If true, abort any currently running stream before starting this one.\n * Used for multitask_strategy: \"interrupt\" and \"rollback\" to unblock\n * the queue so the new run request can proceed immediately.\n */\n abortPrevious?: boolean;\n }\n ): Promise<void> => {\n if (startOptions?.abortPrevious) {\n this.abortRef.abort();\n }\n this.queueSize += 1;\n const queued = this.queue.then(() => this.enqueue(action, options));\n this.queue = queued;\n await queued;\n };\n\n stop = async (\n historyValues: StateType,\n options: {\n onStop?: (options: {\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }) => void;\n }\n ): Promise<void> => {\n this.abortRef.abort();\n this.abortRef = new AbortController();\n\n options.onStop?.({ mutate: this.getMutateFn(\"stop\", historyValues) });\n };\n\n clear = () => {\n // Cancel any running streams\n this.abortRef.abort();\n this.abortRef = new AbortController();\n\n // Set the stream state to null\n this.setState({ error: undefined, values: null, isLoading: false });\n\n // Clear any pending messages\n this.messages.clear();\n\n // Clear subagent state\n this.subagentManager.clear();\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","names":[],"sources":["../../src/ui/manager.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type {\n CheckpointsStreamEvent,\n CustomStreamEvent,\n DebugStreamEvent,\n ErrorStreamEvent,\n EventsStreamEvent,\n FeedbackStreamEvent,\n MessagesTupleStreamEvent,\n MetadataStreamEvent,\n TasksStreamEvent,\n ToolsStreamEvent,\n UpdatesStreamEvent,\n ValuesStreamEvent,\n} from \"../types.stream.js\";\nimport { MessageTupleManager, toMessageDict } from \"./messages.js\";\nimport { StreamError } from \"./errors.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport {\n SubagentManager,\n extractToolCallIdFromNamespace,\n isSubagentNamespace,\n} from \"./subagents.js\";\nimport type { SubagentStreamInterface } from \"./types.js\";\n\n/**\n * Special ID used by LangGraph's messagesStateReducer to signal\n * that all messages should be removed from the state.\n */\nexport const REMOVE_ALL_MESSAGES = \"__remove_all__\";\n\ntype GetUpdateType<\n Bag extends BagTemplate,\n StateType extends Record<string, unknown>\n> = Bag extends { UpdateType: unknown }\n ? Bag[\"UpdateType\"]\n : Partial<StateType>;\n\ntype GetCustomEventType<Bag extends BagTemplate> = Bag extends {\n CustomEventType: unknown;\n}\n ? Bag[\"CustomEventType\"]\n : unknown;\n\ntype EventStreamMap<StateType, UpdateType, CustomType> = {\n values: ValuesStreamEvent<StateType>;\n updates: UpdatesStreamEvent<UpdateType>;\n custom: CustomStreamEvent<CustomType>;\n debug: DebugStreamEvent;\n messages: MessagesTupleStreamEvent;\n events: EventsStreamEvent;\n metadata: MetadataStreamEvent;\n checkpoints: CheckpointsStreamEvent<StateType>;\n tasks: TasksStreamEvent<StateType, UpdateType>;\n error: ErrorStreamEvent;\n feedback: FeedbackStreamEvent;\n tools: ToolsStreamEvent;\n};\n\nexport type EventStreamEvent<StateType, UpdateType, CustomType> =\n EventStreamMap<StateType, UpdateType, CustomType>[keyof EventStreamMap<\n StateType,\n UpdateType,\n CustomType\n >];\n\ninterface StreamManagerEventCallbacks<\n StateType extends Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> {\n onUpdateEvent?: (\n data: UpdatesStreamEvent<GetUpdateType<Bag, StateType>>[\"data\"],\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n onCustomEvent?: (\n data: GetCustomEventType<Bag>,\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n onMetadataEvent?: (data: MetadataStreamEvent[\"data\"]) => void;\n onLangChainEvent?: (data: EventsStreamEvent[\"data\"]) => void;\n onDebugEvent?: (\n data: DebugStreamEvent[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onCheckpointEvent?: (\n data: CheckpointsStreamEvent<StateType>[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onTaskEvent?: (\n data: TasksStreamEvent<StateType, GetUpdateType<Bag, StateType>>[\"data\"],\n options: { namespace: string[] | undefined }\n ) => void;\n onToolEvent?: (\n data: ToolsStreamEvent[\"data\"],\n options: {\n namespace: string[] | undefined;\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }\n ) => void;\n}\n\n/**\n * Options for StreamManager constructor.\n */\nexport interface StreamManagerOptions {\n /**\n * Throttle the stream updates.\n * If a number is provided, updates are throttled to the given milliseconds.\n * If `true`, updates are batched in a single macrotask.\n * If `false`, updates are not throttled.\n */\n throttle: number | boolean;\n\n /**\n * Tool names that indicate subagent invocation.\n *\n * When an AI message contains tool calls with these names, they are\n * automatically tracked as subagent executions. This enables the\n * `subagents`, `activeSubagents`, `getSubagent()`, and `getSubagentsByType()`\n * properties on the stream.\n *\n * @default [\"task\"]\n *\n * @example\n * ```typescript\n * // Track both \"task\" and \"delegate\" as subagent tools\n * subagentToolNames: [\"task\", \"delegate\", \"spawn_agent\"]\n * ```\n */\n subagentToolNames?: string[];\n\n /**\n * Filter out messages from subagent streams in the main messages array.\n *\n * When enabled, messages from subagraph executions (those with a `tools:` namespace)\n * are excluded from `stream.messages`. Instead, these messages are tracked\n * per-subagent and accessible via `stream.subagents.get(id).messages`.\n *\n * This is useful for deep agent architectures where you want to display\n * the main conversation separately from subagent activity.\n *\n * @default false\n *\n * @example\n * ```typescript\n * const stream = useStream({\n * assistantId: \"my-agent\",\n * filterSubagentMessages: true,\n * });\n *\n * // Main thread messages only (no subagent messages)\n * stream.messages\n *\n * // Access subagent messages individually\n * stream.subagents.get(\"call_xyz\").messages\n * ```\n */\n filterSubagentMessages?: boolean;\n\n /**\n * Converts a @langchain/core BaseMessage to the desired output format.\n *\n * Defaults to `toMessageDict` which produces plain Message objects.\n * Framework SDKs pass `toMessageClass` (identity) to keep class instances.\n */\n toMessage?: (chunk: BaseMessage) => Message | BaseMessage;\n}\n\nexport class StreamManager<\n StateType extends Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> {\n private abortRef = new AbortController();\n\n private messages: MessageTupleManager;\n\n private subagentManager: SubagentManager;\n\n private listeners = new Set<() => void>();\n\n private throttle: number | boolean;\n\n private filterSubagentMessages: boolean;\n\n private toMessage: (chunk: BaseMessage) => Message | BaseMessage;\n\n private queue: Promise<unknown> = Promise.resolve();\n\n private queueSize: number = 0;\n\n private state: {\n isLoading: boolean;\n values: [values: StateType, kind: \"stream\" | \"stop\"] | null;\n error: unknown;\n /** Version counter to force React re-renders on subagent changes */\n version: number;\n };\n\n constructor(messages: MessageTupleManager, options: StreamManagerOptions) {\n this.messages = messages;\n this.state = {\n isLoading: false,\n values: null,\n error: undefined,\n version: 0,\n };\n this.throttle = options.throttle;\n this.filterSubagentMessages = options.filterSubagentMessages ?? false;\n this.toMessage = options.toMessage ?? toMessageDict;\n this.subagentManager = new SubagentManager({\n subagentToolNames: options.subagentToolNames,\n onSubagentChange: () => this.bumpVersion(),\n toMessage: this.toMessage,\n });\n }\n\n /**\n * Increment version counter to trigger React re-renders.\n * Called when subagent state changes.\n */\n private bumpVersion = () => {\n this.state = { ...this.state, version: this.state.version + 1 };\n this.notifyListeners();\n };\n\n /**\n * Get all subagents as a Map.\n */\n getSubagents(): Map<string, SubagentStreamInterface> {\n return this.subagentManager.getSubagents();\n }\n\n /**\n * Get all currently running subagents.\n */\n getActiveSubagents(): SubagentStreamInterface[] {\n return this.subagentManager.getActiveSubagents();\n }\n\n /**\n * Get a specific subagent by tool call ID.\n */\n getSubagent(toolCallId: string): SubagentStreamInterface | undefined {\n return this.subagentManager.getSubagent(toolCallId);\n }\n\n /**\n * Get all subagents of a specific type.\n */\n getSubagentsByType(type: string): SubagentStreamInterface[] {\n return this.subagentManager.getSubagentsByType(type);\n }\n\n /**\n * Get all subagents triggered by a specific AI message.\n */\n getSubagentsByMessage(messageId: string): SubagentStreamInterface[] {\n return this.subagentManager.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent state from historical messages.\n *\n * This method should be called when loading thread history to restore\n * subagent visualization after:\n * - Page refresh (when stream has already completed)\n * - Loading thread history\n * - Navigating between threads\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 reconstructSubagents(\n messages: Message[],\n options?: { skipIfPopulated?: boolean }\n ): void {\n this.subagentManager.reconstructFromMessages(messages, options);\n }\n\n /**\n * Fetch and restore internal messages for reconstructed subagents from their\n * subgraph checkpoints. Should be called after `reconstructSubagents` to\n * restore the full subagent conversation after a page refresh.\n *\n * Subagent messages are persisted in the LangGraph checkpointer under a\n * subgraph-specific `checkpoint_ns` (e.g. `tools:<uuid>`). This method\n * discovers the correct namespace by inspecting the main thread's intermediate\n * history checkpoints, where each pending task's `checkpoint.checkpoint_ns`\n * identifies the subgraph. Tasks are matched to tool calls by their Send index\n * (`task.path[1]`), which corresponds to the order of tool calls in the AI\n * message — no deepagent-specific metadata required.\n *\n * @param threads - Client with a `getHistory` method (e.g. `client.threads`)\n * @param threadId - The parent thread ID\n * @param options - Optional configuration\n * @param options.messagesKey - Key in state values containing messages (default: \"messages\")\n * @param options.signal - AbortSignal to cancel in-flight requests on effect cleanup\n */\n async fetchSubagentHistory(\n threads: {\n getHistory<V extends Record<string, unknown>>(\n threadId: string,\n options?: {\n limit?: number;\n checkpoint?: { checkpoint_ns?: string };\n signal?: AbortSignal;\n }\n ): Promise<\n Array<{\n values: V;\n tasks?: Array<{\n id: string;\n name: string;\n path?: unknown[];\n checkpoint?: { checkpoint_ns?: string } | null;\n }>;\n }>\n >;\n },\n threadId: string,\n options?: { messagesKey?: string; signal?: AbortSignal }\n ): Promise<void> {\n const messagesKey = options?.messagesKey ?? \"messages\";\n const signal = options?.signal;\n\n /**\n * Bail immediately if already cancelled (React Strict Mode cleanup)\n */\n if (signal?.aborted) {\n return;\n }\n\n /**\n * Only fetch for subagents that have no messages (reconstructed from history)\n */\n const toFetch = [...this.subagentManager.getSubagents().entries()].filter(\n ([, s]) => s.messages.length === 0\n );\n\n /**\n * Bail immediately if there are no subagents to fetch\n */\n if (toFetch.length === 0) {\n return;\n }\n\n /**\n * Step 1: Discover subgraph namespaces from intermediate history\n *\n * When LangGraph dispatches parallel tool calls (v2 mode), each is a\n * separate Send task with a unique UUID-based checkpoint_ns. The intermediate\n * history checkpoints record these as `tasks[i]` where:\n * - `tasks[i].checkpoint.checkpoint_ns` = \"tools:<uuid>\" for each subgraph\n * - `tasks[i].path = [\"__pregel_push\", sendIndex]` matches tool_calls order\n *\n * By matching task Send index → tool_call position in the AI message we can\n * derive the subgraph namespace for every tool call without any external\n * metadata on the ToolMessage itself.\n */\n let toolCallIdToNamespace: Map<string, string> | undefined;\n\n try {\n /**\n * Fetch enough history to include the intermediate checkpoint where\n * tool-call tasks were pending (typically within the last 10 checkpoints).\n */\n const mainHistory = await threads.getHistory<Record<string, unknown>>(\n threadId,\n { limit: 20, signal }\n );\n\n for (const checkpoint of mainHistory) {\n const { tasks } = checkpoint;\n if (!tasks || tasks.length === 0) {\n continue;\n }\n\n /**\n * When a completed checkpoint contains task results, each task.result\n * has a ToolMessage whose tool_call_id directly and unambiguously maps\n * the task to the LLM tool call that triggered it. This is more robust\n * than positional alignment: it works even when a step mixes subagent\n * tool calls with other tool calls, and requires no assumptions about\n * the ordering of tasks vs tool_calls.\n *\n * LangGraph v2 dispatches each parallel tool call as a separate PUSH\n * task (\"__pregel_push\"). The subgraph checkpoint_ns is constructed as\n * `task.name + \":\" + task.id`, mirroring algo.ts:\n * taskCheckpointNamespace = checkpointNamespace + \":\" + taskId\n * where checkpointNamespace = task.name for root-level tasks.\n *\n * task.checkpoint is always null for completed tasks, so we derive the\n * namespace from task.name + task.id rather than task.checkpoint.checkpoint_ns.\n */\n const directMap = new Map<string, string>();\n\n for (const task of tasks) {\n if (\n !Array.isArray(task.path) ||\n task.path[0] !== \"__pregel_push\" ||\n typeof task.id !== \"string\" ||\n typeof task.name !== \"string\"\n ) {\n continue;\n }\n\n /**\n * Read tool_call_id directly from the task's result ToolMessage.\n */\n const resultMessages = (\n task as unknown as { result?: { messages?: unknown[] } }\n ).result?.messages;\n\n if (Array.isArray(resultMessages)) {\n for (const msg of resultMessages) {\n const m = msg as Record<string, unknown>;\n if (\n m.type === \"tool\" &&\n typeof m.tool_call_id === \"string\" &&\n toFetch.some(([id]) => id === m.tool_call_id)\n ) {\n directMap.set(m.tool_call_id, `${task.name}:${task.id}`);\n }\n }\n }\n }\n\n if (directMap.size > 0) {\n toolCallIdToNamespace = directMap;\n break;\n }\n\n /**\n * Fallback for checkpoints where task results are not yet populated\n * (tasks are still pending). Use positional alignment via the Send\n * index in task.path[1] as a secondary strategy.\n */\n const pushTasks = tasks.filter(\n (t) =>\n Array.isArray(t.path) &&\n t.path[0] === \"__pregel_push\" &&\n typeof t.path[1] === \"number\" &&\n typeof t.id === \"string\" &&\n typeof t.name === \"string\"\n );\n if (pushTasks.length === 0) continue;\n\n /**\n * Find the AI message with subagent tool calls to align by Send index.\n */\n const msgs = checkpoint.values[messagesKey];\n if (!Array.isArray(msgs)) continue;\n\n let aiMessage: Record<string, unknown> | undefined;\n for (let i = msgs.length - 1; i >= 0; i -= 1) {\n const m = msgs[i] as Record<string, unknown>;\n if (\n m.type === \"ai\" &&\n Array.isArray(m.tool_calls) &&\n m.tool_calls.length > 0 &&\n (m.tool_calls as Array<{ name: string }>).some((tc) =>\n this.subagentManager.isSubagentToolCall(tc.name)\n )\n ) {\n aiMessage = m;\n break;\n }\n }\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Only consider subagent tool calls from the AI message — not all tool\n * calls. This ensures regular tool calls (searchWeb, queryDatabase, etc.)\n * are never mistaken for subagents even when they appear in the same step.\n */\n const subagentToolCalls = (\n aiMessage.tool_calls as Array<{ id?: string; name: string }>\n ).filter((tc) => this.subagentManager.isSubagentToolCall(tc.name));\n\n if (subagentToolCalls.length === 0) {\n continue;\n }\n\n /**\n * Sort push tasks by Send index (path[1]) to align with tool_calls order\n */\n const sorted = [...pushTasks].sort((a, b) => {\n const ai = Array.isArray(a.path) ? (a.path[1] as number) : 0;\n const bi = Array.isArray(b.path) ? (b.path[1] as number) : 0;\n return ai - bi;\n });\n\n toolCallIdToNamespace = new Map();\n for (\n let i = 0;\n i < sorted.length && i < subagentToolCalls.length;\n i += 1\n ) {\n const tc = subagentToolCalls[i];\n const task = sorted[i];\n if (tc?.id && task.id && task.name) {\n toolCallIdToNamespace.set(tc.id, `${task.name}:${task.id}`);\n }\n }\n\n if (toolCallIdToNamespace.size > 0) break;\n }\n } catch {\n /**\n * Non-fatal: fall back to subagent.namespace below\n */\n }\n\n /**\n * Step 2: Fetch each subagent's conversation from its subgraph checkpoint\n */\n await Promise.all(\n toFetch.map(async ([toolCallId, subagent]) => {\n /**\n * Priority order for the subgraph checkpoint_ns:\n * 1. Derived from main thread's intermediate task list (preferred, no coupling)\n * 2. Already on the subagent's namespace (e.g. populated during streaming)\n * 3. Skip — we cannot reliably identify the namespace\n */\n const checkpointNs =\n toolCallIdToNamespace?.get(toolCallId) ??\n (subagent.namespace.length > 0\n ? subagent.namespace.join(\"|\")\n : undefined);\n\n if (!checkpointNs) return;\n\n try {\n const history = await threads.getHistory<Record<string, unknown>>(\n threadId,\n {\n checkpoint: { checkpoint_ns: checkpointNs },\n limit: 1,\n signal,\n }\n );\n\n /**\n * If the HTTP request was cancelled mid-flight the getHistory call\n * would have thrown an AbortError (caught below). If we reach here the\n * fetch completed successfully, so always process the result.\n */\n const latestState = history[0];\n if (!latestState?.values) return;\n\n const messages = latestState.values[messagesKey];\n if (!Array.isArray(messages) || messages.length === 0) return;\n\n /**\n * Normalize messages: promote tool_calls from additional_kwargs to top\n * level when the checkpointer serialized them in the legacy format.\n */\n const normalizedMessages = messages.map((msg) => {\n const m = msg as Record<string, unknown>;\n if (\n m.type === \"ai\" &&\n (!m.tool_calls || (m.tool_calls as unknown[]).length === 0)\n ) {\n const ak = m.additional_kwargs as\n | Record<string, unknown>\n | undefined;\n const legacy = ak?.tool_calls;\n if (Array.isArray(legacy) && legacy.length > 0) {\n return { ...m, tool_calls: legacy };\n }\n }\n return m;\n });\n\n this.subagentManager.updateSubagentFromSubgraphState(\n toolCallId,\n normalizedMessages as Message[],\n latestState.values\n );\n } catch {\n /**\n * Ignore AbortError and other transient errors\n */\n }\n })\n );\n }\n\n /**\n * Check if any subagents are currently tracked.\n */\n hasSubagents(): boolean {\n return this.subagentManager.hasSubagents();\n }\n\n private setState = (newState: Partial<typeof this.state>) => {\n this.state = { ...this.state, ...newState };\n this.notifyListeners();\n };\n\n private notifyListeners = () => {\n this.listeners.forEach((listener) => listener());\n };\n\n subscribe = (listener: () => void): (() => void) => {\n if (this.throttle === false) {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n const timeoutMs = this.throttle === true ? 0 : this.throttle;\n let timeoutId: NodeJS.Timeout | number | undefined;\n\n const throttledListener = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n clearTimeout(timeoutId);\n listener();\n }, timeoutMs);\n };\n\n this.listeners.add(throttledListener);\n return () => {\n clearTimeout(timeoutId);\n this.listeners.delete(throttledListener);\n };\n };\n\n getSnapshot = () => this.state;\n\n get isLoading() {\n return this.state.isLoading;\n }\n\n get values() {\n return this.state.values?.[0] ?? null;\n }\n\n get error() {\n return this.state.error;\n }\n\n setStreamValues = (\n values:\n | (StateType | null)\n | ((prev: StateType | null, kind: \"stream\" | \"stop\") => StateType | null),\n kind: \"stream\" | \"stop\" = \"stream\"\n ) => {\n if (typeof values === \"function\") {\n const [prevValues, prevKind] = this.state.values ?? [null, \"stream\"];\n const nextValues = values(prevValues, prevKind);\n this.setState({ values: nextValues != null ? [nextValues, kind] : null });\n } else {\n const nextValues = values != null ? [values, kind] : null;\n this.setState({ values: nextValues as [StateType, \"stream\" | \"stop\"] });\n }\n };\n\n private getMutateFn = (kind: \"stream\" | \"stop\", historyValues: StateType) => {\n return (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => {\n const stateValues = (this.state.values ?? [null, \"stream\"])[0];\n const prev = {\n ...historyValues,\n ...stateValues,\n };\n const next = typeof update === \"function\" ? update(prev) : update;\n this.setStreamValues({ ...prev, ...next }, kind);\n };\n };\n\n private matchEventType = <\n T extends keyof EventStreamMap<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >(\n expected: T,\n actual: EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[\"event\"],\n _data: EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[\"data\"]\n ): _data is EventStreamMap<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >[T][\"data\"] => {\n return expected === actual || actual.startsWith(`${expected}|`);\n };\n\n protected enqueue = async (\n action: (\n signal: AbortSignal\n ) => Promise<\n AsyncGenerator<\n EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >\n >,\n options: {\n getMessages: (values: StateType) => Message[];\n\n setMessages: (current: StateType, messages: Message[]) => StateType;\n\n initialValues: StateType;\n\n callbacks: StreamManagerEventCallbacks<StateType, Bag>;\n\n onSuccess: () =>\n | StateType\n | null\n | undefined\n | void\n | Promise<StateType | null | undefined | void>;\n\n onError: (error: unknown) => void | Promise<void>;\n\n onFinish?: () => void;\n }\n ) => {\n try {\n this.queueSize = Math.max(0, this.queueSize - 1);\n this.setState({ isLoading: true, error: undefined });\n this.abortRef = new AbortController();\n\n const run = await action(this.abortRef.signal);\n\n let streamError: StreamError | undefined;\n for await (const { event, data } of run) {\n if (event === \"error\") {\n streamError = new StreamError(data);\n break;\n }\n\n const namespace = event.includes(\"|\")\n ? event.split(\"|\").slice(1)\n : undefined;\n\n const mutate = this.getMutateFn(\"stream\", options.initialValues);\n\n if (event === \"metadata\") options.callbacks.onMetadataEvent?.(data);\n if (event === \"events\") options.callbacks.onLangChainEvent?.(data);\n\n if (this.matchEventType(\"updates\", event, data)) {\n options.callbacks.onUpdateEvent?.(data, { namespace, mutate });\n\n // Track subagent streaming updates from subgraph namespaces\n // Mark the subagent as running when we receive updates\n // The actual message content is handled via addMessageToSubagent\n if (namespace && isSubagentNamespace(namespace)) {\n const namespaceId = extractToolCallIdFromNamespace(namespace);\n if (namespaceId && this.filterSubagentMessages) {\n this.subagentManager.markRunningFromNamespace(\n namespaceId,\n namespace\n );\n }\n }\n\n // Also register subagents from main agent updates (tool_calls in messages)\n // AND process tool results to complete subagents\n // This is needed because tool_calls often appear complete in updates\n // before they appear in the messages stream\n if (!namespace || !isSubagentNamespace(namespace)) {\n const updateData = data as Record<string, unknown>;\n for (const nodeData of Object.values(updateData)) {\n if (\n nodeData &&\n typeof nodeData === \"object\" &&\n \"messages\" in nodeData\n ) {\n const { messages } = nodeData as { messages: unknown[] };\n if (Array.isArray(messages)) {\n for (const msg of messages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n\n // Register subagents from AI messages with tool_calls\n if (\n msgObj.type === \"ai\" &&\n \"tool_calls\" in msgObj &&\n Array.isArray(msgObj.tool_calls)\n ) {\n this.subagentManager.registerFromToolCalls(\n msgObj.tool_calls as Array<{\n id?: string;\n name: string;\n args: Record<string, unknown> | string;\n }>,\n msgObj.id as string | undefined\n );\n }\n\n // Complete subagents from tool messages (task results)\n if (\n msgObj.type === \"tool\" &&\n \"tool_call_id\" in msgObj &&\n typeof msgObj.tool_call_id === \"string\"\n ) {\n const content =\n typeof msgObj.content === \"string\"\n ? msgObj.content\n : JSON.stringify(msgObj.content);\n const status =\n \"status\" in msgObj && msgObj.status === \"error\"\n ? \"error\"\n : \"success\";\n this.subagentManager.processToolMessage(\n msgObj.tool_call_id,\n content,\n status\n );\n }\n }\n }\n }\n }\n }\n }\n\n if (this.matchEventType(\"custom\", event, data)) {\n options.callbacks.onCustomEvent?.(data, { namespace, mutate });\n }\n\n if (this.matchEventType(\"checkpoints\", event, data)) {\n options.callbacks.onCheckpointEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"tasks\", event, data)) {\n options.callbacks.onTaskEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"debug\", event, data)) {\n options.callbacks.onDebugEvent?.(data, { namespace });\n }\n\n if (this.matchEventType(\"tools\", event, data)) {\n options.callbacks.onToolEvent?.(data, { namespace, mutate });\n }\n\n // Handle values events - use startsWith to match both \"values\" and \"values|tools:xxx\"\n if (event === \"values\" || event.startsWith(\"values|\")) {\n // Check if this is a subgraph values event (for namespace mapping and values)\n if (namespace && isSubagentNamespace(namespace)) {\n const namespaceId = extractToolCallIdFromNamespace(namespace);\n if (namespaceId && this.filterSubagentMessages) {\n const valuesData = data as Record<string, unknown>;\n\n // Try to establish namespace mapping from the initial human message\n const messages = valuesData.messages as unknown[];\n if (Array.isArray(messages) && messages.length > 0) {\n const firstMsg = messages[0] as Record<string, unknown>;\n if (\n firstMsg?.type === \"human\" &&\n typeof firstMsg?.content === \"string\"\n ) {\n this.subagentManager.matchSubgraphToSubagent(\n namespaceId,\n firstMsg.content\n );\n }\n }\n\n // Update the subagent's values with the full state\n this.subagentManager.updateSubagentValues(\n namespaceId,\n valuesData\n );\n }\n } else if (\n data &&\n typeof data === \"object\" &&\n \"__interrupt__\" in data\n ) {\n const interruptData = data as Partial<StateType>;\n this.setStreamValues(\n (prev) => ({ ...prev, ...interruptData } as StateType)\n );\n } else {\n this.setStreamValues(data as StateType);\n }\n }\n\n if (this.matchEventType(\"messages\", event, data)) {\n const [serialized, metadata] = data;\n\n // Check if this message is from a subagent namespace\n const rawCheckpointNs =\n (metadata?.langgraph_checkpoint_ns as string | undefined) ||\n (metadata?.checkpoint_ns as string | undefined);\n const checkpointNs: string | undefined =\n typeof rawCheckpointNs === \"string\" ? rawCheckpointNs : undefined;\n const isFromSubagent = isSubagentNamespace(checkpointNs);\n const toolCallId = isFromSubagent\n ? extractToolCallIdFromNamespace(checkpointNs?.split(\"|\"))\n : undefined;\n\n // If filtering is enabled and this is a subagent message,\n // add it to the subagent's messages instead of the main stream\n if (this.filterSubagentMessages && isFromSubagent && toolCallId) {\n // Add to subagent's message list\n this.subagentManager.addMessageToSubagent(\n toolCallId,\n serialized,\n metadata\n );\n continue;\n }\n\n const messageId = this.messages.add(serialized, metadata);\n if (!messageId) {\n console.warn(\n \"Failed to add message to manager, no message ID found\"\n );\n continue;\n }\n\n this.setStreamValues((streamValues) => {\n const values = {\n ...options.initialValues,\n ...streamValues,\n };\n\n // Assumption: we're concatenating the message\n let messages = options.getMessages(values).slice();\n const { chunk, index } =\n this.messages.get(messageId, messages.length) ?? {};\n\n if (!chunk || index == null) return values;\n if (chunk.getType() === \"remove\") {\n // Check for special REMOVE_ALL_MESSAGES sentinel\n if (chunk.id === REMOVE_ALL_MESSAGES) {\n // Clear all messages when __remove_all__ is received\n messages = [];\n } else {\n messages.splice(index, 1);\n }\n } else {\n const msgDict = this.toMessage(chunk) as Message;\n messages[index] = msgDict;\n\n // Track subagents from AI messages with tool calls (main agent only)\n if (\n !isFromSubagent &&\n msgDict.type === \"ai\" &&\n \"tool_calls\" in msgDict &&\n Array.isArray(msgDict.tool_calls)\n ) {\n this.subagentManager.registerFromToolCalls(\n msgDict.tool_calls,\n msgDict.id as string | undefined\n );\n }\n\n // Complete subagents when tool messages arrive (main agent only)\n if (\n !isFromSubagent &&\n msgDict.type === \"tool\" &&\n \"tool_call_id\" in msgDict\n ) {\n const tcId = msgDict.tool_call_id as string;\n const content =\n typeof msgDict.content === \"string\"\n ? msgDict.content\n : JSON.stringify(msgDict.content);\n const status =\n \"status\" in msgDict && msgDict.status === \"error\"\n ? \"error\"\n : \"success\";\n this.subagentManager.processToolMessage(tcId, content, status);\n }\n }\n\n return options.setMessages(values, messages);\n });\n }\n }\n\n if (streamError != null) throw streamError;\n\n // Skip onSuccess when the stream was aborted (e.g., by multitask interrupt).\n // This avoids unnecessary HTTP calls (like history fetching) that would\n // delay the next queued stream from starting.\n if (!this.abortRef.signal.aborted) {\n const values = await options.onSuccess?.();\n if (typeof values !== \"undefined\" && this.queueSize === 0) {\n this.setStreamValues(values);\n }\n }\n } catch (error) {\n if (\n !(\n error instanceof Error && // eslint-disable-line no-instanceof/no-instanceof\n (error.name === \"AbortError\" || error.name === \"TimeoutError\")\n )\n ) {\n console.error(error);\n this.setState({ error });\n await options.onError?.(error);\n }\n } finally {\n this.setState({ isLoading: false });\n this.abortRef = new AbortController();\n options.onFinish?.();\n }\n };\n\n start = async (\n action: (\n signal: AbortSignal\n ) => Promise<\n AsyncGenerator<\n EventStreamEvent<\n StateType,\n GetUpdateType<Bag, StateType>,\n GetCustomEventType<Bag>\n >\n >\n >,\n options: {\n getMessages: (values: StateType) => Message[];\n\n setMessages: (current: StateType, messages: Message[]) => StateType;\n\n initialValues: StateType;\n\n callbacks: StreamManagerEventCallbacks<StateType, Bag>;\n\n onSuccess: () =>\n | StateType\n | null\n | undefined\n | void\n | Promise<StateType | null | undefined | void>;\n\n onError: (error: unknown) => void | Promise<void>;\n\n onFinish?: () => void;\n },\n startOptions?: {\n /**\n * If true, abort any currently running stream before starting this one.\n * Used for multitask_strategy: \"interrupt\" and \"rollback\" to unblock\n * the queue so the new run request can proceed immediately.\n */\n abortPrevious?: boolean;\n }\n ): Promise<void> => {\n if (startOptions?.abortPrevious) {\n this.abortRef.abort();\n }\n this.queueSize += 1;\n const queued = this.queue.then(() => this.enqueue(action, options));\n this.queue = queued;\n await queued;\n };\n\n stop = async (\n historyValues: StateType,\n options: {\n onStop?: (options: {\n mutate: (\n update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)\n ) => void;\n }) => void;\n }\n ): Promise<void> => {\n this.abortRef.abort();\n this.abortRef = new AbortController();\n\n options.onStop?.({ mutate: this.getMutateFn(\"stop\", historyValues) });\n };\n\n clear = () => {\n // Cancel any running streams\n this.abortRef.abort();\n this.abortRef = new AbortController();\n\n // Set the stream state to null\n this.setState({ error: undefined, values: null, isLoading: false });\n\n // Clear any pending messages\n this.messages.clear();\n\n // Clear subagent state\n this.subagentManager.clear();\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,372 @@
1
+ const require_messages = require("./messages.cjs");
2
+ const require_tools = require("../utils/tools.cjs");
3
+ const require_manager = require("./manager.cjs");
4
+ const require_interrupts = require("./interrupts.cjs");
5
+ //#region src/ui/orchestrator-custom.ts
6
+ /**
7
+ * Create a custom transport thread state.
8
+ * @param values - The values to use.
9
+ * @param threadId - The ID of the thread to use.
10
+ * @returns The custom transport thread state.
11
+ */
12
+ function createCustomTransportThreadState(values, threadId) {
13
+ return {
14
+ values,
15
+ next: [],
16
+ tasks: [],
17
+ metadata: void 0,
18
+ created_at: null,
19
+ checkpoint: {
20
+ thread_id: threadId,
21
+ checkpoint_id: null,
22
+ checkpoint_ns: "",
23
+ checkpoint_map: null
24
+ },
25
+ parent_checkpoint: null
26
+ };
27
+ }
28
+ /**
29
+ * Framework-agnostic orchestrator for custom transport streams.
30
+ *
31
+ * Encapsulates all business logic shared across React, Vue, Svelte, and Angular
32
+ * for custom transport (non-LGP) streaming.
33
+ */
34
+ var CustomStreamOrchestrator = class {
35
+ stream;
36
+ messageManager;
37
+ #options;
38
+ #historyValues;
39
+ #threadId;
40
+ #branch = "";
41
+ #listeners = /* @__PURE__ */ new Set();
42
+ #version = 0;
43
+ #streamUnsub = null;
44
+ #disposed = false;
45
+ /**
46
+ * Create a new {@link CustomStreamOrchestrator} instance.
47
+ *
48
+ * @param options - Configuration options for the custom transport stream,
49
+ * including thread ID, transport, callbacks, and subagent settings.
50
+ */
51
+ constructor(options) {
52
+ this.#options = options;
53
+ this.#threadId = options.threadId ?? null;
54
+ this.messageManager = new require_messages.MessageTupleManager();
55
+ this.stream = new require_manager.StreamManager(this.messageManager, {
56
+ throttle: options.throttle ?? false,
57
+ subagentToolNames: options.subagentToolNames,
58
+ filterSubagentMessages: options.filterSubagentMessages,
59
+ toMessage: options.toMessage ?? require_messages.toMessageClass
60
+ });
61
+ this.#historyValues = options.initialValues ?? {};
62
+ this.#streamUnsub = this.stream.subscribe(() => {
63
+ this.#notify();
64
+ });
65
+ const historyMessages = this.#getMessages(this.#historyValues);
66
+ if (options.filterSubagentMessages && !this.stream.isLoading && historyMessages.length > 0) this.stream.reconstructSubagents(historyMessages, { skipIfPopulated: true });
67
+ }
68
+ /**
69
+ * Register a listener that is called whenever the orchestrator state changes.
70
+ *
71
+ * @param listener - Callback invoked on each state change.
72
+ * @returns An unsubscribe function that removes the listener.
73
+ */
74
+ subscribe = (listener) => {
75
+ this.#listeners.add(listener);
76
+ return () => {
77
+ this.#listeners.delete(listener);
78
+ };
79
+ };
80
+ /**
81
+ * Return the current version number, incremented on each state change.
82
+ * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).
83
+ *
84
+ * @returns The current version counter.
85
+ */
86
+ getSnapshot = () => this.#version;
87
+ #notify() {
88
+ if (this.#disposed) return;
89
+ this.#version += 1;
90
+ for (const listener of this.#listeners) listener();
91
+ }
92
+ /**
93
+ * Synchronize the external thread ID with the orchestrator.
94
+ * If the ID has changed, the current stream is cleared and listeners
95
+ * are notified.
96
+ *
97
+ * @param newId - The new thread ID, or `null` to clear.
98
+ */
99
+ syncThreadId(newId) {
100
+ if (newId !== this.#threadId) {
101
+ this.#threadId = newId;
102
+ this.stream.clear();
103
+ this.#notify();
104
+ }
105
+ }
106
+ #getMessages = (value) => {
107
+ const messagesKey = this.#options.messagesKey ?? "messages";
108
+ return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
109
+ };
110
+ #setMessages = (current, messages) => {
111
+ const messagesKey = this.#options.messagesKey ?? "messages";
112
+ return {
113
+ ...current,
114
+ [messagesKey]: messages
115
+ };
116
+ };
117
+ /**
118
+ * The current stream state values, falling back to an empty object
119
+ * when no stream values are available.
120
+ */
121
+ get values() {
122
+ return this.stream.values ?? {};
123
+ }
124
+ /**
125
+ * The raw stream state values, or `null` if no stream has been started
126
+ * or values have not yet been received.
127
+ */
128
+ get streamValues() {
129
+ return this.stream.values;
130
+ }
131
+ /** The most recent stream error, or `undefined` if no error occurred. */
132
+ get error() {
133
+ return this.stream.error;
134
+ }
135
+ /** Whether a stream is currently in progress. */
136
+ get isLoading() {
137
+ return this.stream.isLoading;
138
+ }
139
+ /** The current branch identifier. */
140
+ get branch() {
141
+ return this.#branch;
142
+ }
143
+ /**
144
+ * Update the current branch and notify listeners.
145
+ *
146
+ * @param value - The new branch identifier.
147
+ */
148
+ setBranch(value) {
149
+ this.#branch = value;
150
+ this.#notify();
151
+ }
152
+ /**
153
+ * All messages from the current stream values, converted to
154
+ * {@link BaseMessage} instances. Returns an empty array when no
155
+ * stream values are available.
156
+ */
157
+ get messages() {
158
+ if (!this.stream.values) return [];
159
+ return require_messages.ensureMessageInstances(this.#getMessages(this.stream.values));
160
+ }
161
+ /**
162
+ * All tool calls paired with their results extracted from the
163
+ * current stream messages.
164
+ */
165
+ get toolCalls() {
166
+ if (!this.stream.values) return [];
167
+ return require_tools.getToolCallsWithResults(this.#getMessages(this.stream.values));
168
+ }
169
+ /**
170
+ * Get tool calls (with results) that belong to a specific AI message.
171
+ *
172
+ * @param message - The AI message whose tool calls to retrieve.
173
+ * @returns Tool calls associated with the given message.
174
+ */
175
+ getToolCalls(message) {
176
+ if (!this.stream.values) return [];
177
+ return require_tools.getToolCallsWithResults(this.#getMessages(this.stream.values)).filter((tc) => tc.aiMessage.id === message.id);
178
+ }
179
+ /**
180
+ * All active interrupts from the current stream values.
181
+ * Returns a single breakpoint interrupt when the interrupt array is
182
+ * present but empty, or an empty array when no interrupts exist.
183
+ */
184
+ get interrupts() {
185
+ if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) {
186
+ const valueInterrupts = this.stream.values.__interrupt__;
187
+ if (valueInterrupts.length === 0) return [{ when: "breakpoint" }];
188
+ return valueInterrupts;
189
+ }
190
+ return [];
191
+ }
192
+ /**
193
+ * The first active interrupt extracted from the current stream values,
194
+ * or `undefined` if there are no interrupts.
195
+ */
196
+ get interrupt() {
197
+ return require_interrupts.extractInterrupts(this.stream.values);
198
+ }
199
+ /**
200
+ * Retrieve stream-level metadata for a given message.
201
+ *
202
+ * @param message - The message to look up metadata for.
203
+ * @param index - Optional positional index used as fallback message ID.
204
+ * @returns The metadata associated with the message, or `undefined`
205
+ * if no stream metadata is available.
206
+ */
207
+ getMessagesMetadata(message, index) {
208
+ const streamMetadata = this.messageManager.get(message.id)?.metadata;
209
+ if (streamMetadata != null) return {
210
+ messageId: message.id ?? String(index),
211
+ firstSeenState: void 0,
212
+ branch: void 0,
213
+ branchOptions: void 0,
214
+ streamMetadata
215
+ };
216
+ }
217
+ /** A map of all tracked subagent streams, keyed by tool call ID. */
218
+ get subagents() {
219
+ return this.stream.getSubagents();
220
+ }
221
+ /** The subset of subagent streams that are currently active (loading). */
222
+ get activeSubagents() {
223
+ return this.stream.getActiveSubagents();
224
+ }
225
+ /**
226
+ * Look up a single subagent stream by its tool call ID.
227
+ *
228
+ * @param toolCallId - The tool call ID that initiated the subagent.
229
+ * @returns The subagent stream, or `undefined` if not found.
230
+ */
231
+ getSubagent(toolCallId) {
232
+ return this.stream.getSubagent(toolCallId);
233
+ }
234
+ /**
235
+ * Retrieve all subagent streams matching a given tool name / type.
236
+ *
237
+ * @param type - The subagent type (tool name) to filter by.
238
+ * @returns An array of matching subagent streams.
239
+ */
240
+ getSubagentsByType(type) {
241
+ return this.stream.getSubagentsByType(type);
242
+ }
243
+ /**
244
+ * Retrieve all subagent streams associated with a specific AI message.
245
+ *
246
+ * @param messageId - The ID of the parent AI message.
247
+ * @returns An array of subagent streams linked to the message.
248
+ */
249
+ getSubagentsByMessage(messageId) {
250
+ return this.stream.getSubagentsByMessage(messageId);
251
+ }
252
+ /**
253
+ * Reconstruct subagent streams from history values when subagent
254
+ * filtering is enabled and the stream is not currently loading.
255
+ * This is a no-op if subagents are already populated.
256
+ */
257
+ reconstructSubagentsIfNeeded() {
258
+ const hvMessages = this.#getMessages(this.#historyValues);
259
+ if (this.#options.filterSubagentMessages && !this.stream.isLoading && hvMessages.length > 0) this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });
260
+ }
261
+ /**
262
+ * Abort the current stream and invoke the `onStop` callback
263
+ * if one was provided in the options.
264
+ */
265
+ stop() {
266
+ this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
267
+ }
268
+ /**
269
+ * Switch to a different thread. If the thread ID actually changed,
270
+ * the current stream is cleared and listeners are notified.
271
+ *
272
+ * @param newThreadId - The thread ID to switch to, or `null` to clear.
273
+ */
274
+ switchThread(newThreadId) {
275
+ if (newThreadId !== this.#threadId) {
276
+ this.#threadId = newThreadId;
277
+ this.stream.clear();
278
+ this.#notify();
279
+ }
280
+ }
281
+ /**
282
+ * Start a new stream run against the custom transport.
283
+ *
284
+ * This is the low-level submit entry point that handles thread ID
285
+ * resolution, optimistic value merging, and transport invocation.
286
+ * Prefer {@link submit} unless you need to bypass higher-level wrappers.
287
+ *
288
+ * @param values - The input values to send, or `null`/`undefined` for
289
+ * a resume-style invocation.
290
+ * @param submitOptions - Optional per-call overrides such as
291
+ * `optimisticValues`, `config`, `command`, and error callbacks.
292
+ */
293
+ async submitDirect(values, submitOptions) {
294
+ const currentThreadId = this.#options.threadId ?? null;
295
+ if (currentThreadId !== this.#threadId) {
296
+ this.#threadId = currentThreadId;
297
+ this.stream.clear();
298
+ }
299
+ let usableThreadId = this.#threadId ?? submitOptions?.threadId;
300
+ this.stream.setStreamValues(() => {
301
+ if (submitOptions?.optimisticValues != null) return {
302
+ ...this.#historyValues,
303
+ ...typeof submitOptions.optimisticValues === "function" ? submitOptions.optimisticValues(this.#historyValues) : submitOptions.optimisticValues
304
+ };
305
+ return { ...this.#historyValues };
306
+ });
307
+ await this.stream.start(async (signal) => {
308
+ if (!usableThreadId) {
309
+ usableThreadId = crypto.randomUUID();
310
+ this.#threadId = usableThreadId;
311
+ this.#options.onThreadId?.(usableThreadId);
312
+ }
313
+ if (!usableThreadId) throw new Error("Failed to obtain valid thread ID.");
314
+ return this.#options.transport.stream({
315
+ input: values,
316
+ context: submitOptions?.context,
317
+ command: submitOptions?.command,
318
+ streamSubgraphs: submitOptions?.streamSubgraphs,
319
+ signal,
320
+ config: {
321
+ ...submitOptions?.config,
322
+ configurable: {
323
+ thread_id: usableThreadId,
324
+ ...submitOptions?.config?.configurable
325
+ }
326
+ }
327
+ });
328
+ }, {
329
+ getMessages: this.#getMessages,
330
+ setMessages: this.#setMessages,
331
+ initialValues: {},
332
+ callbacks: this.#options,
333
+ onSuccess: () => {
334
+ if (!usableThreadId) return void 0;
335
+ const finalValues = this.stream.values ?? this.#historyValues;
336
+ this.#options.onFinish?.(createCustomTransportThreadState(finalValues, usableThreadId), void 0);
337
+ },
338
+ onError: (error) => {
339
+ this.#options.onError?.(error, void 0);
340
+ submitOptions?.onError?.(error, void 0);
341
+ }
342
+ });
343
+ }
344
+ /**
345
+ * Submit input values and start a new stream run.
346
+ *
347
+ * Delegates to {@link submitDirect}. Override or wrap this method
348
+ * in framework adapters to add queuing or other middleware.
349
+ *
350
+ * @param values - The input values to send, or `null`/`undefined` for
351
+ * a resume-style invocation.
352
+ * @param submitOptions - Optional per-call overrides.
353
+ */
354
+ async submit(values, submitOptions) {
355
+ await this.submitDirect(values, submitOptions);
356
+ }
357
+ /**
358
+ * Tear down the orchestrator. Marks the instance as disposed,
359
+ * unsubscribes from the stream, and aborts any in-progress stream.
360
+ * After calling this method, no further notifications will be emitted.
361
+ */
362
+ dispose() {
363
+ this.#disposed = true;
364
+ this.#streamUnsub?.();
365
+ this.#streamUnsub = null;
366
+ this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
367
+ }
368
+ };
369
+ //#endregion
370
+ exports.CustomStreamOrchestrator = CustomStreamOrchestrator;
371
+
372
+ //# sourceMappingURL=orchestrator-custom.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-custom.cjs","names":["#options","#historyValues","#threadId","MessageTupleManager","StreamManager","toMessageClass","#streamUnsub","#notify","#getMessages","#listeners","#version","#disposed","#branch","ensureMessageInstances","getToolCallsWithResults","extractInterrupts","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport { extractInterrupts } from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return Array.isArray(value[messagesKey])\n ? (value[messagesKey] as Message[])\n : [];\n };\n\n #setMessages = (current: StateType, messages: Message[]): StateType => {\n const messagesKey = this.#options.messagesKey ?? \"messages\";\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n const valueInterrupts = this.stream.values.__interrupt__;\n if (valueInterrupts.length === 0) return [{ when: \"breakpoint\" }];\n return valueInterrupts;\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n}\n"],"mappings":"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"}