Skip to content

Choose & configure a provider

This guide covers the chat.Config fields, how each provider is activated and credentialed, and the two providers that need extra setup: openai-compatible (a required BaseURL and Model) and claude-local (a local CLI binary).

The Config fields

chat.Config carries provider behaviour. It is passed inside chat.Settings to chat.New. Only Provider is effectively required (and even that defaults); everything else has a sane zero value.

Field Type Description
Provider Provider The provider constant. Defaults to ProviderClaude when unset and AI_PROVIDER is not set.
Model string Model name. Falls back to a per-provider default when empty. Required for ProviderOpenAICompatible.
Token string API key. Optional when resolvable from config references or a well-known env var.
Credentials CredentialConfig Credential references (env-var name, keychain ref, literal) supplied by the host. Token wins when both are set.
BaseURL string API endpoint override. Required for ProviderOpenAICompatible. Validated by ValidateBaseURL.
SystemPrompt string Initial system prompt. Placed in each provider's native system slot (Claude's system field, OpenAI's first system message, Gemini's config + history).
ResponseSchema any JSON schema forcing structured output for Ask.
SchemaName / SchemaDescription string Name and description for the response schema.
MaxSteps int Maximum ReAct loop iterations in Chat. Zero uses the default (20).
MaxTokens int Maximum tokens per response. Zero uses the provider default (OpenAI 4096, Claude 8192, Gemini 8192).
RequestTimeout time.Duration Per-request timeout. Zero uses DefaultChatRequestTimeout (5m).
HTTPClient *http.Client Injected transport used verbatim. Nil builds a plain bounded client from RequestTimeout.
ParallelTools bool Run multiple tool calls in one ReAct step concurrently. Off by default.
MaxParallelTools int Concurrency cap for parallel tools. Zero uses the default (5).
Seed *int64 Optional sampling seed for OpenAI / OpenAI-compatible. Nil (default) omits the seed so the model samples normally.
UsageObserver func(Usage) Opt-in hook fired once per provider round-trip with that round-trip's token usage.
AllowInsecureBaseURL bool Test-only; permits http BaseURLs for httptest.Server. Tagged json:"-" so config files cannot set it.

See the pkg.go.dev reference for the full field list, including the test-only exec/genai override hooks.

Activate a provider by blank import

Each API provider lives in its own module. Blank-import it once (typically in main) to register it with the core; then reference it by its Provider constant.

Provider constant String Blank import Credential env var
chat.ProviderClaude claude _ "gitlab.com/phpboyscout/go/chat-anthropic" ANTHROPIC_API_KEY (chatanthropic.EnvClaudeKey)
chat.ProviderOpenAI openai _ "gitlab.com/phpboyscout/go/chat-openai" OPENAI_API_KEY (chatopenai.EnvOpenAIKey)
chat.ProviderOpenAICompatible openai-compatible _ "gitlab.com/phpboyscout/go/chat-openai" backend-dependent (Token)
chat.ProviderGemini gemini _ "gitlab.com/phpboyscout/go/chat-gemini" GEMINI_API_KEY (chatgemini.EnvGeminiKey)
chat.ProviderClaudeLocal claude-local none — ships in the core none — the claude binary is pre-authenticated

The openai and openai-compatible providers are both registered by the single chat-openai import.

Resolve a credential

Every API provider resolves its key through one shared five-step cascade (chat.ResolveAPIKey). The first non-empty source wins; each step is trimmed so a half-configured value cannot mask a fully-configured one below it:

  1. Direct tokenConfig.Token.
  2. Env-var referenceConfig.Credentials.Env names an env var; the value is read with os.Getenv. The secret stays out of any config file.
  3. Keychain referenceConfig.Credentials.Keychain is a "service/account" pair resolved through the host-injected Config.Credentials.Lookup func. With no lookup wired, this step is skipped.
  4. LiteralConfig.Credentials.Key, an inline value (legacy; least preferred).
  5. Well-known env varANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY, the ecosystem fallback used by most SDKs and CI platforms.

The simplest path is to export the well-known env var and leave Token and Credentials empty:

import (
    "gitlab.com/phpboyscout/go/chat"
    _ "gitlab.com/phpboyscout/go/chat-anthropic"
)

// ANTHROPIC_API_KEY is set in the environment; nothing else needed.
client, err := chat.New(ctx, chat.Settings{
    Config: chat.Config{Provider: chat.ProviderClaude},
})

A host that keeps secrets in a config file or keychain populates Config.Credentials instead — see credential security.

Using go-tool-base? Its adapter maps the framework's ai.provider, AI_PROVIDER, and provider api config sections onto these fields for you; that adapter lives in go-tool-base, not this module.

OpenAI-compatible endpoints

ProviderOpenAICompatible targets any backend that speaks the OpenAI API — Ollama, Groq, Fireworks AI, Together AI, LM Studio, vLLM, and others. It is registered by the chat-openai import. Both BaseURL and Model are required (there is no default model — names are backend-specific), and the BaseURL must pass endpoint validation.

import (
    "gitlab.com/phpboyscout/go/chat"
    _ "gitlab.com/phpboyscout/go/chat-openai"
)

// Ollama (local)
ollama, err := chat.New(ctx, chat.Settings{Config: chat.Config{
    Provider: chat.ProviderOpenAICompatible,
    BaseURL:  "http://localhost:11434/v1",
    Model:    "llama3.2",
    Token:    "ollama", // Ollama ignores the token; any non-empty value works

    // A localhost HTTP endpoint is non-HTTPS; permitted only in tests.
    AllowInsecureBaseURL: true,
}})

// Groq (cloud, HTTPS)
groq, err := chat.New(ctx, chat.Settings{Config: chat.Config{
    Provider: chat.ProviderOpenAICompatible,
    BaseURL:  "https://api.groq.com/openai/v1",
    Model:    "llama-3.3-70b-versatile",
    Token:    os.Getenv("GROQ_API_KEY"),
}})

Non-HTTPS endpoints. ValidateBaseURL rejects http:// unless AllowInsecureBaseURL is set, which is intended for httptest.Server targets only. For a plaintext local model, prefer an HTTPS proxy in production; the flag exists so tests can point at a local server, not as a way to disable TLS generally.

Token chunking falls back to the cl100k_base encoding for model names the tokenizer does not recognise, so Ollama and other non-OpenAI model names are handled gracefully.

Claude Local (the claude CLI)

ProviderClaudeLocal routes requests through a locally installed, pre-authenticated claude CLI binary instead of the Anthropic API. It is valuable in secure or air-gapped environments where outbound HTTPS to api.anthropic.com is blocked but the binary is permitted. It ships in the core — no blank import and no API key required.

Requirements:

  • The claude CLI installed and on PATH.
  • Authenticated once (claude login).
npm install -g @anthropic-ai/claude-code
claude login
import "gitlab.com/phpboyscout/go/chat" // no provider import needed

client, err := chat.New(ctx, chat.Settings{Config: chat.Config{
    Provider:     chat.ProviderClaudeLocal,
    Model:        "claude-sonnet-4-6", // optional; uses claude's default if empty
    SystemPrompt: "You are a helpful assistant.",
}})

Multi-turn continuity is maintained via session IDs captured from the CLI's JSON output and passed back with --resume. Two limitations set claude-local apart: it does not support tool calling (SetTools returns an error; MCP-based tools are planned) and it does not stream. It also reports no reliable token usage — see Providers.