{"version":3,"file":"tool_node.cjs","names":["isBaseMessage","RunnableCallable","tool","isCommand","ToolMessage","e: any","isGraphInterrupt","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","combinedOutputs: (\n      | { messages: BaseMessage[] }\n      | BaseMessage[]\n      | Command\n    )[]","parentCommand: Command | null","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 * @deprecated `ToolNode` has been moved to {@link https://www.npmjs.com/package/langchain langchain} package.\n * Update your import to `import { ToolNode } from \"langchain\";`\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 * @deprecated Use new `ToolNode` from {@link https://www.npmjs.com/package/langchain langchain} package instead.\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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"}