Add a Tool
In shortGive your agent a callable function with ToolNode and conditional routing.
- 2 min read
- 6 sections
- Updated
- v0.9.2
- Markdown
Tools let the agent call your application logic during a conversation. The model decides when to call a tool, and ToolNode handles the execution.
This page adds a get_weather tool to the agent from the previous page.
How tool calling works
flowchart LR
Start([START]) --> Agent[Agent\ncalls model]
Agent -->|tool call requested| Tool[ToolNode\nexecutes tool]
Tool --> Agent
Agent -->|no more tool calls| End([END])
- The model returns a message with one or more tool calls.
ToolNodeexecutes the requested functions.- The results go back to the model as
toolmessages. - The model uses the results to form a final reply.
- When there are no more tool calls, the graph ends.
Write the tool
A tool is a regular Python function with a docstring. The docstring becomes the description the model sees.
def get_weather(location: str) -> str:
"""Get the current weather for a specific location."""
# In a real app this would call a weather API
return f"The weather in {location} is sunny and 22°C."Build the graph with tools
Create agent_with_tool.py:
from tenxgraph.core.graph import Agent, StateGraph, ToolNode
from tenxgraph.core.state import AgentState, Message
from tenxgraph.utils import END
def get_weather(location: str) -> str:
"""Get the current weather for a specific location."""
return f"The weather in {location} is sunny and 22°C."
# Wrap your functions in a ToolNode
tool_node = ToolNode([get_weather])
# Agent knows to route to "TOOL" when it needs to call a function
agent = Agent(
model="google/gemini-2.5-flash",
system_prompt=[
{
"role": "system",
"content": "You are a helpful assistant. Use tools when you need specific information.",
}
],
tool_node="TOOL",
)
graph = StateGraph(AgentState)
graph.add_node("MAIN", agent)
graph.add_node("TOOL", tool_node)
def route(state: AgentState) -> str:
"""Route to TOOL if the last message has tool calls, otherwise END."""
if not state.context:
return END
last = state.context[-1]
if hasattr(last, "tools_calls") and last.tools_calls and last.role == "assistant":
return "TOOL"
if last.role == "tool":
return "MAIN"
return END
graph.add_conditional_edges("MAIN", route, {"TOOL": "TOOL", END: END})
graph.add_edge("TOOL", "MAIN")
graph.set_entry_point("MAIN")
app = graph.compile()
result = app.invoke(
{"messages": [Message.text_message("What is the weather in London?")]},
config={"thread_id": "beginner-tool-demo"},
)
print(result["messages"][-1].text())Run it:
python agent_with_tool.pyExpected output (exact wording varies):
The weather in London is sunny and 22°C.Injectable parameters
Tool functions can receive extra information automatically. Add tool_call_id or state as optional parameters and 10xGraph injects them without exposing them in the tool schema:
from tenxgraph.core.state import AgentState
def get_weather(
location: str,
state: AgentState | None = None,
tool_call_id: str | None = None,
) -> str:
"""Get the current weather for a specific location."""
if state:
print(f"Messages in context: {len(state.context)}")
return f"The weather in {location} is sunny and 22°C."The injected parameters are not visible to the model. Only location appears in the tool schema.
What you learned
- Wrap functions in
ToolNodeto make them available to the agent. - The
routefunction checks the last message to decide whether to call tools or end. - Tool functions can receive
stateandtool_call_idas injectable parameters. tool_node="TOOL"tells theAgentwhich node name to expect tool results from.
Next step
Preserve conversation state across calls with Add memory.