Documentation
¶
Index ¶
- Constants
- Variables
- func NormalizeImageMediaType(s string) string
- type AgentEventType
- type CollectOptions
- type CollectedStream
- type CompletionRequest
- type ImageBlock
- type Message
- type MessageRole
- type Provider
- type ProviderCapabilities
- type ReasoningBlock
- type StreamEvent
- type StreamEventType
- type TokenUsage
- type ToolCall
- type ToolDefinition
- type TurnSession
- type TurnSessionProvider
- type Usage
Constants ¶
const ( // FinishReasonLength means the response was truncated at the output token // cap (OpenAI finish_reason=="length", Anthropic stop_reason=="max_tokens", // Gemini finishReason=="MAX_TOKENS"). FinishReasonLength = "length" // FinishReasonContentFilter means the response was withheld or cut off by a // content/safety filter (OpenAI finish_reason=="content_filter", // Gemini finishReason=="SAFETY"). FinishReasonContentFilter = "content_filter" )
Normalized terminal finish reasons for responses that did not end normally. Providers map their native stop reasons onto these so consumers can detect a truncated or filtered response regardless of which provider produced it. A normal completion leaves the finish reason empty.
Variables ¶
var ErrCompactionUnsupported = errors.New("zeroruntime: native compaction unsupported")
ErrCompactionUnsupported is returned by TurnSession.Compact when the provider has no native server-side compaction (every default adapter). Callers treat it as "use the local summarizer path", not as a run failure.
Functions ¶
func NormalizeImageMediaType ¶
NormalizeImageMediaType canonicalizes a caller-supplied image type to one of the allow-listed MIME strings (image/png, image/jpeg, image/gif, image/webp) or "" when the input is outside the allow-list (the caller then rejects it).
It lowercases and trims the input, strips a leading "data:<m>;base64," prefix (using <m>), maps a bare png|jpeg|jpg|gif|webp to image/<x> (jpg->jpeg), and passes through an already-image/<x> value in the allow-list (image/jpg is also folded to image/jpeg). It is pure and has no dependencies.
Types ¶
type AgentEventType ¶
type AgentEventType string
AgentEventType is the stable PRD-level event stream shared by TUI, headless output, sessions, and future editor integrations.
const ( AgentEventText AgentEventType = "text" AgentEventToolCall AgentEventType = "tool_call" AgentEventToolResult AgentEventType = "tool_result" AgentEventThinking AgentEventType = "thinking" AgentEventUsage AgentEventType = "usage" AgentEventPlanUpdate AgentEventType = "plan_update" AgentEventError AgentEventType = "error" AgentEventTurnEnd AgentEventType = "turn_end" )
type CollectOptions ¶
type CollectOptions struct {
OnText func(string)
OnReasoning func(string)
OnUsage func(Usage)
// OnToolCallStart fires when a tool call opens (id + tool name), and
// OnToolCallDelta fires for each streamed argument fragment. Together they let
// a surface render a tool call's arguments LIVE (e.g. a file being written)
// instead of waiting for the whole call to accumulate. nil is a no-op.
OnToolCallStart func(id, name string)
OnToolCallDelta func(id, fragment string)
}
CollectOptions provides callbacks for consumers that need live stream updates.
type CollectedStream ¶
type CollectedStream struct {
Text string
ToolCalls []ToolCall
Usage Usage
Error string
DroppedToolCalls int // malformed tool calls the provider could not dispatch
// FinishReason is the provider's normalized terminal stop reason when the
// response did not end normally (FinishReasonLength / FinishReasonContentFilter).
// It is empty for a normal completion. Truncated reports whether it is set.
FinishReason string
// ReasoningBlocks are the response's preserved reasoning artifacts (Anthropic
// thinking blocks) that must be replayed on the next turn. Empty for providers
// or runs without extended thinking.
ReasoningBlocks []ReasoningBlock
// HasReasoning records whether the provider streamed reasoning deltas. The
// deltas remain non-answer content, but they still prove the turn was live.
HasReasoning bool
}
CollectedStream is the non-streaming summary of provider events.
func CollectStream ¶
func CollectStream(ctx context.Context, events <-chan StreamEvent) CollectedStream
CollectStream drains provider events into text, tool calls, usage, and error state.
func CollectStreamWithOptions ¶
func CollectStreamWithOptions(ctx context.Context, events <-chan StreamEvent, options CollectOptions) CollectedStream
CollectStreamWithOptions drains provider events and emits optional live callbacks.
func (CollectedStream) Truncated ¶
func (collected CollectedStream) Truncated() bool
Truncated reports whether the response ended for a non-normal reason (the output was cut at the token cap or withheld by a content filter), so callers can warn instead of treating a clipped answer as complete.
type CompletionRequest ¶
type CompletionRequest struct {
Messages []Message
Tools []ToolDefinition
// ReasoningEffort, when non-empty, asks a reasoning-capable model to spend the
// given level of thinking effort ("minimal"/"low"/"medium"/"high"). Each
// provider adapter maps it to its own API shape (OpenAI reasoning_effort,
// Anthropic/Gemini thinking budgets) and ignores it for models that do not
// support reasoning. Empty means "let the provider decide".
ReasoningEffort string
// PromptCacheKey, when non-empty, is an opaque stable identifier for the
// conversation (the session ID). Providers with server-side prefix-cache
// routing forward it — OpenAI `prompt_cache_key` — so consecutive requests
// land on a replica that already holds the cached prompt prefix instead of
// re-billing the full prefix each turn. Providers without an equivalent
// ignore it.
PromptCacheKey string
}
CompletionRequest groups provider input messages and available tools.
type ImageBlock ¶
ImageBlock is a normalized image attachment carried on a Message. Data is the RAW decoded image bytes (no base64, no data: prefix); each provider encodes it into its own wire format. MediaType is a normalized MIME, e.g. "image/png".
func CloneImageBlocks ¶
func CloneImageBlocks(in []ImageBlock) []ImageBlock
CloneImageBlocks deep-copies a slice of ImageBlock, including each Data byte slice, so the returned blocks share no backing array with the input. It returns nil for a nil or empty input (preserving the text-only "no images" representation). Use it wherever image-carrying messages are seeded or copied so raw image bytes are never aliased across history/request/result copies.
type Message ¶
type Message struct {
Role MessageRole
Content string
ToolCalls []ToolCall
ToolCallID string
Images []ImageBlock // optional; nil for text-only messages
Reasoning []ReasoningBlock // optional; preserved thinking blocks to replay
}
Message is a normalized conversation turn passed to providers.
func SeedMessages ¶
SeedMessages creates the initial system and user turns for a request. It is a text-only convenience that delegates to SeedMessagesWithImages with no images (the user turn's Images stays nil, byte-identical to the prior behavior).
func SeedMessagesWithImages ¶
func SeedMessagesWithImages(systemPrompt string, userPrompt string, images []ImageBlock) []Message
SeedMessagesWithImages creates the initial system and user turns and attaches any image attachments to the user turn. images may be nil (text-only). The images are deep-copied so the seeded message never aliases the caller's slice or the underlying Data bytes (a later mutation of the caller's bytes can never reach into the conversation history).
type MessageRole ¶
type MessageRole string
MessageRole identifies the origin of a conversation message.
const ( MessageRoleSystem MessageRole = "system" MessageRoleUser MessageRole = "user" MessageRoleAssistant MessageRole = "assistant" MessageRoleTool MessageRole = "tool" )
type Provider ¶
type Provider interface {
StreamCompletion(ctx context.Context, request CompletionRequest) (<-chan StreamEvent, error)
}
Provider streams normalized completion events for one request.
type ProviderCapabilities ¶ added in v0.5.0
type ProviderCapabilities struct {
// Model is the resolved API model id (informational; may be empty).
Model string
// ContextWindow is the model's max input context in tokens; 0 = unknown.
ContextWindow int
// MaxOutputTokens is the model's max output tokens per turn; 0 = unknown.
MaxOutputTokens int
// SupportsVision mirrors the registry's vision capability.
SupportsVision bool
// SupportsReasoning mirrors the registry's reasoning capability.
SupportsReasoning bool
// SupportsPromptCache mirrors the registry's prompt-cache capability.
SupportsPromptCache bool
// ReasoningEfforts lists the accepted effort tiers, weakest to strongest.
// nil/empty means the model exposes no effort control.
ReasoningEfforts []string
// NativeCompaction reports server-side compaction support. Always false for
// the default adapter; a future native-compaction session sets it, and the
// loop branches on it to call TurnSession.Compact instead of the local
// summarizer.
NativeCompaction bool
}
ProviderCapabilities is a flat, provider-agnostic projection of a resolved model's static capabilities. It is deliberately plain data — no modelregistry or reasoning types — because modelregistry imports zeroruntime, so a typed reference here would form an import cycle. The providers factory populates it from the model-registry entry it already resolves; a zero value means the capabilities are unknown, which every consumer must treat as "assume nothing".
type ReasoningBlock ¶
type ReasoningBlock struct {
Provider string // adapter that produced and can replay this block ("anthropic", "gemini")
Type string // provider block type ("thinking", "redacted_thinking")
Text string // human-readable reasoning text (empty for redacted/opaque blocks)
Signature string // cryptographic signature the provider requires on replay
Data string // opaque provider payload (e.g. Anthropic redacted_thinking data)
}
ReasoningBlock is a provider-emitted reasoning artifact that must be replayed verbatim on later turns or the provider rejects the (tool-using) conversation: Anthropic requires thinking / redacted_thinking blocks be passed back with their signatures. Only the adapter named by Provider interprets a block; other adapters ignore foreign blocks, so a mid-run provider switch is safe.
type StreamEvent ¶
type StreamEvent struct {
Type StreamEventType
Content string
ToolCallID string
ToolName string
ToolCallSignature string // opaque reasoning signature bound to this call (Gemini thoughtSignature)
ArgumentsFragment string
Usage Usage
Error string
// FinishReason carries the provider's normalized terminal stop reason when a
// response did not end normally (e.g. FinishReasonLength when the output hit
// the token cap, or FinishReasonContentFilter when it was filtered). It is
// empty for a normal completion. Providers set it on the terminal/done event.
FinishReason string
// ReasoningBlocks carries completed reasoning artifacts (Anthropic thinking /
// redacted_thinking blocks) that must be preserved for replay. Providers attach
// them to the terminal/done event; the collector accumulates them.
ReasoningBlocks []ReasoningBlock
}
StreamEvent is one normalized event emitted by a streaming provider.
type StreamEventType ¶
type StreamEventType string
StreamEventType identifies one event in a provider completion stream.
const ( StreamEventText StreamEventType = "text" // StreamEventReasoning carries live reasoning deltas that must never be // folded into answer text or persisted as assistant content. StreamEventReasoning StreamEventType = "reasoning" StreamEventToolCallStart StreamEventType = "tool-call-start" StreamEventToolCallDelta StreamEventType = "tool-call-delta" StreamEventToolCallEnd StreamEventType = "tool-call-end" // StreamEventToolCallDropped signals the model attempted a tool call that // was malformed (no usable name/id) and could not be dispatched. The agent // uses this to ask the model to retry instead of silently ending the turn. StreamEventToolCallDropped StreamEventType = "tool-call-dropped" StreamEventUsage StreamEventType = "usage" StreamEventDone StreamEventType = "done" StreamEventError StreamEventType = "error" )
type TokenUsage ¶
type TokenUsage struct {
InputTokens int
PromptTokens int
CachedInputTokens int
// CacheWriteTokens is the cache-creation (cache-write) portion of the input,
// billed at a premium rate by providers that support it (e.g. Anthropic).
// Like CachedInputTokens it is a SUBSET of InputTokens, not additive.
CacheWriteTokens int
OutputTokens int
CompletionTokens int
ReasoningTokens int
}
TokenUsage accepts provider-specific token aliases before normalization.
type ToolCall ¶
type ToolCall struct {
ID string
Name string
Arguments string
// Signature carries a provider's opaque reasoning signature bound to this call
// (Gemini attaches a thoughtSignature to a functionCall part). It must be
// echoed back with the call on later turns or the provider may reject the
// multi-turn function-calling conversation. Empty for providers that do not
// use it. Only the originating adapter interprets it.
Signature string
}
ToolCall is a normalized assistant request to run a tool.
type ToolDefinition ¶
ToolDefinition describes a model-visible tool and its JSON-schema parameters.
type TurnSession ¶ added in v0.5.0
type TurnSession interface {
// Prewarm optionally primes provider-side state before the first Stream.
// It must be safe to skip entirely: the default adapter no-ops and returns
// nil. A non-nil error is advisory — callers proceed without prewarming
// (best-effort, never fatal).
Prewarm(ctx context.Context) error
// Stream issues one completion request. The signature is identical to
// Provider.StreamCompletion so the default adapter forwards verbatim and
// callers' stream handling stays byte-for-byte unchanged.
Stream(ctx context.Context, request CompletionRequest) (<-chan StreamEvent, error)
// Compact asks the provider to compact the conversation server-side and
// returns the replacement messages. The default adapter returns
// ErrCompactionUnsupported; callers then keep their local summarizer path.
Compact(ctx context.Context, request CompletionRequest) ([]Message, error)
// Close releases per-run provider state. It must be idempotent and safe to
// call after a mid-run swap as well as at run teardown. Default: no-op.
Close() error
}
TurnSession is one provider conversation for the lifetime of a single agent run: many turns, compaction summaries, and any mid-run model swaps each open a fresh session. It owns whatever per-run provider state an optimized implementation keeps warm (a pooled connection, a cached-prefix handle). The default adapter holds nothing and every method degrades to today's one-shot request path.
type TurnSessionProvider ¶ added in v0.5.0
type TurnSessionProvider interface {
// OpenTurnSession starts a session for one run. Everything a session needs
// per request (messages, tools, reasoning effort, prompt-cache key) already
// arrives on Stream, so nothing beyond ctx is passed here — keeping the
// seam narrow. The default adapter never errors; a real implementation may
// fail a handshake, which callers surface as a clean run-start error.
OpenTurnSession(ctx context.Context) (TurnSession, error)
// Capabilities returns the resolved model's static capability projection.
Capabilities() ProviderCapabilities
}
TurnSessionProvider opens a TurnSession for one run and exposes the resolved model's static capabilities. The providers factory builds the default implementation by wrapping an existing Provider.
func NewProviderTurnSessionProvider ¶ added in v0.5.0
func NewProviderTurnSessionProvider(provider Provider, caps ProviderCapabilities) TurnSessionProvider
NewProviderTurnSessionProvider wraps an existing Provider as a default TurnSessionProvider. caps may be the zero value (unknown) for callers that only need streaming behavior; the providers factory supplies a populated projection.
type Usage ¶
type Usage struct {
InputTokens int
OutputTokens int
PromptTokens int
CompletionTokens int
CachedInputTokens int
CacheWriteTokens int
ReasoningTokens int
}
Usage records normalized token accounting reported by a provider.
Token accounting is consistent across providers: InputTokens is the TOTAL prompt size (uncached + cache-read + cache-write); CachedInputTokens (cache read, discounted) and CacheWriteTokens (cache creation, premium) are subsets of it, so uncached input = InputTokens - CachedInputTokens - CacheWriteTokens. OutputTokens is the TOTAL output size, including hidden reasoning tokens when a provider reports them separately; ReasoningTokens is a subset of OutputTokens, not an additive count.
func NormalizeUsage ¶
func NormalizeUsage(input TokenUsage) (Usage, error)
NormalizeUsage converts provider token aliases into the shared runtime shape.
func (Usage) BillableOutputTokens ¶
func (Usage) EffectiveInputTokens ¶
func (Usage) EffectiveOutputTokens ¶
func (Usage) TotalTokens ¶
TotalTokens returns prompt plus completion tokens.