Tool calling
Tools are how agents reach outside the prompt — to query the knowledge graph, look up records, delegate to a team lead, or plan a write. This page covers the mechanics: what a tool definition looks like, how the multi-round loop works, and how errors flow back to the agent.
Tool definition shape
Each tool is declared in the registry (agents/registry.py) as a
ToolDef and converted to the provider's tool-call format at
dispatch. A definition carries its parameters, how it executes, and —
for writes — whether it needs confirmation:
ToolDef(
name="quick_lookup",
description="Search any module's records directly without delegating.",
params=[
ToolParam("table", "string", "Table to query", required=True,
enum=["companies", "contacts", "deals", "projects", "invoices", ...]),
ToolParam("query", "string", "Search term (name, title, etc.)"),
ToolParam("limit", "integer", "Max results (default 10)"),
],
method="GET", # GET reads · POST/PATCH/DELETE write
requires_confirmation=False, # True for writes → plan-and-confirm
autonomy="gated", # gated | autonomous (writes only)
)
The description field is what the model reads to decide when to use
the tool. Write it like a help line: short, action-oriented, explicit
about what the tool returns.
Multi-round semantics
An agent can call tools across several rounds in a single user turn, serialized as a tool-use loop:
user: "Which of my late invoices are on stalled projects?"
└─ round 1
└─ tool_use(graph_search, {query: "overdue invoices"})
← tool_result: [3 nodes]
└─ tool_use(graph_traverse, {from: invoice, edge: "billed_to", ...})
← tool_result: [companies → projects]
└─ round 2
└─ tool_use(quick_lookup, {table: "projects", status: "on_hold"})
← tool_result: [1 project]
└─ final text + citations
The cap is 5 tool-use rounds per turn. Hitting it forces a final response — the model can't chain indefinitely. The same cap applies at every tier (orchestrator, lead, specialist), so a delegation chain has a bounded, predictable ceiling.
Several tools in one round
The model may emit multiple tool calls in a single response when
they're independent. The platform runs them in order and returns
one combined tool_result block on the next round, preserving order.
From the model's view it's a single batched step, which keeps the
context window compact. (Execution is sequential, not concurrent —
the ceiling is the round cap, not wall-clock parallelism.)
Core orchestrator tools
| Tool | Purpose | When it's picked |
|---|---|---|
quick_lookup | Single-table read | "How many open deals?" / "find company Acme" |
graph_search | Semantic + fuzzy entity search | Almost every run — the discovery primitive |
graph_traverse | Walk typed edges (multi-hop) | Cross-module questions |
graph_context | Neighbourhood around an entity | Grounding an answer |
graph_add_edge | Record a typed relationship | Linking entities |
project_margins | Per-project profitability in one call | "Which retainers lose money?" |
delegate_to_<module>_lead | Hand work to a domain lead | Anything that touches a module's data |
Module write tools (crm_create_company, finance_create_invoice,
task_create, …) live on the team leads and specialists, not the
orchestrator — see Subagents. The
orchestrator reasons and routes; the leads own the writes.
Error handling
Tool failures return as tool_result blocks with an error flag and,
when possible, a hint:
{
"type": "tool_result",
"tool_use_id": "toolu_01...",
"is_error": true,
"content": "quick_lookup found no matches. Try a broader query or a different table."
}
The agent can then adjust parameters and retry, substitute a different tool, answer with partial data (flagging the gap), or bail out to the user with what it tried. Transient LLM errors (rate limits, 5xx) are retried inside the client before the agent sees them — it gets a clean response or a final exhausted-retries error.
Writes never execute inline
No tool mutates real state during a turn. A tool with
requires_confirmation=True (any POST/PATCH/DELETE) produces a
planned action, not a live write. The plan is serialized and
SHA-256 hashed at preview; the /confirm endpoint re-hashes at
execution and rejects on any mismatch — so the write that runs is
exactly the one you approved, byte for byte. This is the platform's
only write path; there is no auto-execute tool.
Autonomy is a second axis on write tools:
gated(default) — withheld entirely from unattended runs (automations). Money, people, publishing, and deletes stay here.autonomous— reversible, internal writes that an automation may run on its own.
An unattended run never even sees a gated tool, so it can't plan a call it has no human to confirm. See Subagents → Autonomy.
Telemetry
Every tool call is recorded in the turn trace with:
- Tool name + input.
- Latency.
- Result size.
- Success / error / retry count.
Visible in Settings → Agent runs → <run> → Tool calls — useful when a run "feels slow" and you want to see which call dominated.
Read next
- Orchestrator — the root agent and its toolset.
- Subagents — the leads and specialists that own the writes.