Documentation
¶
Overview ¶
Package model defines a neutral model registry + per-turn model-selection seam.
It is policy-free: oss ships a Registry (the available models + a default) and a Selector interface whose default impl (CapabilityDefault) only enforces capability matching. A distribution (e.g. sahara) plugs in a Selector that applies cost/complexity routing — that policy lives there, NOT in oss core.
Index ¶
- Constants
- Variables
- func ActiveModelFromMessage(message protocol.ChatMessage) string
- func KnownReasoningEfforts() []string
- func NormalizeReasoningEffort(value string) (string, error)
- func StampActiveModel(message *protocol.ChatMessage, name string)
- type Attempt
- type Capabilities
- type CapabilityDefault
- type Model
- type ProviderConfig
- type ReasoningConfig
- type Registry
- type SelectInput
- type Selector
Constants ¶
const MetaActiveModel = "active_model"
MetaActiveModel is the assistant-message metadata key carrying the worker's authoritative model selection for the addressed workspace/thread. Remote UI clients use it to mirror the worker state without parsing command text or assuming their local model registry has the same default.
Variables ¶
var ErrInvalidRegistryFile = errors.New("model: invalid registry file")
ErrInvalidRegistryFile is the sentinel wrapping every malformed-models.yaml error, so a distribution can errors.Is against it (and wrap it in its own config error) rather than string-matching.
Functions ¶
func ActiveModelFromMessage ¶ added in v0.0.2
func ActiveModelFromMessage(message protocol.ChatMessage) string
ActiveModelFromMessage returns the authoritative model stamped by the worker. Malformed or absent metadata is treated as unknown.
func KnownReasoningEfforts ¶ added in v0.0.2
func KnownReasoningEfforts() []string
KnownReasoningEfforts returns the provider-neutral effort vocabulary in display order. A model allowlist can narrow this set.
func NormalizeReasoningEffort ¶ added in v0.0.2
NormalizeReasoningEffort canonicalizes a user/config value. "med" is a convenience alias; the provider wire value remains "medium".
func StampActiveModel ¶ added in v0.0.2
func StampActiveModel(message *protocol.ChatMessage, name string)
StampActiveModel records name on message when it is non-empty. Existing metadata is preserved.
Types ¶
type Attempt ¶
Attempt records a model that failed within the current turn. Reason is the provider failure classification as a string (kept a string so this package stays free of a provider dependency); empty when unknown.
type Capabilities ¶
type Capabilities struct {
Vision bool `json:"vision" yaml:"vision"`
Tools bool `json:"tools" yaml:"tools"`
Audio bool `json:"audio" yaml:"audio"`
}
Capabilities describes what a model supports. Extensible; v1 gates on Vision (the modality that actually varies across frontier models) and Tools (the harness cannot function without tool-calling).
func (Capabilities) Satisfies ¶
func (c Capabilities) Satisfies(req Capabilities) bool
Satisfies reports whether c covers every capability required by req.
type CapabilityDefault ¶
type CapabilityDefault struct{}
CapabilityDefault is oss's neutral Selector: it keeps the configured default when that model satisfies the turn's required capabilities, otherwise it falls back to the first capable model in the registry, otherwise to the default (best-effort — selection never fails the turn). No cost/complexity policy.
func (CapabilityDefault) SelectModel ¶
func (CapabilityDefault) SelectModel(_ context.Context, in SelectInput) (string, error)
type Model ¶
type Model struct {
Name string `json:"name" yaml:"name"`
Capabilities Capabilities `json:"capabilities" yaml:"capabilities"`
Tier string `json:"tier,omitempty" yaml:"tier,omitempty"`
Provider string `json:"provider,omitempty" yaml:"provider,omitempty"`
// Reasoning declares the operator default and optional allowlist for
// request-scoped reasoning effort. It does not change the upstream model ID.
Reasoning ReasoningConfig `json:"reasoning,omitzero" yaml:"reasoning,omitempty"`
// Context is the model's total context window in tokens (0 = unknown). Used to
// budget compaction to the model actually being called — critical when a turn
// escalates from a large-context orchestrator to a smaller-context vision model,
// so history is trimmed to fit the target instead of overflowing it.
Context int `json:"context,omitempty" yaml:"context,omitempty"`
}
Model is a registry entry: a logical name (what the provider/sidecar routes to a real upstream) plus capabilities and an open Tier label for distribution-side routing policies (e.g. a sahara cost router's "light"/"primary"). Provider is the optional NAME of a ProviderConfig (in the registry's provider set) this model routes to; empty means "use the runner's single configured provider".
type ProviderConfig ¶
type ProviderConfig struct {
Name string `json:"name" yaml:"name"`
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`
APIKey string `json:"api_key,omitempty" yaml:"api_key,omitempty"`
APIKeyEnv string `json:"api_key_env,omitempty" yaml:"api_key_env,omitempty"`
AuthProfile string `json:"auth_profile,omitempty" yaml:"auth_profile,omitempty"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
}
ProviderConfig is a named upstream a model can be routed to: a base URL, an inline API key (APIKey) or the env var holding it (APIKeyEnv), and a wire Format ("openai"/"responses"/"native"). It is pure data — construction of an actual provider client from it lives in the turn package (which imports provider), keeping this package free of a provider dependency. Missing fields are filled from the runner's env default by the resolver, not here.
type ReasoningConfig ¶ added in v0.0.2
type ReasoningConfig struct {
DefaultEffort string `json:"default_effort,omitempty" yaml:"default_effort,omitempty"`
AllowedEfforts []string `json:"allowed_efforts,omitempty" yaml:"allowed_efforts,omitempty"`
}
ReasoningConfig controls request-scoped reasoning effort for one model. AllowedEfforts is optional: an empty list means the registry imposes no model-specific restriction beyond the neutral known-value validation.
func (ReasoningConfig) Allows ¶ added in v0.0.2
func (c ReasoningConfig) Allows(effort string) bool
Allows reports whether an already-normalized effort is admitted by the model-specific allowlist. An empty allowlist is intentionally unrestricted.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the set of available models + the default. Built from config (sahara) or left nil (oss falls back to the runner's single configured model).
func LoadRegistry ¶
LoadRegistry reads a models.yaml at path into a *Registry. A missing file returns (nil, nil): no registry means the consumer keeps its single configured model + provider. A present file that is malformed, or lists no models, is an error (wrapping ErrInvalidRegistryFile). Env vars are NOT resolved and defaults are NOT filled here — the file is parsed verbatim; resolution happens later in the per-model provider resolver.
func NewRegistry ¶
NewRegistry builds a registry from models + a default name. Duplicate names keep the first occurrence. defaultName need not be present (Default() reports absence); callers decide how to handle a missing default.
func NewRegistryWithProviders ¶
func NewRegistryWithProviders(models []Model, defaultName string, providers []ProviderConfig) *Registry
NewRegistryWithProviders is NewRegistry plus a set of named provider configs a model can reference (Model.Provider). Duplicate provider names keep the first occurrence. Providers with an empty Name are skipped.
func (*Registry) Capable ¶
func (r *Registry) Capable(req Capabilities) []Model
Capable returns the models (declaration order) that satisfy req.
func (*Registry) DefaultName ¶
DefaultName returns the configured default model name (may be empty).
func (*Registry) ProviderFor ¶
func (r *Registry) ProviderFor(modelName string) (ProviderConfig, bool)
ProviderFor returns the ProviderConfig the named model references. It reports (_, false) when the registry is nil, the model is unknown, the model declares no provider, or the referenced provider name is not configured — in every one of those cases the caller should fall back to the default provider.
type SelectInput ¶
type SelectInput struct {
Addr protocol.MessageAddress
User protocol.ChatMessage
Required Capabilities
Registry *Registry
Default string
// Attempts are the models that already failed this turn, in order (empty on
// the initial pick). The runner re-consults the Selector after a *retryable*
// provider failure that same-model recovery (backoff, context trim) could not
// resolve, so a Selector can avoid a model that just failed and escalate
// (e.g. to a larger-context or higher tier). Returning "" declines further
// fallback and surfaces the error. oss's CapabilityDefault always declines on
// retry — cross-model fallback is opt-in via a distribution Selector.
Attempts []Attempt
}
SelectInput is the per-turn context handed to a Selector. Required is the capability set this turn needs (e.g. Vision when the message carries images); Default is the runner's configured default model name.
type Selector ¶
type Selector interface {
SelectModel(ctx context.Context, in SelectInput) (string, error)
}
Selector picks the model name for a turn. oss calls it for the auto path only (an explicit /model or spawn(model=) override bypasses it). The default impl is CapabilityDefault; a distribution plugs in a cost/complexity router.