{"version":3,"file":"tool_node.cjs","names":["isBaseMessage","RunnableCallable","isCommand","ToolMessage","isGraphInterrupt","Command","_isSend","END"],"sources":["../../src/prebuilt/tool_node.ts"],"sourcesContent":["import {\n  BaseMessage,\n  ToolMessage,\n  AIMessage,\n  isBaseMessage,\n  isAIMessage,\n} from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport { DynamicTool, StructuredToolInterface } from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport { RunnableCallable } from \"../utils.js\";\nimport { MessagesAnnotation } from \"../graph/messages_annotation.js\";\nimport { isGraphInterrupt } from \"../errors.js\";\nimport { END, isCommand, Command, _isSend, Send } from \"../constants.js\";\n\nexport type ToolNodeOptions = {\n  name?: string;\n  tags?: string[];\n  handleToolErrors?: boolean;\n};\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n  Array.isArray(input) && input.every(isBaseMessage);\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 = (input: unknown): input is { lg_tool_call: ToolCall } =>\n  typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * A node that runs the tools requested in the last AIMessage. It can be used\n * either in StateGraph with a \"messages\" key or in MessageGraph. If multiple\n * tool calls are requested, they will be run in parallel. The output will be\n * a list of ToolMessages, one for each tool call.\n *\n * @example\n * ```ts\n * import { ToolNode } from \"@langchain/langgraph/prebuilt\";\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n * import { AIMessage } from \"@langchain/core/messages\";\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 *\n * @example\n * ```ts\n * import {\n *   StateGraph,\n *   MessagesAnnotation,\n * } from \"@langchain/langgraph\";\n * import { ToolNode } from \"@langchain/langgraph/prebuilt\";\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n * import { ChatAnthropic } from \"@langchain/anthropic\";\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 modelWithTools = new ChatAnthropic({\n *   model: \"claude-3-haiku-20240307\",\n *   temperature: 0\n * }).bindTools(tools);\n *\n * const toolNodeForGraph = new ToolNode(tools)\n *\n * const shouldContinue = (state: typeof MessagesAnnotation.State) => {\n *   const { messages } = state;\n *   const lastMessage = messages[messages.length - 1];\n *   if (\"tool_calls\" in lastMessage && Array.isArray(lastMessage.tool_calls) && lastMessage.tool_calls?.length) {\n *     return \"tools\";\n *   }\n *   return \"__end__\";\n * }\n *\n * const callModel = async (state: typeof MessagesAnnotation.State) => {\n *   const { messages } = state;\n *   const response = await modelWithTools.invoke(messages);\n *   return { messages: response };\n * }\n *\n * const graph = new StateGraph(MessagesAnnotation)\n *   .addNode(\"agent\", callModel)\n *   .addNode(\"tools\", toolNodeForGraph)\n *   .addEdge(\"__start__\", \"agent\")\n *   .addConditionalEdges(\"agent\", shouldContinue)\n *   .addEdge(\"tools\", \"agent\")\n *   .compile();\n *\n * const inputs = {\n *   messages: [{ role: \"user\", content: \"what is the weather in SF?\" }],\n * };\n *\n * const stream = await graph.stream(inputs, {\n *   streamMode: \"values\",\n * });\n *\n * for await (const { messages } of stream) {\n *   console.log(messages);\n * }\n * // Returns the messages in the state at each step of execution\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<T = any> extends RunnableCallable<T, T> {\n  tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n  handleToolErrors = true;\n\n  trace = false;\n\n  constructor(\n    tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n    options?: ToolNodeOptions\n  ) {\n    const { name, tags, handleToolErrors } = options ?? {};\n    super({ name, tags, func: (input, config) => this.run(input, config) });\n    this.tools = tools;\n    this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n  }\n\n  protected async runTool(\n    call: ToolCall,\n    config: RunnableConfig\n  ): Promise<ToolMessage | Command> {\n    const tool = this.tools.find((tool) => tool.name === call.name);\n    try {\n      if (tool === undefined) {\n        throw new Error(`Tool \"${call.name}\" not found.`);\n      }\n      const output = await tool.invoke({ ...call, type: \"tool_call\" }, config);\n\n      if (\n        (isBaseMessage(output) && output.getType() === \"tool\") ||\n        isCommand(output)\n      ) {\n        return output as ToolMessage | Command;\n      }\n\n      return new ToolMessage({\n        status: \"success\",\n        name: tool.name,\n        content: typeof output === \"string\" ? output : JSON.stringify(output),\n        tool_call_id: call.id!,\n      });\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (e: any) {\n      if (!this.handleToolErrors) throw e;\n\n      if (isGraphInterrupt(e)) {\n        // `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        throw e;\n      }\n\n      return new ToolMessage({\n        status: \"error\",\n        content: `Error: ${e.message}\\n Please fix your mistakes.`,\n        name: call.name,\n        tool_call_id: call.id ?? \"\",\n      });\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  protected async run(input: unknown, config: RunnableConfig): Promise<T> {\n    let outputs: (ToolMessage | Command)[];\n\n    if (isSendInput(input)) {\n      outputs = [await this.runTool(input.lg_tool_call, config)];\n    } else {\n      let messages: BaseMessage[];\n      if (isBaseMessageArray(input)) {\n        messages = input;\n      } else if (isMessagesState(input)) {\n        messages = input.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 (isAIMessage(message)) {\n          aiMessage = message;\n          break;\n        }\n      }\n\n      if (aiMessage == null || !isAIMessage(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)) ?? []\n      );\n    }\n\n    // Preserve existing behavior for non-command tool outputs for backwards compatibility\n    if (!outputs.some(isCommand)) {\n      return (Array.isArray(input) ? outputs : { messages: outputs }) as T;\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(input) ? [output] : { messages: [output] }\n        );\n      }\n    }\n\n    if (parentCommand) {\n      combinedOutputs.push(parentCommand);\n    }\n\n    return combinedOutputs as T;\n  }\n}\n\n/**\n * A conditional edge function that determines whether to route to a tools node or end the graph.\n *\n * This function is designed to be used as a conditional edge in a LangGraph state graph to implement\n * the common pattern of checking if an AI message contains tool calls that need to be executed.\n *\n * @param state - The current state of the graph, which can be either:\n *   - An array of `BaseMessage` objects, where the last message is checked for tool calls\n *   - A state object conforming to `MessagesAnnotation.State`, which contains a `messages` array\n *\n * @returns A string indicating the next node to route to:\n *   - `\"tools\"` - If the last message contains tool calls that need to be executed\n *   - `END` - If there are no tool calls, indicating the graph should terminate\n *\n * @example\n * ```typescript\n * import { StateGraph, MessagesAnnotation, END, START } from \"@langchain/langgraph\";\n * import { ToolNode, toolsCondition } from \"@langchain/langgraph/prebuilt\";\n *\n * const graph = new StateGraph(MessagesAnnotation)\n *   .addNode(\"agent\", agentNode)\n *   .addNode(\"tools\", new ToolNode([searchTool, calculatorTool]))\n *   .addEdge(START, \"agent\")\n *   .addConditionalEdges(\"agent\", toolsCondition, [\"tools\", END])\n *   .addEdge(\"tools\", \"agent\")\n *   .compile();\n * ```\n *\n * @remarks\n * The function checks the last message in the state for the presence of `tool_calls`.\n * If the message is an `AIMessage` with one or more tool calls, it returns `\"tools\"`,\n * indicating that the graph should route to a tools node (typically a `ToolNode`) to\n * execute those tool calls. Otherwise, it returns `END` to terminate the graph execution.\n *\n * This is a common pattern in agentic workflows where an AI model decides whether to\n * use tools or provide a final response.\n */\nexport function toolsCondition(\n  state: BaseMessage[] | typeof MessagesAnnotation.State\n): \"tools\" | typeof END {\n  const message = Array.isArray(state)\n    ? state[state.length - 1]\n    : state.messages[state.messages.length - 1];\n\n  if (\n    message !== undefined &&\n    \"tool_calls\" in message &&\n    ((message as AIMessage).tool_calls?.length ?? 0) > 0\n  ) {\n    return \"tools\";\n  } else {\n    return END;\n  }\n}\n"],"mappings":"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"}