The layers
catalog & pi — Wire It Together
Two ways to connect credentials, providers, and models: let pi decide, or own the registry with catalog
- Choosing between pkg/pi and pkg/catalog as your entry point
- Understanding what a model spec string resolves against
- Outgrowing environment-variable auto-detection
You can connect credentials, providers, models, and agents with pkg/pi or
pkg/catalog.
Both entry points fill the same registry. A spec string resolves to model
metadata and one provider, which bind into an ai.LanguageModel. The agent
layers build on that binding.
Let pi decide
// No registry, no provider construction: the first call detects both.msg, err := pi.GenerateText(ctx, "openai-completions/gpt-5-mini", pi.Prompt{ Messages: []pi.Message{ai.UserMessage("Say hello.")},})
a, err := pi.DurableAgent(ctx, "anthropic-messages/claude-sonnet-4-6", durable.WithStore(store), durable.WithSessionID("ticket-8472"),)The detection chain runs in this order, and the first match wins.
| Order | Source | Provider ID |
|---|---|---|
| 1 | ANTHROPIC_API_KEY or OAuth token | anthropic-messages |
| 2 | OPENROUTER_API_KEY | openai-responses |
| 3 | OPENAI_OAUTH_TOKEN | openai-responses |
| 4 | OPENAI_API_KEY | openai-completions |
| 5 | GOOGLE_API_KEY | google |
pi.AddDetector(myStoredLogin) // higher priority, before the first resolution
d, err := pi.Detect("") // which source answeredfmt.Println(d.Name, d.Source)GenerateText, GenerateObject, GenerateImage, GenerateSpeech, StreamText,
Agent, and DurableAgent all run through the process-wide Default catalog.
Own the wiring with catalog
cat := catalog.New()cat.RegisterTextProvider(openai.ID, prov, openai.Models()...)cat.RegisterAgent("claude-cli", claude.Factory) // a spec prefix names a kind// ... RegisterImageProvider, RegisterSpeechProvider, RegisterModel
model, err := cat.LanguageModel("openai-completions/gpt-5-mini")a, err := cat.Agent("claude-cli/sonnet", agent.WithMaxTurns(20))A Catalog keeps one provider map per capability — text, image, and speech — and
one shared model index. Nothing is process-wide, so a test registry and a
production registry can live in the same binary.
Move from pi to catalog
Move when you need more than auto-detection: several credentials for one provider, a custom base URL, a private provider, a test registry, or an explicit agent factory.
msg, err := pi.GenerateText(ctx, spec, prompt)msg, err := cat.GenerateText(ctx, spec, prompt)Your specs, prompts, and agent options do not change. You replace implicit registration with explicit registration.