langchain 1.5.12 → 1.5.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ToolNode.cjs","names":["BaseMessage","ToolInvocationError","ToolMessage","RunnableCallable","isGraphInterrupt","MiddlewareError","mergeAbortSignals","isCommand","ToolInputParsingException","AIMessage","Command","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\n/* oxlint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n StateDefinitionInit,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { MiddlewareError, ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\n/**\n * Error message template for when middleware adds tools that can't be executed.\n * This happens when middleware modifies tools in wrapModelCall but doesn't provide\n * a wrapToolCall handler to execute them.\n */\nconst getInvalidToolError = (\n toolName: string,\n availableTools: string[]\n): string =>\n `Error: ${toolName} is not a valid tool, try one of [${availableTools.join(\", \")}].`;\n\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (\n input: unknown\n): input is { lg_tool_call: ToolCall; jumpTo?: string } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (ToolInvocationError.isInstance(error)) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends StateDefinitionInit = any,\n ContextSchema extends InteropZodObject = any,\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateDefinitionInit>[\"State\"] &\n AgentBuiltInState,\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * A recoverable tool error (e.g. tool-input schema validation) can be\n * rewrapped as a {@link MiddlewareError} with the original error on `.cause`\n * — once per `wrapToolCall` middleware, so it may be nested several layers\n * deep. Walk the cause chain to the root; if it's a {@link ToolInvocationError},\n * unwrap it so the intended `handleToolErrors` self-correction path still\n * applies. Genuine middleware errors stay fatal by default.\n */\n let effectiveError = error;\n let errorFromMiddleware = isMiddlewareError;\n if (isMiddlewareError) {\n let unwrapped: unknown = error;\n while (MiddlewareError.isInstance(unwrapped)) {\n unwrapped = unwrapped.cause;\n }\n if (ToolInvocationError.isInstance(unwrapped)) {\n effectiveError = unwrapped;\n errorFromMiddleware = false;\n }\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (errorFromMiddleware && this.handleToolErrors !== true) {\n throw effectiveError;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw effectiveError;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(effectiveError, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw effectiveError;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${effectiveError}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw effectiveError;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n store: lgConfig?.store,\n configurable: lgConfig?.configurable,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request.\n * For dynamically registered tools, this may be undefined.\n */\n const registeredTool = this.tools.find((t) => t.name === call.name);\n\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n *\n * The handler now accepts an overridden tool from the request, allowing\n * middleware to provide tool implementations for dynamically registered tools.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall, tool: requestTool } = request;\n\n /**\n * Use the tool from the request (which may be overridden via spread syntax)\n * or fall back to finding it in registered tools.\n * This allows middleware to provide dynamic tool implementations.\n */\n const tool =\n requestTool ?? this.tools.find((t) => t.name === toolCall.name);\n\n if (tool === undefined) {\n /**\n * Tool not found - return a graceful error message rather than throwing.\n * This allows the LLM to see the error and potentially retry.\n */\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(toolCall.name, availableTools),\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n\n /**\n * Cast tool to a common invokable type.\n * The tool can be from registered tools (StructuredToolInterface | DynamicTool | RunnableToolLike)\n * or from middleware override (ClientTool | ServerTool).\n */\n const invokableTool = tool as\n | StructuredToolInterface\n | DynamicTool\n | RunnableToolLike;\n\n try {\n const output = await invokableTool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: invokableTool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Create request object for middleware\n * Cast to ToolCallRequest<AgentBuiltInState> to satisfy type constraints\n * of wrapToolCall which expects AgentBuiltInState\n */\n const request: ToolCallRequest<AgentBuiltInState> = {\n toolCall: call,\n tool: registeredTool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - if tool wasn't found, return graceful error\n */\n if (!registeredTool) {\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(call.name, availableTools),\n tool_call_id: call.id!,\n name: call.name,\n status: \"error\",\n });\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & AgentBuiltInState,\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call: _, jumpTo: __, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToolNode.cjs","names":["BaseMessage","ToolInvocationError","ToolMessage","RunnableCallable","isGraphInterrupt","MiddlewareError","mergeAbortSignals","isCommand","ToolInputParsingException","AIMessage","Command","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\n/* oxlint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n StateDefinitionInit,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { MiddlewareError, ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\n/**\n * Error message template for when middleware adds tools that can't be executed.\n * This happens when middleware modifies tools in wrapModelCall but doesn't provide\n * a wrapToolCall handler to execute them.\n */\nconst getInvalidToolError = (\n toolName: string,\n availableTools: string[]\n): string =>\n `Error: ${toolName} is not a valid tool, try one of [${availableTools.join(\", \")}].`;\n\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (\n input: unknown\n): input is { lg_tool_call: ToolCall; jumpTo?: string } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (ToolInvocationError.isInstance(error)) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends StateDefinitionInit = any,\n ContextSchema extends InteropZodObject = any,\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateDefinitionInit>[\"State\"] &\n AgentBuiltInState,\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * A recoverable tool error (e.g. tool-input schema validation) can be\n * rewrapped as a {@link MiddlewareError} with the original error on `.cause`\n * — once per `wrapToolCall` middleware, so it may be nested several layers\n * deep. Walk the cause chain to the root; if it's a {@link ToolInvocationError},\n * unwrap it so the intended `handleToolErrors` self-correction path still\n * applies. Genuine middleware errors stay fatal by default.\n */\n let effectiveError = error;\n let errorFromMiddleware = isMiddlewareError;\n if (isMiddlewareError) {\n let unwrapped: unknown = error;\n while (MiddlewareError.isInstance(unwrapped)) {\n unwrapped = unwrapped.cause;\n }\n if (ToolInvocationError.isInstance(unwrapped)) {\n effectiveError = unwrapped;\n errorFromMiddleware = false;\n }\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (errorFromMiddleware && this.handleToolErrors !== true) {\n throw effectiveError;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw effectiveError;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(effectiveError, call);\n if (result && ToolMessage.isInstance(result)) {\n result.status ??= \"error\";\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw effectiveError;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${effectiveError}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n status: \"error\",\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw effectiveError;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n store: lgConfig?.store,\n configurable: lgConfig?.configurable,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request.\n * For dynamically registered tools, this may be undefined.\n */\n const registeredTool = this.tools.find((t) => t.name === call.name);\n\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n *\n * The handler now accepts an overridden tool from the request, allowing\n * middleware to provide tool implementations for dynamically registered tools.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall, tool: requestTool } = request;\n\n /**\n * Use the tool from the request (which may be overridden via spread syntax)\n * or fall back to finding it in registered tools.\n * This allows middleware to provide dynamic tool implementations.\n */\n const tool =\n requestTool ?? this.tools.find((t) => t.name === toolCall.name);\n\n if (tool === undefined) {\n /**\n * Tool not found - return a graceful error message rather than throwing.\n * This allows the LLM to see the error and potentially retry.\n */\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(toolCall.name, availableTools),\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n\n /**\n * Cast tool to a common invokable type.\n * The tool can be from registered tools (StructuredToolInterface | DynamicTool | RunnableToolLike)\n * or from middleware override (ClientTool | ServerTool).\n */\n const invokableTool = tool as\n | StructuredToolInterface\n | DynamicTool\n | RunnableToolLike;\n\n try {\n const output = await invokableTool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: invokableTool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Create request object for middleware\n * Cast to ToolCallRequest<AgentBuiltInState> to satisfy type constraints\n * of wrapToolCall which expects AgentBuiltInState\n */\n const request: ToolCallRequest<AgentBuiltInState> = {\n toolCall: call,\n tool: registeredTool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - if tool wasn't found, return graceful error\n */\n if (!registeredTool) {\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(call.name, availableTools),\n tool_call_id: call.id!,\n name: call.name,\n status: \"error\",\n });\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & AgentBuiltInState,\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call: _, jumpTo: __, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
@@ -32,7 +32,8 @@ function defaultHandleToolErrors(error, toolCall) {
32
32
  if (ToolInvocationError.isInstance(error)) return new ToolMessage({
33
33
  content: error.message,
34
34
  tool_call_id: toolCall.id,
35
- name: toolCall.name
35
+ name: toolCall.name,
36
+ status: "error"
36
37
  });
37
38
  /**
38
39
  * Catch all other tool errors and convert to ToolMessage
@@ -40,7 +41,8 @@ function defaultHandleToolErrors(error, toolCall) {
40
41
  return new ToolMessage({
41
42
  content: `${error}\n Please fix your mistakes.`,
42
43
  tool_call_id: toolCall.id,
43
- name: toolCall.name
44
+ name: toolCall.name,
45
+ status: "error"
44
46
  });
45
47
  }
46
48
  /**
@@ -157,7 +159,10 @@ var ToolNode = class extends RunnableCallable {
157
159
  */
158
160
  if (typeof this.handleToolErrors === "function") {
159
161
  const result = this.handleToolErrors(effectiveError, call);
160
- if (result && ToolMessage.isInstance(result)) return result;
162
+ if (result && ToolMessage.isInstance(result)) {
163
+ result.status ??= "error";
164
+ return result;
165
+ }
161
166
  /**
162
167
  * `handleToolErrors` returned undefined - re-raise
163
168
  */
@@ -165,7 +170,8 @@ var ToolNode = class extends RunnableCallable {
165
170
  } else if (this.handleToolErrors) return new ToolMessage({
166
171
  name: call.name,
167
172
  content: `${effectiveError}\n Please fix your mistakes.`,
168
- tool_call_id: call.id
173
+ tool_call_id: call.id,
174
+ status: "error"
169
175
  });
170
176
  /**
171
177
  * Shouldn't reach here, but throw as fallback
@@ -1 +1 @@
1
- {"version":3,"file":"ToolNode.js","names":[],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\n/* oxlint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n StateDefinitionInit,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { MiddlewareError, ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\n/**\n * Error message template for when middleware adds tools that can't be executed.\n * This happens when middleware modifies tools in wrapModelCall but doesn't provide\n * a wrapToolCall handler to execute them.\n */\nconst getInvalidToolError = (\n toolName: string,\n availableTools: string[]\n): string =>\n `Error: ${toolName} is not a valid tool, try one of [${availableTools.join(\", \")}].`;\n\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (\n input: unknown\n): input is { lg_tool_call: ToolCall; jumpTo?: string } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (ToolInvocationError.isInstance(error)) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends StateDefinitionInit = any,\n ContextSchema extends InteropZodObject = any,\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateDefinitionInit>[\"State\"] &\n AgentBuiltInState,\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * A recoverable tool error (e.g. tool-input schema validation) can be\n * rewrapped as a {@link MiddlewareError} with the original error on `.cause`\n * — once per `wrapToolCall` middleware, so it may be nested several layers\n * deep. Walk the cause chain to the root; if it's a {@link ToolInvocationError},\n * unwrap it so the intended `handleToolErrors` self-correction path still\n * applies. Genuine middleware errors stay fatal by default.\n */\n let effectiveError = error;\n let errorFromMiddleware = isMiddlewareError;\n if (isMiddlewareError) {\n let unwrapped: unknown = error;\n while (MiddlewareError.isInstance(unwrapped)) {\n unwrapped = unwrapped.cause;\n }\n if (ToolInvocationError.isInstance(unwrapped)) {\n effectiveError = unwrapped;\n errorFromMiddleware = false;\n }\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (errorFromMiddleware && this.handleToolErrors !== true) {\n throw effectiveError;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw effectiveError;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(effectiveError, call);\n if (result && ToolMessage.isInstance(result)) {\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw effectiveError;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${effectiveError}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw effectiveError;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n store: lgConfig?.store,\n configurable: lgConfig?.configurable,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request.\n * For dynamically registered tools, this may be undefined.\n */\n const registeredTool = this.tools.find((t) => t.name === call.name);\n\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n *\n * The handler now accepts an overridden tool from the request, allowing\n * middleware to provide tool implementations for dynamically registered tools.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall, tool: requestTool } = request;\n\n /**\n * Use the tool from the request (which may be overridden via spread syntax)\n * or fall back to finding it in registered tools.\n * This allows middleware to provide dynamic tool implementations.\n */\n const tool =\n requestTool ?? this.tools.find((t) => t.name === toolCall.name);\n\n if (tool === undefined) {\n /**\n * Tool not found - return a graceful error message rather than throwing.\n * This allows the LLM to see the error and potentially retry.\n */\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(toolCall.name, availableTools),\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n\n /**\n * Cast tool to a common invokable type.\n * The tool can be from registered tools (StructuredToolInterface | DynamicTool | RunnableToolLike)\n * or from middleware override (ClientTool | ServerTool).\n */\n const invokableTool = tool as\n | StructuredToolInterface\n | DynamicTool\n | RunnableToolLike;\n\n try {\n const output = await invokableTool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: invokableTool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Create request object for middleware\n * Cast to ToolCallRequest<AgentBuiltInState> to satisfy type constraints\n * of wrapToolCall which expects AgentBuiltInState\n */\n const request: ToolCallRequest<AgentBuiltInState> = {\n toolCall: call,\n tool: registeredTool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - if tool wasn't found, return graceful error\n */\n if (!registeredTool) {\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(call.name, availableTools),\n tool_call_id: call.id!,\n name: call.name,\n status: \"error\",\n });\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & AgentBuiltInState,\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call: _, jumpTo: __, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToolNode.js","names":[],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\n/* oxlint-disable no-instanceof/no-instanceof */\nimport { BaseMessage, ToolMessage, AIMessage } from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type LangGraphRunnableConfig,\n StateDefinitionInit,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { MiddlewareError, ToolInvocationError } from \"../errors.js\";\nimport type {\n WrapToolCallHook,\n ToolCallRequest,\n ToAnnotationRoot,\n} from \"../middleware/types.js\";\nimport type { AgentBuiltInState } from \"../runtime.js\";\n\n/**\n * Error message template for when middleware adds tools that can't be executed.\n * This happens when middleware modifies tools in wrapModelCall but doesn't provide\n * a wrapToolCall handler to execute them.\n */\nconst getInvalidToolError = (\n toolName: string,\n availableTools: string[]\n): string =>\n `Error: ${toolName} is not a valid tool, try one of [${availableTools.join(\", \")}].`;\n\n/**\n * The name of the tool node in the state graph.\n */\nexport const TOOLS_NODE_NAME = \"tools\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * **Default behavior** (matches Python):\n * - Catches only `ToolInvocationError` (invalid arguments from model) and converts to ToolMessage\n * - Re-raises all other errors including errors from `wrapToolCall` middleware\n *\n * If `true`:\n * - Catches all errors and returns a ToolMessage with the error\n *\n * If `false`:\n * - All errors are thrown immediately\n *\n * If a function is provided:\n * - If function returns a `ToolMessage`, use it as the result\n * - If function returns `undefined`, re-raise the error\n *\n * @default A function that only catches ToolInvocationError\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n /**\n * Optional wrapper function for tool execution.\n * Allows middleware to intercept and modify tool calls before execution.\n * The wrapper receives the tool call request and a handler function to execute the tool.\n */\n wrapToolCall?: WrapToolCallHook;\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(BaseMessage.isInstance);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (\n input: unknown\n): input is { lg_tool_call: ToolCall; jumpTo?: string } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * Default error handler for tool errors.\n *\n * This is applied to errors from baseHandler (tool execution).\n * For errors from wrapToolCall middleware, those are handled separately\n * and will bubble up by default.\n *\n * Catches all tool execution errors and converts them to ToolMessage.\n * This allows the LLM to see the error and potentially retry with different arguments.\n */\nfunction defaultHandleToolErrors(\n error: unknown,\n toolCall: ToolCall\n): ToolMessage | undefined {\n if (ToolInvocationError.isInstance(error)) {\n return new ToolMessage({\n content: error.message,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n /**\n * Catch all other tool errors and convert to ToolMessage\n */\n return new ToolMessage({\n content: `${error}\\n Please fix your mistakes.`,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n}\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod/v3\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\nexport class ToolNode<\n StateSchema extends StateDefinitionInit = any,\n ContextSchema extends InteropZodObject = any,\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) =\n defaultHandleToolErrors;\n\n wrapToolCall: WrapToolCallHook | undefined;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors, signal, wrapToolCall } =\n options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateDefinitionInit>[\"State\"] &\n AgentBuiltInState,\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = signal;\n this.wrapToolCall = wrapToolCall;\n }\n\n /**\n * Handle errors from tool execution or middleware.\n * @param error - The error to handle\n * @param call - The tool call that caused the error\n * @param isMiddlewareError - Whether the error came from wrapToolCall middleware\n * @returns ToolMessage if error is handled, otherwise re-throws\n */\n #handleError(\n error: unknown,\n call: ToolCall,\n isMiddlewareError: boolean\n ): ToolMessage {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n if (isGraphInterrupt(error)) {\n throw error;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw error;\n }\n\n /**\n * A recoverable tool error (e.g. tool-input schema validation) can be\n * rewrapped as a {@link MiddlewareError} with the original error on `.cause`\n * — once per `wrapToolCall` middleware, so it may be nested several layers\n * deep. Walk the cause chain to the root; if it's a {@link ToolInvocationError},\n * unwrap it so the intended `handleToolErrors` self-correction path still\n * applies. Genuine middleware errors stay fatal by default.\n */\n let effectiveError = error;\n let errorFromMiddleware = isMiddlewareError;\n if (isMiddlewareError) {\n let unwrapped: unknown = error;\n while (MiddlewareError.isInstance(unwrapped)) {\n unwrapped = unwrapped.cause;\n }\n if (ToolInvocationError.isInstance(unwrapped)) {\n effectiveError = unwrapped;\n errorFromMiddleware = false;\n }\n }\n\n /**\n * If error is from middleware and handleToolErrors is not true, bubble up\n * (default handler and false both re-raise middleware errors)\n */\n if (errorFromMiddleware && this.handleToolErrors !== true) {\n throw effectiveError;\n }\n\n /**\n * If handleToolErrors is false, throw all errors\n */\n if (!this.handleToolErrors) {\n throw effectiveError;\n }\n\n /**\n * Apply handleToolErrors to the error\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(effectiveError, call);\n if (result && ToolMessage.isInstance(result)) {\n result.status ??= \"error\";\n return result;\n }\n\n /**\n * `handleToolErrors` returned undefined - re-raise\n */\n throw effectiveError;\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${effectiveError}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n status: \"error\",\n });\n }\n\n /**\n * Shouldn't reach here, but throw as fallback\n */\n throw effectiveError;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig,\n state: AgentBuiltInState\n ): Promise<ToolMessage | Command> {\n /**\n * Build runtime from LangGraph config\n */\n const lgConfig = config as LangGraphRunnableConfig;\n const runtime = {\n context: lgConfig?.context,\n store: lgConfig?.store,\n configurable: lgConfig?.configurable,\n writer: lgConfig?.writer,\n interrupt: lgConfig?.interrupt,\n signal: lgConfig?.signal,\n };\n\n /**\n * Find the tool instance to include in the request.\n * For dynamically registered tools, this may be undefined.\n */\n const registeredTool = this.tools.find((t) => t.name === call.name);\n\n /**\n * Define the base handler that executes the tool.\n * When wrapToolCall middleware is present, this handler does NOT catch errors\n * so the middleware can handle them.\n * When no middleware, errors are caught and handled here.\n *\n * The handler now accepts an overridden tool from the request, allowing\n * middleware to provide tool implementations for dynamically registered tools.\n */\n const baseHandler = async (\n request: ToolCallRequest\n ): Promise<ToolMessage | Command> => {\n const { toolCall, tool: requestTool } = request;\n\n /**\n * Use the tool from the request (which may be overridden via spread syntax)\n * or fall back to finding it in registered tools.\n * This allows middleware to provide dynamic tool implementations.\n */\n const tool =\n requestTool ?? this.tools.find((t) => t.name === toolCall.name);\n\n if (tool === undefined) {\n /**\n * Tool not found - return a graceful error message rather than throwing.\n * This allows the LLM to see the error and potentially retry.\n */\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(toolCall.name, availableTools),\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n });\n }\n\n /**\n * Cast tool to a common invokable type.\n * The tool can be from registered tools (StructuredToolInterface | DynamicTool | RunnableToolLike)\n * or from middleware override (ClientTool | ServerTool).\n */\n const invokableTool = tool as\n | StructuredToolInterface\n | DynamicTool\n | RunnableToolLike;\n\n try {\n const output = await invokableTool.invoke(\n { ...toolCall, type: \"tool_call\" },\n {\n ...config,\n /**\n * extend to match ToolRuntime\n */\n config,\n toolCallId: toolCall.id!,\n state: config.configurable?.__pregel_scratchpad?.currentTaskInput,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (ToolMessage.isInstance(output) || isCommand(output)) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: invokableTool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: toolCall.id!,\n });\n } catch (e: unknown) {\n /**\n * Handle errors from tool execution (not from wrapToolCall)\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, toolCall);\n }\n /**\n * Re-throw to be handled by caller\n */\n throw e;\n }\n };\n\n /**\n * Create request object for middleware\n * Cast to ToolCallRequest<AgentBuiltInState> to satisfy type constraints\n * of wrapToolCall which expects AgentBuiltInState\n */\n const request: ToolCallRequest<AgentBuiltInState> = {\n toolCall: call,\n tool: registeredTool,\n state,\n runtime,\n };\n\n /**\n * If wrapToolCall is provided, use it to wrap the tool execution\n */\n if (this.wrapToolCall) {\n try {\n return await this.wrapToolCall(request, baseHandler);\n } catch (e: unknown) {\n /**\n * Handle middleware errors\n */\n return this.#handleError(e, call, true);\n }\n }\n\n /**\n * No wrapToolCall - if tool wasn't found, return graceful error\n */\n if (!registeredTool) {\n const availableTools = this.tools.map((t) => t.name);\n return new ToolMessage({\n content: getInvalidToolError(call.name, availableTools),\n tool_call_id: call.id!,\n name: call.name,\n status: \"error\",\n });\n }\n\n /**\n * No wrapToolCall - execute tool directly and handle errors here\n */\n try {\n return await baseHandler(request);\n } catch (e: unknown) {\n /**\n * Handle tool errors when no middleware provided\n */\n return this.#handleError(e, call, false);\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & AgentBuiltInState,\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n const { lg_tool_call: _, jumpTo: __, ...newState } = state;\n outputs = [await this.runTool(state.lg_tool_call, config, newState)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (AIMessage.isInstance(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (!AIMessage.isInstance(aiMessage)) {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config, state)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n return x instanceof Send;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langchain",
3
- "version": "1.5.12",
3
+ "version": "1.5.15",
4
4
  "description": "Typescript bindings for langchain",
5
5
  "author": "LangChain",
6
6
  "license": "MIT",
@@ -54,14 +54,14 @@
54
54
  "vitest": "^4.1.11",
55
55
  "yaml": "^2.9.0",
56
56
  "@langchain/anthropic": "1.5.11",
57
- "@langchain/aws": "1.4.5",
58
- "@langchain/core": "^1.2.12",
59
- "@langchain/fireworks": "0.2.13",
60
- "@langchain/openai": "1.5.13",
61
- "@langchain/tsconfig": "0.0.1"
57
+ "@langchain/aws": "1.4.6",
58
+ "@langchain/core": "^1.2.14",
59
+ "@langchain/fireworks": "0.2.16",
60
+ "@langchain/tsconfig": "0.0.1",
61
+ "@langchain/openai": "1.6.1"
62
62
  },
63
63
  "peerDependencies": {
64
- "@langchain/core": "^1.2.12"
64
+ "@langchain/core": "^1.2.14"
65
65
  },
66
66
  "dependencies": {
67
67
  "@langchain/langgraph": "^1.4.13",