langgraph: add incorrect tool name handling to ToolNode (#1052)

This commit is contained in:
Vadym Barda
2024-07-17 21:33:46 -04:00
committed by GitHub
parent c2e25e2ac2
commit 83089c3a7f
2 changed files with 50 additions and 2 deletions
+25 -2
View File
@@ -9,6 +9,11 @@ from langchain_core.tools import tool as create_tool
from langgraph.utils import RunnableCallable
INVALID_TOOL_NAME_ERROR_TEMPLATE = (
"Error: {requested_tool} is not a valid tool, try one of [{available_tools}]."
)
TOOL_CALL_ERROR_TEMPLATE = "Error: {error}\n Please fix your mistakes."
class ToolNode(RunnableCallable):
"""A node that runs the tools called in the last AIMessage.
@@ -68,13 +73,22 @@ class ToolNode(RunnableCallable):
raise ValueError("Last message is not an AIMessage")
def run_one(call: ToolCall):
if (requested_tool := call["name"]) not in self.tools_by_name:
content = INVALID_TOOL_NAME_ERROR_TEMPLATE.format(
requested_tool=requested_tool,
available_tools=", ".join(self.tools_by_name.keys()),
)
return ToolMessage(
content, name=requested_tool, tool_call_id=call["id"]
)
try:
input = {**call, **{"type": "tool_call"}}
return self.tools_by_name[call["name"]].invoke(input, config)
except Exception as e:
if not self.handle_tool_errors:
raise e
content = f"Error: {repr(e)}\n Please fix your mistakes."
content = TOOL_CALL_ERROR_TEMPLATE.format(error=repr(e))
return ToolMessage(content, name=call["name"], tool_call_id=call["id"])
with get_executor_for_config(config) as executor:
@@ -100,13 +114,22 @@ class ToolNode(RunnableCallable):
raise ValueError("Last message is not an AIMessage")
async def run_one(call: ToolCall):
if (requested_tool := call["name"]) not in self.tools_by_name:
content = INVALID_TOOL_NAME_ERROR_TEMPLATE.format(
requested_tool=requested_tool,
available_tools=", ".join(self.tools_by_name.keys()),
)
return ToolMessage(
content, name=requested_tool, tool_call_id=call["id"]
)
try:
input = {**call, **{"type": "tool_call"}}
return await self.tools_by_name[call["name"]].ainvoke(input, config)
except Exception as e:
if not self.handle_tool_errors:
raise e
content = f"Error: {repr(e)}\n Please fix your mistakes."
content = TOOL_CALL_ERROR_TEMPLATE.format(error=repr(e))
return ToolMessage(content, name=call["name"], tool_call_id=call["id"])
outputs = await asyncio.gather(*(run_one(call) for call in message.tool_calls))
+25
View File
@@ -253,6 +253,31 @@ async def test_tool_node():
}
)
# incorrect tool name
result_incorrect_name = ToolNode([tool1, tool2]).invoke(
{
"messages": [
AIMessage(
"hi?",
tool_calls=[
{
"name": "tool3",
"args": {"some_val": 1, "some_other_val": "foo"},
"id": "some 0",
}
],
)
]
}
)
tool_message: ToolMessage = result_incorrect_name["messages"][-1]
assert tool_message.type == "tool"
assert (
tool_message.content
== "Error: tool3 is not a valid tool, try one of [tool1, tool2]."
)
assert tool_message.tool_call_id == "some 0"
def my_function(some_val: int, some_other_val: str) -> str:
return f"{some_val} - {some_other_val}"