Tools
Typed function tools with schema-from-types, toolsets, and per-reply scoping.
A tool lets the model do something — look up an order, book a table, hand off to another agent. In agents-go a tool is a typed Go function; its JSON Schema is derived from the input type by reflection, so there's no schema to hand-write or keep in sync. The usual tool bug — the schema the model sees and the code that runs drifting apart — simply can't happen: the contract is the type.
Define a tool
Define the input and output types
Fields become parameters. Struct tags add the model-visible description and
validation constraints (description, min/max, enum, format, pattern).
type WeatherInput struct {
City string `json:"city" description:"city name" min:"1"`
Units string `json:"units" description:"temperature units" enum:"celsius|fahrenheit"`
}
type WeatherOutput struct {
Summary string `json:"summary"`
TempC float64 `json:"temp_c"`
}Write the handler
The signature is func(context.Context, *tool.RunContext, *In) (*Out, error).
Return an error to tell the model the call failed; the runtime surfaces it as the
tool result so the model can recover.
getWeather, err := tool.New("get_weather",
func(ctx context.Context, run *tool.RunContext, in *WeatherInput) (*WeatherOutput, error) {
// ... call your weather API ...
return &WeatherOutput{Summary: "clear", TempC: 21.5}, nil
},
tool.WithDescription("Get the current weather for a city."),
)
if err != nil {
return err
}The schema is derived once at construction and cached. It's deterministic — sorted keys, stable ordering — so it's safe to snapshot.
Attach it to an agent
AgentOptions.Tools accepts a single tool, a []tool.Entry, a toolset, or a
*tool.Context.
agent := agents.MustNewAgent(agents.AgentOptions{
Instructions: "Help users with the weather. Use get_weather for live data.",
Tools: []tool.Entry{getWeather},
})When the model calls the tool during a turn, the runtime decodes the arguments
into *WeatherInput, runs your handler, and folds the result back into the reply
(Speech & the turn).
RunContext: reach the turn and request-scoped data
The handler's *tool.RunContext is the tool's handle on the live turn:
run.WaitForPlayout(ctx)— finish speaking this step before continuing.run.DisallowInterruptions()— make this step's speech uninterruptible.- Hand off or delegate —
agents.RequestHandoff(run, target, returns)/agents.RunTask(ctx, run, task)(Agents & handoffs).
Set Config.UserData (an any) to pass request-scoped dependencies — a DB
handle, the authenticated user, a tenant ID — into your tools, and read it back
off run.UserData:
type deps struct{ db *sql.DB; userID string }
session, _ := agents.NewSession(agents.Config{
LLM: "openai/gpt-4o",
UserData: &deps{db: db, userID: "u_123"},
})
lookup, _ := tool.New("lookup_orders",
func(ctx context.Context, run *tool.RunContext, _ *struct{}) (*Orders, error) {
d := run.UserData.(*deps) // the value set on the session
return queryOrders(ctx, d.db, d.userID)
},
)WaitForPlayout holds up the turn until the audio finishes. Use it only when
ordering against speech matters ("say it, then act") — not by default.
Restrict tools for one reply
You can limit which tools a single reply may call, by tool ID (the function name), without changing the agent — useful to force a step:
session.GenerateReply(agents.GenerateReplyOptions{
UserInput: "Book it.",
Tools: []string{"book_table"}, // only this tool available this reply
})See Speech & the turn for other per-reply controls.
Toolsets & dynamic tools
A Toolset provides tools that can change at runtime and share setup/teardown —
build one with tool.NewToolset. Two are built in:
- Tool proxy (
tool.NewToolProxyToolset) — forwards to tools resolved elsewhere (e.g. an MCP server), so remote tools appear as native ones. - Tool search (
tool.NewToolSearchToolset) — exposes a large catalogue behind a search step, so the model isn't shown hundreds of tools at once.
Runtime tools with no Go type (MCP-provided, fully dynamic) use tool.RawTool,
which carries an explicit schema instead of a reflected one.
Next
- Models & providers — give the agent a brain and a voice.
- Full API: Reference → Tools.