Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
go/claude-api/tool-use.md
1# Tool Use — Go23For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).45## Tool Use67### Tool Runner (Beta — Recommended)89**Beta:** The Go SDK provides `BetaToolRunner` for automatic tool use loops via the `toolrunner` package.1011```go12import (13"context"14"fmt"15"log"1617"github.com/anthropics/anthropic-sdk-go"18"github.com/anthropics/anthropic-sdk-go/toolrunner"19)2021// Define tool input with jsonschema tags for automatic schema generation22type GetWeatherInput struct {23City string `json:"city" jsonschema:"required,description=The city name"`24}2526// Create a tool with automatic schema generation from struct tags27weatherTool, err := toolrunner.NewBetaToolFromJSONSchema(28"get_weather",29"Get current weather for a city",30func(ctx context.Context, input GetWeatherInput) (anthropic.BetaToolResultBlockParamContentUnion, error) {31return anthropic.BetaToolResultBlockParamContentUnion{32OfText: &anthropic.BetaTextBlockParam{33Text: fmt.Sprintf("The weather in %s is sunny, 72°F", input.City),34},35}, nil36},37)38if err != nil {39log.Fatal(err)40}4142// Create a tool runner that handles the conversation loop automatically43runner := client.Beta.Messages.NewToolRunner(44[]anthropic.BetaTool{weatherTool},45anthropic.BetaToolRunnerParams{46BetaMessageNewParams: anthropic.BetaMessageNewParams{47Model: anthropic.ModelClaudeOpus4_8,48MaxTokens: 16000,49Messages: []anthropic.BetaMessageParam{50anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What's the weather in Paris?")),51},52},53MaxIterations: 5,54},55)5657// Run until Claude produces a final response58message, err := runner.RunToCompletion(context.Background())59if err != nil {60log.Fatal(err)61}6263// RunToCompletion returns *BetaMessage; content is []BetaContentBlockUnion.64// Narrow via AsAny() switch — note the Beta-namespace types (BetaTextBlock,65// not TextBlock):66for _, block := range message.Content {67switch block := block.AsAny().(type) {68case anthropic.BetaTextBlock:69fmt.Println(block.Text)70}71}72```7374**Key features of the Go tool runner:**7576- Automatic schema generation from Go structs via `jsonschema` tags77- `RunToCompletion()` for simple one-shot usage78- `All()` iterator for processing each message in the conversation79- `NextMessage()` for step-by-step iteration80- Streaming variant via `NewToolRunnerStreaming()` with `AllStreaming()`8182### Manual Loop8384For fine-grained control over the agentic loop, define tools with `ToolParam`, check `StopReason`, execute tools yourself, and feed `tool_result` blocks back. This is the pattern when you need to intercept, validate, or log tool calls.8586Derived from `anthropic-sdk-go/examples/tools/main.go`.8788```go89package main9091import (92"context"93"encoding/json"94"fmt"95"log"9697"github.com/anthropics/anthropic-sdk-go"98)99100func main() {101client := anthropic.NewClient()102103// 1. Define tools. ToolParam.InputSchema uses a map, no struct tags needed.104addTool := anthropic.ToolParam{105Name: "add",106Description: anthropic.String("Add two integers"),107InputSchema: anthropic.ToolInputSchemaParam{108Properties: map[string]any{109"a": map[string]any{"type": "integer"},110"b": map[string]any{"type": "integer"},111},112},113}114// ToolParam must be wrapped in ToolUnionParam for the Tools slice115tools := []anthropic.ToolUnionParam{{OfTool: &addTool}}116117messages := []anthropic.MessageParam{118anthropic.NewUserMessage(anthropic.NewTextBlock("What is 2 + 3?")),119}120121for {122resp, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{123Model: anthropic.ModelClaudeSonnet4_6,124MaxTokens: 16000,125Messages: messages,126Tools: tools,127})128if err != nil {129log.Fatal(err)130}131132// 2. Append the assistant response to history BEFORE processing tool calls.133// resp.ToParam() converts Message → MessageParam in one call.134messages = append(messages, resp.ToParam())135136// 3. Walk content blocks. ContentBlockUnion is a flattened struct;137// use block.AsAny().(type) to switch on the actual variant.138toolResults := []anthropic.ContentBlockParamUnion{}139for _, block := range resp.Content {140switch variant := block.AsAny().(type) {141case anthropic.TextBlock:142fmt.Println(variant.Text)143case anthropic.ToolUseBlock:144// 4. Parse the tool input. Use variant.JSON.Input.Raw() to get the145// raw JSON — block.Input is json.RawMessage, not the parsed value.146var in struct {147A int `json:"a"`148B int `json:"b"`149}150if err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &in); err != nil {151log.Fatal(err)152}153result := fmt.Sprintf("%d", in.A+in.B)154// 5. NewToolResultBlock(toolUseID, content, isError) builds the155// ContentBlockParamUnion for you. block.ID is the tool_use_id.156toolResults = append(toolResults,157anthropic.NewToolResultBlock(block.ID, result, false))158}159}160161// 6. Exit when Claude stops asking for tools162if resp.StopReason != anthropic.StopReasonToolUse {163break164}165166// 7. Tool results go in a user message (variadic: all results in one turn)167messages = append(messages, anthropic.NewUserMessage(toolResults...))168}169}170```171172**Key API surface:**173174| Symbol | Purpose |175|---|---|176| `resp.ToParam()` | Convert `Message` response → `MessageParam` for history |177| `block.AsAny().(type)` | Type-switch on `ContentBlockUnion` variants |178| `variant.JSON.Input.Raw()` | Raw JSON string of tool input (for `json.Unmarshal`) |179| `anthropic.NewToolResultBlock(id, content, isError)` | Build `tool_result` block |180| `anthropic.NewUserMessage(blocks...)` | Wrap tool results as a user turn |181| `anthropic.StopReasonToolUse` | `StopReason` constant to check loop termination |182| `anthropic.ToolUnionParam{OfTool: &t}` | Wrap `ToolParam` in the union for `Tools:` |183184---185186## Anthropic-Defined Tools187188Version-suffixed struct names with `Param` suffix. `Name`/`Type` are `constant.*` types — zero value marshals correctly, so `{}` works. Wrap in `ToolUnionParam` with the matching `Of*` field. Web search and code execution are server-executed; bash and text editor are client-executed (you handle the `tool_use` locally — see `shared/tool-use-concepts.md`).189190```go191Tools: []anthropic.ToolUnionParam{192{OfWebSearchTool20260209: &anthropic.WebSearchTool20260209Param{}},193{OfBashTool20250124: &anthropic.ToolBash20250124Param{}},194{OfTextEditor20250728: &anthropic.ToolTextEditor20250728Param{}},195{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},196},197```198199Also available: `WebFetchTool20260209Param`, `ToolSearchToolBm25_20251119Param`, `ToolSearchToolRegex20251119Param`. For the advisor and memory tools, use `BetaAdvisorTool20260301Param` / `BetaMemoryTool20250818Param` in the beta namespace on `client.Beta.Messages.New`.200201### Advisor tool (beta)202203Server-side — no tool_result round-trip. The advisor model must be ≥ the executor (top-level) model; invalid pairs return 400.204205```go206response, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{207Model: anthropic.ModelClaudeSonnet4_6,208MaxTokens: 4096,209Tools: []anthropic.BetaToolUnionParam{210{OfAdvisorTool20260301: &anthropic.BetaAdvisorTool20260301Param{211Model: anthropic.ModelClaudeOpus4_8,212}},213},214Messages: []anthropic.BetaMessageParam{ /* ... */ },215Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaAdvisorTool2026_03_01},216})217```218219---220221