Skip to main content

Provider Registry

The provider registry allows you to register and access AI providers globally.

Registry Functions​

The package-level functions operate on a shared global registry:

// Register a provider in the global registry
func RegisterProvider(name string, p provider.Provider)

// Get a registered provider from the global registry
func GetProvider(name string) (provider.Provider, error)

// Resolve a "provider:model" string directly to a model, using the global registry
func ResolveLanguageModel(model string) (provider.LanguageModel, error)
func ResolveEmbeddingModel(model string) (provider.EmbeddingModel, error)
func ResolveImageModel(model string) (provider.ImageModel, error)
func ResolveSpeechModel(model string) (provider.SpeechModel, error)
func ResolveTranscriptionModel(model string) (provider.TranscriptionModel, error)
func ResolveRerankingModel(model string) (provider.RerankingModel, error)

// GetGlobalRegistry returns the shared *Registry instance the above functions use
func GetGlobalRegistry() *Registry

NoSuchProviderError is returned when a provider ID can't be resolved or doesn't support the requested model type:

type NoSuchProviderError struct {
ProviderID string
ModelID string
ModelType string
AvailableProviders []string
Reason string
}

Registry Type​

For an isolated registry (instead of the shared global one), use NewRegistry:

func NewRegistry(opts ...RegistryOption) *Registry

func WithSeparator(separator string) RegistryOption // default ":"
func WithLanguageModelMiddleware(mw ...*middleware.LanguageModelMiddleware) RegistryOption
func WithImageModelMiddleware(mw ...*middleware.ImageModelMiddleware) RegistryOption

*Registry exposes the same operations as methods: RegisterProvider, GetProvider, ListProviders, ResolveLanguageModel, ResolveEmbeddingModel, ResolveImageModel, ResolveSpeechModel, ResolveTranscriptionModel, ResolveRerankingModel, plus alias and tool helpers (RegisterAlias, ListAliases, RegisterTool, LookupTool, ListTools).

Examples​

Registering Providers​

package main

import (
"github.com/digitallysavvy/go-ai/pkg/providers/anthropic"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
"github.com/digitallysavvy/go-ai/pkg/registry"
)

func main() {
// Register OpenAI
registry.RegisterProvider("openai", openai.New(openai.Config{
APIKey: "openai-key",
}))

// Register Anthropic
registry.RegisterProvider("anthropic", anthropic.New(anthropic.Config{
APIKey: "anthropic-key",
}))
}

Getting Providers​

// Get a provider by name
p, err := registry.GetProvider("openai")
if err != nil {
log.Fatal(err)
}

// Get a model
model, err := p.LanguageModel("gpt-4")
if err != nil {
log.Fatal(err)
}

Resolving a "provider:model" String Directly​

// Equivalent to GetProvider("openai") then LanguageModel("gpt-4")
model, err := registry.ResolveLanguageModel("openai:gpt-4")
if err != nil {
log.Fatal(err)
}

Listing Registered Providers​

providers := registry.GetGlobalRegistry().ListProviders()
fmt.Println("Available providers:")
for _, name := range providers {
fmt.Printf(" - %s\n", name)
}

Checking Provider Existence​

There's no dedicated Has-style check; call GetProvider and inspect the error:

if _, err := registry.GetProvider("openai"); err == nil {
fmt.Println("OpenAI is registered")
}

Using with Configuration​

type Config struct {
ProviderName string
ModelID string
}

func getModel(cfg Config) (provider.LanguageModel, error) {
p, err := registry.GetProvider(cfg.ProviderName)
if err != nil {
return nil, fmt.Errorf("provider not found: %w", err)
}

model, err := p.LanguageModel(cfg.ModelID)
if err != nil {
return nil, fmt.Errorf("model not found: %w", err)
}

return model, nil
}

// Usage
config := Config{
ProviderName: "openai",
ModelID: "gpt-4",
}

model, err := getModel(config)
if err != nil {
log.Fatal(err)
}

Dynamic Provider Selection​

func generateWithProvider(providerName, modelID, prompt string) (string, error) {
// Get provider from registry
p, err := registry.GetProvider(providerName)
if err != nil {
return "", fmt.Errorf("provider %s not found: %w", providerName, err)
}

// Get model
model, err := p.LanguageModel(modelID)
if err != nil {
return "", fmt.Errorf("model %s not found: %w", modelID, err)
}

// Generate
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
return "", err
}

return result.Text, nil
}

// Usage
text, err := generateWithProvider("openai", "gpt-4", "Hello!")

Multi-Provider Setup​

func setupProviders(config map[string]string) error {
providers := map[string]provider.Provider{
"openai": openai.New(openai.Config{
APIKey: config["openai_key"],
}),
"anthropic": anthropic.New(anthropic.Config{
APIKey: config["anthropic_key"],
}),
"google": google.New(google.Config{
APIKey: config["google_key"],
}),
}

for name, p := range providers {
registry.RegisterProvider(name, p)
}

return nil
}

// Usage
config := map[string]string{
"openai_key": os.Getenv("OPENAI_API_KEY"),
"anthropic_key": os.Getenv("ANTHROPIC_API_KEY"),
"google_key": os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY"),
}

if err := setupProviders(config); err != nil {
log.Fatal(err)
}

Provider Fallback​

func generateWithFallback(modelConfigs []struct{ Provider, Model string }, prompt string) (string, error) {
var lastErr error

for _, cfg := range modelConfigs {
p, err := registry.GetProvider(cfg.Provider)
if err != nil {
lastErr = err
continue
}

model, err := p.LanguageModel(cfg.Model)
if err != nil {
lastErr = err
continue
}

result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
})
if err != nil {
lastErr = err
continue
}

return result.Text, nil
}

return "", fmt.Errorf("all providers failed: %w", lastErr)
}

// Usage with fallback chain
configs := []struct{ Provider, Model string }{
{"openai", "gpt-4"},
{"anthropic", "claude-3-opus"},
{"google", "gemini-pro"},
}

text, err := generateWithFallback(configs, "Hello!")

Error Handling​

_, err := registry.GetProvider("unknown")
if err != nil {
var notFound *registry.NoSuchProviderError
if errors.As(err, &notFound) {
log.Printf("Provider %q is not registered (available: %v)", notFound.ProviderID, notFound.AvailableProviders)
} else {
log.Fatal("Registry error:", err)
}
}

See Also​