Tools
Create type-safe tools with Zod schemas and automatic execution. Supports regular tools, generator tools with progress, manual tools, human-in-the-loop tools, and automatic multi-turn execution.
Create type-safe tools with Zod schemas and automatic execution. Supports regular tools, generator tools with progress, manual tools, human-in-the-loop tools, and automatic multi-turn execution.
The tool() function creates type-safe tools with Zod schema validation:
The SDK supports four types of tools, automatically detected from your configuration:
Standard tools with an execute function:
Tools that yield progress updates during execution. Add eventSchema to enable generator mode:
Progress events are streamed to consumers via getToolStream() and getFullResponsesStream().
Tools without automatic execution - you handle the tool calls yourself:
Use getToolCalls() to retrieve manual tool calls for processing.
HITL tools extend manual-tool semantics with two sync-or-async hooks that let you decide per call whether to respond programmatically or pause for a human:
onToolCalled — fires when the model invokes the tool. Return a value to feed the model directly (like a regular execute), or return null to pause the loop like a manual tool. The caller resumes later by supplying a function_call_output item.onResponseReceived — optional. Fires on a later turn when an incoming function_call_output matches a prior call of this tool (by callId → function_call.name). It receives the caller-supplied raw result and returns the value sent to the model. Throwing surfaces as a tool error to the model.An outputSchema is required for HITL tools — it validates both the onToolCalled return value (when non-null) and the value delivered via function_call_output (whether transformed by onResponseReceived or passed through directly).
When onToolCalled returns null, the conversation state moves to status: 'awaiting_hitl' and the paused call surfaces via getToolCalls() / getPendingToolCalls(). Resume by calling callModel again with a function_call_output item for each paused call in the input.
HITL tools differ from requireApproval: approval gates pause before execution for a yes/no decision, while HITL tools let onToolCalled run arbitrary logic first and only pause when it returns null. Use HITL when the decision is data-driven (e.g., amount thresholds, risk scoring); use requireApproval when you always want explicit human consent. See Tool Approval & State.
Define what parameters the tool accepts:
Define the structure of results returned to the model:
Define progress/status events for generator tools:
The SDK provides utilities to extract types from tools:
as constUse as const for full type inference on tool calls:
Tool execute functions receive a flat context object as
their second argument. It merges TurnContext fields
with a tools map and a setContext() method:
Tools can declare a contextSchema to receive typed,
persistent context data from the caller. Context is
keyed by tool name and persists across turns.
Pass context keyed by tool name:
Use an async function for one-time initialization that needs to fetch data:
resolveContext runs once at turn 0 to seed the
context store. For per-turn mutations, use
setContext() inside your tool’s execute function.
Tools can update their own context using setContext().
Changes persist across turns via the shared store and
are visible immediately — context.local is a live
getter that always reads the latest values:
Use getContextUpdates() on ModelResult to observe
context mutations in real time:
Use sharedSchema on tool() and sharedContextSchema
on callModel to share typed state across tools:
context.local is scoped to one tool.
context.shared is visible to all tools and persists
across turns. Pass the same sharedSchema to each tool
for typed access, and sharedContextSchema to
callModel for runtime validation.
callModel automatically executes tools and handles multi-turn conversations. When the model calls a tool, the SDK executes it, sends the result back, and continues until the model provides a final response.
When you provide tools with execute functions:
Limit the maximum number of tool execution rounds:
Setting maxToolRounds: 0 disables automatic execution - you get raw tool calls.
Use a function for dynamic control:
The function receives TurnContext and returns true to continue or false to stop.
Get all tool calls from the initial response (before auto-execution):
Stream tool calls as they complete:
Stream both argument deltas and preliminary results:
When using getFullResponsesStream(), you can also receive tool.result events that fire when a tool execution completes:
The tool.result event provides the final output from tool execution along with all intermediate preliminaryResults that were yielded during execution (for generator tools). This is useful when you need both real-time progress updates and a summary of all progress at completion.
When the model calls multiple tools, they execute in parallel:
For tools without execute functions:
Access execution metadata through getResponse():
Errors in execute functions are caught and sent back to the model:
Invalid tool arguments are caught before execution:
Handle errors gracefully in execute functions:
Add .describe() to help the model understand parameters:
Design tools to be safely re-executable:
Wrap long-running operations: