Anthropic Claude LLM provider

Anthropic Claude provider for Piko's LLM service. It covers completions, streaming, tool/function calling, and structured output.

Overview

This provider implements llm.ProviderPort against the Anthropic Messages API. It serves the current Claude models (Opus, Sonnet, Haiku) and supports synchronous completions, server-sent streaming, native tool use, image input, and structured-output requests. ListModels reports a 200k token context window for the Claude 4 family. The provider does not support frequency or presence penalties, deterministic seed, parallel tool calls, or per-message names, so requests that set those fields ignore them.

The Anthropic Messages API has no dedicated structured-output endpoint. The provider emulates it with a forced synthetic tool call whose schema matches the requested type, then extracts the result from the tool-call arguments. Callers send the same ResponseFormat JSON-schema request used with any other provider and receive a typed response. The translation is invisible.

The Anthropic API requires max_tokens on every request, so the provider exposes DefaultMaxTokens (8192) as a fallback when callers do not set a per-request limit. Without it, requests fail at the API. All public methods on the provider are safe for concurrent use.

The provider is a separate Go module. Add it with go get piko.sh/piko/wdk/llm/llm_provider_anthropic. It is pure Go with no build tags and no CGO, so it runs unchanged in interpreted dev mode (dev-i) and in compiled builds.

Requirements

  • An Anthropic API key with permission to call the Messages endpoint. Resolve via ANTHROPIC_API_KEY or any registered config resolver.
  • Network egress to api.anthropic.com (or your BaseURL override if you proxy through a gateway).

Configuration

import (
    "os"

    "piko.sh/piko/wdk/llm/llm_provider_anthropic"
)

provider, err := llm_provider_anthropic.NewAnthropicProvider(llm_provider_anthropic.Config{
    APIKey:           os.Getenv("ANTHROPIC_API_KEY"), // required
    DefaultModel:     "claude-sonnet-4-5-20250929",   // optional; package default if empty
    DefaultMaxTokens: 8192,                           // optional; package default if 0
    BaseURL:          "",                             // optional; leave empty for the official endpoint
})
if err != nil {
    return err
}

Config.Validate() rejects missing API keys at construction time. Config.WithDefaults() populates DefaultModel and DefaultMaxTokens from the package constants when those fields are empty.

Bootstrap

Register the provider through Piko's LLM service. piko.New returns an *SSRServer. Name the default explicitly with WithDefaultLLMProvider. There is no first-registered-wins fallback. When no call to WithDefaultLLMProvider names a default, completion and streaming calls that omit a provider name fail with ErrNoDefaultProvider.

server := piko.New(
    piko.WithLLMProvider("anthropic", provider),
    piko.WithDefaultLLMProvider("anthropic"),
)

The provider satisfies the standard llm.ProviderPort, so registration needs no custom glue. Once registered it joins the shared LLM service and uses the same request and response path as every other provider. The container configures a cache manager and a budget manager for that service, so caching and budget tracking apply without extra code. Anthropic prompt-cache reads surface through the normal usage accounting as CachedTokens, so cost and cache metrics work for this provider too.

For a multi-provider setup (for example Anthropic for chat, OpenAI for embeddings), register both and pick the default explicitly.

The container registers the provider's Close method for graceful shutdown. On close the provider cancels in-flight streams, drains them within a bounded timeout, and releases idle connections.

Calling the service

With Anthropic set as the default, the LLM service routes completions to it:

resp, err := llmService.Complete(ctx, &llm.CompletionRequest{
    Messages: []llm.Message{
        {Role: llm.RoleUser, Content: "Summarise this changelog."},
    },
})

A structured-output request sets ResponseFormat to a JSON schema. The provider runs the synthetic tool round-trip and returns the JSON in the response content.

See also

Other LLM providers:

  • OpenAI, widest model selection, native structured-output API.
  • Gemini, cheapest competent option, multimodal-native.
  • Mistral, open-weight European provider with strong code models.
  • Grok, xAI provider for Grok models.
  • Ollama, local inference for offline or privacy-sensitive workloads.
  • Voyage, embedding-only specialist.

Framework docs:

External: