Documentation
¶
Index ¶
- Constants
- Variables
- func CanonicalClaudeCodeModelID(modelID string, fallback ...string) string
- func CanonicalOpenRouterModelID(modelID string, fallback ...string) string
- func CanonicalVertexModelID(modelID string, fallback ...string) string
- func CatalogClampEffort(provider string, modelID, effort string) string
- func CatalogContextWindow(provider string, modelID string, fallback int64) int64
- func CatalogDefaultMaxTokens(provider string, modelID string, fallback int64) int64
- func CatalogModelIDs(provider string) []string
- func CatalogResolveEffort(providerID string, modelID, effort string) string
- func CatalogSupportsImages(provider string, modelID string, fallback ...bool) bool
- func CheapestModel(providerID string) string
- func ClaudeCodeResolveBinary(pc config.ProviderConfig) string
- func DefaultProviderID() string
- func FilterVertexModelOptions(all []string) []string
- func LoadModelsDev(ctx context.Context) error
- func MissingAPIKeyError(envKey string, hint ...string) error
- func ModelsDevLoaded() bool
- func NewOpenAICompatModel(cfg OpenAICompatConfig) model.LLM
- func NormalizeModelID(modelID string) string
- func OpenRouterProviderOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
- func ProviderConfigured(cfg config.Config, id string) bool
- func Register(p Provider)
- func ResolveModelID(p Provider, explicit string, cfg config.Config) string
- func ResolveOpenRouterAPIKey(pc config.ProviderConfig) string
- func ResolveOpenRouterBaseURL(pc config.ProviderConfig) string
- func SaveSettings(cfg *config.Config, id string, s ProviderSettings)
- func SettingValue(pc config.ProviderConfig, f SettingField) string
- func SteeringPrompt(opts SteeringOptions) string
- func StepCostUSD(providerID, modelID string, ...) (float64, bool)
- func ValidateVertexLocation(s string) error
- func ValidateVertexProject(s string) error
- func ValidateVertexServiceAccountKey(s string) error
- func VertexProviderOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
- func VertexResolveLocation(pc config.ProviderConfig) string
- func VertexResolveProject(pc config.ProviderConfig) string
- func VertexResolveServiceAccountKey(pc config.ProviderConfig) string
- func WithObservedToolSink(ctx context.Context, sink ObservedToolSink) context.Context
- func WithWebSearchAvailable(ctx context.Context, available bool) context.Context
- type CheapModeler
- type ClaudeCode
- func (ClaudeCode) BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
- func (ClaudeCode) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
- func (ClaudeCode) CanonicalModelID(modelID, fallback string) string
- func (ClaudeCode) CheapModel() string
- func (ClaudeCode) Configured(pc config.ProviderConfig) bool
- func (ClaudeCode) ContextWindow(modelID string) int64
- func (ClaudeCode) DefaultModel() string
- func (ClaudeCode) DisplayName() string
- func (ClaudeCode) EffortOptions() []string
- func (ClaudeCode) HasNativeWebSearch() bool
- func (ClaudeCode) ID() string
- func (ClaudeCode) ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
- func (ClaudeCode) MaxOutputTokens(modelID string) int64
- func (ClaudeCode) ModelOptions() []string
- func (ClaudeCode) Settings() []SettingField
- func (ClaudeCode) SupportsImages(modelID string) bool
- type ClaudeExtraUsage
- type ClaudeUsage
- type ClaudeUsageWindow
- type ModelInfo
- type ModelLister
- type ModelMeta
- type ModelPricing
- type NativeWebSearchProvider
- type ObservedToolSink
- type OpenAICompatConfig
- type OpenRouter
- func (OpenRouter) BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
- func (OpenRouter) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
- func (OpenRouter) CanonicalModelID(modelID, fallback string) string
- func (OpenRouter) Configured(pc config.ProviderConfig) bool
- func (OpenRouter) ContextWindow(modelID string) int64
- func (OpenRouter) DefaultModel() string
- func (OpenRouter) DisplayName() string
- func (OpenRouter) EffortOptions() []string
- func (OpenRouter) ID() string
- func (OpenRouter) ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
- func (OpenRouter) MaxOutputTokens(modelID string) int64
- func (OpenRouter) ModelOptions() []string
- func (OpenRouter) Settings() []SettingField
- func (OpenRouter) SupportsImages(modelID string) bool
- type Provider
- type ProviderSettings
- type SettingField
- type SteeringOptions
- type Vertex
- func (Vertex) BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
- func (Vertex) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
- func (Vertex) CanonicalModelID(modelID, fallback string) string
- func (Vertex) Configured(pc config.ProviderConfig) bool
- func (Vertex) ContextWindow(modelID string) int64
- func (Vertex) DefaultModel() string
- func (Vertex) DisplayName() string
- func (Vertex) EffortOptions() []string
- func (Vertex) ID() string
- func (Vertex) ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
- func (Vertex) MaxOutputTokens(modelID string) int64
- func (Vertex) ModelOptions() []string
- func (Vertex) Settings() []SettingField
- func (Vertex) SupportsImages(modelID string) bool
Constants ¶
const ( ClaudeCodeProviderID = "claude-code" ClaudeCodeDefaultModel = "default" ClaudeCodeCheapModel = "haiku" ClaudeCodeFieldBinary = "binary" ClaudeCodeEnvBinary = "ASK_CLAUDE_BIN" ClaudeCodeDefaultBin = "claude" ClaudeCodeContextWindow = 200_000 ClaudeCodeMaxOutputToken = 64_000 )
const ( ModelsDevDefaultURL = "https://models.dev/api.json" ModelsDevCacheTTL = 24 * time.Hour )
const ( OpenRouterProviderID = "openrouter" OpenRouterDefaultModel = "anthropic/claude-3.7-sonnet" OpenRouterDefaultBaseURL = "https://openrouter.ai/api/v1" OpenRouterEnvAPIKey = "OPENROUTER_API_KEY" OpenRouterFieldAPIKey = "apiKey" OpenRouterFieldBaseURL = "baseURL" )
const ( VertexProviderID = "vertex" VertexDefaultModel = "gemini-3.7-flash" VertexDefaultLocation = "global" VertexContextWindow = 1_048_576 VertexFallbackMaxOutputTokens = 65_536 VertexEnvApplicationCredentials = "GOOGLE_APPLICATION_CREDENTIALS" VertexEnvCloudProject = "GOOGLE_CLOUD_PROJECT" VertexFieldProject = "project" VertexFieldLocation = "location" VertexFieldServiceAccountKey = "serviceAccountKey" )
const MaxOutputTokensGemini int64 = 65_536
MaxOutputTokensGemini is the maximum output token limit for Gemini 3.7 Flash and Gemini models.
Variables ¶
var ( ModelsDevURL = ModelsDevDefaultURL ModelsDevHTTPClient = http.DefaultClient ModelsDevCachePath = func() (string, error) { home, err := os.UserHomeDir() if err != nil { return "", err } return filepath.Join(home, ".config", "ask", "cache", "models-dev.json"), nil } )
var ClaudeCodeEffortOptions = []string{"low", "medium", "high", "xhigh", "max"}
ClaudeCodeEffortOptions are the CLI's effort levels; ask's global picker offers the first three.
var ClaudeCodeModelOptions = CatalogModelIDs(ClaudeCodeProviderID)
ClaudeCodeModelOptions are the catalog ids the picker shows for Claude Code.
var GlobalEffortOptions = []string{"low", "medium", "high"}
GlobalEffortOptions are the standard reasoning effort levels.
var ListOpenRouterModels = func(ctx context.Context, pc config.ProviderConfig) ([]string, error) { metas, err := fetchOpenRouterModels(ctx, ResolveOpenRouterBaseURL(pc)) if err != nil { return nil, err } cacheOpenRouterMeta(metas) ids := make([]string, 0, len(metas)) for _, m := range metas { ids = append(ids, m.ID) } return ids, nil }
var ListVertexModels = func(ctx context.Context, pc config.ProviderConfig) ([]string, error) { client, err := VertexNewClient(ctx, pc) if err != nil { return nil, err } var models []string page, err := client.Models.List(ctx, nil) if err != nil { return nil, err } for _, m := range page.Items { name := m.Name name = strings.TrimPrefix(name, "publishers/google/models/") name = strings.TrimPrefix(name, "models/") if strings.Contains(strings.ToLower(name), "claude") || strings.Contains(strings.ToLower(name), "anthropic") { continue } if name != "" { models = append(models, name) } } return models, nil }
ListVertexModels queries the Vertex AI / Gemini API dynamically for available models.
var ModelMetaLookup = ModelMetaFor
ModelMetaLookup is the seam StepCostUSD reads through; tests swap it to stand in for the models.dev / live-listing layers.
var OpenRouterEffortOptions = GlobalEffortOptions
var OpenRouterModelBuilder = func(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error) { apiKey := ResolveOpenRouterAPIKey(pc) if apiKey == "" { return nil, MissingAPIKeyError(OpenRouterEnvAPIKey) } baseURL := ResolveOpenRouterBaseURL(pc) return NewOpenAICompatModel(OpenAICompatConfig{ ModelID: modelID, APIKey: apiKey, BaseURL: baseURL, Headers: openRouterHeaders(), EncodeReasoning: openRouterReasoningEncoder(baseURL), }), nil }
var OpenRouterModelOptions = CatalogModelIDs(OpenRouterProviderID)
var VertexCredentialsLoader = func(path string) (*auth.Credentials, error) { return credentials.NewCredentialsFromFile(credentials.ServiceAccount, path, &credentials.DetectOptions{ Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"}, }) }
VertexCredentialsLoader is the swappable loader for service account *auth.Credentials.
var VertexEffortOptions = GlobalEffortOptions
var VertexModel = func(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error) { cfg, err := vertexClientConfig(pc) if err != nil { return nil, err } return gemini.NewModel(ctx, modelID, cfg) }
VertexModel constructs a model.LLM backed by Vertex AI via ADK's gemini package. Swappable in tests.
var VertexModelOptions = FilterVertexModelOptions(CatalogModelIDs(VertexProviderID))
var VertexNewClient = func(ctx context.Context, pc config.ProviderConfig) (*genai.Client, error) { cfg, err := vertexClientConfig(pc) if err != nil { return nil, err } return genai.NewClient(ctx, cfg) }
VertexNewClient constructs a genai.Client configured for Vertex AI — the model listing needs the raw client. Swappable in tests.
var VertexPrepareCredentials = func(pc config.ProviderConfig) (*auth.Credentials, error) { saKeyPath := VertexResolveServiceAccountKey(pc) if saKeyPath == "" { return nil, nil } if _, err := os.Stat(saKeyPath); err != nil { return nil, fmt.Errorf("vertex: read service account key %s: %w", saKeyPath, err) } return VertexCredentialsLoader(saKeyPath) }
VertexPrepareCredentials resolves the SA key path, validates it is readable, and loads *auth.Credentials; nil credentials mean ADC.
Functions ¶
func CanonicalClaudeCodeModelID ¶
CanonicalClaudeCodeModelID passes through a known alias or full model name; only an empty id falls back. The CLI accepts aliases ("opus") and full names ("claude-opus-5") alike, so ask does not second-guess an unrecognized id.
func CanonicalOpenRouterModelID ¶
CanonicalOpenRouterModelID normalizes the model ID and falls back to fallback if the model ID is empty.
func CanonicalVertexModelID ¶
CanonicalVertexModelID normalizes the model ID and falls back to fallback (or VertexDefaultModel) if the model ID is empty or represents a legacy/unrecognized model from another provider.
func CatalogClampEffort ¶
CatalogClampEffort clamps a picked effort onto what the model actually offers.
func CatalogContextWindow ¶
CatalogContextWindow returns the model's context window, or fallback.
func CatalogDefaultMaxTokens ¶
CatalogDefaultMaxTokens returns the model's published default max-output-tokens budget, or fallback.
func CatalogModelIDs ¶
CatalogModelIDs returns the provider's model ids in catalog order.
func CatalogResolveEffort ¶
CatalogResolveEffort maps global abstract effort levels onto concrete ReasoningLevels.
func CatalogSupportsImages ¶
CatalogSupportsImages reports image-attachment capability, defaulting to fallback.
func CheapestModel ¶
CheapestModel picks the provider's cheapest model: the one it names through CheapModeler, else the lowest list price (input plus output USD per 1M) among its catalog options, skipping deprecated ones; with no known price it falls back to the provider's default model.
func ClaudeCodeResolveBinary ¶
func ClaudeCodeResolveBinary(pc config.ProviderConfig) string
ClaudeCodeResolveBinary: config value wins, then ASK_CLAUDE_BIN, then the default "claude".
func DefaultProviderID ¶
func DefaultProviderID() string
DefaultProviderID is the id of the first registered provider — what an empty config resolves to.
func FilterVertexModelOptions ¶
FilterVertexModelOptions strips Claude / Anthropic ids from the Vertex model list.
func LoadModelsDev ¶
LoadModelsDev makes models.dev data available to ModelsDevMeta: memory first, then a disk cache younger than ModelsDevCacheTTL, then the network (refreshing the disk cache). A failed fetch falls back to a stale disk cache rather than returning nothing.
func MissingAPIKeyError ¶
MissingAPIKeyError returns a descriptive error when an API key is missing.
func ModelsDevLoaded ¶
func ModelsDevLoaded() bool
func NewOpenAICompatModel ¶
func NewOpenAICompatModel(cfg OpenAICompatConfig) model.LLM
NewOpenAICompatModel builds an ADK model.LLM backed by the official OpenAI Go SDK, pointed at cfg.BaseURL. The SDK owns the wire protocol (streaming aggregation, tool-call IDs, usage, vision); this type only translates between genai and OpenAI types.
func NormalizeModelID ¶
NormalizeModelID trims provider prefixes ("vertex/", "publishers/google/models/", "models/") to ensure model identifiers match registered catalog IDs.
func OpenRouterProviderOptions ¶
func OpenRouterProviderOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
OpenRouterProviderOptions carries ask's effort intent through genai's ThinkingConfig and sets the output-token budget. The effort is passed verbatim; the per-model capability gate and clamp live in the reasoning encoder, which has OpenRouter's live model metadata.
func ProviderConfigured ¶
ProviderConfigured reports whether provider id can run with cfg — false for an unknown id or one missing its credentials.
func Register ¶
func Register(p Provider)
Register adds p to the registry, replacing an earlier registration with the same id in place. A malformed provider — empty id, or a setting whose key is empty, duplicated, or reserved — panics: that is a programming error, not a runtime condition.
func ResolveModelID ¶
ResolveModelID picks the model a session on p should run: the explicit id when one was given, else the configured one, else the provider default — canonicalized either way.
func ResolveOpenRouterAPIKey ¶
func ResolveOpenRouterAPIKey(pc config.ProviderConfig) string
ResolveOpenRouterAPIKey: config value wins, then OPENROUTER_API_KEY.
func ResolveOpenRouterBaseURL ¶
func ResolveOpenRouterBaseURL(pc config.ProviderConfig) string
ResolveOpenRouterBaseURL: config value wins, then the default endpoint.
func SaveSettings ¶
func SaveSettings(cfg *config.Config, id string, s ProviderSettings)
SaveSettings writes s into cfg under provider id, keeping the provider's declared fields untouched.
func SettingValue ¶
func SettingValue(pc config.ProviderConfig, f SettingField) string
SettingValue resolves f against pc: the stored value, else the env fallback, else the default.
func SteeringPrompt ¶
func SteeringPrompt(opts SteeringOptions) string
func StepCostUSD ¶
func StepCostUSD(providerID, modelID string, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens int) (float64, bool)
StepCostUSD prices one call's token usage against the model's per-1M rates: cache reads at the cached-input rate, cache writes at the cache-write rate (crush's formula). ok=false when no price is known.
func ValidateVertexLocation ¶
ValidateVertexLocation accepts the literal "global" or a region id in the canonical GCP shape ("us-central1", "europe-west4").
func ValidateVertexProject ¶
ValidateVertexProject screens a project id draft. Empty is invalid: the session would fail at start with "project is required", so the field visibly requires a value instead.
func ValidateVertexServiceAccountKey ¶
ValidateVertexServiceAccountKey accepts an empty string (ADC) or the path of a readable file, tilde-expanded.
func VertexProviderOptions ¶
func VertexProviderOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
VertexProviderOptions translates ask's effort picker onto Gemini's thinking controls and configures max tokens.
func VertexResolveLocation ¶
func VertexResolveLocation(pc config.ProviderConfig) string
VertexResolveLocation: config value wins, then the default location.
func VertexResolveProject ¶
func VertexResolveProject(pc config.ProviderConfig) string
VertexResolveProject: config value wins, then GOOGLE_CLOUD_PROJECT.
func VertexResolveServiceAccountKey ¶
func VertexResolveServiceAccountKey(pc config.ProviderConfig) string
VertexResolveServiceAccountKey: config value wins, then GOOGLE_APPLICATION_CREDENTIALS; "" means ADC. The path is tilde-expanded so a saved "~/keys/vertex.json" works.
func WithObservedToolSink ¶
func WithObservedToolSink(ctx context.Context, sink ObservedToolSink) context.Context
WithObservedToolSink attaches a sink for natively-executed tool activity.
func WithWebSearchAvailable ¶
WithWebSearchAvailable records whether ask's own web_search tool can run (i.e. a Brave API key is configured). ModelBuilder sets this from config so a provider's BuildModel can decide whether to enable a native fallback.
Types ¶
type CheapModeler ¶
type CheapModeler interface {
CheapModel() string
}
CheapModeler is the optional capability of naming the provider's cheapest model outright. CheapestModel consults it before list prices, so a subscription provider whose catalog carries no USD rates (Claude Code) still routes background calls like memory extraction to its smallest model instead of its default.
type ClaudeCode ¶
type ClaudeCode struct{}
ClaudeCode is the provider that forks the `claude` CLI in headless stream-json mode and drives it with ask's own tools, prompt, and modals. Claude Code never runs a tool itself: `--tools ""` strips every built-in and ask registers as an in-process (sdk-type) MCP server over the child's stdio, so the ADK loop executes every tool exactly as it does for Vertex or OpenRouter. Auth is whatever the `claude` binary is logged in as (Claude subscription or ANTHROPIC_API_KEY in the environment); ask never stores a credential.
func (ClaudeCode) BuildModel ¶
func (ClaudeCode) BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
BuildModel returns the lock-step adapter. It does not spawn the child — the process starts on the first GenerateContent — but it fails fast if the binary cannot be found, so a misconfigured session errors at session start.
func (ClaudeCode) CallOptions ¶
func (ClaudeCode) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
CallOptions rides ask's effort onto a ThinkingConfig; the adapter reads the resulting ThinkingLevel back into a --effort flag when it spawns the child.
func (ClaudeCode) CanonicalModelID ¶
func (ClaudeCode) CanonicalModelID(modelID, fallback string) string
func (ClaudeCode) CheapModel ¶
func (ClaudeCode) CheapModel() string
CheapModel is the smallest alias the CLI accepts. The plan bills by quota, not USD, so the catalog has no prices for CheapestModel to rank.
func (ClaudeCode) Configured ¶
func (ClaudeCode) Configured(pc config.ProviderConfig) bool
Configured reports whether the claude binary resolves. Auth lives in the binary, so there is no credential to check.
func (ClaudeCode) ContextWindow ¶
func (ClaudeCode) ContextWindow(modelID string) int64
func (ClaudeCode) DefaultModel ¶
func (ClaudeCode) DefaultModel() string
func (ClaudeCode) DisplayName ¶
func (ClaudeCode) DisplayName() string
func (ClaudeCode) EffortOptions ¶
func (ClaudeCode) EffortOptions() []string
func (ClaudeCode) HasNativeWebSearch ¶
func (ClaudeCode) HasNativeWebSearch() bool
HasNativeWebSearch reports that Claude Code can run web search in its own runtime. ask uses this as the fallback when no Brave key is configured; see NativeWebSearchProvider.
func (ClaudeCode) ID ¶
func (ClaudeCode) ID() string
func (ClaudeCode) ListModels ¶
func (ClaudeCode) ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
ListModels returns the account's live model list by spawning a short-lived child, reading the initialize control response's `models` array, and killing it — the same handshake a session does, without a turn. Falls back to the static catalog if the probe fails so the picker is never empty.
func (ClaudeCode) MaxOutputTokens ¶
func (ClaudeCode) MaxOutputTokens(modelID string) int64
func (ClaudeCode) ModelOptions ¶
func (ClaudeCode) ModelOptions() []string
func (ClaudeCode) Settings ¶
func (ClaudeCode) Settings() []SettingField
func (ClaudeCode) SupportsImages ¶
func (ClaudeCode) SupportsImages(modelID string) bool
type ClaudeExtraUsage ¶
type ClaudeExtraUsage struct {
IsEnabled bool
MonthlyLimit float64
UsedCredits float64
HasLimit bool // MonthlyLimit was present (non-null) in the response
}
ClaudeExtraUsage is the pay-as-you-go dollar budget attached to a paid plan ("extra usage"). When enabled with a monthly limit it is the account's dollar ceiling — the answer to "budget controlled by dollars".
type ClaudeUsage ¶
type ClaudeUsage struct {
FiveHour *ClaudeUsageWindow
SevenDay *ClaudeUsageWindow
SevenDayOpus *ClaudeUsageWindow
SevenDaySonnet *ClaudeUsageWindow
Extra ClaudeExtraUsage
FetchedAt time.Time
}
ClaudeUsage is the parsed /api/oauth/usage response. Each window pointer is nil when the endpoint returned null for that bucket (e.g. seven_day_opus for a plan without Opus weekly tracking).
func CachedClaudeUsage ¶
func CachedClaudeUsage() (ClaudeUsage, bool)
CachedClaudeUsage returns the last fetched snapshot without touching the network. ok is false until a fetch has succeeded at least once. This is the render-path accessor: the TUI reads it every frame while a background refresh keeps it current.
func ClaudeCodeUsage ¶
func ClaudeCodeUsage(ctx context.Context) (ClaudeUsage, error)
ClaudeCodeUsage returns the current usage snapshot, refreshing from the network when the cached one is stale. Concurrent callers serialize on the cache mutex, so a burst of tabs refreshing at once produces one network call. On any failure the last good snapshot is returned alongside the error (the caller keeps showing it); with no snapshot yet, a zero value + error.
type ClaudeUsageWindow ¶
type ClaudeUsageWindow struct {
Utilization float64
ResetsAt time.Time // zero when the endpoint omitted resets_at
// Dollar view of the window; HasDollars is set only when the endpoint
// populated limit_dollars (i.e. the account is billed by dollars).
HasDollars bool
UsedDollars float64
LimitDollars float64
RemainingDollars float64
}
ClaudeUsageWindow is one rate-limit bucket: how much of it is used and when it resets. Utilization is a percentage in [0, 100]. On dollar-budgeted accounts (enterprise / pay-as-you-go) the same window also carries a dollar view — used/limit/remaining — which is nil on plain subscription accounts.
type ModelInfo ¶
type ModelInfo struct {
ID string
Name string
ContextWindow int64
DefaultMaxTokens int64
SupportsImages bool
ReasoningLevels []string
// Pricing is the published list price (USD per 1M tokens) so the cost
// meter and the picker work offline; nil when unknown.
Pricing *ModelPricing
}
ModelInfo describes model metadata without external catalog dependencies.
type ModelLister ¶
type ModelLister interface {
ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
}
ModelLister is the optional capability of enumerating the models a provider currently serves. A provider without it is listed from the static catalog only.
type ModelMeta ¶
type ModelMeta struct {
ID string
Name string
Description string
ContextWindow int64
MaxOutputTokens int64
// Pricing is USD per 1M tokens; nil means no price is known.
Pricing *ModelPricing
InputModalities []string
Reasoning bool
ReasoningLevels []string
KnowledgeCutoff string
ReleaseDate string
// Status is "" (current), "beta", or "deprecated".
Status string
}
ModelMeta is the merged, display-ready description of one model: the static catalog seeds it, models.dev fills what the provider's own API does not publish, and a provider's live listing (OpenRouter) wins over both.
func ModelMetaFor ¶
ModelMetaFor layers every known source for providerID/modelID. It never touches the network — callers load models.dev and the provider listings ahead of time — so a miss on every layer reports ok=false.
Precedence, for every provider:
- Description: models.dev first; the provider's own text is only the fallback when models.dev has none (OpenRouter truncates its text server-side, Vertex publishes none at all).
- Everything else (limits, pricing, modalities, effort levels, dates): the provider's live listing wins over models.dev, which wins over the static catalog — the provider is authoritative for what it serves and bills.
A new provider's native layer goes through mergeProviderNative so it inherits both rules.
func ModelsDevMeta ¶
ModelsDevMeta is an in-memory lookup; it reports ok=false until LoadModelsDev has succeeded, for unmapped providers, and for unknown ids.
type ModelPricing ¶
type NativeWebSearchProvider ¶
type NativeWebSearchProvider interface {
HasNativeWebSearch() bool
}
NativeWebSearchProvider is the optional capability of running web search in the provider's own runtime, used as a fallback when ask's Brave-backed web_search tool is unavailable (no API key). When HasNativeWebSearch reports true and no Brave key is configured, the session omits ask's web_search tool and the provider enables its native one (gated by the WebSearchAvailable context flag ModelBuilder sets, read in BuildModel). Claude Code implements this; Vertex and OpenRouter do not.
type ObservedToolSink ¶
type ObservedToolSink interface {
// ObservedToolCall reports a native tool call as it begins.
ObservedToolCall(id, name string, input map[string]any)
// ObservedToolResult reports the native call's result. id matches the
// call's id; name is the tool name captured at the call.
ObservedToolResult(id, name, output string, isError bool)
}
ObservedToolSink receives tool activity that the provider ran natively (not via ask's MCP bridge). ask injects one at model-build time through the build context; a nil sink (any non-interactive build) simply drops the events.
type OpenAICompatConfig ¶
type OpenAICompatConfig struct {
ModelID string
APIKey string
BaseURL string
Headers map[string]string
// EncodeReasoning injects a requested effort ("low"/"medium"/"high") into
// the request for the given model. Providers differ in wire shape and in
// which models support reasoning, so the provider supplies it; nil means the
// endpoint gets no reasoning controls.
EncodeReasoning func(params *openai.ChatCompletionNewParams, modelID, effort string)
}
OpenAICompatConfig configures a shared OpenAI-compatible model.LLM. Any provider that speaks the OpenAI Chat Completions protocol (OpenRouter today, a native OpenAI / DeepSeek / Kimi endpoint tomorrow) is a thin wrapper over this: a base URL, a key, optional headers, and how it encodes reasoning.
type OpenRouter ¶
type OpenRouter struct{}
OpenRouter is the OpenRouter provider: any model behind the OpenAI Chat Completions protocol at openrouter.ai, keyed by an API key.
func (OpenRouter) BuildModel ¶
func (OpenRouter) BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
func (OpenRouter) CallOptions ¶
func (OpenRouter) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
func (OpenRouter) CanonicalModelID ¶
func (OpenRouter) CanonicalModelID(modelID, fallback string) string
func (OpenRouter) Configured ¶
func (OpenRouter) Configured(pc config.ProviderConfig) bool
func (OpenRouter) ContextWindow ¶
func (OpenRouter) ContextWindow(modelID string) int64
func (OpenRouter) DefaultModel ¶
func (OpenRouter) DefaultModel() string
func (OpenRouter) DisplayName ¶
func (OpenRouter) DisplayName() string
func (OpenRouter) EffortOptions ¶
func (OpenRouter) EffortOptions() []string
func (OpenRouter) ID ¶
func (OpenRouter) ID() string
func (OpenRouter) ListModels ¶
func (OpenRouter) ListModels(ctx context.Context, pc config.ProviderConfig) ([]string, error)
func (OpenRouter) MaxOutputTokens ¶
func (OpenRouter) MaxOutputTokens(modelID string) int64
func (OpenRouter) ModelOptions ¶
func (OpenRouter) ModelOptions() []string
func (OpenRouter) Settings ¶
func (OpenRouter) Settings() []SettingField
func (OpenRouter) SupportsImages ¶
func (OpenRouter) SupportsImages(modelID string) bool
type Provider ¶
type Provider interface {
// ID is the short stable identifier stored in config ("vertex").
ID() string
// DisplayName is the human-readable name used in UI copy and errors.
DisplayName() string
// DefaultModel is the model used when the user has not picked one.
DefaultModel() string
// ModelOptions are the static catalog ids the picker shows before a
// live listing lands.
ModelOptions() []string
// EffortOptions are the /effort choices; empty hides /effort.
EffortOptions() []string
// Settings declares the provider's configuration fields. The /config
// screen renders them, the model picker's key prompt asks for the
// Secret one, and Configured is judged against them.
Settings() []SettingField
// Configured reports whether pc (with the fields' env fallbacks)
// carries the credentials the provider needs. Never touches the
// network.
Configured(pc config.ProviderConfig) bool
// BuildModel constructs the ADK LLM for modelID from pc.
BuildModel(ctx context.Context, pc config.ProviderConfig, modelID string) (model.LLM, error)
// CanonicalModelID normalizes a user- or config-supplied model id. An
// empty or foreign id resolves to fallback; an empty fallback means
// DefaultModel.
CanonicalModelID(modelID, fallback string) string
// CallOptions maps ask's effort onto the wire request for modelID.
CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
// SupportsImages reports whether modelID accepts image attachments.
SupportsImages(modelID string) bool
// ContextWindow is modelID's input window in tokens.
ContextWindow(modelID string) int64
// MaxOutputTokens is modelID's output budget in tokens.
MaxOutputTokens(modelID string) int64
}
Provider is the contract every in-process LLM provider satisfies. The TUI, the headless engine, the /config screen, and the model picker are written against this interface and the registry below, so adding a provider is implementing it and adding it to builtin. Every method is required; optional capabilities are separate interfaces (ModelLister) that call sites discover by type assertion.
type ProviderSettings ¶
type ProviderSettings struct {
Model string `json:"model"`
Effort string `json:"effort"`
SlashCommands []config.ProviderSlashEntry `json:"slashCommands,omitempty"`
}
ProviderSettings is the per-provider slice of configuration the TUI reads and writes: the picked model, the reasoning effort (global — every provider shares Config.Effort), and the discovered slash commands.
func LoadSettings ¶
func LoadSettings(cfg config.Config, id string) ProviderSettings
LoadSettings reads provider id's settings out of cfg.
type SettingField ¶
type SettingField struct {
// Key is the field's key in config.ProviderConfig.Fields.
Key string
// Title is the row label.
Title string
// Hint is shown while editing the field.
Hint string
// Secret masks the value in the UI and marks the field as the
// credential the model picker prompts for.
Secret bool
// EnvKey is the environment variable consulted when the field is
// unset.
EnvKey string
// Default is the value used when neither config nor env sets one.
Default string
// Validate rejects a draft before it is saved; nil accepts anything.
Validate func(string) error
}
SettingField is one configuration field a provider declares. The /config → <provider> screen is rendered from these, one row per field.
func FieldByKey ¶
func FieldByKey(p Provider, key string) (SettingField, bool)
FieldByKey returns p's setting with the given key.
func SecretField ¶
func SecretField(p Provider) (SettingField, bool)
SecretField returns p's credential field, if it declares one.
type SteeringOptions ¶
type Vertex ¶
type Vertex struct{}
Vertex is the Vertex AI provider: Gemini through ADK's gemini model, authenticated with Google Cloud ADC or an explicit service-account key.
func (Vertex) BuildModel ¶
func (Vertex) CallOptions ¶
func (Vertex) CallOptions(modelID, effort string) (*genai.GenerateContentConfig, *float64)
func (Vertex) CanonicalModelID ¶
func (Vertex) Configured ¶
func (Vertex) Configured(pc config.ProviderConfig) bool
func (Vertex) ContextWindow ¶
func (Vertex) DefaultModel ¶
func (Vertex) DisplayName ¶
func (Vertex) EffortOptions ¶
func (Vertex) ListModels ¶
func (Vertex) MaxOutputTokens ¶
func (Vertex) ModelOptions ¶
func (Vertex) Settings ¶
func (Vertex) Settings() []SettingField