Documentation
¶
Overview ¶
Package chat defines provider-agnostic chat types and the Provider interface that all model backends implement.
The types in this package form the canonical request/response shape used across the SDK. Concrete providers (OpenAI, Anthropic, local models, ...) translate to and from these types so that higher-level code can remain backend-independent.
Index ¶
- Variables
- func ContextHeaders(ctx context.Context) (map[string]string, bool)
- func ProviderOptionsFor[T any](po map[string]any, providerName string) (T, error)
- func SanitizeErrorBody(body []byte) string
- func ValidateToolCallArguments(args string) error
- func WithContextHeaders(ctx context.Context, headers map[string]string) context.Context
- type Chunk
- type Client
- type FilePart
- type ImagePart
- type Message
- type Part
- type PartType
- type Parts
- type Provider
- type ReasoningPart
- type Request
- type Response
- type Role
- type Stream
- type TextPart
- type Tool
- type ToolCall
- type ToolCallDelta
- type ToolChoice
- type ToolChoiceType
- type UnsupportedContentError
- type Usage
- type Warning
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoProvider indicates the Client has no underlying Provider configured. ErrNoProvider = errors.New("chat: no provider configured") // ErrInvalidRequest indicates the Request is malformed or missing // required fields (for example, no Model or no Messages). ErrInvalidRequest = errors.New("chat: invalid request") // unreachable or returned a transient failure. ErrProviderUnavailable = errors.New("chat: provider unavailable") // ErrRateLimited indicates the upstream provider rejected the request // due to rate limiting or quota exhaustion. ErrRateLimited = errors.New("chat: rate limited") // ErrAuthFailed indicates the provider rejected the supplied credentials. ErrAuthFailed = errors.New("chat: authentication failed") // ErrContextLength indicates the request exceeds the model's maximum // supported context length. ErrContextLength = errors.New("chat: context length exceeded") // ErrUnsupported indicates the provider does not support a requested // capability (for example, streaming or tool calls). ErrUnsupported = errors.New("chat: unsupported operation") )
var ErrInvalidPart = errors.New("chat: invalid part")
ErrInvalidPart indicates a Part is malformed (e.g. neither URL nor Data set on an ImagePart, or both set, or missing MediaType for inline data). Provider implementations may wrap this when rejecting content.
var ErrUnsupportedContent = errors.New("chat: unsupported content")
ErrUnsupportedContent indicates a Part kind is not supported by the provider/model for the current request. Providers wrap this with context (provider, model, part type) when rejecting content.
Functions ¶
func ContextHeaders ¶
ContextHeaders returns the extra headers stored in ctx, or nil if none were set.
func ProviderOptionsFor ¶
ProviderOptionsFor extracts the provider-specific options bucket from a ProviderOptions map (typically Request.ProviderOptions or Message.ProviderOptions) into a typed value.
providerName is the key used to namespace the bucket — by convention the provider's Provider.Name return value, e.g. "openai", "ollama".
Two input shapes are supported transparently:
- The bucket is already the typed Options struct (or a pointer to one) — it is returned as-is.
- The bucket is a map[string]any (e.g. constructed from JSON) — it is re-marshalled and decoded into T using encoding/json so that JSON tags on T's fields are honoured.
If po is nil or the providerName key is absent, the zero value of T is returned with a nil error. Decoding errors are wrapped.
Example provider-side use:
type Options struct {
ReasoningEffort string `json:"reasoning_effort,omitempty"`
}
opts, err := chat.ProviderOptionsFor[Options](req.ProviderOptions, "openai")
func SanitizeErrorBody ¶ added in v0.1.12
SanitizeErrorBody trims an HTTP error response body down to a short, display-safe snippet for embedding in an error message. HTML bodies (edge/gateway error pages such as Cloudflare's 502/504 pages, which can run to several KB of markup) are collapsed to a short marker instead of being embedded verbatim — the status code already conveys the failure, and embedding raw HTML has repeatedly overwhelmed caller UIs that print error text directly to a terminal or notification banner. Non-HTML bodies are truncated to maxErrorBodySnippet bytes with a marker appended when trimmed.
func ValidateToolCallArguments ¶
ValidateToolCallArguments reports whether the given Arguments string is parseable as a JSON object. It is a best-effort sanity check; providers may emit pre-validated JSON, or fragments that need concatenation upstream of this call.
func WithContextHeaders ¶
WithContextHeaders attaches extra HTTP headers to a context so that provider implementations can inject them into outbound requests. Multiple callers can attach headers; later calls overwrite earlier values for the same key.
Types ¶
type Chunk ¶
type Chunk struct {
Delta string `json:"delta,omitempty"`
ReasoningDelta string `json:"reasoning_delta,omitempty"`
Role Role `json:"role,omitempty"`
ToolCallDeltas []ToolCallDelta `json:"tool_call_deltas,omitempty"`
FinishReason string `json:"finish_reason,omitempty"`
Usage *Usage `json:"usage,omitempty"`
Warnings []Warning `json:"warnings,omitempty"`
ProviderMetadata map[string]any `json:"provider_metadata,omitempty"`
Done bool `json:"done,omitempty"`
}
Chunk is a single increment in a streaming chat completion.
Usage is a pointer because token totals are typically only known at the end of a stream; intermediate chunks carry Usage == nil and the final chunk (Done == true) carries the aggregate usage.
ReasoningDelta carries incremental reasoning/thinking text emitted by providers that support it (Anthropic thinking, Gemini thinking, OpenAI o1). Providers that do not produce reasoning leave it empty.
ProviderMetadata carries opaque provider response data that must be preserved when a streamed assistant turn is sent back to that provider.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a thin, provider-agnostic facade over a Provider. It centralises concerns that are independent of the underlying backend (such as toggling the streaming flag on the request) and provides a single entry point that higher-level code can depend on.
func NewClient ¶
NewClient returns a Client backed by the given Provider. The Provider may be nil; in that case the Client's methods will return ErrNoProvider.
func (*Client) Chat ¶
Chat performs a non-streaming chat completion. It forces req.Stream to false before delegating to the underlying Provider. If the Client or its Provider is nil, Chat returns ErrNoProvider.
func (*Client) ChatStream ¶
ChatStream performs a streaming chat completion. It forces req.Stream to true before delegating to the underlying Provider. If the Client or its Provider is nil, ChatStream returns ErrNoProvider.
type FilePart ¶
type FilePart struct {
URL string `json:"url,omitempty"`
Data []byte `json:"data,omitempty"`
MediaType string `json:"media_type,omitempty"`
Name string `json:"name,omitempty"`
ProviderMetadata map[string]any `json:"provider_metadata,omitempty"`
}
FilePart is a generic file content fragment (PDF, audio, etc.). Exactly one of URL or Data must be set; MediaType is required when Data is set.
func NewFileData ¶
NewFileData constructs a FilePart from raw bytes.
func NewFileURL ¶
NewFileURL constructs a FilePart from a URL.
type ImagePart ¶
type ImagePart struct {
// URL points at a remote image or a data: URI. Mutually exclusive
// with Data.
URL string `json:"url,omitempty"`
// Data carries the raw image bytes. Mutually exclusive with URL.
Data []byte `json:"data,omitempty"`
// MediaType is the IANA media type (e.g. "image/png"). Required
// when Data is set.
MediaType string `json:"media_type,omitempty"`
// ProviderMetadata carries provider-specific per-part options
// (e.g. Anthropic cache control, OpenAI image detail level).
ProviderMetadata map[string]any `json:"provider_metadata,omitempty"`
}
ImagePart is an image content fragment. Exactly one of URL or Data must be set. MediaType (e.g. "image/png") is required when Data is set and recommended for URLs that lack a discriminating extension.
func NewImageData ¶
NewImageData constructs an ImagePart from raw bytes plus MediaType. MediaType is required; if empty the part is still constructed but downstream providers may reject or warn on it.
func NewImageURL ¶
NewImageURL constructs an ImagePart from a URL (remote or data: URI).
type Message ¶
type Message struct {
Role Role `json:"role"`
Content string `json:"content,omitempty"`
Parts Parts `json:"parts,omitempty"`
Name string `json:"name,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
ProviderOptions map[string]any `json:"provider_options,omitempty"`
}
Message is a single entry in a chat conversation.
Multimodal content is carried on Message.Parts. The legacy Message.Content string remains for ergonomic text-only construction — when Parts is nil, providers treat Content as a single TextPart; when Parts is non-nil, Parts is canonical and Content is ignored on the request path. On the response path, providers populate both fields: Parts as the source of truth, Content as the concatenation of all TextPart text for back-compat.
Tool integration uses two additional fields:
- Assistant messages that called tools carry Message.ToolCalls; Content/Parts may also be present alongside tool calls for some providers.
- Messages with RoleTool carry the tool's output in Content and reference the originating call via Message.ToolCallID.
ProviderOptions allows per-message provider-specific options keyed by provider name, mirroring Request.ProviderOptions. This is rarely needed at the call site but is useful for things like Anthropic's per-block cache control or OpenAI's per-message attachments.
func (Message) GetParts ¶
GetParts returns the canonical Parts slice for the message:
- If Parts is non-nil, it is returned as-is.
- Otherwise, if Content is non-empty, a single-element slice containing a TextPart is returned.
- Otherwise, nil is returned.
Provider implementations should call GetParts (not access Message.Content directly) so that callers using either field are handled uniformly.
type Part ¶
type Part interface {
// Type returns the Part's discriminator.
Type() PartType
// contains filtered or unexported methods
}
Part is a single content fragment of a Message or Response.
Parts replace the historical "Content string" field as the canonical representation of multimodal content. The Part interface is sealed (only types defined in this package implement it) so that providers can safely type-switch on the concrete kind.
Note on tool calls/results: tool invocations and their outputs are currently carried on Message.ToolCalls / Message.ToolCallID rather than as parts. This means Parts does not represent a fully-ordered transcript when tool calls are interleaved with text in an assistant turn. Providers that require strict ordering of content blocks (e.g. Anthropic Messages API with thinking signatures) will gain dedicated ToolCallPart / ToolResultPart types in a follow-up iteration.
type PartType ¶
type PartType string
PartType identifies a Part's concrete kind. It is used both for type discrimination on the wire ("type" JSON tag) and for callers inspecting a Parts slice without a type switch.
type Parts ¶
type Parts []Part
Parts is an ordered slice of Part. It implements custom JSON marshal/unmarshal so that the "type" discriminator round-trips correctly through encoding/json.
func (Parts) HasNonText ¶
HasNonText reports whether any part is something other than a TextPart. This is the canonical capability check for providers that can only handle text and need to emit warnings or errors.
func (Parts) MarshalJSON ¶
MarshalJSON encodes the slice as a JSON array of objects, each carrying a "type" discriminator alongside the part's fields.
func (Parts) Text ¶
Text concatenates the text content of every TextPart, preserving order. Non-text parts are skipped entirely. No separator is inserted between adjacent text parts; callers that need a lossy textual representation including non-text placeholders should iterate Parts themselves.
func (*Parts) UnmarshalJSON ¶
UnmarshalJSON decodes a JSON array of part objects back into concrete Part values, dispatching on the "type" discriminator.
type Provider ¶
type Provider interface {
// Name returns a short, stable identifier for the provider
// (for example, "openai", "anthropic", "ollama").
Name() string
// Chat performs a non-streaming chat completion.
Chat(ctx context.Context, req Request) (Response, error)
// ChatStream performs a streaming chat completion. Callers must Close
// the returned Stream when finished.
ChatStream(ctx context.Context, req Request) (Stream, error)
}
Provider is implemented by chat model backends. Implementations translate between the provider-agnostic Request/Response/Chunk types defined in this package and their underlying API.
type ReasoningPart ¶
type ReasoningPart struct {
Text string `json:"text"`
ProviderMetadata map[string]any `json:"provider_metadata,omitempty"`
}
ReasoningPart carries chain-of-thought / thinking content emitted by the model. ProviderMetadata holds opaque provider replay tokens that must be preserved verbatim for multi-turn conversations (notably Anthropic thinking-block signatures); the SDK does not interpret it.
type Request ¶
type Request struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
MaxTokens int `json:"max_tokens,omitempty"`
Temperature float32 `json:"temperature,omitempty"`
TopP float32 `json:"top_p,omitempty"`
Stop []string `json:"stop,omitempty"`
Stream bool `json:"stream,omitempty"`
Tools []Tool `json:"tools,omitempty"`
ToolChoice *ToolChoice `json:"tool_choice,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
ProviderOptions map[string]any `json:"provider_options,omitempty"`
}
Request is a provider-agnostic chat completion request.
Only Model and Messages are required; all other fields are optional and providers should treat zero values as "unspecified" and apply their own defaults.
ProviderOptions carries provider-specific options keyed by provider name (for example "openai", "anthropic", "ollama"). Each provider reads only its own bucket and ignores keys for other providers, so the same Request can be shared across providers without modification. Use the ProviderOptionsFor helper to extract a typed options struct from inside a provider implementation.
type Response ¶
type Response struct {
ID string `json:"id,omitempty"`
Model string `json:"model,omitempty"`
Role Role `json:"role,omitempty"`
Content string `json:"content"`
Parts Parts `json:"parts,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
FinishReason string `json:"finish_reason,omitempty"`
Usage Usage `json:"usage"`
Warnings []Warning `json:"warnings,omitempty"`
ProviderMetadata map[string]any `json:"provider_metadata,omitempty"`
}
Response is a non-streaming chat completion result.
When the model invoked tools, ToolCalls is non-empty and FinishReason is "tool_calls". Content may still be present alongside tool calls for some providers.
Parts is the canonical multimodal representation of the assistant's reply (text + reasoning + future image/file outputs). Content is populated as the concatenation of all TextPart text for back-compat and ergonomic text-only consumption.
type Role ¶
type Role string
Role identifies the author of a Message in a chat conversation.
const ( // RoleSystem is used for high-level instructions or persona setup. RoleSystem Role = "system" // RoleUser is used for end-user messages. RoleUser Role = "user" // RoleAssistant is used for model-generated replies. RoleAssistant Role = "assistant" // RoleTool is used for tool/function call results fed back to the model. RoleTool Role = "tool" )
Standard chat roles. Providers map these to their own role vocabularies.
type Stream ¶
type Stream interface {
// Next returns the next chunk. It returns io.EOF when the stream is
// exhausted.
Next(ctx context.Context) (Chunk, error)
// Close releases resources associated with the stream.
Close() error
}
Stream is an iterator over Chunks produced by a streaming chat completion.
Next returns io.EOF (and a zero Chunk) when the stream is exhausted; any other non-nil error indicates a stream failure. Callers must Close the stream exactly once, even after receiving io.EOF, to release resources.
type TextPart ¶
type TextPart struct {
Text string `json:"text"`
}
TextPart is a plain-text content fragment.
func NewTextPart ¶
NewTextPart returns a TextPart wrapping text.
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters json.RawMessage `json:"parameters,omitempty"`
}
Tool describes a callable tool/function that the model may invoke.
Parameters is a JSON Schema (RFC 8927-compatible / OpenAPI-compatible) describing the tool's expected input. Providers translate Tool into their wire format (OpenAI/DeepSeek "function", Gemini "functionDeclaration", Ollama "tools").
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Arguments string `json:"arguments"`
}
ToolCall is a single tool invocation requested by the model.
ID is the provider-assigned identifier used to match a subsequent RoleTool message to this call. Some providers (notably Ollama) do not emit IDs; in that case the SDK synthesises one (call_<index>) so that downstream code can correlate calls and results uniformly.
Arguments is the JSON-encoded argument object as a string, matching the wire shape used by every provider we target.
func AssembleToolCalls ¶
func AssembleToolCalls(deltas []ToolCallDelta) []ToolCall
AssembleToolCalls reconstructs complete [ToolCall]s from an ordered sequence of [ToolCallDelta]s as emitted by a streaming provider.
Deltas with the same Index are folded into a single ToolCall: the first delta carrying ID/Name sets those fields, and ArgsDelta is concatenated across all deltas for that Index. Indices that never receive an ID are assigned a synthetic id of "call_<index>" so that downstream tool execution can still correlate results back to calls when the upstream provider does not supply IDs (e.g. Ollama).
The returned slice is sorted by Index ascending.
type ToolCallDelta ¶
type ToolCallDelta struct {
Index int `json:"index"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
ArgsDelta string `json:"args_delta,omitempty"`
}
ToolCallDelta is an incremental update to a single tool call within a streaming response. Multiple parallel tool calls are distinguished by Index.
On the first delta for a given Index, ID and Name are populated; on subsequent deltas only ArgsDelta is appended (the JSON arguments arrive token-by-token). Consumers concatenate ArgsDelta across all deltas with the same Index to reconstruct the full Arguments string.
Some providers (Ollama) emit a complete tool call in a single chunk rather than streaming arguments — in that case ID/Name are populated and ArgsDelta carries the entire JSON arguments at once.
type ToolChoice ¶
type ToolChoice struct {
Type ToolChoiceType `json:"type"`
Name string `json:"name,omitempty"`
}
ToolChoice constrains the model's tool selection behaviour. When Type is ToolChoiceTool, Name identifies the required tool.
type ToolChoiceType ¶
type ToolChoiceType string
ToolChoiceType controls how the model decides which (if any) tool to call.
const ( // ToolChoiceAuto lets the model choose freely (default when tools are present). ToolChoiceAuto ToolChoiceType = "auto" // ToolChoiceNone forbids tool calls; the model must answer with text. ToolChoiceNone ToolChoiceType = "none" // ToolChoiceRequired forces the model to call any tool. ToolChoiceRequired ToolChoiceType = "required" // ToolChoiceTool forces the model to call a specific named tool. ToolChoiceTool ToolChoiceType = "tool" )
type UnsupportedContentError ¶
UnsupportedContentError is the typed form of ErrUnsupportedContent carrying enough context to compose a useful error message and to be matched via errors.As. It always errors.Is matches ErrUnsupportedContent.
func (*UnsupportedContentError) Error ¶
func (e *UnsupportedContentError) Error() string
Error implements error.
func (*UnsupportedContentError) Unwrap ¶
func (e *UnsupportedContentError) Unwrap() error
Unwrap allows errors.Is(err, ErrUnsupportedContent) matching.
type Usage ¶
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
// CachedTokens is the portion of PromptTokens served from a cache
// (OpenAI's automatic prefix cache, or an Anthropic cache-control
// read), billed at a reduced rate. Zero when the provider doesn't
// report it or nothing was served from cache.
CachedTokens int `json:"cached_tokens,omitempty"`
// CacheCreationTokens is Anthropic-specific: the token count written
// to the cache on this call (billed at a premium over normal input
// tokens, the cost of the cache warming up). Zero for providers with
// no separate cache-write charge, e.g. OpenAI's automatic caching.
CacheCreationTokens int `json:"cache_creation_tokens,omitempty"`
}
Usage reports token accounting for a chat completion.
type Warning ¶
type Warning struct {
// Message is the human-readable warning text.
Message string `json:"message"`
// Type is an optional machine-readable category, e.g.
// "unsupported-content", "deprecated-option".
Type string `json:"type,omitempty"`
}
Warning is a non-fatal provider message (e.g. "image part dropped: model is text-only"). Providers attach warnings to Response.Warnings or Chunk.Warnings; core aggregates them onto StepResult/GenerateResult.