provider

package
v0.1.8-rc.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: Apache-2.0 Imports: 43 Imported by: 0

Documentation

Overview

Package provider implements the multi-provider system for sol. This matches opencode's provider architecture for supporting multiple LLM providers. Provider information comes from the validated Airlock model catalog.

Index

Constants

View Source
const (
	CapText          = "text"
	CapVision        = "vision"
	CapImageGen      = "image_gen"
	CapSearch        = "search"
	CapEmbedding     = "embedding"
	CapSpeech        = "speech"
	CapTranscription = "transcription"
	CapReranking     = "reranking"
)

Capability constants. These are the strings exposed over the API and used as keys in the UI capability matrix. Keep them lowercase snake_case.

Two axes:

  • Kind-derived (CapEmbedding/CapSpeech/CapTranscription/CapReranking, plus CapText/CapImageGen which double as kinds). True when the provider has at least one model of that kind.
  • Modality-derived (CapVision). True when the provider has at least one language model that accepts the corresponding extra input modality.
View Source
const (
	CatalogURL      = "https://models.airlock.run/models.json"
	RefreshInterval = 12 * time.Hour
)
View Source
const OpenRouterBaseURL = "https://openrouter.ai/api/v1"

OpenRouterBaseURL is OpenRouter's OpenAI-compatible API root. Used as the default when a configured provider leaves the base URL blank.

Variables

View Source
var AttachmentOverlay = map[string]AttachmentPolicy{
	"openai": {
		SupportsURL:         true,
		SupportsFileURL:     false,
		MaxURLImages:        50,
		MaxURLBytesPerImage: 18 * 1024 * 1024,
		MaxInlineBytesTotal: 40 * 1024 * 1024,
	},
	"anthropic": {
		SupportsURL:         true,
		SupportsFileURL:     true,
		MaxURLImages:        50,
		MaxURLBytesPerImage: 4*1024*1024 + 512*1024,
		MaxInlineBytesTotal: 24 * 1024 * 1024,
	},
	"google": {
		SupportsURL:         true,
		SupportsFileURL:     true,
		MaxURLImages:        100,
		MaxURLBytesPerImage: 20 * 1024 * 1024,
		MaxInlineBytesTotal: 80 * 1024 * 1024,
	},
	"vertex": {
		SupportsURL:         true,
		SupportsFileURL:     true,
		MaxURLImages:        100,
		MaxURLBytesPerImage: 20 * 1024 * 1024,
		MaxInlineBytesTotal: 80 * 1024 * 1024,
	},
	"bedrock": {
		SupportsURL:         true,
		SupportsFileURL:     true,
		MaxURLImages:        50,
		MaxURLBytesPerImage: 4*1024*1024 + 512*1024,
		MaxInlineBytesTotal: 24 * 1024 * 1024,
	},
	"xai": {
		SupportsURL:         true,
		SupportsFileURL:     false,
		MaxURLImages:        50,
		MaxURLBytesPerImage: 18 * 1024 * 1024,
		MaxInlineBytesTotal: 40 * 1024 * 1024,
	},
	"openaicompat": {
		SupportsURL:         true,
		SupportsFileURL:     false,
		MaxURLImages:        5,
		MaxURLBytesPerImage: 3*1024*1024 + 512*1024,
		MaxInlineBytesTotal: 5 * 1024 * 1024,
	},
}

AttachmentOverlay is the per-provider override map, keyed by provider_id. Values are applied as-is — not merged with DefaultAttachmentPolicy — so each entry must be complete.

Covered: every provider in goai whose message conversion accepts a message.FilePart carrying a URL data variant.

Sizing references (as of 2026-Q2 docs):

Our caps sit *below* each provider's hard limit to leave headroom for JSON framing, tool schemas, prompt bytes, etc. `MaxInlineBytesTotal` is the base64-encoded byte budget (roughly 1.33× the raw byte count).

View Source
var DefaultAttachmentPolicy = AttachmentPolicy{
	MaxInlineBytesTotal: 5 * 1024 * 1024,
	SupportsURL:         false,
}

DefaultAttachmentPolicy is the fallback — inline-only, 5 MiB request cap.

Functions

func AllProviders

func AllProviders() (map[string]*ModelsDevProvider, error)

AllProviders returns the Airlock model catalog enriched with search-only provider stubs. Callers that want the source catalog unmodified should call LoadProviders directly.

The catalog is remotely refreshed and has an embedded fallback. The only hand-maintained entries in Sol are search providers (overlay.go).

Deprecated models (Status == "deprecated") are dropped so they don't surface in pickers / catalogs. Runtime lookups via GetModelInfo go through LoadProviders directly and so still resolve — agents configured on a now-deprecated model keep running, they're just hidden from the dropdown.

Merge semantics, in order:

  1. Start from LoadProviders().
  2. Synthesize stubs for search-only providers absent from the catalog (e.g. brave). Their search capability is derived from SearchBackend.
  3. Drop deprecated entries from every provider in the merged set.

The returned map's inner *ModelsDevProvider pointers are clones whenever we touched the provider, so callers can mutate top-level safely. Caches are unchanged.

func CreateEmbeddingModel

func CreateEmbeddingModel(providerID, modelID string, opts Options) model.EmbeddingModel

CreateEmbeddingModel creates an embedding model from provider and model IDs.

func CreateImageModel

func CreateImageModel(providerID, modelID string, opts Options) model.ImageModel

CreateImageModel creates an image generation model from provider and model IDs.

func CreateModel

func CreateModel(providerID, modelID string, opts Options) stream.Model

CreateModel creates a language model from provider and model IDs. This is the main entry point for getting a model instance.

func CreateProxyModel

func CreateProxyModel(fullModelID string, opts ProxyOptions) stream.Model

CreateProxyModel creates a model that proxies LLM calls through an Airlock-compatible endpoint. The full model string (e.g., "anthropic/claude-sonnet-4-20250514") is passed to the proxy which resolves credentials and forwards to the real provider.

func CreateSpeechModel

func CreateSpeechModel(providerID, modelID string, opts Options) model.SpeechModel

CreateSpeechModel creates a text-to-speech model from provider and model IDs.

func CreateTranscriptionModel

func CreateTranscriptionModel(providerID, modelID string, opts Options) model.TranscriptionModel

CreateTranscriptionModel creates a speech-to-text model from provider and model IDs.

func GetContextLimit

func GetContextLimit(providerID, modelID string) int

func GetDisplayName

func GetDisplayName(providerID string) string

GetDisplayName returns the display name for a provider. Uses the active model catalog when available.

func GetEnvVarName

func GetEnvVarName(providerID string) string

GetEnvVarName returns the primary environment variable name for a provider's API key. Uses the active model catalog when available.

func GetOutputLimit

func GetOutputLimit(providerID, modelID string) int

func ListProviders

func ListProviders() []string

func LoadProviders

func LoadProviders() (map[string]*ModelsDevProvider, error)

LoadProviders returns the active validated catalog immediately. The embedded snapshot is always available; the first call starts a non-blocking refresh.

func MaxOutputTokens

func MaxOutputTokens(modelID string) int

MaxOutputTokens returns the appropriate max output tokens for a model. This matches opencode's defaults for reasoning vs non-reasoning models.

func ParseModel

func ParseModel(model string) (providerID, modelID string)

ParseModel parses a "provider/model" string into provider and model IDs. This matches opencode's parseModel function. Examples:

  • "openai/gpt-4o-mini" → ("openai", "gpt-4o-mini")
  • "anthropic/claude-3-5-sonnet" → ("anthropic", "claude-3-5-sonnet")
  • "gpt-4o-mini" → ("openai", "gpt-4o-mini") // defaults to openai

func ProviderOptions

func ProviderOptions(providerID, modelID, sessionID string) map[string]any

ProviderOptions returns the provider-specific options for a model. This matches opencode's ProviderTransform.options() function.

func SearchBackend

func SearchBackend(providerID string) string

SearchBackend returns the sol/websearch backend client name for a provider, or "" if the provider doesn't offer web search.

func StartPeriodicRefresh added in v0.1.2

func StartPeriodicRefresh(ctx context.Context)

StartPeriodicRefresh starts one immediate refresh and one periodic ticker.

func SupportsInputModality

func SupportsInputModality(providerID, modelID, modality string) bool

func ValidateCatalogJSON

func ValidateCatalogJSON(data []byte) error

ValidateCatalogJSON validates a candidate for the embedded catalog snapshot.

Types

type AttachmentPolicy

type AttachmentPolicy struct {
	// MaxInlineBytesTotal caps the total base64-encoded attachment bytes in
	// a single request body. Parts that don't fit are evicted (oldest first)
	// and replaced with a text placeholder that tells the LLM how to
	// re-attach.
	MaxInlineBytesTotal int

	// SupportsURL is true when the provider accepts http(s):// URLs for
	// image file parts (a FilePart with an image/* type and a URL data
	// variant). Anthropic + Google also accept non-image files by URL (see
	// SupportsFileURL).
	SupportsURL bool

	// SupportsFileURL is true when the provider accepts http(s):// URLs for
	// non-image file parts (a FilePart with a URL data variant). Anthropic +
	// Google support PDFs and other file types by URL; OpenAI currently does
	// not on the chat path.
	SupportsFileURL bool

	// MaxURLImages caps how many image/file parts per request can be sent
	// as URLs before we fall back to inline. Shared across both kinds to
	// keep the provider from rejecting oversized fan-out fetches.
	MaxURLImages int

	// MaxURLBytesPerImage is the per-object size ceiling when sending URLs.
	// Objects above this are fetched and inlined (or evicted) rather than
	// referenced.
	MaxURLBytesPerImage int
}

AttachmentPolicy describes how a given provider/model accepts image and file attachments. Used by airlock's attachref resolver to decide between URL mode (presigned S3 link) and inline mode (base64-encoded bytes), and to enforce per-request size caps.

Defaults are conservative: inline-only, 5 MiB per-request budget. Provider overrides (see AttachmentOverlay) relax these where the upstream API is known to support URL references.

func PolicyFor

func PolicyFor(providerID, modelID string) AttachmentPolicy

PolicyFor returns the attachment policy for a given provider/model pair. modelID is accepted for future model-level overrides but currently unused.

type CapabilitySet

type CapabilitySet struct {
	Text          bool
	Vision        bool
	ImageGen      bool
	Search        bool
	Embedding     bool
	Speech        bool
	Transcription bool
	Reranking     bool
}

CapabilitySet is the set of high-level capabilities a model or provider offers. Derived from catalog modalities, model kind, and the overlay's extras.

func CapabilitiesFromModel

func CapabilitiesFromModel(m ModelInfo) CapabilitySet

CapabilitiesFromModel derives the capability set for a single model from its kind plus its catalog modality list. Search is never set at the model level — it's a provider capability (see ProviderCapabilities).

Kind-derived capabilities trust the catalog. Modalities add orthogonal capabilities to language models, such as vision and image output.

func ProviderCapabilities

func ProviderCapabilities(p *ModelsDevProvider) CapabilitySet

ProviderCapabilities unions per-model capabilities across every model in the provider, then ORs in "search" when the provider has a web-search backend (SearchBackend). Search is a provider feature, not derivable from any single model's modalities, so it's the one capability sourced outside the models.

A provider with no models is valid — e.g. brave, a search-only stub — in which case the result is just its search capability.

func (CapabilitySet) List

func (c CapabilitySet) List() []string

List returns the set as a sorted slice of capability strings in the canonical UI order.

type ModelCapabilities

type ModelCapabilities struct {
	// IsReasoningModel indicates if the model is a reasoning model
	IsReasoningModel bool

	// SystemMessageMode determines how system messages should be handled.
	// "system" - use standard system role
	// "developer" - convert to developer role (for reasoning models)
	// "remove" - remove system messages entirely
	SystemMessageMode string

	// DefaultReasoningEffort is the default reasoning effort level for this model.
	// Empty string means no default (non-reasoning model or special case like gpt-5-pro).
	DefaultReasoningEffort string

	// DefaultMaxOutputTokens is the recommended max output tokens for this model.
	// 0 means use the standard default.
	DefaultMaxOutputTokens int
}

ModelCapabilities describes capabilities of a model. This matches opencode's getResponsesModelConfig() in openai-responses-language-model.ts

func GetModelCapabilities

func GetModelCapabilities(modelID string) ModelCapabilities

GetModelCapabilities returns capabilities for a given model ID. This matches opencode's getResponsesModelConfig() function.

type ModelCost

type ModelCost struct {
	Input      float64 `json:"input"`
	Output     float64 `json:"output"`
	CacheRead  float64 `json:"cache_read,omitempty"`
	CacheWrite float64 `json:"cache_write,omitempty"`
}

type ModelInfo

type ModelInfo struct {
	ID           string           `json:"id"`
	Name         string           `json:"name"`
	Kind         ModelKind        `json:"kind,omitempty"`
	Family       string           `json:"family,omitempty"`
	ReleaseDate  string           `json:"release_date,omitempty"`
	Attachment   bool             `json:"attachment,omitempty"`
	Reasoning    bool             `json:"reasoning,omitempty"`
	Temperature  bool             `json:"temperature,omitempty"`
	ToolCall     bool             `json:"tool_call,omitempty"`
	Modalities   *ModelModalities `json:"modalities,omitempty"`
	Cost         *ModelCost       `json:"cost,omitempty"`
	Limit        *ModelLimit      `json:"limit,omitempty"`
	Status       string           `json:"status,omitempty"`
	Experimental json.RawMessage  `json:"experimental,omitempty"`
}

ModelInfo represents a model in the Airlock catalog.

func GetModelInfo

func GetModelInfo(providerID, modelID string) (*ModelInfo, bool)

type ModelKind

type ModelKind string

ModelKind classifies a model's primary purpose as published by the catalog.

const (
	KindLanguage      ModelKind = "language"
	KindEmbedding     ModelKind = "embedding"
	KindImage         ModelKind = "image"
	KindAudio         ModelKind = "audio"
	KindVideo         ModelKind = "video"
	KindSpeech        ModelKind = "speech"        // text-to-speech
	KindTranscription ModelKind = "transcription" // speech-to-text
	KindReranking     ModelKind = "reranking"
)

type ModelLimit

type ModelLimit struct {
	Context int `json:"context"`
	Input   int `json:"input,omitempty"`
	Output  int `json:"output"`
}

type ModelModalities

type ModelModalities struct {
	Input  []string `json:"input"`
	Output []string `json:"output"`
}

func GetModalities

func GetModalities(providerID, modelID string) *ModelModalities

func (*ModelModalities) SupportsInput

func (m *ModelModalities) SupportsInput(modality string) bool

type ModelsDevProvider

type ModelsDevProvider struct {
	ID      string               `json:"id"`
	Name    string               `json:"name"`
	API     string               `json:"api,omitempty"`
	NPM     string               `json:"npm,omitempty"`
	Env     []string             `json:"env"`
	Aliases []string             `json:"aliases,omitempty"`
	Models  map[string]ModelInfo `json:"models"`
}

ModelsDevProvider represents one provider in the models.dev-compatible Airlock model catalog.

func GetProviderInfo

func GetProviderInfo(providerID string) (*ModelsDevProvider, bool)

type Options

type Options struct {
	APIKey  string
	BaseURL string
}

Options holds configuration for creating a provider.

type ProxyOptions

type ProxyOptions struct {
	BaseURL string // Proxy server URL (e.g., "http://localhost:8080")
	Token   string // Bearer token for authentication
}

ProxyOptions holds configuration for creating a proxy-backed model.

Directories

Path Synopsis
internal
updatecatalog command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL