Documentation
¶
Overview ¶
Package llm is a multi-provider Go SDK for LLM inference endpoints: OpenAI, Google Gemini, DeepSeek, Z.ai, Kimi (Moonshot) and Anthropic, plus any custom OpenAI-compatible gateway.
Design highlights:
- Multiple authenticated endpoints simultaneously, discovered from the environment via <PROVIDER>_API_KEY (aliases supported).
- Dynamic model discovery (ListModels) — no static model profile tables.
- One canonical request/response shape (OpenAI-compatible); Anthropic and Gemini formats are translated by per-format serializers.
- Zero external dependencies: stdlib only.
- Streaming with idle watchdog, hard wall-clock deadline, abort-with- partial-result, and retries that never duplicate partial output.
Index ¶
- Constants
- Variables
- func SetStreamIdleTimeout(d time.Duration)
- func StreamIdleTimeout() time.Duration
- type APIError
- type ChatClient
- func (c *ChatClient) Call(ctx context.Context, req *ChatRequest) (*ChatResult, error)
- func (c *ChatClient) CallStream(ctx context.Context, req *ChatRequest, onDelta func(Delta) error) (*ChatResult, error)
- func (c *ChatClient) Model() string
- func (c *ChatClient) ProviderID() string
- func (c *ChatClient) RequestTimeout() time.Duration
- func (c *ChatClient) SetRequestTimeout(d time.Duration)
- type ChatRequest
- type ChatResult
- type ConfigError
- type Delta
- type DeltaKind
- type Format
- type ListOption
- type Message
- type Model
- type Option
- type Provider
- type ProviderConfig
- type ProviderOption
- type Quirks
- type RateLimitError
- type Role
- type SDK
- type StreamAbortedError
- type SystemBlock
- type ToolCall
- type ToolDef
- type Usage
Constants ¶
const ( FinishStop = "stop" FinishLength = "length" FinishToolCalls = "tool_calls" FinishContentFilter = "content_filter" )
Canonical finish reasons.
const (
DefaultTimeout = 120 * time.Second
)
Transport tuning defaults, shared by every provider client an SDK builds.
Variables ¶
var ErrIdleTimeout = errors.New("llm: stream idle timeout")
ErrIdleTimeout is returned (with the partial result) when a stream goes silent longer than the idle watchdog after the first delta has been emitted. Before the first delta, idle timeouts are retried instead.
Functions ¶
func SetStreamIdleTimeout ¶ added in v0.2.1
SetStreamIdleTimeout overrides the SSE idle watchdog. Call at startup, before the first request; non-positive values are ignored.
func StreamIdleTimeout ¶ added in v0.2.1
StreamIdleTimeout reports the active idle watchdog (introspection/tests).
Types ¶
type APIError ¶
APIError is a non-2xx provider response. Status 0 with a non-nil underlying error form is not used; network failures surface as plain wrapped errors. Message is the provider's own error text when parseable. API keys are never included in any error text.
type ChatClient ¶
type ChatClient struct {
// contains filtered or unexported fields
}
ChatClient runs chat completions against one provider+model pair. Learn-once fallbacks are shared by every client from the same Provider; request timeouts are per client. It is safe for concurrent use.
func (*ChatClient) Call ¶
func (c *ChatClient) Call(ctx context.Context, req *ChatRequest) (*ChatResult, error)
Call runs a buffered chat completion.
func (*ChatClient) CallStream ¶
func (c *ChatClient) CallStream(ctx context.Context, req *ChatRequest, onDelta func(Delta) error) (*ChatResult, error)
CallStream runs a streaming chat completion. onDelta receives canonical fragments; returning an error from it aborts generation — CallStream then returns the partial result alongside *StreamAbortedError.
func (*ChatClient) ProviderID ¶
func (c *ChatClient) ProviderID() string
ProviderID returns the bound provider's id.
func (*ChatClient) RequestTimeout ¶
func (c *ChatClient) RequestTimeout() time.Duration
RequestTimeout reports the per-request timeout (streaming wall-clock deadline).
func (*ChatClient) SetRequestTimeout ¶
func (c *ChatClient) SetRequestTimeout(d time.Duration)
SetRequestTimeout adjusts the per-request timeout. Call before the first request.
type ChatRequest ¶
type ChatRequest struct {
Model string
Messages []Message
System []SystemBlock
Tools []ToolDef
Thinking string
ThinkingBudget int
MaxTokens int
Temperature float64
TopP float64
Stop []string
}
ChatRequest is the canonical request. Model is filled from the ChatClient when empty. Thinking accepts "", "enabled", "disabled", "low", "medium", "high", "max" and is translated per provider format. Temperature and TopP: 0 means use the provider default (field omitted); use a negative value to explicitly send 0. Stop maps to each provider's stop-sequence field.
type ChatResult ¶
type ChatResult struct {
Content string
ReasoningContent string
// ThinkingSignature authenticates ReasoningContent (Anthropic extended
// thinking). Consumers must carry it back on the next assistant Message
// for tool loops to stay valid.
ThinkingSignature string
ToolCalls []ToolCall
FinishReason string
Usage Usage
}
ChatResult is the canonical response for both buffered and streaming calls.
type ConfigError ¶
type ConfigError struct{ Msg string }
ConfigError reports SDK misuse: unknown provider id, provider without an API key, or malformed options. Never retryable.
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
type Delta ¶
Delta is one streamed fragment. Text is the fragment for this event, not accumulated output.
type DeltaKind ¶
type DeltaKind int
DeltaKind discriminates streamed fragments.
const ( // DeltaReasoning is a thinking/reasoning fragment, usually before content. DeltaReasoning DeltaKind = iota // DeltaContent is an assistant text fragment. DeltaContent // DeltaToolArgs is a tool-call argument fragment (partial JSON). ToolIndex // and, on the first fragment of a call, ToolID/ToolName identify the call. DeltaToolArgs )
type Format ¶
type Format string
Format identifies a wire protocol family. The SDK translates the single canonical request shape into exactly one of these.
const ( // FormatOpenAI is the OpenAI chat-completions protocol — also spoken by // DeepSeek, Z.ai (GLM), Kimi/Moonshot and most self-hosted gateways. FormatOpenAI Format = "openai" // FormatAnthropic is the Anthropic Messages API. FormatAnthropic Format = "anthropic" // FormatGemini is the Google Gemini generateContent API. FormatGemini Format = "gemini" )
type ListOption ¶
type ListOption func(*listOpts)
ListOption tweaks ListModels.
func ForceRefresh ¶
func ForceRefresh() ListOption
ForceRefresh bypasses the model cache for this call and refreshes it.
type Message ¶
type Message struct {
Role Role
Content string
ReasoningContent string
// ThinkingSignature authenticates ReasoningContent for providers that
// require thinking to be replayed verbatim (Anthropic signature).
ThinkingSignature string
ToolCalls []ToolCall
ToolCallID string
ToolName string
// Cache marks this user message for Anthropic prompt caching
// (cache_control ephemeral on the text block). Ignored on other
// formats and on non-user roles.
Cache bool
}
Message is one canonical chat message. For RoleTool messages, ToolCallID and ToolName identify the call being answered and Content carries the tool result. ReasoningContent is provider-reported thinking text (deepseek-reasoner, anthropic thinking, gemini thoughts). The SDK replays it where a provider requires conversation continuity: OpenAI-format assistant messages echo it as reasoning_content (DeepSeek/GLM tool loops), and Anthropic re-serializes a signed thinking block as the first content block when ThinkingSignature is also set.
type Model ¶
type Model struct {
ID string
DisplayName string
CreatedAt time.Time
ContextWindow int // input token limit, 0 = unknown
MaxOutputTokens int // 0 = unknown
Capabilities []string
}
Model is one accessible model, as reported by a provider's models endpoint. Fields the provider does not report stay zero — the SDK never guesses.
type Option ¶
type Option func(*SDK)
Option configures an SDK at construction time.
func FromEnv ¶
func FromEnv() Option
FromEnv resolves <PROVIDER>_API_KEY (aliases included, primary first) and optional <PROVIDER>_BASE_URL overrides via os.LookupEnv. Providers without a key stay registered but unauthenticated.
func WithEnv ¶
WithEnv resolves API keys and base-URL overrides from the environment using lookup — the testable twin of FromEnv.
func WithModelCacheTTL ¶
WithModelCacheTTL sets the ListModels cache TTL. Zero disables caching — every call hits the provider's models endpoint.
func WithProvider ¶
func WithProvider(id string, popts ...ProviderOption) Option
WithProvider configures one provider — a built-in id (override) or a new custom provider (requires WithFormat and WithBaseURL, plus auth).
func WithRequestTimeout ¶
WithRequestTimeout sets the default per-request timeout for all chat clients (default 120s). Streaming calls use it as the hard wall-clock deadline.
func WithTransport ¶
func WithTransport(rt http.RoundTripper) Option
WithTransport replaces the SDK's pooled HTTP transport (tests, proxies).
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider is one configured endpoint with dynamic model discovery.
func (*Provider) Authenticated ¶
Authenticated reports whether an API key resolved.
func (*Provider) Config ¶
func (p *Provider) Config() ProviderConfig
Config returns the provider configuration. The copy carries the API key: treat it as a secret; it is never logged by the SDK itself.
func (*Provider) ListModels ¶
ListModels discovers the models accessible to this provider's account, on the fly — no static tables. Results are cached per SDK instance for the cache TTL (default 5 min; WithModelCacheTTL(0) disables). Fields the provider does not report stay zero.
type ProviderConfig ¶
type ProviderConfig struct {
ID string
Format Format
BaseURL string
APIKey string
// EnvKeys lists environment variable names to consult, primary first
// (aliases after). Resolution stops at the first non-empty value.
EnvKeys []string
Quirks Quirks
}
ProviderConfig fully describes one inference endpoint. APIKey is resolved from EnvKeys (primary first) or set explicitly; it is never included in error text, logs, or String() output.
func (ProviderConfig) String ¶
func (c ProviderConfig) String() string
type ProviderOption ¶
type ProviderOption func(*ProviderConfig)
ProviderOption configures one provider entry.
func WithAPIKey ¶
func WithAPIKey(key string) ProviderOption
WithAPIKey sets an explicit API key (overrides env).
func WithBaseURL ¶
func WithBaseURL(url string) ProviderOption
WithBaseURL overrides the provider's default base URL.
func WithEnvKeys ¶
func WithEnvKeys(keys ...string) ProviderOption
WithEnvKeys sets env var names consulted for this provider's key, primary first.
func WithFormat ¶
func WithFormat(f Format) ProviderOption
WithFormat sets the wire format (custom providers).
func WithQuirks ¶
func WithQuirks(q Quirks) ProviderOption
WithQuirks overrides protocol quirk flags.
type Quirks ¶
type Quirks struct {
// ThinkingObject: provider accepts the Anthropic-style top-level
// "thinking" object (Anthropic, DeepSeek, Z.ai GLM).
ThinkingObject bool
// ReasoningEffort: provider accepts reasoning_effort (OpenAI, GLM-5.3+).
ReasoningEffort bool
// ForceThinking lists model-name prefixes that reject
// thinking.type=disabled outright (GLM-5.3 always reasons; the
// documented migration is {type: enabled} + reasoning_effort "low").
ForceThinking []string
// AnthropicVersion is the anthropic-version header value required by
// FormatAnthropic providers ("2023-06-01").
AnthropicVersion string
}
Quirks carries per-provider protocol deviations, resolved at registration time. This replaces odek's URL-sniffing: a custom base URL gets its format's default quirks unless the caller overrides them explicitly.
type RateLimitError ¶
RateLimitError is the final failure after persistent 429 responses. RetryAfter carries the last observed Retry-After hint (0 if none).
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
func (*RateLimitError) Unwrap ¶
func (e *RateLimitError) Unwrap() error
Unwrap exposes the embedded APIError so errors.As(err, *APIError) reaches Status/Retryable without a type switch.
type SDK ¶
type SDK struct {
// contains filtered or unexported fields
}
SDK is a configured set of LLM endpoints. Build one with New and options:
sdk := llm.New(llm.FromEnv())
Providers are authenticated when an API key resolves from the environment or is set explicitly; every authenticated provider is usable concurrently through the SDK's shared connection pool.
func New ¶
New builds an SDK with the built-in provider registry and the given options. Options apply in order; later WithProvider calls for the same id override earlier ones.
func (*SDK) Chat ¶
func (s *SDK) Chat(providerID, model string) (*ChatClient, error)
Chat returns a chat client bound to a provider and model.
type StreamAbortedError ¶
type StreamAbortedError struct{ Reason error }
StreamAbortedError is returned by CallStream when the delta handler aborted generation. CallStream also returns the partial ChatResult assembled so far alongside this error.
func (*StreamAbortedError) Error ¶
func (e *StreamAbortedError) Error() string
func (*StreamAbortedError) Unwrap ¶
func (e *StreamAbortedError) Unwrap() error
type SystemBlock ¶
SystemBlock is one system-prompt segment. On Anthropic each block maps to a system text block (Cache marks it for prompt caching); on OpenAI-format providers blocks concatenate into a leading system message; on Gemini they become systemInstruction parts.
type ToolDef ¶
type ToolDef struct {
Name string
Description string
Parameters json.RawMessage
}
ToolDef declares a callable tool. Parameters is a JSON Schema object (json.RawMessage so callers can pass through marshaled schemas verbatim).
type Usage ¶
type Usage struct {
PromptTokens int
CompletionTokens int
ReasoningTokens int
CacheReadTokens int
CacheCreationTokens int
CachedTokens int
CacheReported bool
}
Usage reports token accounting. Fields the provider does not report stay 0. PromptTokens is exclusive (uncached-only) after provider-specific normalization: OpenAI cached_tokens and DeepSeek hit/miss are subsets of prompt_tokens and are subtracted; Anthropic reports cache volumes exclusively and is left alone. Cache volumes live in the cache fields so budget enforcement can sum without double-counting.