Documentation
¶
Overview ¶
Package metaagent provides a generic framework for building AI agents.
The framework is fully generic over three type parameters:
- Req: The request type (must implement promptbuilder.Bindable)
- Resp: The structured response type returned by the agent
- CB: The callbacks type providing tool implementations
This design allows agents to be composed with any combination of tools from the toolcall package (worktree tools, finding tools, custom tools).
Model Support ¶
New is the compatibility constructor. Its model parameter determines which executor path is used:
- Models starting with "gemini-" use Google's Generative AI SDK (native)
- Models starting with "claude-" use the configured legacy Claude backend
- Models in "publisher/model" format use Vertex AI's OpenAI-compatible Chat Completions endpoint, except ids whose model.Info sets ExplicitRouteOnly (such as "xai/*"), which New rejects
NewRouted is the recommended constructor for new agents and migrations. NewVertexRouter configures declared Vertex routes for one project and region. NewRouterWithAdapters registers typed adapters for other providers or custom settings in one call. An application constructs a modelrouter.Registry, registers typed adapters by provider in the matching protocol registry, and selects a provider and logical model. The resolved Plan remains authoritative for the exact provider model ID, effective capabilities, and attribution; credentials and SDK clients stay captured by adapters outside the Plan. NewBedrockOpenAIChatCompletionsAdapter binds Chat Completions to the regional Bedrock Runtime endpoint through the shared SigV4 transport. Bare "gpt-*" logical IDs require an explicit route; New does not infer a provider for them. NewBedrockRuntimeAnthropicMessagesAdapter binds Anthropic Messages through the same Runtime transport. NewBedrockAnthropicMessagesAdapter continues to use Mantle; choosing Runtime requires explicitly registering the new adapter. Routers and route resolutions are safe for concurrent use when their registered adapters are safe for concurrent use. System One routes use the same provider/model selection and backend registration. Their callers use RouteResolution.BindSystemOne to obtain a typed question service rather than NewRouted, which constructs a conversational agent. One provider backend can register chat and System One adapters, and a route is available only when its provider supplies both the selected model and protocol.
Usage ¶
Define your callback type by composing tool callbacks:
type MyCallbacks = toolcall.FindingTools[toolcall.WorktreeTools[toolcall.EmptyTools]]
Create the corresponding tool provider:
tools := toolcall.NewFindingToolsProvider[*Result, toolcall.WorktreeTools[toolcall.EmptyTools]](
toolcall.NewWorktreeToolsProvider[*Result, toolcall.EmptyTools](
toolcall.NewEmptyToolsProvider[*Result](),
),
)
For configuration-driven provider/model switching, construct a Runtime once at startup from an application catalog and named Backend configurations. Pass a Target to agent factories and use NewWithTarget. The runtime shares routers by backend and region and reads no provider-selection environment variables. Existing applications can continue using explicit Router values.
Construct the router once at application startup. For Vertex AI, pass exact application-owned route declarations to NewVertexRouter:
router, err := metaagent.NewVertexRouter(projectID, region, declarations...)
if err != nil {
return err
}
Configure the agent and select one declared provider/model pair:
config := metaagent.Config[*Result, MyCallbacks]{
SystemInstructions: systemPrompt,
UserPrompt: userPrompt,
Tools: tools,
}
agent, err := metaagent.NewRouted[*Request, *Result, MyCallbacks](ctx, router, selection, config)
result, err := agent.Execute(ctx, request, callbacks)
The agent uses the submit_result tool to return structured results. The Resp type's JSON tags define the schema for the tool's payload.
Suspend/Resume (ask-a-friend) ¶
Setting Config.SuspendToolName advertises a held-out ask-a-friend tool; when the model calls it, Execute returns a *checkpoint.Suspension instead of a Resp, and the paused conversation is later continued through the opt-in Resumer capability (obtained via AsResumer). Only the Claude backend supports this today — the Gemini and OpenAI-compatible backends reject a set SuspendToolName at construction until their executors grow suspend support. See the suspend package for the park/wake orchestration around it.
Continuing past the turn budget ¶
A Claude-backed run that spends its whole MaxTurns returns an *executor.MaxTurnsError whose Continuation is the conversation so far. The opt-in Continuer capability (obtained via AsContinuer) picks that conversation up on an agent built from the same Config with a larger MaxTurns, rather than re-running it from the first turn. The larger budget counts the whole conversation, so a continued run spends no more turns than one run at that budget would.
Index ¶
- Variables
- type AdapterRegistrations
- type AdapterRegistries
- type Agent
- func New[Req promptbuilder.Bindable, Resp, CB any](ctx context.Context, projectID, region, modelName string, ...) (Agent[Req, Resp, CB], error)
- func NewOpenAICompatible[Req promptbuilder.Bindable, Resp, CB any](provider OpenAICompatibleProvider, model string, config Config[Resp, CB]) (Agent[Req, Resp, CB], error)
- func NewRouted[Req promptbuilder.Bindable, Resp, CB any](ctx context.Context, router *Router, selection modelrouter.Selection, ...) (Agent[Req, Resp, CB], error)
- func NewWithTarget[Req promptbuilder.Bindable, Resp, CB any](ctx context.Context, target Target, config Config[Resp, CB]) (Agent[Req, Resp, CB], error)
- type AnthropicMessagesAdapter
- func NewAnthropicDirectMessagesAdapter(cfg anthropicauth.Config) (AnthropicMessagesAdapter, error)
- func NewBedrockAnthropicMessagesAdapter(cfg awsauth.Config) (AnthropicMessagesAdapter, error)
- func NewBedrockRuntimeAnthropicMessagesAdapter(cfg awsauth.Config) (AnthropicMessagesAdapter, error)
- func NewVertexAnthropicMessagesAdapter(projectID, region string) (AnthropicMessagesAdapter, error)
- type AnthropicMessagesAdapterRegistry
- type AnthropicMessagesBinding
- type AnthropicMessagesRegistration
- type Backend
- func AnthropicBackend(name string, cfg anthropicauth.Config) Backend
- func BedrockBackend(name string, cfg awsauth.Config, options ...BackendOption) Backend
- func NewAdapterBackend(name string, provider modelrouter.Provider, ...) Backend
- func VertexBackend(name string, cfg VertexConfig, options ...BackendOption) Backend
- type BackendOption
- type Config
- type Continuer
- type GoogleGenAIAdapter
- type GoogleGenAIAdapterRegistry
- type GoogleGenAIBinding
- type GoogleGenAIRegistration
- type OpenAIChatCompletionsAdapter
- type OpenAIChatCompletionsAdapterRegistry
- type OpenAIChatCompletionsBinding
- type OpenAIChatCompletionsRegistration
- type OpenAICompatibleProvider
- type OpenAIResponsesAdapter
- type OpenAIResponsesAdapterRegistry
- type OpenAIResponsesBinding
- type OpenAIResponsesRegistration
- type Resumer
- type RouteResolution
- func (r RouteResolution) BindAnthropicMessages(ctx context.Context, requirements modelrouter.Requirements) (AnthropicMessagesBinding, error)
- func (r RouteResolution) BindGoogleGenAI(ctx context.Context, requirements modelrouter.Requirements) (GoogleGenAIBinding, error)
- func (r RouteResolution) BindSystemOne(ctx context.Context, requirements modelrouter.Requirements) (SystemOneBinding, error)
- func (r RouteResolution) Plan() modelrouter.Plan
- type Router
- func NewBedrockRuntimeRouter(cfg awsauth.Config, routes ...modelrouter.Route) (*Router, error)
- func NewRouter(routes *modelrouter.Registry, adapters AdapterRegistries) (*Router, error)
- func NewRouterWithAdapters(routes *modelrouter.Registry, registrations AdapterRegistrations) (*Router, error)
- func NewVertexRouter(projectID, region string, routes ...modelrouter.Route) (*Router, error)
- type Runtime
- type SystemOneAdapter
- type SystemOneAdapterRegistry
- type SystemOneBinding
- type SystemOneRegistration
- type SystemOneService
- type Target
- type TargetConfig
- type VertexConfig
Examples ¶
- AnthropicBackend
- AsResumer
- BedrockBackend
- New
- NewAdapterBackend
- NewAnthropicDirectMessagesAdapter
- NewBedrockAnthropicMessagesAdapter
- NewBedrockOpenAIChatCompletionsAdapter
- NewBedrockOpenAIResponsesAdapter
- NewBedrockRuntimeAnthropicMessagesAdapter
- NewBedrockRuntimeRouter
- NewOpenAIResponsesAdapterRegistry
- NewOpenAIResponsesBinding
- NewRouted
- NewRouterWithAdapters
- NewRuntime
- NewVertexOpenAIResponsesAdapter
- NewVertexRouter
- NewWithTarget
- RouteResolution.BindGoogleGenAI
- RouteResolution.Plan
- Router.Resolve
- Runtime.Target
- Target.Resolve
- VertexBackend
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidAdapter identifies an invalid adapter registration. ErrInvalidAdapter = errors.New("invalid model adapter") // ErrDuplicateAdapter identifies multiple adapters registered for the same // provider and protocol. ErrDuplicateAdapter = errors.New("duplicate model adapter") // ErrAdapterNotFound identifies a resolved provider and protocol with no // registered adapter. ErrAdapterNotFound = errors.New("model adapter not found") // ErrInvalidBinding identifies an invalid or substituted protocol binding. ErrInvalidBinding = errors.New("invalid model binding") )
var ErrInvalidRouter = errors.New("invalid model router")
ErrInvalidRouter identifies a nil or incomplete explicit router.
Functions ¶
This section is empty.
Types ¶
type AdapterRegistrations ¶ added in v0.10.107
type AdapterRegistrations struct {
GoogleGenAI []GoogleGenAIRegistration
AnthropicMessages []AnthropicMessagesRegistration
OpenAIChatCompletions []OpenAIChatCompletionsRegistration
OpenAIResponses []OpenAIResponsesRegistration
SystemOne []SystemOneRegistration
}
AdapterRegistrations groups typed registrations for application startup. Each adapter captures its provider's explicit configuration. Empty slices register no adapters for that protocol.
type AdapterRegistries ¶ added in v0.10.32
type AdapterRegistries struct {
GoogleGenAI *GoogleGenAIAdapterRegistry
AnthropicMessages *AnthropicMessagesAdapterRegistry
OpenAIChatCompletions *OpenAIChatCompletionsAdapterRegistry
OpenAIResponses *OpenAIResponsesAdapterRegistry
SystemOne *SystemOneAdapterRegistry
}
AdapterRegistries groups the protocol-fixed adapter registries. A nil registry is allowed when an application declares no routes for that protocol; selecting one of those routes returns ErrAdapterNotFound.
type Agent ¶
type Agent[Req promptbuilder.Bindable, Resp, CB any] interface { // Execute runs the agent with the given request and tool callbacks. Execute(ctx context.Context, request Req, callbacks CB) (Resp, error) }
Agent is the interface for a configured meta-agent.
- Req must implement promptbuilder.Bindable.
- Resp is the structured response type.
- CB is the type providing all tool callbacks.
func New ¶
func New[Req promptbuilder.Bindable, Resp, CB any]( ctx context.Context, projectID, region, modelName string, config Config[Resp, CB], ) (Agent[Req, Resp, CB], error)
New is the compatibility constructor. Prefer NewRouted for new agents and migrations that explicitly preserve provider and model configuration. The modelName parameter determines which provider implementation is used:
- Models starting with "gemini-" use Google's Generative AI SDK (native)
- Models starting with "claude-" use the configured legacy Claude backend
- Models in "publisher/model" format use Vertex AI's OpenAI-compatible Chat Completions endpoint, except ids whose model.Info sets ExplicitRouteOnly (such as "xai/*"), which New rejects; construct those with NewWithTarget or NewRouted
Example ¶
ExampleNew demonstrates the retained compatibility constructor. Prefer NewRouted for explicit provider selection in new applications.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/promptbuilder"
"chainguard.dev/driftlessaf/agents/toolcall"
)
// request is an example request type that implements promptbuilder.Bindable.
type request struct {
Query string
}
func (r *request) Bind(p *promptbuilder.Prompt) (*promptbuilder.Prompt, error) {
return p.BindXML("query", struct {
XMLName struct{} `xml:"query"`
Content string `xml:",chardata"`
}{
Content: r.Query,
})
}
// response is an example structured response type.
type response struct {
Answer string `json:"answer"`
}
func main() {
ctx := context.Background()
tools := toolcall.NewEmptyToolsProvider[*response]()
config := metaagent.Config[*response, toolcall.EmptyTools]{
Tools: tools,
}
// An unsupported model prefix returns an error.
_, err := metaagent.New[*request](ctx, "my-project", "us-central1", "unknown-model", config)
if err != nil {
fmt.Println("error:", err)
}
}
Output: error: unsupported model: unknown-model (expected gemini-*, claude-*, or publisher/model format)
func NewOpenAICompatible ¶ added in v0.10.17
func NewOpenAICompatible[Req promptbuilder.Bindable, Resp, CB any]( provider OpenAICompatibleProvider, model string, config Config[Resp, CB], ) (Agent[Req, Resp, CB], error)
NewOpenAICompatible creates an agent for an explicitly configured external OpenAI-compatible backend. Callers must provide the serving provider and token-limit parameter rather than relying on model-name routing.
func NewRouted ¶ added in v0.10.32
func NewRouted[Req promptbuilder.Bindable, Resp, CB any]( ctx context.Context, router *Router, selection modelrouter.Selection, config Config[Resp, CB], ) (Agent[Req, Resp, CB], error)
NewRouted resolves selection, validates every requested capability, invokes exactly one typed adapter, and constructs the matching protocol agent. It never falls back to another provider or protocol.
Example ¶
ExampleNewRouted demonstrates explicit provider selection with a test-only provider that reuses the OpenAI Chat Completions protocol.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/executor/openai/chatcompletionexecutor"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"chainguard.dev/driftlessaf/agents/promptbuilder"
"chainguard.dev/driftlessaf/agents/toolcall"
"github.com/openai/openai-go/v3"
)
// request is an example request type that implements promptbuilder.Bindable.
type request struct {
Query string
}
func (r *request) Bind(p *promptbuilder.Prompt) (*promptbuilder.Prompt, error) {
return p.BindXML("query", struct {
XMLName struct{} `xml:"query"`
Content string `xml:",chardata"`
}{
Content: r.Query,
})
}
// response is an example structured response type.
type response struct {
Answer string `json:"answer"`
}
func main() {
const provider modelrouter.Provider = "example-provider"
selection := modelrouter.Selection{Provider: provider, LogicalModel: "example/model"}
routes, err := modelrouter.NewRegistry(modelrouter.Route{
Selection: selection,
Protocol: modelrouter.ProtocolOpenAIChatCompletions,
ProviderModelID: "opaque-deployment-id",
Attribution: modelrouter.Attribution{
ProviderName: "example.provider",
LegacySystem: "example.provider",
},
Capabilities: modelrouter.Capabilities{
ToolCalling: true,
TerminalSubmission: true,
},
})
if err != nil {
panic(err)
}
adapters, err := metaagent.NewOpenAIChatCompletionsAdapterRegistry(
metaagent.OpenAIChatCompletionsRegistration{
Provider: provider,
Adapter: func(_ context.Context, plan modelrouter.Plan) (metaagent.OpenAIChatCompletionsBinding, error) {
// A real application prepares the SDK client with its provider-owned
// endpoint and credential here, outside the route plan.
return metaagent.NewOpenAIChatCompletionsBinding(
plan, openai.Client{}, chatcompletionexecutor.TokenLimitMaxTokens, nil,
)
},
},
)
if err != nil {
panic(err)
}
router, err := metaagent.NewRouter(routes, metaagent.AdapterRegistries{OpenAIChatCompletions: adapters})
if err != nil {
panic(err)
}
prompt, err := promptbuilder.NewPrompt("answer the query")
if err != nil {
panic(err)
}
agent, err := metaagent.NewRouted[*request](context.Background(), router, selection, metaagent.Config[*response, toolcall.EmptyTools]{
UserPrompt: prompt,
Tools: toolcall.NewEmptyToolsProvider[*response](),
})
if err != nil {
panic(err)
}
fmt.Println(agent != nil)
}
Output: true
func NewWithTarget ¶ added in v0.10.108
func NewWithTarget[Req promptbuilder.Bindable, Resp, CB any](ctx context.Context, target Target, config Config[Resp, CB]) (Agent[Req, Resp, CB], error)
NewWithTarget resolves a startup-owned target and delegates to NewRouted. It preserves configuration, capability, schema, and adapter validation and never falls back to a different provider or the legacy constructor.
Example ¶
target := exampleRuntime().Target(metaagent.TargetConfig{
Provider: modelrouter.ProviderVertexAI, Model: "gemini-2.5-flash", Region: "global",
})
// This step binds the adapter using Application Default Credentials.
_, err := metaagent.NewWithTarget[*request](context.Background(), target, metaagent.Config[*response, toolcall.EmptyTools]{
UserPrompt: promptbuilder.MustNewPrompt("Answer the request."),
Tools: toolcall.NewEmptyToolsProvider[*response](),
})
if err != nil {
fmt.Println(err)
}
type AnthropicMessagesAdapter ¶ added in v0.10.32
type AnthropicMessagesAdapter func(context.Context, modelrouter.Plan) (AnthropicMessagesBinding, error)
AnthropicMessagesAdapter constructs an Anthropic Messages SDK binding for a resolved plan. The adapter may capture provider configuration and credentials, but must return the same plan it receives.
func NewAnthropicDirectMessagesAdapter ¶ added in v0.10.34
func NewAnthropicDirectMessagesAdapter(cfg anthropicauth.Config) (AnthropicMessagesAdapter, error)
NewAnthropicDirectMessagesAdapter constructs an Anthropic-direct adapter for the Anthropic Messages protocol. cfg is supplied explicitly and remains captured by the adapter; this path doesn't read Anthropic backend-selection environment variables or fall back to Vertex AI.
Example ¶
ExampleNewAnthropicDirectMessagesAdapter demonstrates binding an explicit Anthropic workload identity federation configuration to a typed Messages adapter. The route plan remains separate and secret-free.
package main
import (
"chainguard.dev/driftlessaf/agents/anthropicauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
adapter, err := metaagent.NewAnthropicDirectMessagesAdapter(anthropicauth.Config{
FederationRuleID: "fdrl_0123456789",
OrganizationID: "12345678-1234-1234-1234-123456789012",
Source: anthropicauth.SourceGoogle,
})
if err != nil {
return
}
_ = adapter
}
Output:
func NewBedrockAnthropicMessagesAdapter ¶ added in v0.10.34
func NewBedrockAnthropicMessagesAdapter(cfg awsauth.Config) (AnthropicMessagesAdapter, error)
NewBedrockAnthropicMessagesAdapter constructs an AWS Bedrock Mantle adapter for the Anthropic Messages protocol. cfg is supplied explicitly and remains captured by the adapter; credentials are validated only if a Bedrock route selects this adapter.
Example ¶
ExampleNewBedrockAnthropicMessagesAdapter demonstrates binding explicit AWS IAM Identity Center configuration to a typed Bedrock Messages adapter.
package main
import (
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
adapter, err := metaagent.NewBedrockAnthropicMessagesAdapter(awsauth.Config{
Region: "us-east-1",
Profile: "engineering-sso",
})
if err != nil {
return
}
_ = adapter
}
Output:
func NewBedrockRuntimeAnthropicMessagesAdapter ¶ added in v0.10.70
func NewBedrockRuntimeAnthropicMessagesAdapter(cfg awsauth.Config) (AnthropicMessagesAdapter, error)
NewBedrockRuntimeAnthropicMessagesAdapter binds Anthropic Messages to the regional Bedrock Runtime endpoint through the shared SigV4 transport. Credentials are loaded only when a validated Bedrock plan selects the adapter. It does not register routes or verify model access or retention eligibility. NewBedrockAnthropicMessagesAdapter remains the separate Mantle constructor.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
adapter, err := metaagent.NewBedrockRuntimeAnthropicMessagesAdapter(awsauth.Config{
Region: "us-west-2",
Profile: "approved-sso-profile",
})
fmt.Println(adapter != nil, err)
// Construction does not load credentials or invoke a model. Register this
// adapter for ProviderAWSBedrock in the Anthropic Messages registry, using
// an application-owned route with the exact approved inference profile ID.
Output:
func NewVertexAnthropicMessagesAdapter ¶ added in v0.10.32
func NewVertexAnthropicMessagesAdapter(projectID, region string) (AnthropicMessagesAdapter, error)
NewVertexAnthropicMessagesAdapter constructs a Vertex AI adapter for the Anthropic Messages protocol. Application Default Credentials are bound only while constructing the typed Messages service.
type AnthropicMessagesAdapterRegistry ¶ added in v0.10.32
type AnthropicMessagesAdapterRegistry struct {
// contains filtered or unexported fields
}
AnthropicMessagesAdapterRegistry is an immutable provider-keyed registry whose protocol is fixed to Anthropic Messages by its type.
func NewAnthropicMessagesAdapterRegistry ¶ added in v0.10.32
func NewAnthropicMessagesAdapterRegistry(registrations ...AnthropicMessagesRegistration) (*AnthropicMessagesAdapterRegistry, error)
NewAnthropicMessagesAdapterRegistry validates registrations in declaration order.
type AnthropicMessagesBinding ¶ added in v0.10.32
type AnthropicMessagesBinding struct {
// contains filtered or unexported fields
}
AnthropicMessagesBinding carries the typed Messages service and non-secret provider inputs needed by the Claude executor. Its Plan remains the authority for model and attribution values.
func NewAnthropicMessagesBinding ¶ added in v0.10.32
func NewAnthropicMessagesBinding(plan modelrouter.Plan, messages anthropic.MessageService, resourceLabels map[string]string) (AnthropicMessagesBinding, error)
NewAnthropicMessagesBinding validates plan and constructs an Anthropic Messages binding.
func (AnthropicMessagesBinding) Messages ¶ added in v0.10.32
func (b AnthropicMessagesBinding) Messages() anthropic.MessageService
Messages returns the typed Anthropic Messages service carried by b.
func (AnthropicMessagesBinding) Plan ¶ added in v0.10.32
func (b AnthropicMessagesBinding) Plan() modelrouter.Plan
Plan returns the immutable route plan carried by b.
func (AnthropicMessagesBinding) ResourceLabels ¶ added in v0.10.32
func (b AnthropicMessagesBinding) ResourceLabels() map[string]string
ResourceLabels returns a copy of the provider resource labels carried by b.
type AnthropicMessagesRegistration ¶ added in v0.10.32
type AnthropicMessagesRegistration struct {
Provider modelrouter.Provider
Adapter AnthropicMessagesAdapter
}
AnthropicMessagesRegistration registers one provider adapter in an Anthropic Messages adapter registry.
type Backend ¶ added in v0.10.108
type Backend struct {
// contains filtered or unexported fields
}
Backend is an immutable registration for one provider account. Create it with VertexBackend, BedrockBackend, AnthropicBackend, or NewAdapterBackend. Its zero value is invalid. Names default to the provider name; distinct names isolate accounts. Factories capture configuration, never route selection.
func AnthropicBackend ¶ added in v0.10.116
func AnthropicBackend(name string, cfg anthropicauth.Config) Backend
AnthropicBackend captures direct Anthropic authentication configuration. Target regions are ignored, and credentials are discovered only on binding.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/anthropicauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
_, err := metaagent.NewRuntime(nil, metaagent.AnthropicBackend("", anthropicauth.Config{FederationRuleID: "rule", OrganizationID: "org"}))
fmt.Println(err)
}
Output: <nil>
func BedrockBackend ¶ added in v0.10.116
func BedrockBackend(name string, cfg awsauth.Config, options ...BackendOption) Backend
BedrockBackend captures one AWS credential configuration and default region. A target's region overrides cfg.Region. Credentials remain lazy.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
_, err := metaagent.NewRuntime(nil, metaagent.BedrockBackend("", awsauth.Config{Region: "us-east-1"}))
fmt.Println(err)
}
Output: <nil>
func NewAdapterBackend ¶ added in v0.10.116
func NewAdapterBackend(name string, provider modelrouter.Provider, factory func(string) (AdapterRegistrations, error)) Backend
NewAdapterBackend captures a factory for typed provider adapters. It does not invoke the factory until a declared target is resolved. The target region is passed unchanged and forms part of the router cache key, including when empty.
The factory must return configuration-only adapters without loading credentials or making requests; credentials belong in adapter binding after validation. It must capture immutable configuration and return only the specified provider's registrations. Adapters must be safe for concurrent binding. Failed factory calls are not cached. Each Runtime serializes factory calls; a registration reused across runtimes must also support concurrent factory calls.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
calls := 0
backend := metaagent.NewAdapterBackend("account", "example-provider", func(region string) (metaagent.AdapterRegistrations, error) {
calls++
// Return adapters capturing this account's configuration and region.
return metaagent.AdapterRegistrations{}, nil
})
_, err := metaagent.NewRuntime(nil, backend)
fmt.Println(calls, err)
}
Output: 0 <nil>
func VertexBackend ¶ added in v0.10.116
func VertexBackend(name string, cfg VertexConfig, options ...BackendOption) Backend
VertexBackend captures one Vertex project. Every target must supply a region. Construction and target resolution do not discover credentials.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
_, err := metaagent.NewRuntime(nil, metaagent.VertexBackend("primary", metaagent.VertexConfig{ProjectID: "my-project"}))
fmt.Println(err)
}
Output: <nil>
type BackendOption ¶ added in v0.10.142
type BackendOption func(*backendOptions)
BackendOption extends a provider backend with an explicitly configured protocol adapter. The serving provider still owns credentials and transport.
func WithSystemOneAdapter ¶ added in v0.10.142
func WithSystemOneAdapter(adapter SystemOneAdapter) BackendOption
WithSystemOneAdapter adds typed-question serving to a Vertex or Bedrock backend when that provider offers a System One model.
type Config ¶
type Config[Resp, CB any] struct { // SystemInstructions is the system prompt that defines the agent's role and behavior. SystemInstructions *promptbuilder.Prompt // UserPrompt is the template for formatting the user's request. // The Req type is bound to this template via its Bind method. UserPrompt *promptbuilder.Prompt // UserPromptSuffix is an optional static prompt appended as a separate // trailing block of the initial user message, after the bound UserPrompt. // When set, the leading block (UserPrompt with the request bound) gets a // cache breakpoint so executions that differ only in the suffix share its // cache entry. Intended for multi-pass agents reviewing one payload // through different lenses: the payload rides in UserPrompt, the per-pass // lens in the suffix. The request is never bound into the suffix — it // must be fully bound already. On the Gemini and OpenAI-compatible // backends (no per-block cache semantics) the built suffix is // concatenated onto the user prompt with a blank-line separator. UserPromptSuffix *promptbuilder.Prompt // Tools provides all tool definitions for this agent. // Compose providers using toolcall.NewFindingToolsProvider, // toolcall.NewWorktreeToolsProvider, and toolcall.NewEmptyToolsProvider. Tools toolcall.ToolProvider[Resp, CB] // MaxTurns sets the maximum number of conversation turns (LLM round-trips) // before the executor aborts. Zero means use the executor's default. MaxTurns int // ResponsesRequestTimeout bounds each HTTP attempt on a NewRouted // openai-responses agent. Zero inherits the execution deadline. ResponsesRequestTimeout time.Duration // ResponsesExecutionTimeout bounds the entire NewRouted openai-responses // conversation. Zero selects 30 minutes; a shorter caller deadline wins. // These timeout fields do not configure the compatibility New path. // NewRouted rejects nonzero Responses timeouts on other protocols. ResponsesExecutionTimeout time.Duration // ToolCallConcurrency bounds how many of a single turn's tool calls run // concurrently when the model emits more than one (parallel tool use). // Zero means use the executor's default (DefaultToolCallConcurrency). Set // to 1 to force strictly sequential tool dispatch — required for agents // whose tool handlers mutate shared state without their own synchronization. ToolCallConcurrency int // MaxTokens caps the model's output tokens per turn. NewRouted maps it to // the selected protocol's supported output-limit field after route // capability validation. The compatibility New path retains its historical // Claude-only behavior: zero uses 32000, and the Claude executor rejects // values above 128000. Because the executor streams every response, large // values do not risk the SDK's non-streaming HTTP timeout. Raise it for stages // whose turns need room for BOTH extended thinking and a tool call: at high // effort on a large context, adaptive thinking can otherwise consume the // whole budget and stop at max_tokens before the model emits its tool call, // which the executor surfaces as "no content in Claude's response". MaxTokens int64 // ThinkingBudget enables an explicit thinking-token budget. NewRouted maps // it to protocol-supported controls after route capability validation; the // compatibility New path retains its historical Claude-only behavior. Zero // leaves thinking disabled. On Claude, it must be at least 1024 and less // than MaxTokens (or the 32000 default); see claudeexecutor.WithThinking. // On models where the Anthropic API has removed the explicit budget // parameter (Opus 4.7 and later), the executor automatically maps this to // adaptive thinking and the budget value is advisory only. Under New, // Gemini and OpenAI ignore this field. Under NewRouted, Google Gen AI maps // it to its thinking budget and unsupported routes reject it before adapter // construction. // // Deprecated: ThinkingBudget is provider-specific and already advisory-only // on Opus 4.7+. Use Effort, which works across routed protocols; do not set // both. The field will be removed once remaining consumers migrate. ThinkingBudget int64 // Effort sets the provider-neutral reasoning-effort level, controlling how // deeply the model thinks and its overall token spend. Empty (the default) // leaves each backend's model default in place. Every backend maps the // level onto the nearest control the configured model supports: // - Claude: output_config.effort — exact on Opus 4.7+/Sonnet 5/Fable 5; // "xhigh" clamps to "high" on models that predate it (Sonnet 4.6, // Opus 4.5/4.6); dropped with a warning on models without effort // support; see claudeexecutor.WithEffort. // - Gemini: thinkingLevel on Gemini 3.x models, thinkingBudget tiers on // earlier models; see googleexecutor.WithEffort. // - OpenAI Chat Completions: reasoning_effort, where xhigh and max clamp // to "high"; reasoning models only, see chatcompletionexecutor.WithEffort. // - OpenAI Responses (routed construction only): reasoning.effort, sent // unchanged; the route declares the levels its model accepts. // effort.XHigh is recommended for hard coding/agentic work on // Sonnet 5 / Opus 4.7+. Effort effort.Level // ResultValidators gate the terminal submit_result tool. When the model // submits a result that parses into Resp, every validator runs // concurrently against it; any findings reject the submission back to the // model as the tool's result — the agent loop continues until a submission // passes — and a validator error aborts the run. Empty (the default) // accepts every parsed submission. Findings are concatenated in // registration order. Validators must be safe for concurrent use; see // callbacks.ResultValidator. ResultValidators []callbacks.ResultValidator[Resp] // RefusalNudgeMaxRetries bounds how many times a turn refused by // Anthropic's safety classifier is retried with a nudge instead of // failing the run immediately. Zero (the default) leaves a refusal fatal, // same as before this field existed, surfaced as a // *claudeexecutor.RefusalError. The compatibility New path applies it only // to Claude. NewRouted rejects it before adapter construction unless the // route supports refusal recovery. See claudeexecutor.WithRefusalNudge. RefusalNudgeMaxRetries int // MaxToolCallsBeforeFinalize, when positive, soft-caps the agentic loop: // once the model has made this many investigative (non-terminal) tool // calls, the executor injects one instruction to call the terminal submit // tool now and forces that tool on the next turn where the model allows // it. A run that would otherwise exhaust MaxTurns and fail instead // returns a result built from the evidence gathered so far, still subject // to ResultValidators. Zero (the default) disables it. // // Claude backend only: the Gemini and OpenAI-compatible backends reject a // non-zero value at construction rather than silently running uncapped. // Incompatible with ThinkingBudget, whose explicit thinking forbids the // forced tool_choice. See claudeexecutor.WithMaxToolCallsBeforeFinalize. MaxToolCallsBeforeFinalize int // EnforceInputBudget, when true, checks each request's input tokens // before the model call and, when the input does not fit the serving // model's context window less the output headroom, reduces older tool // results and, if it still does not fit, fails with an error matching // agentexecutor.ErrInputTooLarge instead of sending a request the // provider would reject. Claude backend only: the Gemini and // OpenAI-compatible backends, and routed protocols other than Anthropic // Messages, reject it at construction. See claudeexecutor.WithInputBudget. EnforceInputBudget bool // InputContextWindow overrides the context window, in tokens, that // EnforceInputBudget measures against. Zero resolves the window from the // provider-facts registry for the serving model, and construction fails // when the registry does not know it. Ignored unless EnforceInputBudget // is set; must not be negative. InputContextWindow int64 // SuspendToolName, when non-empty, enables the ask-a-friend suspend/resume // capability: the backend advertises a held-out tool by this name, and when // the model calls it, Execute returns a *checkpoint.Suspension (extract it // with checkpoint.AsSuspension) carrying the envelope needed to resume the // paused conversation later, instead of a Resp. A resume-capable caller // obtains the resume path by type-asserting the constructed agent with // AsResumer. // // Claude backend only for now: the Gemini and OpenAI-compatible backends // reject a non-empty SuspendToolName at construction with a clear error // until their executors grow suspend support (DEV-2247 follow-up slices) — // silently ignoring it would advertise a lifecycle that can never fire. // The name must differ from the terminal submit tool's name and from every // caller-registered tool (both validated by the executor). Empty (the // default) leaves suspension disabled and the run's behavior byte-for-byte // unchanged. SuspendToolName string // SuspendToolDescription is the friend-facing description advertised to the // model for the suspend tool. The tool's schema declares two string // properties: question (required) and context (optional), and this // description is what prompts the model to fill context, so name it here. // Ignored when SuspendToolName is empty. SuspendToolDescription string // OmitResultSchemaFields lists JSON property names the terminal submit // tool withholds from the payload schema it advertises // (submitresult.Options.OmitPayloadFields). Resp is unchanged, which is // the point: an agent whose affordances vary at runtime can hide the // fields of a disabled one instead of swapping Resp for a trimmed mirror // type. Swapping Resp also swaps the type the run's trace is recorded // under — agenttrace keys the context tracer by result type — so every // consumer that installed a Tracer[Resp] (eval scorers, CloudEvent // emission) would silently stop receiving traces. // // A withheld field still decodes if a model invents it, so a caller for // which that matters must also ignore it on the returned result. Every // name must match a property of Resp's reflected schema; an unmatched // name fails construction. OmitResultSchemaFields []string // OmitSubmitReasoning removes the terminal tool's separate reasoning // argument. The response type must carry any reasoning the caller needs. OmitSubmitReasoning bool }
Config defines the configuration for a meta-agent instance.
- Resp is the structured response type returned by the agent.
- CB is the type providing all tool callbacks.
type Continuer ¶ added in v0.11.19
type Continuer[Req promptbuilder.Bindable, Resp, CB any] interface { Agent[Req, Resp, CB] // Continue picks the exhausted conversation in env up after its last // turn and runs it with the given tool callbacks. It returns // checkpoint.ErrConfigDrift (wrapped) when this agent's configuration no // longer matches the envelope, signaling the caller to run from scratch. Continue(ctx context.Context, env checkpoint.Envelope, callbacks CB) (Resp, error) }
Continuer is the capability interface a meta-agent satisfies when it can continue a conversation that spent its turn budget, instead of starting it over: the Continuation an exhausted run carries on its executor.MaxTurnsError. Like Resumer it is kept off Agent, and a caller obtains it via AsContinuer.
The typical caller holds two agents built from one Config that differ only in MaxTurns. When the smaller one's run is exhausted, it continues that conversation on the larger one, whose budget counts the whole conversation (see claudeexecutor.Continuer). The callbacks should be the set the exhausted run had: the model has seen those tools' results, and a tool that keeps state across calls must keep it across the continuation too.
Today only the Claude backend implements Continuer. The Gemini and OpenAI-compatible executors return a bare executor.ErrMaxTurns, which carries no continuation, so a caller falls back to a fresh run for them.
func AsContinuer ¶ added in v0.11.19
func AsContinuer[Req promptbuilder.Bindable, Resp, CB any](agent Agent[Req, Resp, CB]) (Continuer[Req, Resp, CB], bool)
AsContinuer type-asserts agent to the Continuer capability. It reports false when the agent's backend cannot continue a conversation, so callers can branch to a fresh run.
type GoogleGenAIAdapter ¶ added in v0.10.32
type GoogleGenAIAdapter func(context.Context, modelrouter.Plan) (GoogleGenAIBinding, error)
GoogleGenAIAdapter constructs a Google Gen AI SDK binding for a resolved plan. The adapter may capture provider configuration and credentials, but must return the same plan it receives.
func NewVertexGoogleGenAIAdapter ¶ added in v0.10.32
func NewVertexGoogleGenAIAdapter(projectID, region string) (GoogleGenAIAdapter, error)
NewVertexGoogleGenAIAdapter constructs a Vertex AI adapter for the Google Gen AI protocol. Application Default Credentials remain captured by the SDK client and never enter a route or plan.
func NewVertexGoogleGenAIAdapterWithRequestTimeout ¶ added in v0.10.38
func NewVertexGoogleGenAIAdapterWithRequestTimeout(projectID, region string, requestTimeout time.Duration) (GoogleGenAIAdapter, error)
NewVertexGoogleGenAIAdapterWithRequestTimeout constructs a Vertex AI adapter whose individual Google Gen AI requests are bounded by requestTimeout. The bound applies to each attempt independently, so the executor's retry policy can recover from a stalled request while the caller's context remains the authority for the overall agent deadline.
type GoogleGenAIAdapterRegistry ¶ added in v0.10.32
type GoogleGenAIAdapterRegistry struct {
// contains filtered or unexported fields
}
GoogleGenAIAdapterRegistry is an immutable provider-keyed registry whose protocol is fixed to Google Gen AI by its type.
func NewGoogleGenAIAdapterRegistry ¶ added in v0.10.32
func NewGoogleGenAIAdapterRegistry(registrations ...GoogleGenAIRegistration) (*GoogleGenAIAdapterRegistry, error)
NewGoogleGenAIAdapterRegistry validates registrations in declaration order.
type GoogleGenAIBinding ¶ added in v0.10.32
type GoogleGenAIBinding struct {
// contains filtered or unexported fields
}
GoogleGenAIBinding carries the typed client and non-secret provider inputs needed by the Google executor. Its Plan remains the authority for model and attribution values.
func NewGoogleGenAIBinding ¶ added in v0.10.32
func NewGoogleGenAIBinding(plan modelrouter.Plan, client *genai.Client, resourceLabels map[string]string) (GoogleGenAIBinding, error)
NewGoogleGenAIBinding validates plan and constructs a Google Gen AI binding.
func (GoogleGenAIBinding) Client ¶ added in v0.10.32
func (b GoogleGenAIBinding) Client() *genai.Client
Client returns the typed Google Gen AI client carried by b.
func (GoogleGenAIBinding) Plan ¶ added in v0.10.32
func (b GoogleGenAIBinding) Plan() modelrouter.Plan
Plan returns the immutable route plan carried by b.
func (GoogleGenAIBinding) ResourceLabels ¶ added in v0.10.32
func (b GoogleGenAIBinding) ResourceLabels() map[string]string
ResourceLabels returns a copy of the provider resource labels carried by b.
type GoogleGenAIRegistration ¶ added in v0.10.32
type GoogleGenAIRegistration struct {
Provider modelrouter.Provider
Adapter GoogleGenAIAdapter
}
GoogleGenAIRegistration registers one provider adapter in a Google Gen AI adapter registry.
type OpenAIChatCompletionsAdapter ¶ added in v0.10.32
type OpenAIChatCompletionsAdapter func(context.Context, modelrouter.Plan) (OpenAIChatCompletionsBinding, error)
OpenAIChatCompletionsAdapter constructs an OpenAI Chat Completions SDK binding for a resolved plan. The adapter may capture provider configuration and credentials, but must return the same plan it receives.
func NewBedrockOpenAIChatCompletionsAdapter ¶ added in v0.10.65
func NewBedrockOpenAIChatCompletionsAdapter(cfg awsauth.Config) (OpenAIChatCompletionsAdapter, error)
NewBedrockOpenAIChatCompletionsAdapter constructs an AWS Bedrock Runtime adapter for the OpenAI Chat Completions protocol. It uses temporary AWS credentials through the shared SigV4 transport, not OpenAI API keys. Credential discovery occurs only when a validated Bedrock plan selects the adapter. cfg selects an explicit region and optional IAM Identity Center profile; an empty profile uses the awsauth web-identity path.
This adapter initializes only the client's Chat service. It does not register routes or verify account access to the plan's exact provider model ID.
Example ¶
ExampleNewBedrockOpenAIChatCompletionsAdapter constructs an adapter without loading credentials or invoking a model. Register it with a test-only route after independently verifying the account's provider model ID and access.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func main() {
adapter, err := metaagent.NewBedrockOpenAIChatCompletionsAdapter(awsauth.Config{
Region: "us-east-1",
Profile: "engineering-sso",
})
if err != nil {
fmt.Println(err)
return
}
_, err = metaagent.NewOpenAIChatCompletionsAdapterRegistry(metaagent.OpenAIChatCompletionsRegistration{
Provider: modelrouter.ProviderAWSBedrock,
Adapter: adapter,
})
fmt.Println(err)
}
Output: <nil>
func NewVertexOpenAIChatCompletionsAdapter ¶ added in v0.10.32
func NewVertexOpenAIChatCompletionsAdapter(projectID, region string) (OpenAIChatCompletionsAdapter, error)
NewVertexOpenAIChatCompletionsAdapter constructs a Vertex AI adapter for the OpenAI Chat Completions protocol. The OAuth token source remains attached to the SDK transport and never enters a route or plan.
type OpenAIChatCompletionsAdapterRegistry ¶ added in v0.10.32
type OpenAIChatCompletionsAdapterRegistry struct {
// contains filtered or unexported fields
}
OpenAIChatCompletionsAdapterRegistry is an immutable provider-keyed registry whose protocol is fixed to OpenAI Chat Completions by its type.
func NewOpenAIChatCompletionsAdapterRegistry ¶ added in v0.10.32
func NewOpenAIChatCompletionsAdapterRegistry(registrations ...OpenAIChatCompletionsRegistration) (*OpenAIChatCompletionsAdapterRegistry, error)
NewOpenAIChatCompletionsAdapterRegistry validates registrations in declaration order.
type OpenAIChatCompletionsBinding ¶ added in v0.10.32
type OpenAIChatCompletionsBinding struct {
// contains filtered or unexported fields
}
OpenAIChatCompletionsBinding carries the typed client and non-secret provider inputs needed by the OpenAI executor. Its Plan remains the authority for model and attribution values.
func NewOpenAIChatCompletionsBinding ¶ added in v0.10.32
func NewOpenAIChatCompletionsBinding( plan modelrouter.Plan, client openai.Client, tokenLimitParameter chatcompletionexecutor.TokenLimitParameter, resourceLabels map[string]string, ) (OpenAIChatCompletionsBinding, error)
NewOpenAIChatCompletionsBinding validates plan and constructs an OpenAI Chat Completions binding.
func (OpenAIChatCompletionsBinding) Client ¶ added in v0.10.32
func (b OpenAIChatCompletionsBinding) Client() openai.Client
Client returns the typed OpenAI client carried by b.
func (OpenAIChatCompletionsBinding) Plan ¶ added in v0.10.32
func (b OpenAIChatCompletionsBinding) Plan() modelrouter.Plan
Plan returns the immutable route plan carried by b.
func (OpenAIChatCompletionsBinding) ResourceLabels ¶ added in v0.10.32
func (b OpenAIChatCompletionsBinding) ResourceLabels() map[string]string
ResourceLabels returns a copy of the provider resource labels carried by b.
func (OpenAIChatCompletionsBinding) TokenLimitParameter ¶ added in v0.10.32
func (b OpenAIChatCompletionsBinding) TokenLimitParameter() chatcompletionexecutor.TokenLimitParameter
TokenLimitParameter returns the request field used for output-token limits.
type OpenAIChatCompletionsRegistration ¶ added in v0.10.32
type OpenAIChatCompletionsRegistration struct {
Provider modelrouter.Provider
Adapter OpenAIChatCompletionsAdapter
}
OpenAIChatCompletionsRegistration registers one provider adapter in an OpenAI Chat Completions adapter registry.
type OpenAICompatibleProvider ¶ added in v0.10.17
type OpenAICompatibleProvider struct {
BaseURL string
APIKey string
Provider chatcompletionexecutor.Provider
TokenLimitParameter chatcompletionexecutor.TokenLimitParameter
}
OpenAICompatibleProvider configures an external OpenAI-compatible backend. APIKey is used only to construct the authenticated client; it is not added to logs, traces, metrics, or resource labels.
type OpenAIResponsesAdapter ¶ added in v0.10.66
type OpenAIResponsesAdapter func(context.Context, modelrouter.Plan) (OpenAIResponsesBinding, error)
OpenAIResponsesAdapter binds one resolved route to a native Responses service.
func NewBedrockOpenAIResponsesAdapter ¶ added in v0.10.69
func NewBedrockOpenAIResponsesAdapter(cfg awsauth.Config) (OpenAIResponsesAdapter, error)
NewBedrockOpenAIResponsesAdapter constructs a native Responses adapter using the shared AWS Bedrock Runtime SigV4 transport. cfg selects an explicit region and optional IAM Identity Center profile; otherwise it uses web identity. Credentials are discovered only after a validated Bedrock route selects this adapter. No OpenAI API key or ambient OPENAI_* configuration is consumed.
The adapter does not register routes, check entitlement or retention, or run inference. The application must verify those prerequisites before execution.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
// Omit Profile in workloads using the approved web-identity configuration.
// Construction validates configuration without discovering credentials.
_, err := metaagent.NewBedrockOpenAIResponsesAdapter(awsauth.Config{Region: "us-west-2", Profile: "approved-sso-profile"})
fmt.Println(err)
}
Output: <nil>
func NewVertexOpenAIResponsesAdapter ¶ added in v0.10.115
func NewVertexOpenAIResponsesAdapter(projectID, region string) (OpenAIResponsesAdapter, error)
NewVertexOpenAIResponsesAdapter constructs a Vertex AI Responses adapter. Application Default Credentials are discovered only when a validated route binds the service. The transport refreshes OAuth tokens for each request; credentials and ambient OPENAI_* settings never enter routes or plans.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
)
func main() {
// Credentials are discovered only when a route binds the service.
_, err := metaagent.NewVertexOpenAIResponsesAdapter("example-project", "global")
fmt.Println(err)
}
Output: <nil>
type OpenAIResponsesAdapterRegistry ¶ added in v0.10.66
type OpenAIResponsesAdapterRegistry struct {
// contains filtered or unexported fields
}
OpenAIResponsesAdapterRegistry is an immutable, protocol-fixed adapter registry.
func NewOpenAIResponsesAdapterRegistry ¶ added in v0.10.66
func NewOpenAIResponsesAdapterRegistry(registrations ...OpenAIResponsesRegistration) (*OpenAIResponsesAdapterRegistry, error)
NewOpenAIResponsesAdapterRegistry validates registrations in declaration order.
Example ¶
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"github.com/openai/openai-go/v3/responses"
)
func main() {
// Supply an authenticated service in the application adapter. This example
// only registers it: neither credentials nor network are accessed here.
adapter := func(_ context.Context, plan modelrouter.Plan) (metaagent.OpenAIResponsesBinding, error) {
return metaagent.NewOpenAIResponsesBinding(plan, responses.ResponseService{}, nil)
}
_, err := metaagent.NewOpenAIResponsesAdapterRegistry(metaagent.OpenAIResponsesRegistration{Provider: "test-provider", Adapter: adapter})
fmt.Println(err)
}
Output: <nil>
type OpenAIResponsesBinding ¶ added in v0.10.66
type OpenAIResponsesBinding struct {
// contains filtered or unexported fields
}
OpenAIResponsesBinding contains a typed service and its immutable route plan.
func NewOpenAIResponsesBinding ¶ added in v0.10.66
func NewOpenAIResponsesBinding(plan modelrouter.Plan, service responses.ResponseService, resourceLabels map[string]string) (OpenAIResponsesBinding, error)
NewOpenAIResponsesBinding validates plan and constructs a Responses binding.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"github.com/openai/openai-go/v3/responses"
)
func main() {
selection := modelrouter.Selection{Provider: "test-provider", LogicalModel: "gpt-5.6-sol"}
routes, err := modelrouter.NewRegistry(modelrouter.Route{Selection: selection, Protocol: modelrouter.ProtocolOpenAIResponses, ProviderModelID: "fixture-deployment", Attribution: modelrouter.Attribution{ProviderName: "test-provider", LegacySystem: "test-provider"}})
if err != nil {
panic(err)
}
plan, err := routes.Resolve(selection)
if err != nil {
panic(err)
}
binding, err := metaagent.NewOpenAIResponsesBinding(plan, responses.ResponseService{}, map[string]string{"region": "fixture"})
if err != nil {
panic(err)
}
_ = binding.Responses() // A typed service, not a Chat Completions client.
fmt.Println(binding.Plan().Protocol(), binding.ResourceLabels()["region"])
}
Output: openai-responses fixture
func (OpenAIResponsesBinding) Plan ¶ added in v0.10.66
func (b OpenAIResponsesBinding) Plan() modelrouter.Plan
Plan returns the immutable route plan.
func (OpenAIResponsesBinding) ResourceLabels ¶ added in v0.10.66
func (b OpenAIResponsesBinding) ResourceLabels() map[string]string
ResourceLabels returns a copy of the non-secret provider labels.
func (OpenAIResponsesBinding) Responses ¶ added in v0.10.66
func (b OpenAIResponsesBinding) Responses() responses.ResponseService
Responses returns a copy of the typed service configuration.
type OpenAIResponsesRegistration ¶ added in v0.10.66
type OpenAIResponsesRegistration struct {
Provider modelrouter.Provider
Adapter OpenAIResponsesAdapter
}
OpenAIResponsesRegistration registers one provider's Responses adapter.
type Resumer ¶ added in v0.9.19
type Resumer[Req promptbuilder.Bindable, Resp, CB any] interface { Agent[Req, Resp, CB] // Resume rebuilds the paused conversation from env and continues it with the // given tool callbacks and human answers. Resume(ctx context.Context, env checkpoint.Envelope, answers map[string]string, callbacks CB) (Resp, error) }
Resumer is the capability interface a resume-capable meta-agent satisfies in addition to Agent. It mirrors Agent.Execute but continues a previously suspended conversation from a checkpoint.Envelope instead of starting fresh.
Resumer is deliberately NOT folded into Agent: keeping it a separate, opt-in capability means the Agent interface never grows and every existing wrapper (usage-capturing decorators, adapters, downstream reconcilers, …) compiles unmodified. A caller that parks and wakes runs obtains it via AsResumer; a caller that only runs fresh conversations depends on Agent unchanged. This mirrors claudeexecutor.Resumer, which is likewise kept off the executor's exported Interface.
Today only the Claude backend implements Resumer; the Gemini and OpenAI-compatible backends gain it together with suspend support in their executors (DEV-2247 follow-up slices), and until then AsResumer reports false for agents built on them.
The answers map keys each pending tool-call ID (from Envelope.PendingToolCalls[i].ID — never re-derived from the tool name) to the human's answer. Answers flow raw: the underlying executor's Resume owns framing (checkpoint.FramedAnswers), and a missing entry is framed as an explicit empty-answer placeholder so no pending tool call is left unanswered. Resume returns checkpoint.ErrConfigDrift (wrapped) when the live executor config no longer matches the envelope, signaling the caller to rebuild from scratch.
func AsResumer ¶ added in v0.9.19
func AsResumer[Req promptbuilder.Bindable, Resp, CB any](agent Agent[Req, Resp, CB]) (Resumer[Req, Resp, CB], bool)
AsResumer type-asserts agent to the Resumer capability. It reports false when the agent's backend does not support suspend/resume, so callers can branch to a fresh-run fallback rather than assume every backend can wake a checkpoint.
Because a meta-agent builds its executor exactly once at construction, a resume path that must run against a *fresh* executor per wake should construct a new agent (via New) inside the reconcile and AsResumer that, rather than reuse a long-lived agent captured in main.
Example ¶
ExampleAsResumer demonstrates obtaining the opt-in resume capability from a constructed agent. AsResumer reports false when the agent's backend does not support suspend/resume, so a waker can branch to a fresh run instead of assuming every backend can wake a checkpoint. Today only the Claude backend (Config.SuspendToolName set) yields a Resumer.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/promptbuilder"
"chainguard.dev/driftlessaf/agents/toolcall"
)
// request is an example request type that implements promptbuilder.Bindable.
type request struct {
Query string
}
func (r *request) Bind(p *promptbuilder.Prompt) (*promptbuilder.Prompt, error) {
return p.BindXML("query", struct {
XMLName struct{} `xml:"query"`
Content string `xml:",chardata"`
}{
Content: r.Query,
})
}
// response is an example structured response type.
type response struct {
Answer string `json:"answer"`
}
// executeOnly is an Agent without the Resume capability, standing in for a
// backend that has not grown suspend/resume support yet.
type executeOnly struct{}
func (executeOnly) Execute(context.Context, *request, toolcall.EmptyTools) (*response, error) {
return &response{}, nil
}
func main() {
var agent metaagent.Agent[*request, *response, toolcall.EmptyTools] = executeOnly{}
if resumer, ok := metaagent.AsResumer[*request](agent); ok {
// Resume the parked conversation: answers are keyed by the pending
// tool-call IDs persisted in the envelope (Envelope.PendingToolCalls).
_ = resumer
fmt.Println("resumable")
} else {
fmt.Println("not resumable: run from scratch")
}
}
Output: not resumable: run from scratch
type RouteResolution ¶ added in v0.10.35
type RouteResolution struct {
// contains filtered or unexported fields
}
RouteResolution carries one route plan together with the Router that resolved it. Its private fields preserve plan provenance while allowing protocol consumers such as judge to request one typed adapter binding. Its exported API exposes no credentials or provider client. A RouteResolution is safe to copy and use concurrently; binding concurrently requires the selected adapter to be safe for concurrent use.
func (RouteResolution) BindAnthropicMessages ¶ added in v0.10.35
func (r RouteResolution) BindAnthropicMessages(ctx context.Context, requirements modelrouter.Requirements) (AnthropicMessagesBinding, error)
BindAnthropicMessages validates requirements and invokes the one Anthropic Messages adapter selected by r.
func (RouteResolution) BindGoogleGenAI ¶ added in v0.10.35
func (r RouteResolution) BindGoogleGenAI(ctx context.Context, requirements modelrouter.Requirements) (GoogleGenAIBinding, error)
BindGoogleGenAI validates requirements and invokes the one Google Gen AI adapter selected by r.
Example ¶
ExampleRouteResolution_BindGoogleGenAI demonstrates requesting the typed provider binding for a previously resolved Google Gen AI route.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"google.golang.org/genai"
)
func main() {
router, selection := exampleGoogleRouter()
resolution, err := router.Resolve(selection)
if err != nil {
panic(err)
}
binding, err := resolution.BindGoogleGenAI(context.Background(), modelrouter.Requirements{MaximumOutputTokens: true})
if err != nil {
panic(err)
}
fmt.Println(binding.Plan().ProviderModelID())
}
func exampleGoogleRouter() (*metaagent.Router, modelrouter.Selection) {
selection := modelrouter.Selection{
Provider: modelrouter.ProviderVertexAI,
LogicalModel: "gemini-flash",
}
routes, err := modelrouter.NewRegistry(modelrouter.Route{
Selection: selection,
Protocol: modelrouter.ProtocolGoogleGenAI,
ProviderModelID: "gemini-2.5-flash",
Attribution: modelrouter.Attribution{
ProviderName: "gcp.vertex_ai",
LegacySystem: "google.vertex",
},
Capabilities: modelrouter.Capabilities{MaximumOutputTokens: true},
})
if err != nil {
panic(err)
}
adapters, err := metaagent.NewGoogleGenAIAdapterRegistry(
metaagent.GoogleGenAIRegistration{
Provider: selection.Provider,
Adapter: func(_ context.Context, plan modelrouter.Plan) (metaagent.GoogleGenAIBinding, error) {
return metaagent.NewGoogleGenAIBinding(plan, &genai.Client{}, nil)
},
},
)
if err != nil {
panic(err)
}
router, err := metaagent.NewRouter(routes, metaagent.AdapterRegistries{GoogleGenAI: adapters})
if err != nil {
panic(err)
}
return router, selection
}
Output: gemini-2.5-flash
func (RouteResolution) BindSystemOne ¶ added in v0.10.142
func (r RouteResolution) BindSystemOne(ctx context.Context, requirements modelrouter.Requirements) (SystemOneBinding, error)
BindSystemOne validates the route and binds the selected provider's typed question service. It does not construct a conversational meta-agent.
func (RouteResolution) Plan ¶ added in v0.10.35
func (r RouteResolution) Plan() modelrouter.Plan
Plan returns the immutable, secret-free plan carried by r.
Example ¶
ExampleRouteResolution_Plan demonstrates inspecting the immutable, secret-free plan before constructing a provider client.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"google.golang.org/genai"
)
func main() {
router, selection := exampleGoogleRouter()
resolution, err := router.Resolve(selection)
if err != nil {
panic(err)
}
fmt.Println(resolution.Plan().ProviderModelID())
}
func exampleGoogleRouter() (*metaagent.Router, modelrouter.Selection) {
selection := modelrouter.Selection{
Provider: modelrouter.ProviderVertexAI,
LogicalModel: "gemini-flash",
}
routes, err := modelrouter.NewRegistry(modelrouter.Route{
Selection: selection,
Protocol: modelrouter.ProtocolGoogleGenAI,
ProviderModelID: "gemini-2.5-flash",
Attribution: modelrouter.Attribution{
ProviderName: "gcp.vertex_ai",
LegacySystem: "google.vertex",
},
Capabilities: modelrouter.Capabilities{MaximumOutputTokens: true},
})
if err != nil {
panic(err)
}
adapters, err := metaagent.NewGoogleGenAIAdapterRegistry(
metaagent.GoogleGenAIRegistration{
Provider: selection.Provider,
Adapter: func(_ context.Context, plan modelrouter.Plan) (metaagent.GoogleGenAIBinding, error) {
return metaagent.NewGoogleGenAIBinding(plan, &genai.Client{}, nil)
},
},
)
if err != nil {
panic(err)
}
router, err := metaagent.NewRouter(routes, metaagent.AdapterRegistries{GoogleGenAI: adapters})
if err != nil {
panic(err)
}
return router, selection
}
Output: gemini-2.5-flash
type Router ¶ added in v0.10.32
type Router struct {
// contains filtered or unexported fields
}
Router combines an immutable route registry with explicitly constructed, typed adapter registries. It contains no package-global registration state. A Router is safe for concurrent use when its registered adapters are safe for concurrent use.
func NewBedrockRuntimeRouter ¶ added in v0.10.108
NewBedrockRuntimeRouter registers the Bedrock Runtime adapters needed by exact route declarations in one AWS region and credential configuration. It supports Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses. It does not infer model IDs, load credentials, or check account-specific model access. The returned router is safe for concurrent use. Mantle requires a separate router built with NewBedrockAnthropicMessagesAdapter and NewRouterWithAdapters.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/awsauth"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func main() {
// Supply exact routes validated for your AWS account and selected API.
route := modelrouter.Route{
Selection: modelrouter.Selection{Provider: modelrouter.ProviderAWSBedrock, LogicalModel: "claude-sonnet-4-6"},
Protocol: modelrouter.ProtocolAnthropicMessages,
ProviderModelID: "anthropic.claude-sonnet-4-6",
Attribution: modelrouter.Attribution{ProviderName: "aws.bedrock", LegacySystem: "aws.bedrock"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
}
_, err := metaagent.NewBedrockRuntimeRouter(awsauth.Config{Region: "us-east-1", Profile: "development"}, route)
fmt.Println(err)
}
Output: <nil>
func NewRouter ¶ added in v0.10.32
func NewRouter(routes *modelrouter.Registry, adapters AdapterRegistries) (*Router, error)
NewRouter constructs an explicit meta-agent router.
func NewRouterWithAdapters ¶ added in v0.10.107
func NewRouterWithAdapters(routes *modelrouter.Registry, registrations AdapterRegistrations) (*Router, error)
NewRouterWithAdapters validates typed registrations and constructs their registries in one call. It does not invoke adapters or load credentials. Routes and registrations are copied; callers can reuse or modify the input slices after construction. As with NewRouter, concurrent binding requires the registered adapter functions to be safe for concurrent use.
Example ¶
ExampleNewRouterWithAdapters registers explicit Anthropic-direct configuration without separate registry construction or environment-driven routing.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/anthropicauth"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func main() {
selection := modelrouter.Selection{Provider: modelrouter.ProviderAnthropic, LogicalModel: "claude-sonnet-4-6"}
routes, err := modelrouter.NewRegistry(modelrouter.Route{
Selection: selection,
Protocol: modelrouter.ProtocolAnthropicMessages,
ProviderModelID: "claude-sonnet-4-6",
Attribution: modelrouter.Attribution{ProviderName: "anthropic", LegacySystem: "anthropic"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
})
if err != nil {
panic(err)
}
adapter, err := metaagent.NewAnthropicDirectMessagesAdapter(anthropicauth.Config{
FederationRuleID: "fdrl_0123456789",
OrganizationID: "12345678-1234-1234-1234-123456789012",
Source: anthropicauth.SourceGoogle,
})
if err != nil {
panic(err)
}
router, err := metaagent.NewRouterWithAdapters(routes, metaagent.AdapterRegistrations{
AnthropicMessages: []metaagent.AnthropicMessagesRegistration{{Provider: selection.Provider, Adapter: adapter}},
})
if err != nil {
panic(err)
}
resolution, err := router.Resolve(selection)
if err != nil {
panic(err)
}
fmt.Println(resolution.Plan().Provider())
}
Output: anthropic
func NewVertexRouter ¶ added in v0.10.107
func NewVertexRouter(projectID, region string, routes ...modelrouter.Route) (*Router, error)
NewVertexRouter constructs a router for explicitly declared Vertex AI routes in one project and region. It registers the Google Gen AI, Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses adapters needed by those routes. It neither infers routes from model names nor loads credentials; NewRouted binds only the chosen route. The returned router is safe for concurrent use.
Construct one router at application startup and share it with agent factories. Use a separate router for each project/region pair. For mixed-provider routing or custom adapter settings, use NewRouterWithAdapters with typed registrations.
Example ¶
ExampleNewVertexRouter constructs a shared router without loading credentials. In mono, obtain the declaration from models.LookupRoute instead of duplicating fleet capabilities in application code.
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func main() {
declaration := exampleVertexDeclaration()
router, err := metaagent.NewVertexRouter("my-project", "global", declaration)
if err != nil {
panic(err)
}
resolution, err := router.Resolve(declaration.Selection)
if err != nil {
panic(err)
}
fmt.Println(resolution.Plan().ProviderModelID())
}
func exampleVertexDeclaration() modelrouter.Route {
return modelrouter.Route{
Selection: modelrouter.Selection{Provider: modelrouter.ProviderVertexAI, LogicalModel: "claude-sonnet-4-6"},
Protocol: modelrouter.ProtocolAnthropicMessages,
ProviderModelID: "claude-sonnet-4-6",
Attribution: modelrouter.Attribution{ProviderName: "gcp.vertex_ai", LegacySystem: "google.vertex"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
}
}
Output: claude-sonnet-4-6
func (*Router) Resolve ¶ added in v0.10.35
func (r *Router) Resolve(selection modelrouter.Selection) (RouteResolution, error)
Resolve resolves selection without loading credentials or invoking an adapter. The returned RouteResolution can bind only the exact plan produced by this Router.
Example ¶
ExampleRouter_Resolve demonstrates resolving once and requesting the typed provider binding for that exact plan.
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
selection := modelrouter.Selection{
Provider: modelrouter.ProviderAnthropic,
LogicalModel: "claude-sonnet-4-6",
}
routes, err := modelrouter.NewRegistry(modelrouter.Route{
Selection: selection,
Protocol: modelrouter.ProtocolAnthropicMessages,
ProviderModelID: "claude-sonnet-4-6",
Attribution: modelrouter.Attribution{
ProviderName: "anthropic",
LegacySystem: "anthropic",
},
Capabilities: modelrouter.Capabilities{MaximumOutputTokens: true},
})
if err != nil {
panic(err)
}
adapters, err := metaagent.NewAnthropicMessagesAdapterRegistry(
metaagent.AnthropicMessagesRegistration{
Provider: selection.Provider,
Adapter: func(_ context.Context, plan modelrouter.Plan) (metaagent.AnthropicMessagesBinding, error) {
// Production adapters return a Messages service built from explicit
// provider credentials.
return metaagent.NewAnthropicMessagesBinding(plan, anthropic.NewMessageService(), nil)
},
},
)
if err != nil {
panic(err)
}
router, err := metaagent.NewRouter(routes, metaagent.AdapterRegistries{AnthropicMessages: adapters})
if err != nil {
panic(err)
}
resolution, err := router.Resolve(selection)
if err != nil {
panic(err)
}
binding, err := resolution.BindAnthropicMessages(context.Background(), modelrouter.Requirements{MaximumOutputTokens: true})
if err != nil {
panic(err)
}
fmt.Println(binding.Plan().ProviderModelID())
}
Output: claude-sonnet-4-6
type Runtime ¶ added in v0.10.108
type Runtime struct {
// contains filtered or unexported fields
}
Runtime owns a route catalog and reusable routers for one application startup. It is safe for concurrent use. It caches configuration, not agents, callbacks, SDK clients, or failed construction attempts. There is no global cache.
func NewRuntime ¶ added in v0.10.108
func NewRuntime(routes []modelrouter.Route, backends ...Backend) (*Runtime, error)
NewRuntime snapshots exact routes and backend registrations without loading credentials. Duplicate names, invalid registrations, and invalid routes fail here. Provider configuration is validated when its target is resolved.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func exampleRuntime() *metaagent.Runtime {
runtime, err := metaagent.NewRuntime([]modelrouter.Route{{
Selection: modelrouter.Selection{Provider: modelrouter.ProviderVertexAI, LogicalModel: "gemini-2.5-flash"},
Protocol: modelrouter.ProtocolGoogleGenAI,
ProviderModelID: "gemini-2.5-flash",
Attribution: modelrouter.Attribution{ProviderName: "gcp.vertex_ai", LegacySystem: "google.vertex"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
}}, metaagent.VertexBackend("", metaagent.VertexConfig{ProjectID: "my-project"}))
if err != nil {
panic(err)
}
return runtime
}
func main() {
runtime := exampleRuntime()
config := metaagent.TargetConfig{Provider: modelrouter.ProviderVertexAI, Model: "gemini-2.5-flash", Region: "global"}
first, selection, err := runtime.Target(config).Resolve()
if err != nil {
panic(err)
}
second, _, err := runtime.Target(config).Resolve()
if err != nil {
panic(err)
}
fmt.Println(selection.Provider, selection.LogicalModel, first == second)
}
Output: vertex gemini-2.5-flash true
func (*Runtime) Target ¶ added in v0.10.108
func (r *Runtime) Target(config TargetConfig) Target
Target describes a role's provider, model, region, and backend. Validation is deferred to Resolve or NewWithTarget so callers use normal constructor errors.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func exampleRuntime() *metaagent.Runtime {
runtime, err := metaagent.NewRuntime([]modelrouter.Route{{
Selection: modelrouter.Selection{Provider: modelrouter.ProviderVertexAI, LogicalModel: "gemini-2.5-flash"},
Protocol: modelrouter.ProtocolGoogleGenAI,
ProviderModelID: "gemini-2.5-flash",
Attribution: modelrouter.Attribution{ProviderName: "gcp.vertex_ai", LegacySystem: "google.vertex"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
}}, metaagent.VertexBackend("", metaagent.VertexConfig{ProjectID: "my-project"}))
if err != nil {
panic(err)
}
return runtime
}
func main() {
target := exampleRuntime().Target(metaagent.TargetConfig{
Provider: modelrouter.ProviderVertexAI,
Model: "gemini-2.5-flash",
Region: "global",
})
_, selection, err := target.Resolve()
if err != nil {
panic(err)
}
fmt.Println(selection.Provider)
}
Output: vertex
type SystemOneAdapter ¶ added in v0.10.142
type SystemOneAdapter func(context.Context, modelrouter.Plan) (SystemOneBinding, error)
SystemOneAdapter binds a resolved route to a provider's serving account.
type SystemOneAdapterRegistry ¶ added in v0.10.142
type SystemOneAdapterRegistry struct {
// contains filtered or unexported fields
}
SystemOneAdapterRegistry holds one adapter per serving provider.
func NewSystemOneAdapterRegistry ¶ added in v0.10.142
func NewSystemOneAdapterRegistry(registrations ...SystemOneRegistration) (*SystemOneAdapterRegistry, error)
NewSystemOneAdapterRegistry validates registrations in declaration order.
type SystemOneBinding ¶ added in v0.10.142
type SystemOneBinding struct {
// contains filtered or unexported fields
}
SystemOneBinding carries the selected route and its typed request service.
func NewSystemOneBinding ¶ added in v0.10.142
func NewSystemOneBinding(plan modelrouter.Plan, service SystemOneService, resourceLabels map[string]string) (SystemOneBinding, error)
NewSystemOneBinding validates the route and service returned by an adapter. Its service pins requests to the route's provider model ID.
func (SystemOneBinding) Plan ¶ added in v0.10.142
func (b SystemOneBinding) Plan() modelrouter.Plan
Plan returns the selected, secret-free route.
func (SystemOneBinding) ResourceLabels ¶ added in v0.10.142
func (b SystemOneBinding) ResourceLabels() map[string]string
ResourceLabels returns a copy of the provider resource labels.
func (SystemOneBinding) Service ¶ added in v0.10.142
func (b SystemOneBinding) Service() SystemOneService
Service returns the typed question service.
type SystemOneRegistration ¶ added in v0.10.142
type SystemOneRegistration struct {
Provider modelrouter.Provider
Adapter SystemOneAdapter
}
SystemOneRegistration registers a provider's System One adapter.
type SystemOneService ¶ added in v0.10.142
type SystemOneService interface {
Ask(context.Context, systemone.Request) (*systemone.Response, error)
}
SystemOneService asks typed questions against one state. A provider adapter may implement it with the System One HTTP client or its own serving API.
type Target ¶ added in v0.10.108
type Target struct {
// contains filtered or unexported fields
}
Target is an immutable selection associated with a startup Runtime. Copying it is safe; the zero value returns ErrInvalidRouter when resolved. Target creation does not validate configuration or discover credentials.
func (Target) Resolve ¶ added in v0.10.108
func (t Target) Resolve() (*Router, modelrouter.Selection, error)
Resolve returns the shared router and exact selection without binding an adapter or loading credentials. Routers are shared by backend and serving region, independent of the model. The caller must still validate its own feature requirements before binding, as NewRouted and judge.NewRouted do.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/metaagent"
"chainguard.dev/driftlessaf/agents/modelrouter"
)
func exampleRuntime() *metaagent.Runtime {
runtime, err := metaagent.NewRuntime([]modelrouter.Route{{
Selection: modelrouter.Selection{Provider: modelrouter.ProviderVertexAI, LogicalModel: "gemini-2.5-flash"},
Protocol: modelrouter.ProtocolGoogleGenAI,
ProviderModelID: "gemini-2.5-flash",
Attribution: modelrouter.Attribution{ProviderName: "gcp.vertex_ai", LegacySystem: "google.vertex"},
Capabilities: modelrouter.Capabilities{ToolCalling: true, TerminalSubmission: true},
}}, metaagent.VertexBackend("", metaagent.VertexConfig{ProjectID: "my-project"}))
if err != nil {
panic(err)
}
return runtime
}
func main() {
_, selection, err := exampleRuntime().Target(metaagent.TargetConfig{
Provider: modelrouter.ProviderVertexAI, Model: "gemini-2.5-flash", Region: "global",
}).Resolve()
if err != nil {
panic(err)
}
fmt.Println(selection.LogicalModel)
}
Output: gemini-2.5-flash
type TargetConfig ¶ added in v0.10.108
type TargetConfig struct {
Provider modelrouter.Provider `env:"PROVIDER"`
Model string `env:"MODEL"`
Region string `env:"REGION"`
Backend string `env:"BACKEND"`
// ResourceLabels are added to adapter labels without replacing provider labels.
ResourceLabels map[string]string
}
TargetConfig selects an exact provider/model pair on a configured backend. It contains no credentials and can be populated from application configuration. Backend defaults to the provider name. Region is required for Vertex AI and ignored for Anthropic-direct. For Bedrock it overrides the configured default region; one of those regions must be set. Catalog probe regions are never defaults.
type VertexConfig ¶ added in v0.10.108
type VertexConfig struct {
// ProjectID is required when resolving a Vertex AI target.
ProjectID string
}
VertexConfig configures the Google Cloud project used by Vertex AI. Authentication uses Application Default Credentials; regions belong to targets.