Concepts · ai
Tools
Defining tools, the Tool interface, execution flow, and result types
- Defining or registering a tool
- Working with tool execution or results
This page gives the tool model for Go functions and provider-hosted tools. Tools let models call Go functions. The SDK handles schema generation, JSON marshaling, and result formatting.
Design decisions
Typed generics over raw JSON. DefineTool[In, Out] generates JSON Schema from Go types at creation time. Invalid types panic at startup. This makes the program error early, not during a conversation.
Tool errors are results, not Go errors. When a tool function returns an error, the SDK converts it to a ToolResult with IsError: true. The model sees the error and can react. It can retry, explain, or try a different approach. Go errors from Run indicate infrastructure problems such as serialization errors or panics. They do not indicate tool-level errors.
Parallel-safe marking. DefineParallelTool sets a flag in ToolInfo. The flag tells the model that it can call this tool concurrently with others. The SDK does not enforce parallelism. The flag is a hint to the model.
Tool interface
Any type that implements Tool can be used. The interface contains Info() and Run() methods. DefineTool returns a ToolDef that implements it. Custom tools can implement the interface directly. Use that path for full control over schema and execution.
Function tools vs. server tools
ToolInfo.Kind distinguishes the two flavors. ToolKindFunction ("function") is the client-run function tool described above. ToolKindServer ("server") marks a provider-hosted tool, such as web search and code execution. The provider runs server tools on its own infrastructure. Branching logic in the agent and provider adapters compares against ToolKindServer. An unset Kind, the empty zero value of ToolKind, is treated as a function tool.
Construct server tools with DefineServerTool:
agent.WithTools( ai.DefineServerTool(ai.ToolInfo{ ServerType: ai.ServerToolWebSearch, ServerConfig: map[string]any{"max_uses": 5}, }),)ServerType is one of the canonical ai.ServerToolType constants, such as ServerToolWebSearch and ServerToolCodeExecution. ServerConfig is a free-form map. Each provider adapter consumes the keys it understands and ignores the rest. Server tools share the same WithTools plumbing as function tools, so the two flavors mix freely. The agent advertises both to the model but runs only the function tools. Server-tool calls are filtered out with tc.Server == true before the executor runs. See Server-Side Tools for per-provider coverage.
Execution flow
- Model returns a
ToolCallcontent block withID,Name, andArguments. - Agent matches the tool by name and creates a
ToolCallReq. Rundeserializes input, calls the typed function, and serializes output.- Errors from the function become
IsError: trueresults visible to the model.
For server tools, the provider runs the call inline and returns the result on the same ToolCall block. In that case, Server == true and Output is populated. The agent emits one EventToolEnd per server call. It skips local execution and the tool_execution_* events.
Streaming progress
ToolCallReq.OnUpdate enables streaming partial results during long-running tool execution. The agent loop forwards these as tool_execution_update events.
Output serialization
string becomes a text result. []byte becomes a media result. ai.ToolResult passes through unchanged, and the framework stamps the call ID. Everything else becomes JSON-marshaled text.
Attaching context to a result
ToolResult.Extra holds content blocks that something other than the tool put there. Contents() renders the result and then appends Extra, so the injected blocks land after the output of the tool. An AfterTool hook is the usual writer, and ai.Reminder is the usual block. See Content.
A failed result carries Extra too. The tool failed; the context attached to it did not.
Design: blocks, not a longer Content string. Appending the injected text to Content would be simpler and would lose the boundary. The model could not tell the output of the tool from the rules stapled to it, and a hook could not find what it had already injected. Each provider keeps the boundary in whatever way its wire format allows: separate content blocks on Anthropic, a context key beside result on Gemini, and a blank line where the result is one string.
Rich results skip the output schema. A tool whose output type is ai.ToolResult produces results that vary per call. Examples include images, PDFs, and mixed text-and-media. Therefore, DefineTool generates no output schema for it. This lets a tool return media through the same typed DefineTool path as a plain string tool. It does not need a hand-written Tool implementation.