@librechat/agents 3.2.59 → 3.2.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/graphs/Graph.cjs +31 -7
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/run.cjs +4 -0
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +95 -10
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +31 -7
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/run.mjs +4 -0
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +95 -10
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +21 -3
- package/dist/types/run.d.ts +1 -0
- package/dist/types/tools/ToolNode.d.ts +57 -1
- package/dist/types/types/hitl.d.ts +49 -3
- package/dist/types/types/run.d.ts +21 -0
- package/dist/types/types/tools.d.ts +37 -1
- package/package.json +4 -4
- package/src/graphs/Graph.ts +74 -28
- package/src/run.ts +4 -0
- package/src/specs/ask-user-question-batch.test.ts +289 -0
- package/src/specs/tool-error-resume.test.ts +194 -0
- package/src/tools/ToolNode.ts +172 -27
- package/src/tools/__tests__/hitl.test.ts +48 -0
- package/src/types/hitl.ts +49 -3
- package/src/types/run.ts +21 -0
- package/src/types/tools.ts +37 -1
package/dist/cjs/run.cjs
CHANGED
|
@@ -74,6 +74,7 @@ var Run = class Run {
|
|
|
74
74
|
toolOutputReferences;
|
|
75
75
|
eagerEventToolExecution;
|
|
76
76
|
codeSessionToolNames;
|
|
77
|
+
interruptingToolNames;
|
|
77
78
|
toolExecution;
|
|
78
79
|
subagentUsageSink;
|
|
79
80
|
indexTokenCountMap;
|
|
@@ -115,6 +116,7 @@ var Run = class Run {
|
|
|
115
116
|
this.toolOutputReferences = config.toolOutputReferences;
|
|
116
117
|
this.eagerEventToolExecution = config.eagerEventToolExecution;
|
|
117
118
|
this.codeSessionToolNames = config.codeSessionToolNames;
|
|
119
|
+
this.interruptingToolNames = config.interruptingToolNames;
|
|
118
120
|
this.toolExecution = config.toolExecution;
|
|
119
121
|
this.subagentUsageSink = config.subagentUsageSink;
|
|
120
122
|
if (!config.graphConfig) throw new Error("Graph config not provided");
|
|
@@ -173,6 +175,7 @@ var Run = class Run {
|
|
|
173
175
|
standardGraph.toolOutputReferences = this.toolOutputReferences;
|
|
174
176
|
standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;
|
|
175
177
|
standardGraph.codeSessionToolNames = this.codeSessionToolNames;
|
|
178
|
+
standardGraph.interruptingToolNames = this.interruptingToolNames;
|
|
176
179
|
standardGraph.toolExecution = this.toolExecution;
|
|
177
180
|
this.Graph = standardGraph;
|
|
178
181
|
return standardGraph.createWorkflow();
|
|
@@ -196,6 +199,7 @@ var Run = class Run {
|
|
|
196
199
|
multiAgentGraph.toolOutputReferences = this.toolOutputReferences;
|
|
197
200
|
multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;
|
|
198
201
|
multiAgentGraph.codeSessionToolNames = this.codeSessionToolNames;
|
|
202
|
+
multiAgentGraph.interruptingToolNames = this.interruptingToolNames;
|
|
199
203
|
multiAgentGraph.toolExecution = this.toolExecution;
|
|
200
204
|
this.Graph = multiAgentGraph;
|
|
201
205
|
return multiAgentGraph.createWorkflow();
|
package/dist/cjs/run.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["HandlerRegistry","StandardGraph","MultiAgentGraph","MemorySaver","executeHooks","HumanMessage","createTokenCounter","encodingForModel","resolveLangfuseConfig","Command","BaseCallbackHandler","appendCallbacks","createLangfuseTraceMetadata","getLangfuseTraceName","createLangfuseHandler","INTERRUPT","withLangfuseRuntimeScope","resolveLangfuseRuntimeScope","withLangfuseAttributes","disposeLangfuseHandler","PromptTemplate","initializeModel","isOpenAILike","ChatOpenAI","AzureChatOpenAI","RunnableLambda","createCompletionTitleRunnable","createTitleRunnable","findCallback","isLangfuseCallbackHandler"],"sources":["../../src/run.ts"],"sourcesContent":["// src/run.ts\nimport { HumanMessage } from '@langchain/core/messages';\nimport { PromptTemplate } from '@langchain/core/prompts';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport {\n Command,\n INTERRUPT,\n MemorySaver,\n isInterrupted,\n} from '@langchain/langgraph';\nimport type {\n MessageContentComplex,\n BaseMessage,\n} from '@langchain/core/messages';\nimport type { StringPromptValue } from '@langchain/core/prompt_values';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type { HookRegistry } from '@/hooks';\nimport type * as t from '@/types';\nimport {\n createLangfuseTraceMetadata,\n createLangfuseHandler,\n disposeLangfuseHandler,\n getLangfuseTraceName,\n isLangfuseCallbackHandler,\n withLangfuseAttributes,\n} from '@/langfuse';\nimport {\n resolveLangfuseRuntimeScope,\n withLangfuseRuntimeScope,\n} from '@/langfuseRuntimeScope';\nimport {\n appendCallbacks,\n findCallback,\n type CallbackEntry,\n} from '@/utils/callbacks';\nimport {\n createCompletionTitleRunnable,\n createTitleRunnable,\n} from '@/utils/title';\nimport { createTokenCounter, encodingForModel } from '@/utils/tokens';\nimport { initializeLangfuseTracing } from './instrumentation';\nimport { GraphEvents, Callback, TitleMethod } from '@/common';\nimport { MultiAgentGraph } from '@/graphs/MultiAgentGraph';\nimport { resolveLangfuseConfig } from '@/langfuseConfig';\nimport { StandardGraph } from '@/graphs/Graph';\nimport { initializeModel } from '@/llm/init';\nimport { HandlerRegistry } from '@/events';\nimport { isOpenAILike } from '@/utils/llm';\nimport { executeHooks } from '@/hooks';\n\nexport const defaultOmitOptions = new Set([\n 'stream',\n 'thinking',\n 'streaming',\n 'maxTokens',\n 'clientOptions',\n 'thinkingConfig',\n 'thinkingBudget',\n 'includeThoughts',\n 'maxOutputTokens',\n 'additionalModelRequestFields',\n]);\n\nconst CUSTOM_GRAPH_EVENTS = new Set<string>([\n GraphEvents.ON_AGENT_UPDATE,\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_RUN_STEP_COMPLETED,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n GraphEvents.ON_TOOL_EXECUTE,\n GraphEvents.ON_SUMMARIZE_START,\n GraphEvents.ON_SUMMARIZE_DELTA,\n GraphEvents.ON_SUMMARIZE_COMPLETE,\n GraphEvents.ON_SUBAGENT_UPDATE,\n GraphEvents.ON_AGENT_LOG,\n GraphEvents.ON_CONTEXT_USAGE,\n GraphEvents.ON_CUSTOM_EVENT,\n]);\n\nconst DIRECT_DISPATCHED_STEP_EVENTS = new Set<string>([\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n]);\n\nfunction getStepScopedEventId(data: unknown): string | undefined {\n if (data == null || typeof data !== 'object') {\n return undefined;\n }\n const candidate = data as { id?: unknown };\n return typeof candidate.id === 'string' ? candidate.id : undefined;\n}\n\nfunction isLangGraphResumeMapForInterrupt(\n value: unknown,\n interruptId: string\n): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(value, interruptId);\n}\n\ntype InterruptStateSnapshot = {\n config?: RunnableConfig;\n tasks?: Array<{\n interrupts?: Array<{ id?: string }>;\n }>;\n};\n\ntype WorkflowWithStateHistory = {\n getStateHistory?(\n config: RunnableConfig\n ): AsyncIterableIterator<InterruptStateSnapshot>;\n};\n\nexport class Run<_T extends t.BaseGraphState> {\n id: string;\n private tokenCounter?: t.TokenCounter;\n private handlerRegistry?: HandlerRegistry;\n private hookRegistry?: HookRegistry;\n private humanInTheLoop?: t.HumanInTheLoopConfig;\n private langfuse?: t.LangfuseConfig;\n private toolOutputReferences?: t.ToolOutputReferencesConfig;\n private eagerEventToolExecution?: t.EagerEventToolExecutionConfig;\n private codeSessionToolNames?: string[];\n private toolExecution?: t.ToolExecutionConfig;\n private subagentUsageSink?: t.SubagentUsageSink;\n private indexTokenCountMap?: Record<string, number>;\n calibrationRatio: number = 1;\n graphRunnable?: t.CompiledStateWorkflow;\n Graph: StandardGraph | MultiAgentGraph | undefined;\n returnContent: boolean = false;\n private skipCleanup: boolean = false;\n /**\n * Whether the compiled graph was built with a checkpointer (host-supplied\n * or the HITL `MemorySaver` fallback). Captured at graph creation because\n * the constructor can later overwrite `Graph.compileOptions` with the raw\n * caller options, dropping the fallback checkpointer from that metadata.\n */\n private hasCheckpointer: boolean = false;\n private _streamResult: t.MessageContentComplex[] | undefined;\n /**\n * Captured interrupt payload typed as `unknown` because the SDK\n * does not validate the runtime shape — custom graph nodes can\n * raise interrupts with arbitrary payloads (not just the SDK's\n * `HumanInterruptPayload` union). The public `getInterrupt<T>()`\n * lets callers assert the type they expect.\n */\n private _interrupt: t.RunInterruptResult<unknown> | undefined;\n private _haltedReason: string | undefined;\n\n private constructor(config: Partial<t.RunConfig>) {\n const runId = config.runId ?? '';\n if (!runId) {\n throw new Error('Run ID not provided');\n }\n\n this.id = runId;\n this.tokenCounter = config.tokenCounter;\n this.indexTokenCountMap = config.indexTokenCountMap;\n if (config.calibrationRatio != null && config.calibrationRatio > 0) {\n this.calibrationRatio = config.calibrationRatio;\n }\n\n const handlerRegistry = new HandlerRegistry();\n\n if (config.customHandlers) {\n for (const [eventType, handler] of Object.entries(\n config.customHandlers\n )) {\n handlerRegistry.register(eventType, handler);\n }\n }\n\n this.handlerRegistry = handlerRegistry;\n this.hookRegistry = config.hooks;\n this.humanInTheLoop = config.humanInTheLoop;\n this.langfuse = config.langfuse;\n this.toolOutputReferences = config.toolOutputReferences;\n this.eagerEventToolExecution = config.eagerEventToolExecution;\n this.codeSessionToolNames = config.codeSessionToolNames;\n this.toolExecution = config.toolExecution;\n this.subagentUsageSink = config.subagentUsageSink;\n\n if (!config.graphConfig) {\n throw new Error('Graph config not provided');\n }\n\n /** Handle different graph types */\n if (config.graphConfig.type === 'multi-agent') {\n this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.handlerRegistry = handlerRegistry;\n }\n } else {\n /** Default to legacy graph for 'standard' or undefined type */\n this.graphRunnable = this.createLegacyGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.compileOptions =\n config.graphConfig.compileOptions ?? this.Graph.compileOptions;\n this.Graph.handlerRegistry = handlerRegistry;\n }\n }\n\n if (config.initialSessions && this.Graph) {\n for (const [key, value] of config.initialSessions) {\n this.Graph.sessions.set(key, value);\n }\n }\n\n this.returnContent = config.returnContent ?? false;\n this.skipCleanup = config.skipCleanup ?? false;\n }\n\n private createLegacyGraph(\n config: t.LegacyGraphConfig | t.StandardGraphConfig\n ): t.CompiledStateWorkflow {\n let agentConfig: t.AgentInputs;\n let signal: AbortSignal | undefined;\n\n /** Check if this is a multi-agent style config (has agents array) */\n if ('agents' in config && Array.isArray(config.agents)) {\n if (config.agents.length === 0) {\n throw new Error('At least one agent must be provided');\n }\n agentConfig = config.agents[0];\n signal = config.signal;\n } else {\n /** Legacy path: build agent config from llmConfig */\n const {\n type: _type,\n llmConfig,\n signal: legacySignal,\n tools = [],\n ...agentInputs\n } = config as t.LegacyGraphConfig;\n const { provider, ...clientOptions } = llmConfig;\n\n agentConfig = {\n ...agentInputs,\n tools,\n provider,\n clientOptions,\n agentId: 'default',\n };\n signal = legacySignal;\n }\n\n const standardGraph = new StandardGraph({\n signal,\n runId: this.id,\n agents: [agentConfig],\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n /** Propagate compile options from graph config */\n standardGraph.compileOptions = this.applyHITLCheckpointerFallback(\n config.compileOptions\n );\n this.hasCheckpointer = standardGraph.compileOptions?.checkpointer != null;\n standardGraph.hookRegistry = this.hookRegistry;\n standardGraph.humanInTheLoop = this.humanInTheLoop;\n standardGraph.toolOutputReferences = this.toolOutputReferences;\n standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n standardGraph.codeSessionToolNames = this.codeSessionToolNames;\n standardGraph.toolExecution = this.toolExecution;\n this.Graph = standardGraph;\n return standardGraph.createWorkflow();\n }\n\n private createMultiAgentGraph(\n config: t.MultiAgentGraphConfig\n ): t.CompiledStateWorkflow {\n const { agents, edges, compileOptions } = config;\n\n const multiAgentGraph = new MultiAgentGraph({\n runId: this.id,\n agents,\n edges,\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n\n multiAgentGraph.compileOptions =\n this.applyHITLCheckpointerFallback(compileOptions);\n this.hasCheckpointer = multiAgentGraph.compileOptions?.checkpointer != null;\n\n multiAgentGraph.hookRegistry = this.hookRegistry;\n multiAgentGraph.humanInTheLoop = this.humanInTheLoop;\n multiAgentGraph.toolOutputReferences = this.toolOutputReferences;\n multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n multiAgentGraph.codeSessionToolNames = this.codeSessionToolNames;\n multiAgentGraph.toolExecution = this.toolExecution;\n this.Graph = multiAgentGraph;\n return multiAgentGraph.createWorkflow();\n }\n\n /**\n * When the host opted into HITL via `humanInTheLoop: { enabled: true }`\n * and did not supply a checkpointer, install an in-memory `MemorySaver`\n * so `interrupt()` can persist checkpoints and `Command({ resume })`\n * can rebuild state. The fallback is intentionally process-local:\n * production hosts that need durable resumption across processes /\n * restarts must provide their own checkpointer (Redis, Postgres, etc.)\n * on `compileOptions.checkpointer`.\n *\n * No-op when HITL is off (the default — omitted, or\n * `{ enabled: false }`) or the host already supplied a checkpointer\n * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale\n * behind the default-off stance.\n */\n private applyHITLCheckpointerFallback(\n compileOptions: t.CompileOptions | undefined\n ): t.CompileOptions | undefined {\n if (this.humanInTheLoop?.enabled !== true) {\n return compileOptions;\n }\n if (compileOptions?.checkpointer != null) {\n return compileOptions;\n }\n return {\n ...(compileOptions ?? {}),\n checkpointer: new MemorySaver(),\n };\n }\n\n /**\n * Run RunStart + UserPromptSubmit hooks before the graph stream\n * begins, accumulate any `additionalContext` strings into the input\n * messages, and short-circuit when a hook signals the run should not\n * proceed (deny / ask decision on the prompt, or `preventContinuation`\n * on either hook).\n *\n * Returns `true` when the caller should bail with `undefined` (run\n * was halted before any model call); returns `false` to proceed\n * into the stream loop.\n *\n * ## Side effects\n *\n * On the success path:\n * - Mutates `stateInputs.messages` in place to append a\n * consolidated `HumanMessage` carrying any hook\n * `additionalContext` strings. Safe because the host owns the\n * array and `processStream` is the only consumer until LangGraph\n * reads it.\n *\n * On the halt path (returning `true`):\n * - Sets `this._haltedReason` so callers (and the eventual host)\n * can distinguish a hook-driven halt from a natural completion.\n * - Calls `registry.clearSession(this.id)` and\n * `registry.clearHaltSignal(this.id)` because no resume is\n * expected from a pre-stream halt — the run never entered the\n * graph, so the session/halt state for this run would otherwise\n * leak to the next `processStream` invocation on the same\n * registry. Other concurrent runs on the same registry are\n * untouched (halt signals are scoped per session id).\n * - Sets `config.callbacks = undefined` to drop the callback\n * references the caller built (langfuse handler, custom event\n * handler, etc.) since they won't be exercised. Mirrors the\n * equivalent cleanup the `processStream` `finally` block does\n * on the natural-completion path.\n */\n private async runPreStreamHooks(\n stateInputs: t.IState,\n threadId: string | undefined,\n config: Partial<RunnableConfig>\n ): Promise<boolean> {\n const registry = this.hookRegistry;\n /**\n * Defensive guard: `processStream` already validated `this.Graph`\n * before calling this helper, but TypeScript can't propagate that\n * narrowing across method boundaries. The check keeps the body\n * free of `this.Graph!` non-null assertions.\n */\n if (registry == null || this.Graph == null) {\n return false;\n }\n\n const preStreamContexts: string[] = [];\n\n const runStartResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'RunStart',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n messages: stateInputs.messages,\n },\n sessionId: this.id,\n });\n for (const ctx of runStartResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n /**\n * Honor `preventContinuation` from RunStart before the stream\n * starts. Mid-flight halts (from tool/compact/subagent hooks)\n * route through `HookRegistry.haltRun` and are polled by the\n * stream loop in `processStream` — different mechanism, same\n * intent.\n */\n if (runStartResult.preventContinuation === true) {\n this._haltedReason = runStartResult.stopReason ?? 'preventContinuation';\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n\n const lastHuman = findLastMessageOfType(stateInputs.messages, 'human');\n if (lastHuman != null) {\n const promptResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'UserPromptSubmit',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n prompt: extractPromptText(lastHuman),\n // attachments: not yet wired — Phase 2 will extract\n // non-text content blocks (images, files) from messages\n },\n sessionId: this.id,\n });\n if (\n promptResult.decision === 'deny' ||\n promptResult.decision === 'ask' ||\n promptResult.preventContinuation === true\n ) {\n /**\n * Always set `_haltedReason` so the host can call\n * `getHaltReason()` and distinguish a hook-blocked prompt\n * from a natural empty-output completion. Three signals can\n * land here, each with its own canonical reason string when\n * the hook didn't supply one.\n */\n if (promptResult.preventContinuation === true) {\n this._haltedReason = promptResult.stopReason ?? 'preventContinuation';\n } else if (promptResult.decision === 'deny') {\n this._haltedReason = promptResult.reason ?? 'prompt_denied';\n } else {\n this._haltedReason =\n promptResult.reason ?? 'prompt_requires_approval';\n }\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n for (const ctx of promptResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n }\n\n if (preStreamContexts.length > 0) {\n /**\n * Wraps the joined hook contexts as a `HumanMessage` even though\n * the intent is system-level guidance. Using a `SystemMessage`\n * mid-conversation is rejected by Anthropic and Google providers\n * (system messages must be the leading entry), so the LangChain\n * convention — also used by `ToolNode.convertInjectedMessages`\n * — is `HumanMessage` carrying `additional_kwargs.role` as a\n * marker for hosts inspecting state. The model still sees a\n * user-role message; the `role: 'system'` field is metadata\n * only. Hosts that want a true system message should compose\n * it into the agent's `instructions` config instead.\n */\n stateInputs.messages.push(\n new HumanMessage({\n content: preStreamContexts.join('\\n\\n'),\n additional_kwargs: { role: 'system', source: 'hook' },\n })\n );\n }\n\n return false;\n }\n\n static async create<T extends t.BaseGraphState>(\n config: t.RunConfig\n ): Promise<Run<T>> {\n /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */\n if (config.indexTokenCountMap && !config.tokenCounter) {\n const gc = config.graphConfig;\n const clientOpts =\n 'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;\n const model = (clientOpts as { model?: string } | undefined)?.model ?? '';\n config.tokenCounter = await createTokenCounter(encodingForModel(model));\n }\n return new Run<T>(config);\n }\n\n getRunMessages(): BaseMessage[] | undefined {\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n return this.Graph.getRunMessages();\n }\n\n /**\n * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).\n * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`\n * on the next run for the same conversation so the pruner starts with an accurate\n * scaling factor instead of the default (1).\n */\n getCalibrationRatio(): number {\n return this.calibrationRatio;\n }\n\n getResolvedInstructionOverhead(): number | undefined {\n return this.Graph?.getResolvedInstructionOverhead();\n }\n\n getToolCount(): number {\n return this.Graph?.getToolCount() ?? 0;\n }\n\n /**\n * Creates a custom event callback handler that intercepts custom events\n * and processes them through our handler registry instead of EventStreamCallbackHandler\n */\n private createCustomEventCallback() {\n return async (\n eventName: string,\n data: unknown,\n runId: string,\n tags?: string[],\n metadata?: Record<string, unknown>\n ): Promise<void> => {\n // Step-scoped SDK events are dispatched directly via the handler\n // registry first. Skip callback-based echoes to prevent double\n // handling when LangGraph invokes custom callbacks more than once.\n const stepScopedEventId = getStepScopedEventId(data);\n if (\n DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) &&\n this.Graph != null &&\n stepScopedEventId != null &&\n this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)\n ) {\n return;\n }\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler && this.Graph) {\n return await handler.handle(\n eventName,\n data as\n | t.StreamEventData\n | t.ModelEndData\n | t.RunStep\n | t.RunStepDeltaEvent\n | t.MessageDeltaEvent\n | t.ReasoningDeltaEvent\n | { result: t.ToolEndEvent },\n metadata,\n this.Graph\n );\n }\n };\n }\n\n private shouldClearHookSession(streamThrew: boolean): boolean {\n return this._interrupt == null || this._haltedReason != null || streamThrew;\n }\n\n private isAwaitingResume(streamThrew: boolean): boolean {\n return (\n this._interrupt != null && this._haltedReason == null && !streamThrew\n );\n }\n\n private getStreamLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n if (primaryContext != null) {\n return resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);\n }\n\n for (const context of graph.agentContexts.values()) {\n const langfuse = resolveLangfuseConfig(this.langfuse, context.langfuse);\n if (langfuse != null) {\n return langfuse;\n }\n }\n\n return this.langfuse;\n }\n\n private getStreamToolOutputTracingLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const toolOutputTracingConfigs = Array.from(graph.agentContexts.values())\n .map((context) => {\n return resolveLangfuseConfig(this.langfuse, context.langfuse)\n ?.toolOutputTracing;\n })\n .filter((config): config is t.LangfuseToolOutputTracingConfig => {\n return config != null;\n });\n\n if (toolOutputTracingConfigs.length === 0) {\n return this.langfuse?.toolOutputTracing != null\n ? { toolOutputTracing: this.langfuse.toolOutputTracing }\n : undefined;\n }\n if (toolOutputTracingConfigs.length === 1) {\n return { toolOutputTracing: toolOutputTracingConfigs[0] };\n }\n\n let enabled: boolean | undefined;\n let redactionText: string | undefined;\n let redactedToolNameMatchMode: 'exact' | 'partial' | undefined;\n const redactedToolNames = new Set<string>();\n\n for (const config of toolOutputTracingConfigs) {\n if (config.enabled === false) {\n enabled = false;\n } else if (enabled !== false && config.enabled != null) {\n enabled = config.enabled;\n }\n\n redactionText ??= config.redactionText;\n if (config.redactedToolNameMatchMode === 'partial') {\n redactedToolNameMatchMode = 'partial';\n } else {\n redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;\n }\n\n for (const toolName of config.redactedToolNames ?? []) {\n redactedToolNames.add(toolName);\n }\n }\n\n return {\n toolOutputTracing: {\n ...(enabled != null ? { enabled } : {}),\n ...(redactedToolNames.size > 0\n ? { redactedToolNames: Array.from(redactedToolNames) }\n : {}),\n ...(redactedToolNameMatchMode != null\n ? { redactedToolNameMatchMode }\n : {}),\n ...(redactionText != null ? { redactionText } : {}),\n },\n };\n }\n\n async processStream(\n inputs: t.IState | Command,\n callerConfig: t.RunStreamConfig,\n streamOptions?: t.EventStreamOptions\n ): Promise<MessageContentComplex[] | undefined> {\n if (this.graphRunnable == null) {\n throw new Error(\n 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n const graphRunnable = this.graphRunnable;\n const graph = this.Graph;\n\n /**\n * `Command` inputs (`Command({ resume, update?, goto? })`) are\n * resume-mode invocations: LangGraph rebuilds graph state from the\n * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no\n * new prompt to evaluate) and read run-state from the Graph wrapper\n * instead of `inputs.messages`.\n */\n const isResume = inputs instanceof Command;\n const stateInputs = isResume ? undefined : (inputs as t.IState);\n\n const config: t.RunStreamConfig = {\n recursionLimit: 50,\n ...callerConfig,\n configurable: { ...callerConfig.configurable },\n };\n\n /**\n * Skip `resetValues` on resume — we're continuing an in-flight\n * run, not starting a fresh one. Resetting would wipe the\n * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated\n * `messages`, etc.) the resumed `ToolNode` needs to dispatch\n * tool completions with the correct step ids and re-resolve\n * `{{tool<i>turn<n>}}` references. Pairs with the\n * `awaitingResume` gate on `clearHeavyState` in the `finally`\n * block so the sidecars survive both ends of the interrupt\n * boundary.\n */\n if (!isResume) {\n graph.resetValues(streamOptions?.keepContent);\n }\n this._interrupt = undefined;\n this._haltedReason = undefined;\n this.hookRegistry?.clearHaltSignal(this.id);\n\n /** Custom event callback to intercept and handle custom events */\n const customEventCallback = this.createCustomEventCallback();\n\n const streamCallbacks = streamOptions?.callbacks\n ? this.getCallbacks(streamOptions.callbacks)\n : undefined;\n\n const customHandler = BaseCallbackHandler.fromMethods({\n [Callback.CUSTOM_EVENT]: customEventCallback,\n });\n customHandler.awaitHandlers = true;\n\n config.callbacks = appendCallbacks(\n config.callbacks,\n streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]\n );\n\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n const userId =\n typeof config.configurable?.user_id === 'string'\n ? config.configurable.user_id\n : undefined;\n const sessionId =\n typeof config.configurable?.thread_id === 'string'\n ? config.configurable.thread_id\n : undefined;\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: this.id,\n parentMessageId: config.configurable?.requestBody?.parentMessageId,\n agentId: graph.defaultAgentId,\n agentName: primaryContext?.name,\n });\n const traceName = config.runName ?? getLangfuseTraceName(traceMetadata);\n const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);\n initializeLangfuseTracing(streamLangfuseConfig);\n const langfuseHandler = createLangfuseHandler({\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceMetadata,\n tags: ['librechat', 'agent'],\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n });\n if (langfuseHandler != null) {\n config.runName = traceName;\n config.callbacks = appendCallbacks(config.callbacks, [langfuseHandler]);\n }\n\n if (!this.id) {\n throw new Error('Run ID not provided');\n }\n\n config.run_id = this.id;\n config.configurable = Object.assign(config.configurable ?? {}, {\n run_id: this.id,\n });\n\n /**\n * Default `durability: 'exit'` whenever a checkpointer is active so\n * runs skip per-superstep checkpoint writes and persist only at the\n * exit/interrupt boundary (all HITL/resume needs). An explicit caller\n * value wins; no checkpointer leaves it unset (langgraph default).\n */\n if (config.durability == null && this.hasCheckpointer) {\n config.durability = 'exit';\n }\n\n const threadId = config.configurable.thread_id as string | undefined;\n\n if (this.hookRegistry != null && stateInputs != null) {\n const shouldHalt = await this.runPreStreamHooks(\n stateInputs,\n threadId,\n config\n );\n if (shouldHalt) {\n return undefined;\n }\n }\n\n /**\n * Tracks whether the stream loop threw. Used by the `finally`\n * block to decide whether to honor the interrupt-preservation\n * guard for session hooks: a captured `_interrupt` is only\n * meaningful if the stream completed cleanly. If the loop errored\n * after stashing an interrupt (e.g. a downstream handler throws\n * after the interrupt event landed), the interrupt is stale —\n * preserving session hooks would leak them into the next run.\n */\n let streamThrew = false;\n\n const consumeStream = async (): Promise<void> => {\n /**\n * `streamEvents` accepts both state inputs and `Command` (resume) at\n * runtime, but our `CompiledStateWorkflow` type narrows the first\n * arg to `BaseGraphState`. Cast on the call so the resume path\n * type-checks without widening the wrapper for every caller.\n */\n const stream = graphRunnable.streamEvents(inputs as t.IState, config, {\n raiseError: true,\n /**\n * Prevent EventStreamCallbackHandler from processing custom events.\n * Custom events are already handled via our createCustomEventCallback()\n * which routes them through the handlerRegistry.\n * Without this flag, EventStreamCallbackHandler throws errors when\n * custom events are dispatched for run IDs not in its internal map\n * (due to timing issues in parallel execution or after run cleanup).\n */\n ignoreCustomEvent: true,\n });\n\n for await (const event of stream) {\n const { data, metadata, ...info } = event;\n\n const eventName: t.EventName = info.event;\n\n /** Skip custom events as they're handled by our callback */\n if (CUSTOM_GRAPH_EVENTS.has(eventName)) {\n continue;\n }\n\n /**\n * Detect interrupts surfaced by LangGraph as a synthetic\n * `__interrupt__` field on the streamed chunk and stash the\n * first one for the host to read via `run.getInterrupt()`\n * once the stream drains. Captured as `unknown` because the\n * SDK does not validate the runtime payload shape — the\n * built-in ToolNode raises a `HumanInterruptPayload`\n * (`tool_approval` / `ask_user_question`), but custom nodes\n * can pass any payload to `interrupt()`. Callers narrow with\n * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`\n * guards or assert via `getInterrupt<T>()`.\n */\n if (\n this._interrupt == null &&\n data.chunk != null &&\n isInterrupted<unknown>(data.chunk)\n ) {\n const interrupts = data.chunk[INTERRUPT];\n if (interrupts.length > 0) {\n const first = interrupts[0];\n /**\n * Capture the interrupt unconditionally — `interrupt(null)`\n * and `interrupt(undefined)` are valid pauses (a custom\n * node may want to pause without metadata) and the host\n * still needs to know the run is awaiting resume. Gating\n * on `payload != null` would silently downgrade a paused\n * run to \"completed\" and let the `Stop` hook fire,\n * breaking host resume handling.\n */\n this._interrupt = {\n interruptId: first.id ?? '',\n threadId,\n payload: first.value,\n };\n }\n }\n\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler) {\n await handler.handle(eventName, data, metadata, this.Graph);\n }\n\n /**\n * Mid-flight halt: any hook (PreToolUse, PostToolUse,\n * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)\n * that returned `preventContinuation: true` raises a halt\n * signal on the registry via `executeHooks`. We poll between\n * stream events and break out as soon as one is set so the\n * graph doesn't take another model turn after the halting\n * operation completes.\n *\n * Limitation: the current step (in-flight model call, ongoing\n * tool batch) is not aborted — only the next step is skipped.\n * This matches Claude Code's `continue: false` semantic where\n * the active operation finishes before halting takes effect.\n */\n const haltSignal = this.hookRegistry?.getHaltSignal(this.id);\n if (haltSignal != null) {\n this._haltedReason = haltSignal.reason;\n break;\n }\n }\n\n if (this._interrupt != null) {\n await this.resolveInterruptResumeConfig(config);\n }\n\n /**\n * Skip the Stop hook when the run paused on a HITL interrupt\n * (still pending human input) or was halted by a hook (the host\n * already chose to stop, so a Stop hook firing now would be\n * misleading). The host fires Stop on the resumed-and-completed\n * run instead.\n */\n if (\n this._interrupt == null &&\n this._haltedReason == null &&\n this.hookRegistry?.hasHookFor('Stop', this.id) === true\n ) {\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'Stop',\n runId: this.id,\n threadId,\n agentId: graph.defaultAgentId,\n messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],\n stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)\n },\n sessionId: this.id,\n }).catch(() => {\n /* Stop hook errors must not masquerade as stream failures */\n });\n }\n };\n\n try {\n // When opted in, seed the root trace id from this run's id so feedback /\n // other external signals can be attached to the trace later without a\n // lookup (see SeededTraceIdGenerator in ./instrumentation).\n await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: streamLangfuseConfig,\n langfuseOverlay: this.getStreamToolOutputTracingLangfuseConfig(graph),\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n }),\n () =>\n withLangfuseAttributes(\n {\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceName,\n traceMetadata,\n tags: ['librechat', 'agent'],\n },\n consumeStream\n )\n );\n } catch (err) {\n streamThrew = true;\n if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {\n const runMessages = this.Graph.getRunMessages() ?? [];\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'StopFailure',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n error: err instanceof Error ? err.message : String(err),\n lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),\n },\n sessionId: this.id,\n }).catch(() => {\n /* swallow hook errors — the original error must propagate */\n });\n }\n throw err;\n } finally {\n /**\n * Preserve session-scoped hooks when the run paused on a HITL\n * interrupt — the very next call will be `Run.resume()`, which\n * needs the same policy hooks (e.g., the `PreToolUse` matcher\n * that triggered the interrupt) to fire on the re-executed node\n * and uphold the approval flow. Clearing here would leak the\n * approval gate on resume. The session is cleared instead at\n * natural completion, error (including errors that happen AFTER\n * an interrupt was captured — those interrupts are stale), or\n * hook-driven halt (including hooks that returned BOTH `ask`\n * and `preventContinuation` — the halt wins, no resume is\n * expected, sessions must drop). Every state where no resume\n * is expected clears.\n */\n if (this.shouldClearHookSession(streamThrew)) {\n this.hookRegistry?.clearSession(this.id);\n }\n /**\n * Drop any halt signal raised mid-stream for this run so a\n * subsequent `processStream` / `resume` starts with clean state.\n * The Run captured `_haltedReason` already; the registry entry\n * for this `sessionId` would otherwise spuriously trip the next\n * loop. Other concurrent runs sharing this registry are\n * unaffected — their entries live under their own session ids.\n */\n this.hookRegistry?.clearHaltSignal(this.id);\n await disposeLangfuseHandler(langfuseHandler);\n\n /**\n * Break the reference chain that keeps heavy data alive via\n * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →\n * `@langchain/core` `RunTree.extra[lc:child_config]` →\n * Node.js `AsyncLocalStorage` context captured by timers/promises.\n *\n * Without this, base64-encoded images/PDFs in message content remain\n * reachable from lingering `Timeout` handles until GC runs.\n */\n if (!this.skipCleanup) {\n if (\n (config.configurable as Record<string, unknown> | undefined) != null\n ) {\n for (const key of Object.getOwnPropertySymbols(config.configurable)) {\n const val = config.configurable[key as unknown as string] as\n | Record<string, unknown>\n | undefined;\n if (\n val != null &&\n typeof val === 'object' &&\n 'currentTaskInput' in val\n ) {\n (val as Record<string, unknown>).currentTaskInput = undefined;\n }\n delete config.configurable[key as unknown as string];\n }\n config.configurable = undefined;\n }\n config.callbacks = undefined;\n }\n\n const result = this.returnContent\n ? this.Graph.getContentParts()\n : undefined;\n\n this.calibrationRatio = this.Graph.getCalibrationRatio();\n\n /**\n * Skip `clearHeavyState()` when the run paused on a clean HITL\n * interrupt awaiting resume — `Run.resume()` re-enters the same\n * `ToolNode` instance and needs the sidecars `clearHeavyState`\n * would wipe (`toolCallStepIds` for completion-event step ids,\n * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`\n * substitutions, `sessions` for code-env continuity, plus the\n * `hookRegistry` and `humanInTheLoop` config the interrupt\n * branch itself relies on). Without preservation, the resumed\n * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with\n * an empty step id and downstream stream consumers would drop\n * the result.\n *\n * The natural-completion / error / hook-driven-halt paths still\n * clean up — `_haltedReason != null` or `streamThrew` mean no\n * resume is expected. Cross-process resume (host rebuilds the\n * Run from scratch) is a separate concern; see\n * `HumanInTheLoopConfig` JSDoc.\n */\n const awaitingResume = this.isAwaitingResume(streamThrew);\n if (!this.skipCleanup && !awaitingResume) {\n this.Graph.clearHeavyState();\n }\n\n this._streamResult = result;\n }\n\n return this._streamResult;\n }\n\n /**\n * Returns the pending interrupt captured during the most recent\n * `processStream` (or `resume`) invocation. `undefined` when the run\n * either has not been streamed yet or completed without pausing.\n *\n * Hosts call this immediately after `processStream` returns to decide\n * whether the run is awaiting human input. Persist the returned\n * descriptor (alongside `thread_id` and the agent run config) so a\n * later `resume(decisions)` can rebuild the run.\n *\n * The default `TPayload` is the SDK's `HumanInterruptPayload` union\n * (`tool_approval` / `ask_user_question`), suitable for the common\n * case where interrupts come from the built-in ToolNode or\n * `askUserQuestion()` helper. Hosts that raise custom interrupts\n * from custom graph nodes pass their own type — the SDK does not\n * validate the runtime shape, it just transports whatever the\n * `interrupt()` call carried. When in doubt, narrow with the\n * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type\n * guards (which accept `unknown`) before reading variant-specific\n * fields.\n */\n getInterrupt<TPayload = t.HumanInterruptPayload>():\n | t.RunInterruptResult<TPayload>\n | undefined {\n return this._interrupt as t.RunInterruptResult<TPayload> | undefined;\n }\n\n /**\n * Returns the reason a hook halted the run via\n * `preventContinuation: true`, or `undefined` if no hook halted.\n *\n * Hosts inspect this after `processStream` returns to distinguish a\n * natural completion (`undefined`) from a hook-driven halt (a\n * truthy string). Independent from `getInterrupt()` — a halted run\n * has no interrupt; an interrupted run has no halt reason.\n */\n getHaltReason(): string | undefined {\n return this._haltedReason;\n }\n\n /**\n * Resume a paused HITL run with the value the user (or whatever\n * decided the interrupt) supplied. The default `TResume` covers the\n * `tool_approval` interrupt (the common case): an array of decisions\n * in `action_requests` order, or a record keyed by `tool_call_id`.\n *\n * For other interrupt types (e.g., `ask_user_question` →\n * `AskUserQuestionResolution`, or any custom interrupt a host raises\n * from a custom node), pass the type parameter and the SDK forwards\n * the value through unchanged. LangGraph delivers it as the return\n * value of the original `interrupt()` call inside the paused node.\n *\n * The host MUST construct this Run with the same `thread_id` and the\n * same checkpointer as the original paused run; LangGraph rebuilds\n * graph state from the checkpoint and re-enters the interrupted node\n * from the start.\n */\n /**\n * Returns the per-Run file checkpointer when\n * `toolExecution.local.fileCheckpointing === true` was set on the\n * RunConfig. Hosts can capture extra paths or call `rewind()`\n * directly. Returns undefined when checkpointing is disabled.\n *\n * Construction-time invariant: the checkpointer is shared across\n * every ToolNode the graph compiles (single-agent and multi-agent),\n * so a `rewind()` call here unwinds writes made by ANY agent in the\n * run.\n */\n getFileCheckpointer(): t.LocalFileCheckpointer | undefined {\n return this.Graph?.getOrCreateFileCheckpointer();\n }\n\n /**\n * Convenience wrapper that calls `rewind()` on the per-Run file\n * checkpointer. Restores every file the local engine snapshotted\n * during this Run to its pre-write content (and deletes any path\n * that didn't exist before being created). Returns the count of\n * paths processed; returns 0 when checkpointing is disabled.\n */\n async rewindFiles(): Promise<number> {\n const cp = this.getFileCheckpointer();\n return cp == null ? 0 : cp.rewind();\n }\n\n /**\n * Resume an interrupted run. `commandOptions` forwards langgraph 1.4.5\n * `Command` fields applied together with `resume` in one superstep:\n * - `update`: channel updates committed at the resume point. On a *rebuilt*\n * Run (new instance + durable checkpointer), `update.messages` are the first\n * write the fresh wrapper sees, so they seed the `getRunMessages()` /\n * `returnContent` baseline and are excluded from them (still committed to the\n * checkpoint). Hosts that rebuild + inject messages should persist them\n * directly or read from `getState`. Unreachable without a durable checkpointer.\n * - `goto`: a *dynamic* edge that does not cancel static `addEdge` routes. On\n * the built-in standard graph the fixed `toolNode -> agentNode/END` edge still\n * fires, so `goto` adds rather than replaces (e.g. `goto: END` will not stop a\n * tool-node resume). Intended for custom, Command-routed graphs.\n */\n async resume<TResume = t.ToolApprovalDecision[] | t.ToolApprovalDecisionMap>(\n resumeValue: TResume,\n callerConfig: t.RunStreamConfig,\n streamOptions?: t.EventStreamOptions,\n commandOptions?: Pick<\n ConstructorParameters<typeof Command>[0],\n 'update' | 'goto'\n >\n ): Promise<MessageContentComplex[] | undefined> {\n const interruptId = this._interrupt?.interruptId;\n const scopedResume =\n typeof interruptId === 'string' &&\n interruptId.length > 0 &&\n !isLangGraphResumeMapForInterrupt(resumeValue, interruptId)\n ? { [interruptId]: resumeValue }\n : resumeValue;\n const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);\n // langgraph 1.4.5 applies resume + state update + reroute in one superstep\n // (single checkpoint). `update`/`goto` are omitted unless the caller sets them.\n return this.processStream(\n new Command({\n resume: scopedResume,\n ...(commandOptions?.update !== undefined\n ? { update: commandOptions.update }\n : {}),\n ...(commandOptions?.goto !== undefined\n ? { goto: commandOptions.goto }\n : {}),\n }),\n resumeConfig,\n streamOptions\n );\n }\n\n private async resolveInterruptResumeConfig(\n callerConfig: t.RunStreamConfig\n ): Promise<t.RunStreamConfig> {\n const interrupt = this._interrupt;\n const interruptId = interrupt?.interruptId;\n const workflow = this.graphRunnable as\n | (t.CompiledStateWorkflow & WorkflowWithStateHistory)\n | undefined;\n const stateHistory = workflow?.getStateHistory;\n if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) {\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: interrupt.checkpointId,\n ...(typeof interrupt.checkpointNs === 'string'\n ? { checkpoint_ns: interrupt.checkpointNs }\n : {}),\n },\n };\n }\n if (\n interrupt == null ||\n typeof interruptId !== 'string' ||\n interruptId.length === 0 ||\n typeof stateHistory !== 'function'\n ) {\n return callerConfig;\n }\n\n for await (const snapshot of stateHistory.call(\n this.graphRunnable,\n callerConfig as RunnableConfig\n )) {\n const hasMatchingInterrupt =\n snapshot.tasks?.some(\n (task) =>\n task.interrupts?.some(\n (interrupt) => interrupt.id === interruptId\n ) === true\n ) === true;\n const checkpointConfigurable = snapshot.config?.configurable;\n if (!hasMatchingInterrupt || checkpointConfigurable == null) {\n continue;\n }\n\n const checkpointId = checkpointConfigurable.checkpoint_id;\n const checkpointNs = checkpointConfigurable.checkpoint_ns;\n if (typeof checkpointId === 'string' && checkpointId.length > 0) {\n this._interrupt = {\n ...interrupt,\n checkpointId,\n ...(typeof checkpointNs === 'string' ? { checkpointNs } : {}),\n };\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: checkpointId,\n ...(typeof checkpointNs === 'string'\n ? { checkpoint_ns: checkpointNs }\n : {}),\n },\n };\n }\n }\n\n return callerConfig;\n }\n\n private createSystemCallback<K extends keyof t.ClientCallbacks>(\n clientCallbacks: t.ClientCallbacks,\n key: K\n ): t.SystemCallbacks[K] {\n return ((...args: unknown[]) => {\n const clientCallback = clientCallbacks[key];\n if (clientCallback && this.Graph) {\n (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);\n }\n }) as t.SystemCallbacks[K];\n }\n\n getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {\n return {\n [Callback.TOOL_ERROR]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_ERROR\n ),\n [Callback.TOOL_START]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_START\n ),\n [Callback.TOOL_END]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_END\n ),\n };\n }\n\n async generateTitle({\n provider,\n inputText,\n contentParts,\n titlePrompt,\n clientOptions,\n chainOptions,\n skipLanguage,\n titleMethod = TitleMethod.COMPLETION,\n titlePromptTemplate,\n }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {\n let titleLangfuseHandler: CallbackEntry | undefined;\n let titleLangfuseConfig: t.LangfuseConfig | undefined;\n let titleUserId: string | undefined;\n let titleSessionId: string | undefined;\n const titleContext =\n this.Graph == null\n ? undefined\n : this.Graph.agentContexts.get(this.Graph.defaultAgentId);\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: 'title-' + this.id,\n agentName: titleContext?.name,\n });\n const titleRunName = getLangfuseTraceName(traceMetadata, 'LibreChat Title');\n\n if (chainOptions != null) {\n titleUserId =\n typeof chainOptions.configurable?.user_id === 'string'\n ? chainOptions.configurable.user_id\n : undefined;\n titleSessionId =\n typeof chainOptions.configurable?.thread_id === 'string'\n ? chainOptions.configurable.thread_id\n : undefined;\n titleLangfuseConfig = resolveLangfuseConfig(\n this.langfuse,\n titleContext?.langfuse\n );\n initializeLangfuseTracing(titleLangfuseConfig);\n titleLangfuseHandler = createLangfuseHandler({\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceMetadata,\n tags: ['librechat', 'title'],\n traceIdSeed:\n titleLangfuseConfig?.deterministicTraceId === true\n ? 'title-' + this.id\n : undefined,\n });\n\n if (titleLangfuseHandler != null) {\n chainOptions.callbacks = appendCallbacks(chainOptions.callbacks, [\n titleLangfuseHandler,\n ]);\n }\n }\n\n const convoTemplate = PromptTemplate.fromTemplate(\n titlePromptTemplate ?? 'User: {input}\\nAI: {output}'\n );\n\n const response = contentParts\n .map((part) => {\n if (part?.type === 'text') return part.text;\n return '';\n })\n .join('\\n');\n\n const model = initializeModel({\n provider,\n clientOptions,\n }) as t.ChatModelInstance;\n\n if (\n isOpenAILike(provider) &&\n (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)\n ) {\n model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.temperature as number;\n model.topP = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.topP as number;\n model.frequencyPenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.frequencyPenalty as number;\n model.presencePenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.presencePenalty as number;\n model.n = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.n as number;\n }\n\n const convoToTitleInput = new RunnableLambda({\n func: (\n promptValue: StringPromptValue\n ): { convo: string; inputText: string; skipLanguage?: boolean } => ({\n convo: promptValue.value,\n inputText,\n skipLanguage,\n }),\n }).withConfig({ runName: 'PrepareTitleInput' });\n\n const titleChain =\n titleMethod === TitleMethod.COMPLETION\n ? await createCompletionTitleRunnable(model, titlePrompt)\n : await createTitleRunnable(model, titlePrompt);\n\n /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */\n const fullChain = convoTemplate\n .withConfig({ runName: 'FormatConversation' })\n .pipe(convoToTitleInput)\n .pipe(titleChain)\n .withConfig({ runName: 'GenerateConversationTitle' });\n\n const invokeConfig = Object.assign({}, chainOptions, {\n run_id: this.id,\n runId: this.id,\n runName: chainOptions?.runName ?? titleRunName,\n });\n\n const invokeTitleChain = (\n runtimeConfig: Partial<RunnableConfig>\n ): Promise<{ language?: string; title?: string }> =>\n withLangfuseAttributes(\n {\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceName: runtimeConfig.runName ?? titleRunName,\n traceMetadata,\n tags: ['librechat', 'title'],\n },\n () =>\n fullChain.invoke(\n { input: inputText, output: response },\n runtimeConfig\n )\n );\n\n try {\n try {\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(invokeConfig)\n );\n } catch (_e) {\n // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments\n // but preserve Langfuse tracing if it exists.\n const langfuseHandler = findCallback(\n invokeConfig.callbacks,\n isLangfuseCallbackHandler\n );\n const { callbacks: _cb, ...rest } = invokeConfig;\n const safeConfig = Object.assign({}, rest, {\n callbacks: langfuseHandler ? [langfuseHandler] : [],\n });\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(safeConfig as Partial<RunnableConfig>)\n );\n }\n } finally {\n await disposeLangfuseHandler(titleLangfuseHandler);\n }\n }\n}\n\nfunction findLastMessageOfType(\n messages: BaseMessage[],\n type: string\n): BaseMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].getType() === type) {\n return messages[i];\n }\n }\n return undefined;\n}\n\nfunction extractPromptText(message: BaseMessage): string {\n const content = message.content;\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return String(content);\n }\n const parts: string[] = [];\n for (const block of content) {\n if (\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'text' &&\n 'text' in block &&\n typeof block.text === 'string'\n ) {\n parts.push(block.text);\n }\n }\n return parts.join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["HandlerRegistry","StandardGraph","MultiAgentGraph","MemorySaver","executeHooks","HumanMessage","createTokenCounter","encodingForModel","resolveLangfuseConfig","Command","BaseCallbackHandler","appendCallbacks","createLangfuseTraceMetadata","getLangfuseTraceName","createLangfuseHandler","INTERRUPT","withLangfuseRuntimeScope","resolveLangfuseRuntimeScope","withLangfuseAttributes","disposeLangfuseHandler","PromptTemplate","initializeModel","isOpenAILike","ChatOpenAI","AzureChatOpenAI","RunnableLambda","createCompletionTitleRunnable","createTitleRunnable","findCallback","isLangfuseCallbackHandler"],"sources":["../../src/run.ts"],"sourcesContent":["// src/run.ts\nimport { HumanMessage } from '@langchain/core/messages';\nimport { PromptTemplate } from '@langchain/core/prompts';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport {\n Command,\n INTERRUPT,\n MemorySaver,\n isInterrupted,\n} from '@langchain/langgraph';\nimport type {\n MessageContentComplex,\n BaseMessage,\n} from '@langchain/core/messages';\nimport type { StringPromptValue } from '@langchain/core/prompt_values';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type { HookRegistry } from '@/hooks';\nimport type * as t from '@/types';\nimport {\n createLangfuseTraceMetadata,\n createLangfuseHandler,\n disposeLangfuseHandler,\n getLangfuseTraceName,\n isLangfuseCallbackHandler,\n withLangfuseAttributes,\n} from '@/langfuse';\nimport {\n resolveLangfuseRuntimeScope,\n withLangfuseRuntimeScope,\n} from '@/langfuseRuntimeScope';\nimport {\n appendCallbacks,\n findCallback,\n type CallbackEntry,\n} from '@/utils/callbacks';\nimport {\n createCompletionTitleRunnable,\n createTitleRunnable,\n} from '@/utils/title';\nimport { createTokenCounter, encodingForModel } from '@/utils/tokens';\nimport { initializeLangfuseTracing } from './instrumentation';\nimport { GraphEvents, Callback, TitleMethod } from '@/common';\nimport { MultiAgentGraph } from '@/graphs/MultiAgentGraph';\nimport { resolveLangfuseConfig } from '@/langfuseConfig';\nimport { StandardGraph } from '@/graphs/Graph';\nimport { initializeModel } from '@/llm/init';\nimport { HandlerRegistry } from '@/events';\nimport { isOpenAILike } from '@/utils/llm';\nimport { executeHooks } from '@/hooks';\n\nexport const defaultOmitOptions = new Set([\n 'stream',\n 'thinking',\n 'streaming',\n 'maxTokens',\n 'clientOptions',\n 'thinkingConfig',\n 'thinkingBudget',\n 'includeThoughts',\n 'maxOutputTokens',\n 'additionalModelRequestFields',\n]);\n\nconst CUSTOM_GRAPH_EVENTS = new Set<string>([\n GraphEvents.ON_AGENT_UPDATE,\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_RUN_STEP_COMPLETED,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n GraphEvents.ON_TOOL_EXECUTE,\n GraphEvents.ON_SUMMARIZE_START,\n GraphEvents.ON_SUMMARIZE_DELTA,\n GraphEvents.ON_SUMMARIZE_COMPLETE,\n GraphEvents.ON_SUBAGENT_UPDATE,\n GraphEvents.ON_AGENT_LOG,\n GraphEvents.ON_CONTEXT_USAGE,\n GraphEvents.ON_CUSTOM_EVENT,\n]);\n\nconst DIRECT_DISPATCHED_STEP_EVENTS = new Set<string>([\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n]);\n\nfunction getStepScopedEventId(data: unknown): string | undefined {\n if (data == null || typeof data !== 'object') {\n return undefined;\n }\n const candidate = data as { id?: unknown };\n return typeof candidate.id === 'string' ? candidate.id : undefined;\n}\n\nfunction isLangGraphResumeMapForInterrupt(\n value: unknown,\n interruptId: string\n): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(value, interruptId);\n}\n\ntype InterruptStateSnapshot = {\n config?: RunnableConfig;\n tasks?: Array<{\n interrupts?: Array<{ id?: string }>;\n }>;\n};\n\ntype WorkflowWithStateHistory = {\n getStateHistory?(\n config: RunnableConfig\n ): AsyncIterableIterator<InterruptStateSnapshot>;\n};\n\nexport class Run<_T extends t.BaseGraphState> {\n id: string;\n private tokenCounter?: t.TokenCounter;\n private handlerRegistry?: HandlerRegistry;\n private hookRegistry?: HookRegistry;\n private humanInTheLoop?: t.HumanInTheLoopConfig;\n private langfuse?: t.LangfuseConfig;\n private toolOutputReferences?: t.ToolOutputReferencesConfig;\n private eagerEventToolExecution?: t.EagerEventToolExecutionConfig;\n private codeSessionToolNames?: string[];\n private interruptingToolNames?: string[];\n private toolExecution?: t.ToolExecutionConfig;\n private subagentUsageSink?: t.SubagentUsageSink;\n private indexTokenCountMap?: Record<string, number>;\n calibrationRatio: number = 1;\n graphRunnable?: t.CompiledStateWorkflow;\n Graph: StandardGraph | MultiAgentGraph | undefined;\n returnContent: boolean = false;\n private skipCleanup: boolean = false;\n /**\n * Whether the compiled graph was built with a checkpointer (host-supplied\n * or the HITL `MemorySaver` fallback). Captured at graph creation because\n * the constructor can later overwrite `Graph.compileOptions` with the raw\n * caller options, dropping the fallback checkpointer from that metadata.\n */\n private hasCheckpointer: boolean = false;\n private _streamResult: t.MessageContentComplex[] | undefined;\n /**\n * Captured interrupt payload typed as `unknown` because the SDK\n * does not validate the runtime shape — custom graph nodes can\n * raise interrupts with arbitrary payloads (not just the SDK's\n * `HumanInterruptPayload` union). The public `getInterrupt<T>()`\n * lets callers assert the type they expect.\n */\n private _interrupt: t.RunInterruptResult<unknown> | undefined;\n private _haltedReason: string | undefined;\n\n private constructor(config: Partial<t.RunConfig>) {\n const runId = config.runId ?? '';\n if (!runId) {\n throw new Error('Run ID not provided');\n }\n\n this.id = runId;\n this.tokenCounter = config.tokenCounter;\n this.indexTokenCountMap = config.indexTokenCountMap;\n if (config.calibrationRatio != null && config.calibrationRatio > 0) {\n this.calibrationRatio = config.calibrationRatio;\n }\n\n const handlerRegistry = new HandlerRegistry();\n\n if (config.customHandlers) {\n for (const [eventType, handler] of Object.entries(\n config.customHandlers\n )) {\n handlerRegistry.register(eventType, handler);\n }\n }\n\n this.handlerRegistry = handlerRegistry;\n this.hookRegistry = config.hooks;\n this.humanInTheLoop = config.humanInTheLoop;\n this.langfuse = config.langfuse;\n this.toolOutputReferences = config.toolOutputReferences;\n this.eagerEventToolExecution = config.eagerEventToolExecution;\n this.codeSessionToolNames = config.codeSessionToolNames;\n this.interruptingToolNames = config.interruptingToolNames;\n this.toolExecution = config.toolExecution;\n this.subagentUsageSink = config.subagentUsageSink;\n\n if (!config.graphConfig) {\n throw new Error('Graph config not provided');\n }\n\n /** Handle different graph types */\n if (config.graphConfig.type === 'multi-agent') {\n this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.handlerRegistry = handlerRegistry;\n }\n } else {\n /** Default to legacy graph for 'standard' or undefined type */\n this.graphRunnable = this.createLegacyGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.compileOptions =\n config.graphConfig.compileOptions ?? this.Graph.compileOptions;\n this.Graph.handlerRegistry = handlerRegistry;\n }\n }\n\n if (config.initialSessions && this.Graph) {\n for (const [key, value] of config.initialSessions) {\n this.Graph.sessions.set(key, value);\n }\n }\n\n this.returnContent = config.returnContent ?? false;\n this.skipCleanup = config.skipCleanup ?? false;\n }\n\n private createLegacyGraph(\n config: t.LegacyGraphConfig | t.StandardGraphConfig\n ): t.CompiledStateWorkflow {\n let agentConfig: t.AgentInputs;\n let signal: AbortSignal | undefined;\n\n /** Check if this is a multi-agent style config (has agents array) */\n if ('agents' in config && Array.isArray(config.agents)) {\n if (config.agents.length === 0) {\n throw new Error('At least one agent must be provided');\n }\n agentConfig = config.agents[0];\n signal = config.signal;\n } else {\n /** Legacy path: build agent config from llmConfig */\n const {\n type: _type,\n llmConfig,\n signal: legacySignal,\n tools = [],\n ...agentInputs\n } = config as t.LegacyGraphConfig;\n const { provider, ...clientOptions } = llmConfig;\n\n agentConfig = {\n ...agentInputs,\n tools,\n provider,\n clientOptions,\n agentId: 'default',\n };\n signal = legacySignal;\n }\n\n const standardGraph = new StandardGraph({\n signal,\n runId: this.id,\n agents: [agentConfig],\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n /** Propagate compile options from graph config */\n standardGraph.compileOptions = this.applyHITLCheckpointerFallback(\n config.compileOptions\n );\n this.hasCheckpointer = standardGraph.compileOptions?.checkpointer != null;\n standardGraph.hookRegistry = this.hookRegistry;\n standardGraph.humanInTheLoop = this.humanInTheLoop;\n standardGraph.toolOutputReferences = this.toolOutputReferences;\n standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n standardGraph.codeSessionToolNames = this.codeSessionToolNames;\n standardGraph.interruptingToolNames = this.interruptingToolNames;\n standardGraph.toolExecution = this.toolExecution;\n this.Graph = standardGraph;\n return standardGraph.createWorkflow();\n }\n\n private createMultiAgentGraph(\n config: t.MultiAgentGraphConfig\n ): t.CompiledStateWorkflow {\n const { agents, edges, compileOptions } = config;\n\n const multiAgentGraph = new MultiAgentGraph({\n runId: this.id,\n agents,\n edges,\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n\n multiAgentGraph.compileOptions =\n this.applyHITLCheckpointerFallback(compileOptions);\n this.hasCheckpointer = multiAgentGraph.compileOptions?.checkpointer != null;\n\n multiAgentGraph.hookRegistry = this.hookRegistry;\n multiAgentGraph.humanInTheLoop = this.humanInTheLoop;\n multiAgentGraph.toolOutputReferences = this.toolOutputReferences;\n multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n multiAgentGraph.codeSessionToolNames = this.codeSessionToolNames;\n multiAgentGraph.interruptingToolNames = this.interruptingToolNames;\n multiAgentGraph.toolExecution = this.toolExecution;\n this.Graph = multiAgentGraph;\n return multiAgentGraph.createWorkflow();\n }\n\n /**\n * When the host opted into HITL via `humanInTheLoop: { enabled: true }`\n * and did not supply a checkpointer, install an in-memory `MemorySaver`\n * so `interrupt()` can persist checkpoints and `Command({ resume })`\n * can rebuild state. The fallback is intentionally process-local:\n * production hosts that need durable resumption across processes /\n * restarts must provide their own checkpointer (Redis, Postgres, etc.)\n * on `compileOptions.checkpointer`.\n *\n * No-op when HITL is off (the default — omitted, or\n * `{ enabled: false }`) or the host already supplied a checkpointer\n * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale\n * behind the default-off stance.\n */\n private applyHITLCheckpointerFallback(\n compileOptions: t.CompileOptions | undefined\n ): t.CompileOptions | undefined {\n if (this.humanInTheLoop?.enabled !== true) {\n return compileOptions;\n }\n if (compileOptions?.checkpointer != null) {\n return compileOptions;\n }\n return {\n ...(compileOptions ?? {}),\n checkpointer: new MemorySaver(),\n };\n }\n\n /**\n * Run RunStart + UserPromptSubmit hooks before the graph stream\n * begins, accumulate any `additionalContext` strings into the input\n * messages, and short-circuit when a hook signals the run should not\n * proceed (deny / ask decision on the prompt, or `preventContinuation`\n * on either hook).\n *\n * Returns `true` when the caller should bail with `undefined` (run\n * was halted before any model call); returns `false` to proceed\n * into the stream loop.\n *\n * ## Side effects\n *\n * On the success path:\n * - Mutates `stateInputs.messages` in place to append a\n * consolidated `HumanMessage` carrying any hook\n * `additionalContext` strings. Safe because the host owns the\n * array and `processStream` is the only consumer until LangGraph\n * reads it.\n *\n * On the halt path (returning `true`):\n * - Sets `this._haltedReason` so callers (and the eventual host)\n * can distinguish a hook-driven halt from a natural completion.\n * - Calls `registry.clearSession(this.id)` and\n * `registry.clearHaltSignal(this.id)` because no resume is\n * expected from a pre-stream halt — the run never entered the\n * graph, so the session/halt state for this run would otherwise\n * leak to the next `processStream` invocation on the same\n * registry. Other concurrent runs on the same registry are\n * untouched (halt signals are scoped per session id).\n * - Sets `config.callbacks = undefined` to drop the callback\n * references the caller built (langfuse handler, custom event\n * handler, etc.) since they won't be exercised. Mirrors the\n * equivalent cleanup the `processStream` `finally` block does\n * on the natural-completion path.\n */\n private async runPreStreamHooks(\n stateInputs: t.IState,\n threadId: string | undefined,\n config: Partial<RunnableConfig>\n ): Promise<boolean> {\n const registry = this.hookRegistry;\n /**\n * Defensive guard: `processStream` already validated `this.Graph`\n * before calling this helper, but TypeScript can't propagate that\n * narrowing across method boundaries. The check keeps the body\n * free of `this.Graph!` non-null assertions.\n */\n if (registry == null || this.Graph == null) {\n return false;\n }\n\n const preStreamContexts: string[] = [];\n\n const runStartResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'RunStart',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n messages: stateInputs.messages,\n },\n sessionId: this.id,\n });\n for (const ctx of runStartResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n /**\n * Honor `preventContinuation` from RunStart before the stream\n * starts. Mid-flight halts (from tool/compact/subagent hooks)\n * route through `HookRegistry.haltRun` and are polled by the\n * stream loop in `processStream` — different mechanism, same\n * intent.\n */\n if (runStartResult.preventContinuation === true) {\n this._haltedReason = runStartResult.stopReason ?? 'preventContinuation';\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n\n const lastHuman = findLastMessageOfType(stateInputs.messages, 'human');\n if (lastHuman != null) {\n const promptResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'UserPromptSubmit',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n prompt: extractPromptText(lastHuman),\n // attachments: not yet wired — Phase 2 will extract\n // non-text content blocks (images, files) from messages\n },\n sessionId: this.id,\n });\n if (\n promptResult.decision === 'deny' ||\n promptResult.decision === 'ask' ||\n promptResult.preventContinuation === true\n ) {\n /**\n * Always set `_haltedReason` so the host can call\n * `getHaltReason()` and distinguish a hook-blocked prompt\n * from a natural empty-output completion. Three signals can\n * land here, each with its own canonical reason string when\n * the hook didn't supply one.\n */\n if (promptResult.preventContinuation === true) {\n this._haltedReason = promptResult.stopReason ?? 'preventContinuation';\n } else if (promptResult.decision === 'deny') {\n this._haltedReason = promptResult.reason ?? 'prompt_denied';\n } else {\n this._haltedReason =\n promptResult.reason ?? 'prompt_requires_approval';\n }\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n for (const ctx of promptResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n }\n\n if (preStreamContexts.length > 0) {\n /**\n * Wraps the joined hook contexts as a `HumanMessage` even though\n * the intent is system-level guidance. Using a `SystemMessage`\n * mid-conversation is rejected by Anthropic and Google providers\n * (system messages must be the leading entry), so the LangChain\n * convention — also used by `ToolNode.convertInjectedMessages`\n * — is `HumanMessage` carrying `additional_kwargs.role` as a\n * marker for hosts inspecting state. The model still sees a\n * user-role message; the `role: 'system'` field is metadata\n * only. Hosts that want a true system message should compose\n * it into the agent's `instructions` config instead.\n */\n stateInputs.messages.push(\n new HumanMessage({\n content: preStreamContexts.join('\\n\\n'),\n additional_kwargs: { role: 'system', source: 'hook' },\n })\n );\n }\n\n return false;\n }\n\n static async create<T extends t.BaseGraphState>(\n config: t.RunConfig\n ): Promise<Run<T>> {\n /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */\n if (config.indexTokenCountMap && !config.tokenCounter) {\n const gc = config.graphConfig;\n const clientOpts =\n 'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;\n const model = (clientOpts as { model?: string } | undefined)?.model ?? '';\n config.tokenCounter = await createTokenCounter(encodingForModel(model));\n }\n return new Run<T>(config);\n }\n\n getRunMessages(): BaseMessage[] | undefined {\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n return this.Graph.getRunMessages();\n }\n\n /**\n * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).\n * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`\n * on the next run for the same conversation so the pruner starts with an accurate\n * scaling factor instead of the default (1).\n */\n getCalibrationRatio(): number {\n return this.calibrationRatio;\n }\n\n getResolvedInstructionOverhead(): number | undefined {\n return this.Graph?.getResolvedInstructionOverhead();\n }\n\n getToolCount(): number {\n return this.Graph?.getToolCount() ?? 0;\n }\n\n /**\n * Creates a custom event callback handler that intercepts custom events\n * and processes them through our handler registry instead of EventStreamCallbackHandler\n */\n private createCustomEventCallback() {\n return async (\n eventName: string,\n data: unknown,\n runId: string,\n tags?: string[],\n metadata?: Record<string, unknown>\n ): Promise<void> => {\n // Step-scoped SDK events are dispatched directly via the handler\n // registry first. Skip callback-based echoes to prevent double\n // handling when LangGraph invokes custom callbacks more than once.\n const stepScopedEventId = getStepScopedEventId(data);\n if (\n DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) &&\n this.Graph != null &&\n stepScopedEventId != null &&\n this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)\n ) {\n return;\n }\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler && this.Graph) {\n return await handler.handle(\n eventName,\n data as\n | t.StreamEventData\n | t.ModelEndData\n | t.RunStep\n | t.RunStepDeltaEvent\n | t.MessageDeltaEvent\n | t.ReasoningDeltaEvent\n | { result: t.ToolEndEvent },\n metadata,\n this.Graph\n );\n }\n };\n }\n\n private shouldClearHookSession(streamThrew: boolean): boolean {\n return this._interrupt == null || this._haltedReason != null || streamThrew;\n }\n\n private isAwaitingResume(streamThrew: boolean): boolean {\n return (\n this._interrupt != null && this._haltedReason == null && !streamThrew\n );\n }\n\n private getStreamLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n if (primaryContext != null) {\n return resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);\n }\n\n for (const context of graph.agentContexts.values()) {\n const langfuse = resolveLangfuseConfig(this.langfuse, context.langfuse);\n if (langfuse != null) {\n return langfuse;\n }\n }\n\n return this.langfuse;\n }\n\n private getStreamToolOutputTracingLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const toolOutputTracingConfigs = Array.from(graph.agentContexts.values())\n .map((context) => {\n return resolveLangfuseConfig(this.langfuse, context.langfuse)\n ?.toolOutputTracing;\n })\n .filter((config): config is t.LangfuseToolOutputTracingConfig => {\n return config != null;\n });\n\n if (toolOutputTracingConfigs.length === 0) {\n return this.langfuse?.toolOutputTracing != null\n ? { toolOutputTracing: this.langfuse.toolOutputTracing }\n : undefined;\n }\n if (toolOutputTracingConfigs.length === 1) {\n return { toolOutputTracing: toolOutputTracingConfigs[0] };\n }\n\n let enabled: boolean | undefined;\n let redactionText: string | undefined;\n let redactedToolNameMatchMode: 'exact' | 'partial' | undefined;\n const redactedToolNames = new Set<string>();\n\n for (const config of toolOutputTracingConfigs) {\n if (config.enabled === false) {\n enabled = false;\n } else if (enabled !== false && config.enabled != null) {\n enabled = config.enabled;\n }\n\n redactionText ??= config.redactionText;\n if (config.redactedToolNameMatchMode === 'partial') {\n redactedToolNameMatchMode = 'partial';\n } else {\n redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;\n }\n\n for (const toolName of config.redactedToolNames ?? []) {\n redactedToolNames.add(toolName);\n }\n }\n\n return {\n toolOutputTracing: {\n ...(enabled != null ? { enabled } : {}),\n ...(redactedToolNames.size > 0\n ? { redactedToolNames: Array.from(redactedToolNames) }\n : {}),\n ...(redactedToolNameMatchMode != null\n ? { redactedToolNameMatchMode }\n : {}),\n ...(redactionText != null ? { redactionText } : {}),\n },\n };\n }\n\n async processStream(\n inputs: t.IState | Command,\n callerConfig: t.RunStreamConfig,\n streamOptions?: t.EventStreamOptions\n ): Promise<MessageContentComplex[] | undefined> {\n if (this.graphRunnable == null) {\n throw new Error(\n 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n const graphRunnable = this.graphRunnable;\n const graph = this.Graph;\n\n /**\n * `Command` inputs (`Command({ resume, update?, goto? })`) are\n * resume-mode invocations: LangGraph rebuilds graph state from the\n * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no\n * new prompt to evaluate) and read run-state from the Graph wrapper\n * instead of `inputs.messages`.\n */\n const isResume = inputs instanceof Command;\n const stateInputs = isResume ? undefined : (inputs as t.IState);\n\n const config: t.RunStreamConfig = {\n recursionLimit: 50,\n ...callerConfig,\n configurable: { ...callerConfig.configurable },\n };\n\n /**\n * Skip `resetValues` on resume — we're continuing an in-flight\n * run, not starting a fresh one. Resetting would wipe the\n * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated\n * `messages`, etc.) the resumed `ToolNode` needs to dispatch\n * tool completions with the correct step ids and re-resolve\n * `{{tool<i>turn<n>}}` references. Pairs with the\n * `awaitingResume` gate on `clearHeavyState` in the `finally`\n * block so the sidecars survive both ends of the interrupt\n * boundary.\n */\n if (!isResume) {\n graph.resetValues(streamOptions?.keepContent);\n }\n this._interrupt = undefined;\n this._haltedReason = undefined;\n this.hookRegistry?.clearHaltSignal(this.id);\n\n /** Custom event callback to intercept and handle custom events */\n const customEventCallback = this.createCustomEventCallback();\n\n const streamCallbacks = streamOptions?.callbacks\n ? this.getCallbacks(streamOptions.callbacks)\n : undefined;\n\n const customHandler = BaseCallbackHandler.fromMethods({\n [Callback.CUSTOM_EVENT]: customEventCallback,\n });\n customHandler.awaitHandlers = true;\n\n config.callbacks = appendCallbacks(\n config.callbacks,\n streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]\n );\n\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n const userId =\n typeof config.configurable?.user_id === 'string'\n ? config.configurable.user_id\n : undefined;\n const sessionId =\n typeof config.configurable?.thread_id === 'string'\n ? config.configurable.thread_id\n : undefined;\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: this.id,\n parentMessageId: config.configurable?.requestBody?.parentMessageId,\n agentId: graph.defaultAgentId,\n agentName: primaryContext?.name,\n });\n const traceName = config.runName ?? getLangfuseTraceName(traceMetadata);\n const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);\n initializeLangfuseTracing(streamLangfuseConfig);\n const langfuseHandler = createLangfuseHandler({\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceMetadata,\n tags: ['librechat', 'agent'],\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n });\n if (langfuseHandler != null) {\n config.runName = traceName;\n config.callbacks = appendCallbacks(config.callbacks, [langfuseHandler]);\n }\n\n if (!this.id) {\n throw new Error('Run ID not provided');\n }\n\n config.run_id = this.id;\n config.configurable = Object.assign(config.configurable ?? {}, {\n run_id: this.id,\n });\n\n /**\n * Default `durability: 'exit'` whenever a checkpointer is active so\n * runs skip per-superstep checkpoint writes and persist only at the\n * exit/interrupt boundary (all HITL/resume needs). An explicit caller\n * value wins; no checkpointer leaves it unset (langgraph default).\n */\n if (config.durability == null && this.hasCheckpointer) {\n config.durability = 'exit';\n }\n\n const threadId = config.configurable.thread_id as string | undefined;\n\n if (this.hookRegistry != null && stateInputs != null) {\n const shouldHalt = await this.runPreStreamHooks(\n stateInputs,\n threadId,\n config\n );\n if (shouldHalt) {\n return undefined;\n }\n }\n\n /**\n * Tracks whether the stream loop threw. Used by the `finally`\n * block to decide whether to honor the interrupt-preservation\n * guard for session hooks: a captured `_interrupt` is only\n * meaningful if the stream completed cleanly. If the loop errored\n * after stashing an interrupt (e.g. a downstream handler throws\n * after the interrupt event landed), the interrupt is stale —\n * preserving session hooks would leak them into the next run.\n */\n let streamThrew = false;\n\n const consumeStream = async (): Promise<void> => {\n /**\n * `streamEvents` accepts both state inputs and `Command` (resume) at\n * runtime, but our `CompiledStateWorkflow` type narrows the first\n * arg to `BaseGraphState`. Cast on the call so the resume path\n * type-checks without widening the wrapper for every caller.\n */\n const stream = graphRunnable.streamEvents(inputs as t.IState, config, {\n raiseError: true,\n /**\n * Prevent EventStreamCallbackHandler from processing custom events.\n * Custom events are already handled via our createCustomEventCallback()\n * which routes them through the handlerRegistry.\n * Without this flag, EventStreamCallbackHandler throws errors when\n * custom events are dispatched for run IDs not in its internal map\n * (due to timing issues in parallel execution or after run cleanup).\n */\n ignoreCustomEvent: true,\n });\n\n for await (const event of stream) {\n const { data, metadata, ...info } = event;\n\n const eventName: t.EventName = info.event;\n\n /** Skip custom events as they're handled by our callback */\n if (CUSTOM_GRAPH_EVENTS.has(eventName)) {\n continue;\n }\n\n /**\n * Detect interrupts surfaced by LangGraph as a synthetic\n * `__interrupt__` field on the streamed chunk and stash the\n * first one for the host to read via `run.getInterrupt()`\n * once the stream drains. Captured as `unknown` because the\n * SDK does not validate the runtime payload shape — the\n * built-in ToolNode raises a `HumanInterruptPayload`\n * (`tool_approval` / `ask_user_question`), but custom nodes\n * can pass any payload to `interrupt()`. Callers narrow with\n * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`\n * guards or assert via `getInterrupt<T>()`.\n */\n if (\n this._interrupt == null &&\n data.chunk != null &&\n isInterrupted<unknown>(data.chunk)\n ) {\n const interrupts = data.chunk[INTERRUPT];\n if (interrupts.length > 0) {\n const first = interrupts[0];\n /**\n * Capture the interrupt unconditionally — `interrupt(null)`\n * and `interrupt(undefined)` are valid pauses (a custom\n * node may want to pause without metadata) and the host\n * still needs to know the run is awaiting resume. Gating\n * on `payload != null` would silently downgrade a paused\n * run to \"completed\" and let the `Stop` hook fire,\n * breaking host resume handling.\n */\n this._interrupt = {\n interruptId: first.id ?? '',\n threadId,\n payload: first.value,\n };\n }\n }\n\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler) {\n await handler.handle(eventName, data, metadata, this.Graph);\n }\n\n /**\n * Mid-flight halt: any hook (PreToolUse, PostToolUse,\n * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)\n * that returned `preventContinuation: true` raises a halt\n * signal on the registry via `executeHooks`. We poll between\n * stream events and break out as soon as one is set so the\n * graph doesn't take another model turn after the halting\n * operation completes.\n *\n * Limitation: the current step (in-flight model call, ongoing\n * tool batch) is not aborted — only the next step is skipped.\n * This matches Claude Code's `continue: false` semantic where\n * the active operation finishes before halting takes effect.\n */\n const haltSignal = this.hookRegistry?.getHaltSignal(this.id);\n if (haltSignal != null) {\n this._haltedReason = haltSignal.reason;\n break;\n }\n }\n\n if (this._interrupt != null) {\n await this.resolveInterruptResumeConfig(config);\n }\n\n /**\n * Skip the Stop hook when the run paused on a HITL interrupt\n * (still pending human input) or was halted by a hook (the host\n * already chose to stop, so a Stop hook firing now would be\n * misleading). The host fires Stop on the resumed-and-completed\n * run instead.\n */\n if (\n this._interrupt == null &&\n this._haltedReason == null &&\n this.hookRegistry?.hasHookFor('Stop', this.id) === true\n ) {\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'Stop',\n runId: this.id,\n threadId,\n agentId: graph.defaultAgentId,\n messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],\n stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)\n },\n sessionId: this.id,\n }).catch(() => {\n /* Stop hook errors must not masquerade as stream failures */\n });\n }\n };\n\n try {\n // When opted in, seed the root trace id from this run's id so feedback /\n // other external signals can be attached to the trace later without a\n // lookup (see SeededTraceIdGenerator in ./instrumentation).\n await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: streamLangfuseConfig,\n langfuseOverlay: this.getStreamToolOutputTracingLangfuseConfig(graph),\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n }),\n () =>\n withLangfuseAttributes(\n {\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceName,\n traceMetadata,\n tags: ['librechat', 'agent'],\n },\n consumeStream\n )\n );\n } catch (err) {\n streamThrew = true;\n if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {\n const runMessages = this.Graph.getRunMessages() ?? [];\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'StopFailure',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n error: err instanceof Error ? err.message : String(err),\n lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),\n },\n sessionId: this.id,\n }).catch(() => {\n /* swallow hook errors — the original error must propagate */\n });\n }\n throw err;\n } finally {\n /**\n * Preserve session-scoped hooks when the run paused on a HITL\n * interrupt — the very next call will be `Run.resume()`, which\n * needs the same policy hooks (e.g., the `PreToolUse` matcher\n * that triggered the interrupt) to fire on the re-executed node\n * and uphold the approval flow. Clearing here would leak the\n * approval gate on resume. The session is cleared instead at\n * natural completion, error (including errors that happen AFTER\n * an interrupt was captured — those interrupts are stale), or\n * hook-driven halt (including hooks that returned BOTH `ask`\n * and `preventContinuation` — the halt wins, no resume is\n * expected, sessions must drop). Every state where no resume\n * is expected clears.\n */\n if (this.shouldClearHookSession(streamThrew)) {\n this.hookRegistry?.clearSession(this.id);\n }\n /**\n * Drop any halt signal raised mid-stream for this run so a\n * subsequent `processStream` / `resume` starts with clean state.\n * The Run captured `_haltedReason` already; the registry entry\n * for this `sessionId` would otherwise spuriously trip the next\n * loop. Other concurrent runs sharing this registry are\n * unaffected — their entries live under their own session ids.\n */\n this.hookRegistry?.clearHaltSignal(this.id);\n await disposeLangfuseHandler(langfuseHandler);\n\n /**\n * Break the reference chain that keeps heavy data alive via\n * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →\n * `@langchain/core` `RunTree.extra[lc:child_config]` →\n * Node.js `AsyncLocalStorage` context captured by timers/promises.\n *\n * Without this, base64-encoded images/PDFs in message content remain\n * reachable from lingering `Timeout` handles until GC runs.\n */\n if (!this.skipCleanup) {\n if (\n (config.configurable as Record<string, unknown> | undefined) != null\n ) {\n for (const key of Object.getOwnPropertySymbols(config.configurable)) {\n const val = config.configurable[key as unknown as string] as\n | Record<string, unknown>\n | undefined;\n if (\n val != null &&\n typeof val === 'object' &&\n 'currentTaskInput' in val\n ) {\n (val as Record<string, unknown>).currentTaskInput = undefined;\n }\n delete config.configurable[key as unknown as string];\n }\n config.configurable = undefined;\n }\n config.callbacks = undefined;\n }\n\n const result = this.returnContent\n ? this.Graph.getContentParts()\n : undefined;\n\n this.calibrationRatio = this.Graph.getCalibrationRatio();\n\n /**\n * Skip `clearHeavyState()` when the run paused on a clean HITL\n * interrupt awaiting resume — `Run.resume()` re-enters the same\n * `ToolNode` instance and needs the sidecars `clearHeavyState`\n * would wipe (`toolCallStepIds` for completion-event step ids,\n * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`\n * substitutions, `sessions` for code-env continuity, plus the\n * `hookRegistry` and `humanInTheLoop` config the interrupt\n * branch itself relies on). Without preservation, the resumed\n * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with\n * an empty step id and downstream stream consumers would drop\n * the result.\n *\n * The natural-completion / error / hook-driven-halt paths still\n * clean up — `_haltedReason != null` or `streamThrew` mean no\n * resume is expected. Cross-process resume (host rebuilds the\n * Run from scratch) is a separate concern; see\n * `HumanInTheLoopConfig` JSDoc.\n */\n const awaitingResume = this.isAwaitingResume(streamThrew);\n if (!this.skipCleanup && !awaitingResume) {\n this.Graph.clearHeavyState();\n }\n\n this._streamResult = result;\n }\n\n return this._streamResult;\n }\n\n /**\n * Returns the pending interrupt captured during the most recent\n * `processStream` (or `resume`) invocation. `undefined` when the run\n * either has not been streamed yet or completed without pausing.\n *\n * Hosts call this immediately after `processStream` returns to decide\n * whether the run is awaiting human input. Persist the returned\n * descriptor (alongside `thread_id` and the agent run config) so a\n * later `resume(decisions)` can rebuild the run.\n *\n * The default `TPayload` is the SDK's `HumanInterruptPayload` union\n * (`tool_approval` / `ask_user_question`), suitable for the common\n * case where interrupts come from the built-in ToolNode or\n * `askUserQuestion()` helper. Hosts that raise custom interrupts\n * from custom graph nodes pass their own type — the SDK does not\n * validate the runtime shape, it just transports whatever the\n * `interrupt()` call carried. When in doubt, narrow with the\n * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type\n * guards (which accept `unknown`) before reading variant-specific\n * fields.\n */\n getInterrupt<TPayload = t.HumanInterruptPayload>():\n | t.RunInterruptResult<TPayload>\n | undefined {\n return this._interrupt as t.RunInterruptResult<TPayload> | undefined;\n }\n\n /**\n * Returns the reason a hook halted the run via\n * `preventContinuation: true`, or `undefined` if no hook halted.\n *\n * Hosts inspect this after `processStream` returns to distinguish a\n * natural completion (`undefined`) from a hook-driven halt (a\n * truthy string). Independent from `getInterrupt()` — a halted run\n * has no interrupt; an interrupted run has no halt reason.\n */\n getHaltReason(): string | undefined {\n return this._haltedReason;\n }\n\n /**\n * Resume a paused HITL run with the value the user (or whatever\n * decided the interrupt) supplied. The default `TResume` covers the\n * `tool_approval` interrupt (the common case): an array of decisions\n * in `action_requests` order, or a record keyed by `tool_call_id`.\n *\n * For other interrupt types (e.g., `ask_user_question` →\n * `AskUserQuestionResolution`, or any custom interrupt a host raises\n * from a custom node), pass the type parameter and the SDK forwards\n * the value through unchanged. LangGraph delivers it as the return\n * value of the original `interrupt()` call inside the paused node.\n *\n * The host MUST construct this Run with the same `thread_id` and the\n * same checkpointer as the original paused run; LangGraph rebuilds\n * graph state from the checkpoint and re-enters the interrupted node\n * from the start.\n */\n /**\n * Returns the per-Run file checkpointer when\n * `toolExecution.local.fileCheckpointing === true` was set on the\n * RunConfig. Hosts can capture extra paths or call `rewind()`\n * directly. Returns undefined when checkpointing is disabled.\n *\n * Construction-time invariant: the checkpointer is shared across\n * every ToolNode the graph compiles (single-agent and multi-agent),\n * so a `rewind()` call here unwinds writes made by ANY agent in the\n * run.\n */\n getFileCheckpointer(): t.LocalFileCheckpointer | undefined {\n return this.Graph?.getOrCreateFileCheckpointer();\n }\n\n /**\n * Convenience wrapper that calls `rewind()` on the per-Run file\n * checkpointer. Restores every file the local engine snapshotted\n * during this Run to its pre-write content (and deletes any path\n * that didn't exist before being created). Returns the count of\n * paths processed; returns 0 when checkpointing is disabled.\n */\n async rewindFiles(): Promise<number> {\n const cp = this.getFileCheckpointer();\n return cp == null ? 0 : cp.rewind();\n }\n\n /**\n * Resume an interrupted run. `commandOptions` forwards langgraph 1.4.5\n * `Command` fields applied together with `resume` in one superstep:\n * - `update`: channel updates committed at the resume point. On a *rebuilt*\n * Run (new instance + durable checkpointer), `update.messages` are the first\n * write the fresh wrapper sees, so they seed the `getRunMessages()` /\n * `returnContent` baseline and are excluded from them (still committed to the\n * checkpoint). Hosts that rebuild + inject messages should persist them\n * directly or read from `getState`. Unreachable without a durable checkpointer.\n * - `goto`: a *dynamic* edge that does not cancel static `addEdge` routes. On\n * the built-in standard graph the fixed `toolNode -> agentNode/END` edge still\n * fires, so `goto` adds rather than replaces (e.g. `goto: END` will not stop a\n * tool-node resume). Intended for custom, Command-routed graphs.\n */\n async resume<TResume = t.ToolApprovalDecision[] | t.ToolApprovalDecisionMap>(\n resumeValue: TResume,\n callerConfig: t.RunStreamConfig,\n streamOptions?: t.EventStreamOptions,\n commandOptions?: Pick<\n ConstructorParameters<typeof Command>[0],\n 'update' | 'goto'\n >\n ): Promise<MessageContentComplex[] | undefined> {\n const interruptId = this._interrupt?.interruptId;\n const scopedResume =\n typeof interruptId === 'string' &&\n interruptId.length > 0 &&\n !isLangGraphResumeMapForInterrupt(resumeValue, interruptId)\n ? { [interruptId]: resumeValue }\n : resumeValue;\n const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);\n // langgraph 1.4.5 applies resume + state update + reroute in one superstep\n // (single checkpoint). `update`/`goto` are omitted unless the caller sets them.\n return this.processStream(\n new Command({\n resume: scopedResume,\n ...(commandOptions?.update !== undefined\n ? { update: commandOptions.update }\n : {}),\n ...(commandOptions?.goto !== undefined\n ? { goto: commandOptions.goto }\n : {}),\n }),\n resumeConfig,\n streamOptions\n );\n }\n\n private async resolveInterruptResumeConfig(\n callerConfig: t.RunStreamConfig\n ): Promise<t.RunStreamConfig> {\n const interrupt = this._interrupt;\n const interruptId = interrupt?.interruptId;\n const workflow = this.graphRunnable as\n | (t.CompiledStateWorkflow & WorkflowWithStateHistory)\n | undefined;\n const stateHistory = workflow?.getStateHistory;\n if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) {\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: interrupt.checkpointId,\n ...(typeof interrupt.checkpointNs === 'string'\n ? { checkpoint_ns: interrupt.checkpointNs }\n : {}),\n },\n };\n }\n if (\n interrupt == null ||\n typeof interruptId !== 'string' ||\n interruptId.length === 0 ||\n typeof stateHistory !== 'function'\n ) {\n return callerConfig;\n }\n\n for await (const snapshot of stateHistory.call(\n this.graphRunnable,\n callerConfig as RunnableConfig\n )) {\n const hasMatchingInterrupt =\n snapshot.tasks?.some(\n (task) =>\n task.interrupts?.some(\n (interrupt) => interrupt.id === interruptId\n ) === true\n ) === true;\n const checkpointConfigurable = snapshot.config?.configurable;\n if (!hasMatchingInterrupt || checkpointConfigurable == null) {\n continue;\n }\n\n const checkpointId = checkpointConfigurable.checkpoint_id;\n const checkpointNs = checkpointConfigurable.checkpoint_ns;\n if (typeof checkpointId === 'string' && checkpointId.length > 0) {\n this._interrupt = {\n ...interrupt,\n checkpointId,\n ...(typeof checkpointNs === 'string' ? { checkpointNs } : {}),\n };\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: checkpointId,\n ...(typeof checkpointNs === 'string'\n ? { checkpoint_ns: checkpointNs }\n : {}),\n },\n };\n }\n }\n\n return callerConfig;\n }\n\n private createSystemCallback<K extends keyof t.ClientCallbacks>(\n clientCallbacks: t.ClientCallbacks,\n key: K\n ): t.SystemCallbacks[K] {\n return ((...args: unknown[]) => {\n const clientCallback = clientCallbacks[key];\n if (clientCallback && this.Graph) {\n (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);\n }\n }) as t.SystemCallbacks[K];\n }\n\n getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {\n return {\n [Callback.TOOL_ERROR]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_ERROR\n ),\n [Callback.TOOL_START]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_START\n ),\n [Callback.TOOL_END]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_END\n ),\n };\n }\n\n async generateTitle({\n provider,\n inputText,\n contentParts,\n titlePrompt,\n clientOptions,\n chainOptions,\n skipLanguage,\n titleMethod = TitleMethod.COMPLETION,\n titlePromptTemplate,\n }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {\n let titleLangfuseHandler: CallbackEntry | undefined;\n let titleLangfuseConfig: t.LangfuseConfig | undefined;\n let titleUserId: string | undefined;\n let titleSessionId: string | undefined;\n const titleContext =\n this.Graph == null\n ? undefined\n : this.Graph.agentContexts.get(this.Graph.defaultAgentId);\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: 'title-' + this.id,\n agentName: titleContext?.name,\n });\n const titleRunName = getLangfuseTraceName(traceMetadata, 'LibreChat Title');\n\n if (chainOptions != null) {\n titleUserId =\n typeof chainOptions.configurable?.user_id === 'string'\n ? chainOptions.configurable.user_id\n : undefined;\n titleSessionId =\n typeof chainOptions.configurable?.thread_id === 'string'\n ? chainOptions.configurable.thread_id\n : undefined;\n titleLangfuseConfig = resolveLangfuseConfig(\n this.langfuse,\n titleContext?.langfuse\n );\n initializeLangfuseTracing(titleLangfuseConfig);\n titleLangfuseHandler = createLangfuseHandler({\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceMetadata,\n tags: ['librechat', 'title'],\n traceIdSeed:\n titleLangfuseConfig?.deterministicTraceId === true\n ? 'title-' + this.id\n : undefined,\n });\n\n if (titleLangfuseHandler != null) {\n chainOptions.callbacks = appendCallbacks(chainOptions.callbacks, [\n titleLangfuseHandler,\n ]);\n }\n }\n\n const convoTemplate = PromptTemplate.fromTemplate(\n titlePromptTemplate ?? 'User: {input}\\nAI: {output}'\n );\n\n const response = contentParts\n .map((part) => {\n if (part?.type === 'text') return part.text;\n return '';\n })\n .join('\\n');\n\n const model = initializeModel({\n provider,\n clientOptions,\n }) as t.ChatModelInstance;\n\n if (\n isOpenAILike(provider) &&\n (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)\n ) {\n model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.temperature as number;\n model.topP = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.topP as number;\n model.frequencyPenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.frequencyPenalty as number;\n model.presencePenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.presencePenalty as number;\n model.n = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.n as number;\n }\n\n const convoToTitleInput = new RunnableLambda({\n func: (\n promptValue: StringPromptValue\n ): { convo: string; inputText: string; skipLanguage?: boolean } => ({\n convo: promptValue.value,\n inputText,\n skipLanguage,\n }),\n }).withConfig({ runName: 'PrepareTitleInput' });\n\n const titleChain =\n titleMethod === TitleMethod.COMPLETION\n ? await createCompletionTitleRunnable(model, titlePrompt)\n : await createTitleRunnable(model, titlePrompt);\n\n /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */\n const fullChain = convoTemplate\n .withConfig({ runName: 'FormatConversation' })\n .pipe(convoToTitleInput)\n .pipe(titleChain)\n .withConfig({ runName: 'GenerateConversationTitle' });\n\n const invokeConfig = Object.assign({}, chainOptions, {\n run_id: this.id,\n runId: this.id,\n runName: chainOptions?.runName ?? titleRunName,\n });\n\n const invokeTitleChain = (\n runtimeConfig: Partial<RunnableConfig>\n ): Promise<{ language?: string; title?: string }> =>\n withLangfuseAttributes(\n {\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceName: runtimeConfig.runName ?? titleRunName,\n traceMetadata,\n tags: ['librechat', 'title'],\n },\n () =>\n fullChain.invoke(\n { input: inputText, output: response },\n runtimeConfig\n )\n );\n\n try {\n try {\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(invokeConfig)\n );\n } catch (_e) {\n // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments\n // but preserve Langfuse tracing if it exists.\n const langfuseHandler = findCallback(\n invokeConfig.callbacks,\n isLangfuseCallbackHandler\n );\n const { callbacks: _cb, ...rest } = invokeConfig;\n const safeConfig = Object.assign({}, rest, {\n callbacks: langfuseHandler ? [langfuseHandler] : [],\n });\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(safeConfig as Partial<RunnableConfig>)\n );\n }\n } finally {\n await disposeLangfuseHandler(titleLangfuseHandler);\n }\n }\n}\n\nfunction findLastMessageOfType(\n messages: BaseMessage[],\n type: string\n): BaseMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].getType() === type) {\n return messages[i];\n }\n }\n return undefined;\n}\n\nfunction extractPromptText(message: BaseMessage): string {\n const content = message.content;\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return String(content);\n }\n const parts: string[] = [];\n for (const block of content) {\n if (\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'text' &&\n 'text' in block &&\n typeof block.text === 'string'\n ) {\n parts.push(block.text);\n }\n }\n return parts.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -207,6 +207,13 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
207
207
|
agentLangfuse;
|
|
208
208
|
toolCallStepIds;
|
|
209
209
|
errorHandler;
|
|
210
|
+
/**
|
|
211
|
+
* Tool call ids whose `errorHandler` did NOT dispatch the error completion
|
|
212
|
+
* event (it returned `false` or threw). The output loop must dispatch the
|
|
213
|
+
* completion for these itself — skipping them there would strand the
|
|
214
|
+
* client's tool-call part without a terminal event.
|
|
215
|
+
*/
|
|
216
|
+
undispatchedToolErrors = /* @__PURE__ */ new Set();
|
|
210
217
|
toolUsageCount;
|
|
211
218
|
/** Maps toolCallId → turn captured in runTool, used by handleRunToolCompletions */
|
|
212
219
|
toolCallTurns = /* @__PURE__ */ new Map();
|
|
@@ -249,6 +256,21 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
249
256
|
/** Tool names that bypass event dispatch and execute directly (e.g., graph-managed handoff tools) */
|
|
250
257
|
directToolNames;
|
|
251
258
|
/**
|
|
259
|
+
* Tool names whose in-process body may raise a LangGraph `interrupt()`
|
|
260
|
+
* mid-execution (e.g. `ask_user_question`). Used only to REORDER within
|
|
261
|
+
* the direct group: a tool named here that is *already* direct (a real
|
|
262
|
+
* in-process graphTool — the only kind whose body can reach
|
|
263
|
+
* `interrupt()`) is scheduled ahead of its non-interrupting direct
|
|
264
|
+
* siblings, so a mid-body interrupt unwinds the ToolNode before a
|
|
265
|
+
* non-idempotent sibling executes and LangGraph's resume-time batch
|
|
266
|
+
* re-execution can't double it. This set is deliberately NOT folded
|
|
267
|
+
* into direct classification: a name that resolves to a schema-only
|
|
268
|
+
* event stub (an inherited `toolDefinition` with no executable
|
|
269
|
+
* instance) stays event-dispatched — forcing it direct would invoke
|
|
270
|
+
* the stub, which throws. See {@link t.ToolNodeOptions.interruptingToolNames}.
|
|
271
|
+
*/
|
|
272
|
+
interruptingToolNames;
|
|
273
|
+
/**
|
|
252
274
|
* File checkpointer extracted from the local coding tool bundle when
|
|
253
275
|
* `toolExecution.local.fileCheckpointing === true`. Exposed via
|
|
254
276
|
* {@link getFileCheckpointer}. Undefined when checkpointing is off
|
|
@@ -287,7 +309,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
287
309
|
* other's in-flight state.
|
|
288
310
|
*/
|
|
289
311
|
anonBatchCounter = 0;
|
|
290
|
-
constructor({ tools, toolMap, name, tags, trace, runLangfuse, agentLangfuse, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, eagerEventToolExecution, eagerEventToolExecutions, eagerEventToolUsageCount, agentId, executingAgentId, directToolNames, codeSessionToolNames, maxContextTokens, maxToolResultChars, hookRegistry, humanInTheLoop, toolOutputReferences, toolOutputRegistry, toolExecution, fileCheckpointer }) {
|
|
312
|
+
constructor({ tools, toolMap, name, tags, trace, runLangfuse, agentLangfuse, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, eagerEventToolExecution, eagerEventToolExecutions, eagerEventToolUsageCount, agentId, executingAgentId, directToolNames, interruptingToolNames, codeSessionToolNames, maxContextTokens, maxToolResultChars, hookRegistry, humanInTheLoop, toolOutputReferences, toolOutputRegistry, toolExecution, fileCheckpointer }) {
|
|
291
313
|
super({
|
|
292
314
|
name: name ?? TOOL_NODE_RUN_NAME,
|
|
293
315
|
tags,
|
|
@@ -314,6 +336,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
314
336
|
this.agentId = agentId;
|
|
315
337
|
this.executingAgentId = executingAgentId ?? agentId;
|
|
316
338
|
this.directToolNames = directToolNames;
|
|
339
|
+
this.interruptingToolNames = interruptingToolNames != null && interruptingToolNames.size > 0 ? interruptingToolNames : void 0;
|
|
317
340
|
this.codeSessionToolNames = codeSessionToolNames != null && codeSessionToolNames.length > 0 ? new Set(codeSessionToolNames) : void 0;
|
|
318
341
|
this.maxToolResultChars = maxToolResultChars ?? require_truncation.calculateMaxToolResultChars(maxContextTokens);
|
|
319
342
|
this.hookRegistry = hookRegistry;
|
|
@@ -670,12 +693,20 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
670
693
|
if (!this.handleToolErrors) throw e;
|
|
671
694
|
if ((0, _langchain_langgraph.isGraphInterrupt)(e)) throw e;
|
|
672
695
|
if (this.errorHandler) try {
|
|
673
|
-
await this.errorHandler({
|
|
696
|
+
if (await this.errorHandler({
|
|
674
697
|
error: e,
|
|
675
698
|
id: call.id,
|
|
676
699
|
name: call.name,
|
|
677
700
|
input: call.args
|
|
678
|
-
}, config.metadata)
|
|
701
|
+
}, config.metadata) === false && call.id != null && call.id !== "")
|
|
702
|
+
/**
|
|
703
|
+
* The handler could not dispatch the error completion (typically
|
|
704
|
+
* a resume pass, where a fast-failing tool errors before the
|
|
705
|
+
* step replay registers its run step). Remember the call so the
|
|
706
|
+
* output loop dispatches the completion itself instead of
|
|
707
|
+
* assuming the handler covered it.
|
|
708
|
+
*/
|
|
709
|
+
this.undispatchedToolErrors.add(call.id);
|
|
679
710
|
} catch (handlerError) {
|
|
680
711
|
console.error("Error in errorHandler:", {
|
|
681
712
|
toolName: call.name,
|
|
@@ -1110,7 +1141,8 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1110
1141
|
if ((0, _langchain_langgraph.isCommand)(output)) continue;
|
|
1111
1142
|
const toolMessage = output;
|
|
1112
1143
|
const toolCallId = call.id ?? "";
|
|
1113
|
-
if (toolMessage.status === "error" && this.errorHandler != null)
|
|
1144
|
+
if (toolMessage.status === "error" && this.errorHandler != null) if (this.undispatchedToolErrors.has(toolCallId)) this.undispatchedToolErrors.delete(toolCallId);
|
|
1145
|
+
else continue;
|
|
1114
1146
|
if (this.sessions && this.participatesInCodeSession(call.name)) {
|
|
1115
1147
|
const artifact = toolMessage.artifact;
|
|
1116
1148
|
const execSessionId = artifact?.session_id;
|
|
@@ -1941,6 +1973,61 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1941
1973
|
return converted;
|
|
1942
1974
|
}
|
|
1943
1975
|
/**
|
|
1976
|
+
* Execute a group of direct (in-process) tool calls with interrupt-safe
|
|
1977
|
+
* ordering, returning outputs aligned 1:1 with `directCalls`.
|
|
1978
|
+
*
|
|
1979
|
+
* Fast path (the common case): when no call in the group is in
|
|
1980
|
+
* `interruptingToolNames`, this is a single `Promise.all` — byte-for-byte
|
|
1981
|
+
* the prior behavior, so ordinary batches are unaffected.
|
|
1982
|
+
*
|
|
1983
|
+
* Interrupt-safe path: when the group contains an interrupting tool (e.g.
|
|
1984
|
+
* `ask_user_question`, whose body raises a LangGraph `interrupt()` to
|
|
1985
|
+
* collect a human answer), the interrupting calls run as their own awaited
|
|
1986
|
+
* group **first**; only after they all settle without interrupting do the
|
|
1987
|
+
* remaining (potentially non-idempotent) siblings run. If an interrupting
|
|
1988
|
+
* call throws a `GraphInterrupt`, the `await` below rejects and unwinds the
|
|
1989
|
+
* whole ToolNode *before* any non-interrupting sibling has started — so a
|
|
1990
|
+
* sibling with real side effects (send_email, billing) never executes on
|
|
1991
|
+
* the first pass. On the resume pass LangGraph re-runs the batch from the
|
|
1992
|
+
* top; the interrupting tool resolves with the host's answer instead of
|
|
1993
|
+
* throwing, and the siblings execute for the FIRST time, exactly once.
|
|
1994
|
+
*
|
|
1995
|
+
* Without this ordering, a flat `Promise.all` starts every sibling
|
|
1996
|
+
* concurrently, so a non-idempotent sibling can complete its side effect
|
|
1997
|
+
* before the interrupt unwinds and then run a SECOND time on resume — the
|
|
1998
|
+
* duplicate side effect this method exists to prevent. Interrupting tools
|
|
1999
|
+
* are expected to be side-effect-free (they only suspend), so running them
|
|
2000
|
+
* as a group and re-running them on resume is harmless.
|
|
2001
|
+
*
|
|
2002
|
+
* `batchIndices[i]` is `directCalls[i]`'s position within the parent
|
|
2003
|
+
* ToolNode batch (used for `{{tool<i>turn<n>}}` registration); it is
|
|
2004
|
+
* preserved regardless of execution order. `baseContext` carries the
|
|
2005
|
+
* batch-scoped fields every call shares; `batchIndex` is filled in
|
|
2006
|
+
* per-call here.
|
|
2007
|
+
*/
|
|
2008
|
+
async runDirectBatchInterruptSafe(directCalls, batchIndices, config, baseContext) {
|
|
2009
|
+
const runOne = (call, position) => this.runDirectToolWithLifecycleHooks(call, config, {
|
|
2010
|
+
...baseContext,
|
|
2011
|
+
batchIndex: batchIndices[position]
|
|
2012
|
+
});
|
|
2013
|
+
const interrupting = this.interruptingToolNames;
|
|
2014
|
+
if (!(interrupting != null && directCalls.some((call) => interrupting.has(call.name)))) return Promise.all(directCalls.map((call, i) => runOne(call, i)));
|
|
2015
|
+
const outputs = new Array(directCalls.length);
|
|
2016
|
+
const interruptingPositions = [];
|
|
2017
|
+
const regularPositions = [];
|
|
2018
|
+
for (let i = 0; i < directCalls.length; i++) if (interrupting.has(directCalls[i].name)) interruptingPositions.push(i);
|
|
2019
|
+
else regularPositions.push(i);
|
|
2020
|
+
const interruptingOutputs = await Promise.all(interruptingPositions.map((i) => runOne(directCalls[i], i)));
|
|
2021
|
+
interruptingPositions.forEach((i, k) => {
|
|
2022
|
+
outputs[i] = interruptingOutputs[k];
|
|
2023
|
+
});
|
|
2024
|
+
const regularOutputs = await Promise.all(regularPositions.map((i) => runOne(directCalls[i], i)));
|
|
2025
|
+
regularPositions.forEach((i, k) => {
|
|
2026
|
+
outputs[i] = regularOutputs[k];
|
|
2027
|
+
});
|
|
2028
|
+
return outputs;
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
1944
2031
|
* Execute all tool calls via ON_TOOL_EXECUTE event dispatch.
|
|
1945
2032
|
* Injected messages are placed AFTER ToolMessages to respect provider
|
|
1946
2033
|
* message ordering (AIMessage tool_calls must be immediately followed
|
|
@@ -2077,15 +2164,14 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
2077
2164
|
}
|
|
2078
2165
|
}
|
|
2079
2166
|
const directAdditionalContexts = [];
|
|
2080
|
-
const directOutputs = directCalls.length > 0 ? await
|
|
2081
|
-
batchIndex: directIndices[i],
|
|
2167
|
+
const directOutputs = directCalls.length > 0 ? await this.runDirectBatchInterruptSafe(directCalls, directIndices, config, {
|
|
2082
2168
|
turn,
|
|
2083
2169
|
batchScopeId,
|
|
2084
2170
|
resolvedArgsByCallId,
|
|
2085
2171
|
preBatchSnapshot,
|
|
2086
2172
|
additionalContextsSink: directAdditionalContexts,
|
|
2087
2173
|
runInput: input
|
|
2088
|
-
})
|
|
2174
|
+
}) : [];
|
|
2089
2175
|
if (directCalls.length > 0 && directOutputs.length > 0) await this.handleRunToolCompletions(directCalls, directOutputs, config, resolvedArgsByCallId);
|
|
2090
2176
|
const eventResult = eventCalls.length > 0 ? await this.dispatchToolEvents(eventCalls, config, {
|
|
2091
2177
|
batchIndices: eventIndices,
|
|
@@ -2113,15 +2199,14 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
2113
2199
|
} else {
|
|
2114
2200
|
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2115
2201
|
const directAdditionalContexts = [];
|
|
2116
|
-
const toolOutputs = await
|
|
2117
|
-
batchIndex: i,
|
|
2202
|
+
const toolOutputs = await this.runDirectBatchInterruptSafe(filteredCalls, filteredCalls.map((_call, i) => i), config, {
|
|
2118
2203
|
turn,
|
|
2119
2204
|
batchScopeId,
|
|
2120
2205
|
resolvedArgsByCallId,
|
|
2121
2206
|
preBatchSnapshot,
|
|
2122
2207
|
additionalContextsSink: directAdditionalContexts,
|
|
2123
2208
|
runInput: input
|
|
2124
|
-
})
|
|
2209
|
+
});
|
|
2125
2210
|
await this.handleRunToolCompletions(filteredCalls, toolOutputs, config, resolvedArgsByCallId);
|
|
2126
2211
|
outputs = directAdditionalContexts.length > 0 ? [...toolOutputs, new _langchain_core_messages.HumanMessage({
|
|
2127
2212
|
content: directAdditionalContexts.join("\n\n"),
|