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.md
1# Claude API — Go23> **Note:** The Go SDK supports the Claude API and beta tool use with `BetaToolRunner`. Agent SDK is not yet available for Go.45## Installation67```bash8go get github.com/anthropics/anthropic-sdk-go9```1011## Client Initialization1213```go14import (15"github.com/anthropics/anthropic-sdk-go"16"github.com/anthropics/anthropic-sdk-go/option"17)1819// Default (uses ANTHROPIC_API_KEY env var)20client := anthropic.NewClient()2122// Explicit API key23client := anthropic.NewClient(24option.WithAPIKey("your-api-key"),25)26```2728---2930## Basic Message Request3132```go33response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{34Model: anthropic.ModelClaudeOpus4_6,35MaxTokens: 16000,36Messages: []anthropic.MessageParam{37anthropic.NewUserMessage(anthropic.NewTextBlock("What is the capital of France?")),38},39})40if err != nil {41log.Fatal(err)42}43for _, block := range response.Content {44switch variant := block.AsAny().(type) {45case anthropic.TextBlock:46fmt.Println(variant.Text)47}48}49```5051---5253## Streaming5455```go56stream := client.Messages.NewStreaming(context.Background(), anthropic.MessageNewParams{57Model: anthropic.ModelClaudeOpus4_6,58MaxTokens: 64000,59Messages: []anthropic.MessageParam{60anthropic.NewUserMessage(anthropic.NewTextBlock("Write a haiku")),61},62})6364for stream.Next() {65event := stream.Current()66switch eventVariant := event.AsAny().(type) {67case anthropic.ContentBlockDeltaEvent:68switch deltaVariant := eventVariant.Delta.AsAny().(type) {69case anthropic.TextDelta:70fmt.Print(deltaVariant.Text)71}72}73}74if err := stream.Err(); err != nil {75log.Fatal(err)76}77```7879**Accumulating the final message** (there is no `GetFinalMessage()` on the stream):8081```go82stream := client.Messages.NewStreaming(ctx, params)83message := anthropic.Message{}84for stream.Next() {85message.Accumulate(stream.Current())86}87if err := stream.Err(); err != nil { log.Fatal(err) }88// message.Content now has the complete response89```909192---9394## Tool Use9596### Tool Runner (Beta — Recommended)9798**Beta:** The Go SDK provides `BetaToolRunner` for automatic tool use loops via the `toolrunner` package.99100```go101import (102"context"103"fmt"104"log"105106"github.com/anthropics/anthropic-sdk-go"107"github.com/anthropics/anthropic-sdk-go/toolrunner"108)109110// Define tool input with jsonschema tags for automatic schema generation111type GetWeatherInput struct {112City string `json:"city" jsonschema:"required,description=The city name"`113}114115// Create a tool with automatic schema generation from struct tags116weatherTool, err := toolrunner.NewBetaToolFromJSONSchema(117"get_weather",118"Get current weather for a city",119func(ctx context.Context, input GetWeatherInput) (anthropic.BetaToolResultBlockParamContentUnion, error) {120return anthropic.BetaToolResultBlockParamContentUnion{121OfText: &anthropic.BetaTextBlockParam{122Text: fmt.Sprintf("The weather in %s is sunny, 72°F", input.City),123},124}, nil125},126)127if err != nil {128log.Fatal(err)129}130131// Create a tool runner that handles the conversation loop automatically132runner := client.Beta.Messages.NewToolRunner(133[]anthropic.BetaTool{weatherTool},134anthropic.BetaToolRunnerParams{135BetaMessageNewParams: anthropic.BetaMessageNewParams{136Model: anthropic.ModelClaudeOpus4_6,137MaxTokens: 16000,138Messages: []anthropic.BetaMessageParam{139anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What's the weather in Paris?")),140},141},142MaxIterations: 5,143},144)145146// Run until Claude produces a final response147message, err := runner.RunToCompletion(context.Background())148if err != nil {149log.Fatal(err)150}151152// RunToCompletion returns *BetaMessage; content is []BetaContentBlockUnion.153// Narrow via AsAny() switch — note the Beta-namespace types (BetaTextBlock,154// not TextBlock):155for _, block := range message.Content {156switch block := block.AsAny().(type) {157case anthropic.BetaTextBlock:158fmt.Println(block.Text)159}160}161```162163**Key features of the Go tool runner:**164165- Automatic schema generation from Go structs via `jsonschema` tags166- `RunToCompletion()` for simple one-shot usage167- `All()` iterator for processing each message in the conversation168- `NextMessage()` for step-by-step iteration169- Streaming variant via `NewToolRunnerStreaming()` with `AllStreaming()`170171### Manual Loop172173For 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.174175Derived from `anthropic-sdk-go/examples/tools/main.go`.176177```go178package main179180import (181"context"182"encoding/json"183"fmt"184"log"185186"github.com/anthropics/anthropic-sdk-go"187)188189func main() {190client := anthropic.NewClient()191192// 1. Define tools. ToolParam.InputSchema uses a map, no struct tags needed.193addTool := anthropic.ToolParam{194Name: "add",195Description: anthropic.String("Add two integers"),196InputSchema: anthropic.ToolInputSchemaParam{197Properties: map[string]any{198"a": map[string]any{"type": "integer"},199"b": map[string]any{"type": "integer"},200},201},202}203// ToolParam must be wrapped in ToolUnionParam for the Tools slice204tools := []anthropic.ToolUnionParam{{OfTool: &addTool}}205206messages := []anthropic.MessageParam{207anthropic.NewUserMessage(anthropic.NewTextBlock("What is 2 + 3?")),208}209210for {211resp, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{212Model: anthropic.ModelClaudeSonnet4_6,213MaxTokens: 16000,214Messages: messages,215Tools: tools,216})217if err != nil {218log.Fatal(err)219}220221// 2. Append the assistant response to history BEFORE processing tool calls.222// resp.ToParam() converts Message → MessageParam in one call.223messages = append(messages, resp.ToParam())224225// 3. Walk content blocks. ContentBlockUnion is a flattened struct;226// use block.AsAny().(type) to switch on the actual variant.227toolResults := []anthropic.ContentBlockParamUnion{}228for _, block := range resp.Content {229switch variant := block.AsAny().(type) {230case anthropic.TextBlock:231fmt.Println(variant.Text)232case anthropic.ToolUseBlock:233// 4. Parse the tool input. Use variant.JSON.Input.Raw() to get the234// raw JSON — block.Input is json.RawMessage, not the parsed value.235var in struct {236A int `json:"a"`237B int `json:"b"`238}239if err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &in); err != nil {240log.Fatal(err)241}242result := fmt.Sprintf("%d", in.A+in.B)243// 5. NewToolResultBlock(toolUseID, content, isError) builds the244// ContentBlockParamUnion for you. block.ID is the tool_use_id.245toolResults = append(toolResults,246anthropic.NewToolResultBlock(block.ID, result, false))247}248}249250// 6. Exit when Claude stops asking for tools251if resp.StopReason != anthropic.StopReasonToolUse {252break253}254255// 7. Tool results go in a user message (variadic: all results in one turn)256messages = append(messages, anthropic.NewUserMessage(toolResults...))257}258}259```260261**Key API surface:**262263| Symbol | Purpose |264|---|---|265| `resp.ToParam()` | Convert `Message` response → `MessageParam` for history |266| `block.AsAny().(type)` | Type-switch on `ContentBlockUnion` variants |267| `variant.JSON.Input.Raw()` | Raw JSON string of tool input (for `json.Unmarshal`) |268| `anthropic.NewToolResultBlock(id, content, isError)` | Build `tool_result` block |269| `anthropic.NewUserMessage(blocks...)` | Wrap tool results as a user turn |270| `anthropic.StopReasonToolUse` | `StopReason` constant to check loop termination |271| `anthropic.ToolUnionParam{OfTool: &t}` | Wrap `ToolParam` in the union for `Tools:` |272273---274275## Thinking276277Enable Claude's internal reasoning by setting `Thinking` in `MessageNewParams`. The response will contain `ThinkingBlock` content before the final `TextBlock`.278279**Adaptive thinking is the recommended mode for Claude 4.6+ models.** Claude decides dynamically when and how much to think. Combine with the `effort` parameter for cost-quality control.280281Derived from `anthropic-sdk-go/message.go` (`ThinkingConfigParamUnion`, `NewThinkingConfigAdaptiveParam`).282283```go284// There is no ThinkingConfigParamOfAdaptive helper — construct the union285// struct-literal directly and take the address of the variant.286adaptive := anthropic.NewThinkingConfigAdaptiveParam()287params := anthropic.MessageNewParams{288Model: anthropic.ModelClaudeSonnet4_6,289MaxTokens: 16000,290Thinking: anthropic.ThinkingConfigParamUnion{OfAdaptive: &adaptive},291Messages: []anthropic.MessageParam{292anthropic.NewUserMessage(anthropic.NewTextBlock("How many r's in strawberry?")),293},294}295296resp, err := client.Messages.New(context.Background(), params)297if err != nil {298log.Fatal(err)299}300301// ThinkingBlock(s) precede TextBlock in content302for _, block := range resp.Content {303switch b := block.AsAny().(type) {304case anthropic.ThinkingBlock:305fmt.Println("[thinking]", b.Thinking)306case anthropic.TextBlock:307fmt.Println(b.Text)308}309}310```311312> **Deprecated:** `ThinkingConfigParamOfEnabled(budgetTokens)` (fixed-budget extended thinking) still works on Claude 4.6 but is deprecated. Use adaptive thinking above.313314To disable: `anthropic.ThinkingConfigParamUnion{OfDisabled: &anthropic.ThinkingConfigDisabledParam{}}`.315316---317318## Prompt Caching319320`System` is `[]TextBlockParam`; set `CacheControl` on the last block to cache tools + system together. For placement patterns and the silent-invalidator audit checklist, see `shared/prompt-caching.md`.321322```go323System: []anthropic.TextBlockParam{{324Text: longSystemPrompt,325CacheControl: anthropic.NewCacheControlEphemeralParam(), // default 5m TTL326}},327```328329For 1-hour TTL: `anthropic.CacheControlEphemeralParam{TTL: anthropic.CacheControlEphemeralTTLTTL1h}`. There's also a top-level `CacheControl` on `MessageNewParams` that auto-places on the last cacheable block.330331Verify hits via `resp.Usage.CacheCreationInputTokens` / `resp.Usage.CacheReadInputTokens`.332333---334335## Server-Side Tools336337Version-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.338339```go340Tools: []anthropic.ToolUnionParam{341{OfWebSearchTool20260209: &anthropic.WebSearchTool20260209Param{}},342{OfBashTool20250124: &anthropic.ToolBash20250124Param{}},343{OfTextEditor20250728: &anthropic.ToolTextEditor20250728Param{}},344{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},345},346```347348Also available: `WebFetchTool20260209Param`, `MemoryTool20250818Param`, `ToolSearchToolBm25_20251119Param`, `ToolSearchToolRegex20251119Param`.349350---351352## PDF / Document Input353354`NewDocumentBlock` generic helper accepts any source type. `MediaType`/`Type` are auto-set.355356```go357b64 := base64.StdEncoding.EncodeToString(pdfBytes)358359msg := anthropic.NewUserMessage(360anthropic.NewDocumentBlock(anthropic.Base64PDFSourceParam{Data: b64}),361anthropic.NewTextBlock("Summarize this document"),362)363```364365Other sources: `URLPDFSourceParam{URL: "https://..."}`, `PlainTextSourceParam{Data: "..."}`.366367---368369## Files API (Beta)370371Under `client.Beta.Files`. Method is **`Upload`** (NOT `New`/`Create`), params struct is `BetaFileUploadParams`. The `File` field takes an `io.Reader`; use `anthropic.File()` to attach a filename + content-type for the multipart encoding.372373```go374f, _ := os.Open("./upload_me.txt")375defer f.Close()376377meta, err := client.Beta.Files.Upload(ctx, anthropic.BetaFileUploadParams{378File: anthropic.File(f, "upload_me.txt", "text/plain"),379Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14},380})381// meta.ID is the file_id to reference in subsequent message requests382```383384Other `Beta.Files` methods: `List`, `Delete`, `Download`, `GetMetadata`.385386---387388## Context Editing / Compaction (Beta)389390Use `Beta.Messages.New` with `ContextManagement` on `BetaMessageNewParams`. There is no `NewBetaAssistantMessage` — use `.ToParam()` for the round-trip.391392```go393params := anthropic.BetaMessageNewParams{394Model: anthropic.ModelClaudeOpus4_6, // also supported: ModelClaudeSonnet4_6395MaxTokens: 16000,396Betas: []anthropic.AnthropicBeta{"compact-2026-01-12"},397ContextManagement: anthropic.BetaContextManagementConfigParam{398Edits: []anthropic.BetaContextManagementConfigEditUnionParam{399{OfCompact20260112: &anthropic.BetaCompact20260112EditParam{}},400},401},402Messages: []anthropic.BetaMessageParam{ /* ... */ },403}404405resp, err := client.Beta.Messages.New(ctx, params)406if err != nil {407log.Fatal(err)408}409410// Round-trip: append response to history via .ToParam()411params.Messages = append(params.Messages, resp.ToParam())412413// Read compaction blocks from the response414for _, block := range resp.Content {415if c, ok := block.AsAny().(anthropic.BetaCompactionBlock); ok {416fmt.Println("compaction summary:", c.Content)417}418}419```420421Other edit types: `BetaClearToolUses20250919EditParam`, `BetaClearThinking20251015EditParam`.422