Documentation
¶
Overview ¶
Package models is the adapter layer between core-agent's configuration and concrete LLM backends. The Provider interface keeps the rest of the codebase free of provider-specific imports so additional backends plug in behind the same contract.
Built-in providers:
- "gemini" / "vertex" — google.golang.org/adk/model/gemini
- "anthropic" — Claude via github.com/anthropics/anthropic-sdk-go
Each backend's package init() calls Register so importing the subpackage is enough to make the provider available.
Index ¶
- Variables
- func AutoDetectProvider() string
- func BuiltinsSuppressed(ctx context.Context) bool
- func PromptCacheSuppressed(ctx context.Context) bool
- func Register(name string, c Constructor)
- func ResolveMCPSmallModel(p Provider, mcpSpecific, agenticGeneral string) string
- func ResolveSmallModel(p Provider, override string) string
- func WithoutBuiltins(ctx context.Context) context.Context
- func WithoutPromptCache(ctx context.Context) context.Context
- type AnthropicAPI
- type AnthropicVertex
- type Constructor
- type GeminiAPI
- type GeminiVertex
- type Provider
- type ProviderOptions
- type SmallModelDefaulter
Constants ¶
This section is empty.
Variables ¶
var ErrEmptyResponse = errors.New("model returned no usable content")
ErrEmptyResponse is the provider-agnostic sentinel for "the call succeeded and the model produced nothing usable". Provider adapters that synthesize such an error wrap this so callers can recognize the condition without importing the adapter — gemini.ErrEmptyResponse does, and anything added later should.
It exists because "no content" needs opposite handling in the two places it shows up. Inside the agentic loop it is a fault: a turn that produces nothing leaves the loop with no next action and the session goes idle forever, so the Gemini adapter retries it once and then surfaces it as an error (#220). For a one-shot side question (/btw) the same condition is simply the answer — the model declined, and the operator should be told that rather than shown a stack of provider prose. AskSideQuestion converts it; the loop doesn't.
Match with errors.Is. Never compare messages: the adapters wrap this with their own diagnostic text, which is the part that changes.
Functions ¶
func AutoDetectProvider ¶
func AutoDetectProvider() string
AutoDetectProvider walks the env to pick a default backend. Exported alias of autoDetectProvider for callers that need the provider name BEFORE constructing a Provider (e.g. cmd/core-agent's --task flag resolution needs the provider name to pick a model for a given tier without paying for full provider construction).
Returns "" when no env-based default is detectable. Returns the same canonical name strings as Resolve would route to.
func BuiltinsSuppressed ¶ added in v2.9.0
BuiltinsSuppressed reports whether WithoutBuiltins was applied to ctx. Backends consult it per request, since one model.LLM serves both the agentic loop and the one-shot side calls.
func PromptCacheSuppressed ¶ added in v2.9.0
PromptCacheSuppressed reports whether WithoutPromptCache was applied to ctx. Backends consult it per request, since one model.LLM serves both the agentic loop and the one-shot side calls.
func Register ¶
func Register(name string, c Constructor)
Register installs a Constructor under its provider name. Idiomatically called from package init() in each backend implementation.
func ResolveMCPSmallModel ¶
ResolveMCPSmallModel is ResolveSmallModel's MCP-wrap sibling — layers a per-surface override (mcp.json's agentic_wrap_model or --mcp-agentic-wrap-model) in front of the general chain so operators can pick a different tier for MCP responses than for built-in-tool wrappers. Rationale: MCP responses can be shaped differently enough (structured GKE tables vs. arbitrary fetch_url bodies) that one tier works well for one surface but not the other.
Precedence: mcpSpecific → agenticGeneral → provider default → "".
func ResolveSmallModel ¶
ResolveSmallModel picks the model ID that agentic subtasks should run on. Operator override (a non-empty explicit --agentic-small-model value) always wins. Otherwise: if p implements SmallModelDefaulter, return whatever it reports; if not, return "" — agentic wrappers treat empty as "inherit the parent's model."
func WithoutBuiltins ¶ added in v2.9.0
WithoutBuiltins marks ctx as a request that must go to the model with EXACTLY the tools the caller put on it: no provider-injected server-side built-ins (Gemini's google_search / url_context / code_execution) and no context-cache reference stamped on top.
The /btw side question is the motivating caller. It is documented as tool-less — the operator asks about what already happened, and the answer should come from the transcript, not from a web search the model decided to run. Building the request with a nil Config isn't enough to get that: the Gemini wrapper creates the Config itself and appends its built-ins, and on a Vertex cached turn it also stamps CachedContent onto a request that already carries the full history.
This is the per-call sibling of the model-level builtinsLLM.WithoutBuiltins() unwrap that RunSubtask uses. The unwrap is the right tool when a caller drives the inner model for a whole subtask; the context marker is the right tool for one call on the SHARED model, because it keeps the wrapper's other behavior — notably the empty-response retry — in place. For a feature whose reported symptom is blank answers, dropping that retry to get tool-lessness would trade one bug for another.
A hint, not a guarantee: providers with no built-ins to inject (Anthropic today) ignore it, and it can only take tools away.
func WithoutPromptCache ¶ added in v2.9.0
WithoutPromptCache marks ctx as a one-shot request: a call whose prompt prefix is not expected to recur, so a provider that would normally write a prompt-cache entry should skip it.
Prompt caching trades a write premium now (Anthropic bills 1.25x on the tokens it stores) against cheap reads later (~0.1x). The trade pays off from the second request that carries the same prefix. Some calls are structurally never that second request — core-agent's summarizer and checkpointer send their own system instruction and no tools, the /btw side question sends neither, and a tight-budget subtask runs in a session whose ID never recurs. Their prefixes diverge from the agentic loop's at the first block, so the byte-exact match can't hit even where the history is identical, and writing an entry is a pure 25% surcharge on a call that is already expensive because it re-sends the whole conversation.
This is a hint, not a guarantee: providers without prompt caching (Gemini today) ignore it, and it can only turn caching OFF — a provider whose caching is disabled by config or CLI stays disabled. It lives here rather than on a provider-specific option so callers in pkg/agent can set it without importing a backend.
Types ¶
type AnthropicAPI ¶ added in v2.8.0
type AnthropicAPI struct {
// APIKey overrides ANTHROPIC_API_KEY. Empty falls back to the
// environment, same as the config path.
APIKey string
}
AnthropicAPI selects the Anthropic API backend (api-key auth).
type AnthropicVertex ¶ added in v2.8.0
type AnthropicVertex struct {
// Project and Region identify the Model Garden deployment. Empty
// values fall back to the same env chain as the config path:
// ANTHROPIC_VERTEX_PROJECT_ID then GOOGLE_CLOUD_PROJECT for the
// project; CLOUD_ML_REGION then GOOGLE_CLOUD_LOCATION then the
// "us-east5" default for the region.
Project string
Region string
}
AnthropicVertex selects Anthropic models served through Vertex AI Model Garden (ADC auth).
type Constructor ¶
Constructor builds a Provider from validated config. Tests register alternates via Register so resolution stays decoupled from the imports of any single backend.
type GeminiAPI ¶ added in v2.8.0
type GeminiAPI struct {
// APIKey overrides GOOGLE_API_KEY / GEMINI_API_KEY. Empty falls
// back to the environment, same as the config path.
APIKey string
}
GeminiAPI selects the Gemini API backend (api-key auth). The model ID is NOT part of routing — pass it to Provider.Model(ctx, name) afterwards, exactly as with Resolve.
type GeminiVertex ¶ added in v2.8.0
type GeminiVertex struct {
// Project and Location identify the Vertex deployment. Empty
// values fall back to GOOGLE_CLOUD_PROJECT / GOOGLE_CLOUD_LOCATION,
// same as the config path.
Project string
Location string
}
GeminiVertex selects Gemini via Vertex AI (ADC auth).
type Provider ¶
type Provider interface {
// Name reports the provider identity ("gemini", "vertex", "anthropic").
// Used for telemetry and diagnostic messages.
Name() string
// Model returns a usable model.LLM for the given model ID. The same
// Provider may be asked for several models over its lifetime.
Model(ctx context.Context, modelID string) (model.LLM, error)
}
Provider constructs concrete model.LLM instances on demand. A Provider is bound to one credential source (API key, Vertex project, etc.) at construction time; callers ask for specific models by ID through Model.
func New ¶ added in v2.8.0
func New(opts ProviderOptions) (Provider, error)
New constructs a Provider from per-provider options, routing through the same registry as Resolve — remember to blank-import the backend package (e.g. pkg/models/gemini) exactly as with Resolve. For auto-detection from the environment, use Resolve with a default config (or AutoDetectProvider for the name alone); New is deliberately explicit about the backend.
type ProviderOptions ¶ added in v2.8.0
type ProviderOptions interface {
// contains filtered or unexported methods
}
ProviderOptions is the programmatic counterpart of the config file's `model` block (#492): before it, the only way through the provider registry — Resolve — was to fabricate the on-disk *config.Config struct, which coupled every programmatic embedder to the file schema. Each per-provider struct below carries exactly the fields its backend routes on; New translates it through the same registry Resolve uses, so both paths construct identical providers. The MODEL ID is deliberately not routing state: pass it to Provider.Model(ctx, name) on the returned provider, exactly as with Resolve.
Sealed (the toModelConfig method is unexported) so the set of option shapes evolves with the registry rather than by third-party implementation. Backends with richer knobs (thinking budgets, server-side tools, cache flags) keep exposing them on their own constructors and functional options — gemini.NewAPIKey / gemini.NewVertex / anthropic.New / anthropic.NewVertex remain the full-control path; these structs cover the routing layer's job: pick a backend and point it at credentials. Pass structs by value (a nil *GeminiAPI etc. would panic in the value-receiver call).
Resolve remains the config-file adapter, unchanged.
type SmallModelDefaulter ¶
type SmallModelDefaulter interface {
DefaultSmallModel() string
}
SmallModelDefaulter is an optional Provider extension. A Provider that implements this declares its preferred cheap-tier model — used by core-agent as the default for --agentic-small-model when the operator hasn't pinned one explicitly. Providers without a cheap-tier concept (echo, scripted) simply don't implement this; ResolveSmallModel returns "" for them and callers fall back to inheriting the parent's model.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package anthropic implements models.Provider for Anthropic / Claude.
|
Package anthropic implements models.Provider for Anthropic / Claude. |
|
Package gemini implements models.Provider for the Gemini family, covering both the public Gemini API (API-key auth) and Vertex AI (Application Default Credentials + GCP project).
|
Package gemini implements models.Provider for the Gemini family, covering both the public Gemini API (API-key auth) and Vertex AI (Application Default Credentials + GCP project). |
|
Package mock ships two credential-free LLM providers and a recording wrapper that pair for offline testing of agent flows:
|
Package mock ships two credential-free LLM providers and a recording wrapper that pair for offline testing of agent flows: |