tools.py — langchain Source File
Architecture documentation for tools.py, a python file in the langchain codebase. 7 imports, 0 dependents.
Entity Profile
Dependency Diagram
graph LR 8fc68e0d_37aa_0267_4dec_1aba8ce06a76["tools.py"] 0a919d90_e60a_9150_e4f8_7158b3c7818c["json.py"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> 0a919d90_e60a_9150_e4f8_7158b3c7818c 80d582c5_7cc3_ac96_2742_3dbe1cbd4e2b["langchain_core.agents"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> 80d582c5_7cc3_ac96_2742_3dbe1cbd4e2b 75137834_4ba7_dc43_7ec5_182c05eceedf["langchain_core.exceptions"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> 75137834_4ba7_dc43_7ec5_182c05eceedf d758344f_537f_649e_f467_b9d7442e86df["langchain_core.messages"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> d758344f_537f_649e_f467_b9d7442e86df ac2a9b92_4484_491e_1b48_ec85e71e1d58["langchain_core.outputs"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> ac2a9b92_4484_491e_1b48_ec85e71e1d58 91721f45_4909_e489_8c1f_084f8bd87145["typing_extensions"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> 91721f45_4909_e489_8c1f_084f8bd87145 e160f068_75de_4342_6673_9969b919de85["langchain_classic.agents.agent"] 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 --> e160f068_75de_4342_6673_9969b919de85 style 8fc68e0d_37aa_0267_4dec_1aba8ce06a76 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
import json
from json import JSONDecodeError
from langchain_core.agents import AgentAction, AgentActionMessageLog, AgentFinish
from langchain_core.exceptions import OutputParserException
from langchain_core.messages import (
AIMessage,
BaseMessage,
ToolCall,
)
from langchain_core.outputs import ChatGeneration, Generation
from typing_extensions import override
from langchain_classic.agents.agent import MultiActionAgentOutputParser
class ToolAgentAction(AgentActionMessageLog):
"""Tool agent action."""
tool_call_id: str | None
"""Tool call that this message is responding to."""
def parse_ai_message_to_tool_action(
message: BaseMessage,
) -> list[AgentAction] | AgentFinish:
"""Parse an AI message potentially containing tool_calls."""
if not isinstance(message, AIMessage):
msg = f"Expected an AI message got {type(message)}"
raise TypeError(msg)
actions: list = []
if message.tool_calls:
tool_calls = message.tool_calls
else:
if not message.additional_kwargs.get("tool_calls"):
return AgentFinish(
return_values={"output": message.content},
log=str(message.content),
)
# Best-effort parsing
tool_calls = []
for tool_call in message.additional_kwargs["tool_calls"]:
function = tool_call["function"]
function_name = function["name"]
try:
args = json.loads(function["arguments"] or "{}")
tool_calls.append(
ToolCall(
type="tool_call",
name=function_name,
args=args,
id=tool_call["id"],
),
)
except JSONDecodeError as e:
msg = (
f"Could not parse tool input: {function} because "
f"the `arguments` is not valid JSON."
)
raise OutputParserException(msg) from e
for tool_call in tool_calls:
# A hack here:
# The code that encodes tool input into Open AI uses a special variable
# name called `__arg1` to handle old style tools that do not expose a
# schema and expect a single string argument as an input.
# We unpack the argument here if it exists.
# Open AI does not support passing in a JSON array as an argument.
function_name = tool_call["name"]
_tool_input = tool_call["args"]
tool_input = _tool_input.get("__arg1", _tool_input)
content_msg = f"responded: {message.content}\n" if message.content else "\n"
log = f"\nInvoking: `{function_name}` with `{tool_input}`\n{content_msg}\n"
actions.append(
ToolAgentAction(
tool=function_name,
tool_input=tool_input,
log=log,
message_log=[message],
tool_call_id=tool_call["id"],
),
)
return actions
class ToolsAgentOutputParser(MultiActionAgentOutputParser):
"""Parses a message into agent actions/finish.
If a tool_calls parameter is passed, then that is used to get
the tool names and tool inputs.
If one is not passed, then the AIMessage is assumed to be the final output.
"""
@property
def _type(self) -> str:
return "tools-agent-output-parser"
@override
def parse_result(
self,
result: list[Generation],
*,
partial: bool = False,
) -> list[AgentAction] | AgentFinish:
if not isinstance(result[0], ChatGeneration):
msg = "This output parser only works on ChatGeneration output"
raise ValueError(msg) # noqa: TRY004
message = result[0].message
return parse_ai_message_to_tool_action(message)
@override
def parse(self, text: str) -> list[AgentAction] | AgentFinish:
msg = "Can only parse messages"
raise ValueError(msg)
Domain
Subdomains
Functions
Dependencies
- json.py
- langchain_classic.agents.agent
- langchain_core.agents
- langchain_core.exceptions
- langchain_core.messages
- langchain_core.outputs
- typing_extensions
Source
Frequently Asked Questions
What does tools.py do?
tools.py is a source file in the langchain codebase, written in python. It belongs to the AgentOrchestration domain, ActionLogic subdomain.
What functions are defined in tools.py?
tools.py defines 1 function(s): parse_ai_message_to_tool_action.
What does tools.py depend on?
tools.py imports 7 module(s): json.py, langchain_classic.agents.agent, langchain_core.agents, langchain_core.exceptions, langchain_core.messages, langchain_core.outputs, typing_extensions.
Where is tools.py in the architecture?
tools.py is located at libs/langchain/langchain_classic/agents/output_parsers/tools.py (domain: AgentOrchestration, subdomain: ActionLogic, directory: libs/langchain/langchain_classic/agents/output_parsers).
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free