@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
1 lines • 22 kB
Source Map (JSON)
{"version":3,"file":"orchestrator-custom.cjs","names":["#options","#historyValues","#threadId","MessageTupleManager","StreamManager","toMessageClass","#streamUnsub","#flushPendingHeadlessToolInterrupts","#notify","#getMessages","#listeners","#version","#disposed","#handledHeadlessToolInterruptIds","#branch","ensureMessageInstances","getToolCallsWithResults","userFacingInterruptsFromValuesArray","extractInterrupts","#setMessages"],"sources":["../../src/ui/orchestrator-custom.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nimport { DEFAULT_MESSAGES_KEY } from \"../stream/constants.js\";\nimport type { ThreadState, Interrupt } from \"../schema.js\";\nimport type { StreamMode } from \"../types.stream.js\";\nimport type { Message } from \"../types.messages.js\";\nimport type { BagTemplate } from \"../types.template.js\";\nimport { StreamManager, type EventStreamEvent } from \"./manager.js\";\nimport {\n MessageTupleManager,\n toMessageClass,\n ensureMessageInstances,\n} from \"./messages.js\";\nimport {\n extractInterrupts,\n userFacingInterruptsFromValuesArray,\n} from \"./interrupts.js\";\nimport { getToolCallsWithResults } from \"../utils/tools.js\";\nimport { flushPendingHeadlessToolInterrupts } from \"../headless-tools.js\";\nimport type {\n AnyStreamCustomOptions,\n CustomSubmitOptions,\n MessageMetadata,\n GetUpdateType,\n GetCustomEventType,\n GetInterruptType,\n GetConfigurableType,\n SubagentStreamInterface,\n} from \"./types.js\";\n\n/**\n * Create a custom transport thread state.\n * @param values - The values to use.\n * @param threadId - The ID of the thread to use.\n * @returns The custom transport thread state.\n */\nfunction createCustomTransportThreadState<\n StateType extends Record<string, unknown>,\n>(values: StateType, threadId: string): ThreadState<StateType> {\n return {\n values,\n next: [],\n tasks: [],\n metadata: undefined,\n created_at: null,\n checkpoint: {\n thread_id: threadId,\n checkpoint_id: null,\n checkpoint_ns: \"\",\n checkpoint_map: null,\n },\n parent_checkpoint: null,\n };\n}\n\n/**\n * Framework-agnostic orchestrator for custom transport streams.\n *\n * Encapsulates all business logic shared across React, Vue, Svelte, and Angular\n * for custom transport (non-LGP) streaming.\n */\nexport class CustomStreamOrchestrator<\n StateType extends Record<string, unknown> = Record<string, unknown>,\n Bag extends BagTemplate = BagTemplate,\n> {\n readonly stream: StreamManager<StateType, Bag>;\n\n readonly messageManager: MessageTupleManager;\n\n readonly #options: AnyStreamCustomOptions<StateType, Bag>;\n\n readonly #historyValues: StateType;\n\n #threadId: string | null;\n\n #branch: string = \"\";\n\n #listeners = new Set<() => void>();\n\n #version = 0;\n\n #streamUnsub: (() => void) | null = null;\n\n #disposed = false;\n\n #handledHeadlessToolInterruptIds = new Set<string>();\n\n /**\n * Create a new {@link CustomStreamOrchestrator} instance.\n *\n * @param options - Configuration options for the custom transport stream,\n * including thread ID, transport, callbacks, and subagent settings.\n */\n constructor(options: AnyStreamCustomOptions<StateType, Bag>) {\n this.#options = options;\n\n this.#threadId = options.threadId ?? null;\n\n this.messageManager = new MessageTupleManager();\n this.stream = new StreamManager<StateType, Bag>(this.messageManager, {\n throttle: options.throttle ?? false,\n subagentToolNames: options.subagentToolNames,\n filterSubagentMessages: options.filterSubagentMessages,\n toMessage: options.toMessage ?? toMessageClass,\n });\n\n this.#historyValues = options.initialValues ?? ({} as StateType);\n\n this.#streamUnsub = this.stream.subscribe(() => {\n this.#flushPendingHeadlessToolInterrupts();\n this.#notify();\n });\n\n const historyMessages = this.#getMessages(this.#historyValues);\n if (\n options.filterSubagentMessages &&\n !this.stream.isLoading &&\n historyMessages.length > 0\n ) {\n this.stream.reconstructSubagents(historyMessages, {\n skipIfPopulated: true,\n });\n }\n }\n\n /**\n * Register a listener that is called whenever the orchestrator state changes.\n *\n * @param listener - Callback invoked on each state change.\n * @returns An unsubscribe function that removes the listener.\n */\n subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n };\n\n /**\n * Return the current version number, incremented on each state change.\n * Useful as a cache key for external sync (e.g. `useSyncExternalStore`).\n *\n * @returns The current version counter.\n */\n getSnapshot = (): number => this.#version;\n\n /**\n * Custom transports do not negotiate stream modes with the server the way\n * LangGraph Platform streams do, but framework adapters call this method on\n * both orchestrator variants. Keep the API surface aligned as a no-op.\n */\n trackStreamMode(..._modes: StreamMode[]): void {}\n\n #notify(): void {\n if (this.#disposed) return;\n this.#version += 1;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n /**\n * Synchronize the external thread ID with the orchestrator.\n * If the ID has changed, the current stream is cleared and listeners\n * are notified.\n *\n * @param newId - The new thread ID, or `null` to clear.\n */\n syncThreadId(newId: string | null): void {\n if (newId !== this.#threadId) {\n this.#threadId = newId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n #getMessages = (value: StateType): Message[] => {\n const messagesKey = this.#options.messagesKey ?? DEFAULT_MESSAGES_KEY;\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 ?? DEFAULT_MESSAGES_KEY;\n return { ...current, [messagesKey]: messages };\n };\n\n /**\n * The current stream state values, falling back to an empty object\n * when no stream values are available.\n */\n get values(): StateType {\n return this.stream.values ?? ({} as StateType);\n }\n\n /**\n * The raw stream state values, or `null` if no stream has been started\n * or values have not yet been received.\n */\n get streamValues(): StateType | null {\n return this.stream.values;\n }\n\n /** The most recent stream error, or `undefined` if no error occurred. */\n get error(): unknown {\n return this.stream.error;\n }\n\n /** Whether a stream is currently in progress. */\n get isLoading(): boolean {\n return this.stream.isLoading;\n }\n\n /** The current branch identifier. */\n get branch(): string {\n return this.#branch;\n }\n\n /**\n * Update the current branch and notify listeners.\n *\n * @param value - The new branch identifier.\n */\n setBranch(value: string): void {\n this.#branch = value;\n this.#notify();\n }\n\n /**\n * All messages from the current stream values, converted to\n * {@link BaseMessage} instances. Returns an empty array when no\n * stream values are available.\n */\n get messages(): BaseMessage[] {\n if (!this.stream.values) return [];\n return ensureMessageInstances(\n this.#getMessages(this.stream.values)\n ) as BaseMessage[];\n }\n\n /**\n * All tool calls paired with their results extracted from the\n * current stream messages.\n */\n get toolCalls() {\n if (!this.stream.values) return [];\n return getToolCallsWithResults(this.#getMessages(this.stream.values));\n }\n\n /**\n * Get tool calls (with results) that belong to a specific AI message.\n *\n * @param message - The AI message whose tool calls to retrieve.\n * @returns Tool calls associated with the given message.\n */\n getToolCalls(message: Message) {\n if (!this.stream.values) return [];\n const allToolCalls = getToolCallsWithResults(\n this.#getMessages(this.stream.values)\n );\n return allToolCalls.filter((tc) => tc.aiMessage.id === message.id);\n }\n\n /**\n * All active interrupts from the current stream values.\n * Returns a single breakpoint interrupt when the interrupt array is\n * present but empty, or an empty array when no interrupts exist.\n */\n get interrupts(): Interrupt<GetInterruptType<Bag>>[] {\n if (\n this.stream.values != null &&\n \"__interrupt__\" in this.stream.values &&\n Array.isArray(this.stream.values.__interrupt__)\n ) {\n return userFacingInterruptsFromValuesArray<GetInterruptType<Bag>>(\n this.stream.values.__interrupt__ as Interrupt<GetInterruptType<Bag>>[]\n );\n }\n return [];\n }\n\n /**\n * The first active interrupt extracted from the current stream values,\n * or `undefined` if there are no interrupts.\n */\n get interrupt(): Interrupt<GetInterruptType<Bag>> | undefined {\n return extractInterrupts<GetInterruptType<Bag>>(this.stream.values);\n }\n\n /**\n * Retrieve stream-level metadata for a given message.\n *\n * @param message - The message to look up metadata for.\n * @param index - Optional positional index used as fallback message ID.\n * @returns The metadata associated with the message, or `undefined`\n * if no stream metadata is available.\n */\n getMessagesMetadata(\n message: Message,\n index?: number\n ): MessageMetadata<StateType> | undefined {\n const streamMetadata = this.messageManager.get(message.id)?.metadata;\n if (streamMetadata != null) {\n return {\n messageId: message.id ?? String(index),\n firstSeenState: undefined,\n branch: undefined,\n branchOptions: undefined,\n streamMetadata,\n } as MessageMetadata<StateType>;\n }\n return undefined;\n }\n\n /** A map of all tracked subagent streams, keyed by tool call ID. */\n get subagents(): Map<string, SubagentStreamInterface> {\n return this.stream.getSubagents();\n }\n\n /** The subset of subagent streams that are currently active (loading). */\n get activeSubagents(): SubagentStreamInterface[] {\n return this.stream.getActiveSubagents();\n }\n\n /**\n * Look up a single subagent stream by its tool call ID.\n *\n * @param toolCallId - The tool call ID that initiated the subagent.\n * @returns The subagent stream, or `undefined` if not found.\n */\n getSubagent(toolCallId: string) {\n return this.stream.getSubagent(toolCallId);\n }\n\n /**\n * Retrieve all subagent streams matching a given tool name / type.\n *\n * @param type - The subagent type (tool name) to filter by.\n * @returns An array of matching subagent streams.\n */\n getSubagentsByType(type: string) {\n return this.stream.getSubagentsByType(type);\n }\n\n /**\n * Retrieve all subagent streams associated with a specific AI message.\n *\n * @param messageId - The ID of the parent AI message.\n * @returns An array of subagent streams linked to the message.\n */\n getSubagentsByMessage(messageId: string) {\n return this.stream.getSubagentsByMessage(messageId);\n }\n\n /**\n * Reconstruct subagent streams from history values when subagent\n * filtering is enabled and the stream is not currently loading.\n * This is a no-op if subagents are already populated.\n */\n reconstructSubagentsIfNeeded(): void {\n const hvMessages = this.#getMessages(this.#historyValues);\n if (\n this.#options.filterSubagentMessages &&\n !this.stream.isLoading &&\n hvMessages.length > 0\n ) {\n this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });\n }\n }\n\n /**\n * Abort the current stream and invoke the `onStop` callback\n * if one was provided in the options.\n */\n stop(): void {\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n /**\n * Switch to a different thread. If the thread ID actually changed,\n * the current stream is cleared and listeners are notified.\n *\n * @param newThreadId - The thread ID to switch to, or `null` to clear.\n */\n switchThread(newThreadId: string | null): void {\n if (newThreadId !== this.#threadId) {\n this.#threadId = newThreadId;\n this.#handledHeadlessToolInterruptIds.clear();\n this.stream.clear();\n this.#notify();\n }\n }\n\n /**\n * Start a new stream run against the custom transport.\n *\n * This is the low-level submit entry point that handles thread ID\n * resolution, optimistic value merging, and transport invocation.\n * Prefer {@link submit} unless you need to bypass higher-level wrappers.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides such as\n * `optimisticValues`, `config`, `command`, and error callbacks.\n */\n async submitDirect(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n type UpdateType = GetUpdateType<Bag, StateType>;\n type CustomType = GetCustomEventType<Bag>;\n\n const currentThreadId = this.#options.threadId ?? null;\n if (currentThreadId !== this.#threadId) {\n this.#threadId = currentThreadId;\n this.stream.clear();\n }\n\n let usableThreadId = this.#threadId ?? submitOptions?.threadId;\n\n this.stream.setStreamValues(() => {\n if (submitOptions?.optimisticValues != null) {\n return {\n ...this.#historyValues,\n ...(typeof submitOptions.optimisticValues === \"function\"\n ? submitOptions.optimisticValues(this.#historyValues)\n : submitOptions.optimisticValues),\n };\n }\n\n return { ...this.#historyValues };\n });\n\n await this.stream.start(\n async (signal: AbortSignal) => {\n if (!usableThreadId) {\n usableThreadId = crypto.randomUUID();\n this.#threadId = usableThreadId;\n this.#options.onThreadId?.(usableThreadId);\n }\n\n if (!usableThreadId) {\n throw new Error(\"Failed to obtain valid thread ID.\");\n }\n\n return this.#options.transport.stream({\n input: values,\n context: submitOptions?.context,\n command: submitOptions?.command,\n streamSubgraphs: submitOptions?.streamSubgraphs,\n signal,\n config: {\n ...submitOptions?.config,\n configurable: {\n thread_id: usableThreadId,\n ...submitOptions?.config?.configurable,\n } as unknown as GetConfigurableType<Bag>,\n },\n }) as Promise<\n AsyncGenerator<EventStreamEvent<StateType, UpdateType, CustomType>>\n >;\n },\n {\n getMessages: this.#getMessages,\n setMessages: this.#setMessages,\n initialValues: {} as StateType,\n callbacks: this.#options,\n onSuccess: () => {\n if (!usableThreadId) return undefined;\n\n const finalValues = this.stream.values ?? this.#historyValues;\n this.#options.onFinish?.(\n createCustomTransportThreadState(finalValues, usableThreadId),\n undefined\n );\n\n return undefined;\n },\n onError: (error) => {\n this.#options.onError?.(error, undefined);\n submitOptions?.onError?.(error, undefined);\n },\n }\n );\n }\n\n /**\n * Submit input values and start a new stream run.\n *\n * Delegates to {@link submitDirect}. Override or wrap this method\n * in framework adapters to add queuing or other middleware.\n *\n * @param values - The input values to send, or `null`/`undefined` for\n * a resume-style invocation.\n * @param submitOptions - Optional per-call overrides.\n */\n async submit(\n values: GetUpdateType<Bag, StateType> | null | undefined,\n submitOptions?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>\n ): Promise<void> {\n await this.submitDirect(values, submitOptions);\n }\n\n /**\n * Tear down the orchestrator. Marks the instance as disposed,\n * unsubscribes from the stream, and aborts any in-progress stream.\n * After calling this method, no further notifications will be emitted.\n */\n dispose(): void {\n this.#disposed = true;\n this.#streamUnsub?.();\n this.#streamUnsub = null;\n void this.stream.stop(this.#historyValues, {\n onStop: this.#options.onStop,\n });\n }\n\n #flushPendingHeadlessToolInterrupts(): void {\n flushPendingHeadlessToolInterrupts(\n this.stream.values as Record<string, unknown> | null,\n this.#options.tools,\n this.#handledHeadlessToolInterruptIds,\n {\n onTool: this.#options.onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n this.submit(null, {\n command,\n }),\n }\n );\n }\n}\n"],"mappings":"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"}