provider

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package provider implements a unified interface for creating and managing multiple LLM providers with intelligent routing, fallback strategies, and metrics tracking.

Overview

The provider package provides a consistent way to create and configure any of the supported LLM providers (Anthropic, GitHub Copilot, Ollama, OpenAI) while maintaining backward compatibility and supporting all provider-specific features. It also includes a Router component for managing multiple providers with configurable routing and fallback strategies.

Supported Providers

  • Anthropic (Claude models)
  • GitHub Copilot
  • Ollama (local models)
  • OpenAI (GPT models)

Single Provider Usage

The simplest way to create a provider is using the factory pattern with NewProvider:

model, cleanup, err := provider.NewProvider(ctx, provider.ProviderOpenAI,
	provider.WithModel("gpt-4o"),
	provider.WithTemperature(0.7),
	provider.WithAPIKey("sk-..."),
)
if err != nil {
	return err
}
defer cleanup()

response, err := model.Invoke(ctx, messages)

The factory returns three values:

  • A ChatModel instance that implements the llms.ChatModel interface
  • A cleanup function that must be called to release resources
  • An error if creation fails

Common Configuration Options

All providers support these common options:

WithModel(model string)              // Model name (e.g., "gpt-4o", "claude-3-opus")
WithTemperature(temp float64)        // Temperature (0.0-2.0)
WithMaxTokens(tokens int)            // Maximum tokens to generate
WithTopP(topP float64)               // Top-p sampling (0.0-1.0)
WithStop(sequences []string)         // Stop sequences
WithAPIKey(key string)               // API key for authentication
WithBaseURL(url string)              // Custom base URL

Provider-Specific Configuration

Provider-specific options are set using WithProviderSpecific:

// GitHub Copilot with tools
model, cleanup, err := provider.NewProvider(ctx, provider.ProviderGitHubCopilot,
	provider.WithModel("gpt-4o"),
	provider.WithProviderSpecific("tools", []tools.Tool{myTool}),
	provider.WithProviderSpecific("cli_path", "/usr/local/bin/github-copilot-cli"),
)

// Ollama with custom options
model, cleanup, err := provider.NewProvider(ctx, provider.ProviderOllama,
	provider.WithModel("llama2"),
	provider.WithProviderSpecific("keep_alive", "5m"),
	provider.WithProviderSpecific("num_ctx", 4096),
)

Multi-Provider Router

The Router manages multiple provider instances and routes requests based on configurable strategies:

router, err := provider.NewRouter(ctx,
	[]provider.ProviderEntry{
		{
			Name:         "fast-gpt",
			ProviderType: provider.ProviderOpenAI,
			Options:      []provider.ProviderOption{provider.WithModel("gpt-3.5-turbo")},
			Weight:       3,
			Tags:         []string{"fast", "cheap"},
		},
		{
			Name:         "smart-claude",
			ProviderType: provider.ProviderAnthropic,
			Options:      []provider.ProviderOption{provider.WithModel("claude-3-opus-20240229")},
			Weight:       1,
			Tags:         []string{"smart", "expensive"},
		},
	},
	&provider.WeightedStrategy{},
	provider.WithFallback(&provider.SequentialFallback{Order: []string{"fast-gpt", "smart-claude"}}),
)
if err != nil {
	return err
}
defer router.Cleanup()

// Use router like any ChatModel
response, err := router.Invoke(ctx, messages)

Routing Strategies

The package provides seven built-in routing strategies:

1. SimpleStrategy - Always routes to a specific provider:

strategy := &provider.SimpleStrategy{ProviderName: "fast-gpt"}

2. RoundRobinStrategy - Distributes requests evenly across providers:

strategy := &provider.RoundRobinStrategy{}

3. WeightedStrategy - Routes based on provider weights:

strategy := provider.NewWeightedStrategy(map[string]int{
	"fast-gpt":     3,  // 75% of requests
	"smart-claude": 1,  // 25% of requests
})

4. RuleBasedStrategy - Routes based on request characteristics:

strategy := provider.NewRuleBasedStrategy(
	[]provider.RoutingRule{
		{
			Name:     "complex-to-claude",
			Priority: 100,
			Condition: func(ctx provider.RequestContext) bool {
				return ctx.Complexity == "complex" || ctx.HasToolCalls
			},
			Provider: "smart-claude",
		},
		{
			Name:     "simple-to-gpt",
			Priority: 50,
			Condition: func(ctx provider.RequestContext) bool {
				return ctx.Complexity == "simple"
			},
			Provider: "fast-gpt",
		},
	},
	"fast-gpt", // default provider
)

5. LoadBalancedStrategy - Routes based on performance metrics:

strategy := provider.NewLoadBalancedStrategy(router.GetMetrics())

This strategy automatically selects the provider with the best combination of:

  • Lowest average latency
  • Lowest error rate
  • Least recent usage (for load distribution)

6. LLMRoutingStrategy - Uses an LLM to make intelligent routing decisions:

metaModel, cleanup, _ := provider.NewProvider(ctx, provider.ProviderOpenAI,
	provider.WithModel("gpt-4o-mini"),
)
defer cleanup()

strategy := provider.NewLLMRoutingStrategy(
	metaModel,
	[]string{"fast-gpt", "smart-claude"},
	map[string]string{
		"fast-gpt":     "Fast and cost-effective for simple queries",
		"smart-claude": "Best for complex reasoning and analysis",
	},
)

The LLM analyzes each request and selects the most appropriate provider. Decisions are cached to avoid repeated LLM calls for similar requests.

7. CustomStrategy - User-defined routing logic:

strategy := &provider.CustomStrategy{
	SelectFunc: func(ctx context.Context, reqCtx provider.RequestContext, providers map[string]llms.ChatModel) (string, error) {
		// Custom logic here
		if reqCtx.TotalTokens > 5000 {
			return "smart-claude", nil
		}
		return "fast-gpt", nil
	},
	OnSuccessFunc: func(ctx context.Context, providerName string, latency time.Duration) {
		// Track successes
	},
	OnErrorFunc: func(ctx context.Context, providerName string, err error) {
		// Track errors
	},
}

Fallback Strategies

When a provider fails, the router can automatically try alternative providers:

1. NoFallback - Never retries (default):

provider.WithFallback(&provider.NoFallback{})

2. SequentialFallback - Tries providers in order:

provider.WithFallback(&provider.SequentialFallback{
	Order: []string{"fast-gpt", "smart-claude", "local-ollama"},
})

3. SmartFallback - Selects fallback based on success rate:

provider.WithFallback(&provider.SmartFallback{})

SmartFallback uses metrics to choose the provider with the highest success rate, giving preference to recently successful providers.

Metrics Tracking

The router automatically tracks metrics for all providers:

metrics := router.GetMetrics()
for name, m := range metrics {
	fmt.Printf("Provider: %s\n", name)
	fmt.Printf("  Requests: %d\n", m.RequestCount)
	fmt.Printf("  Errors: %d\n", m.ErrorCount)
	fmt.Printf("  Avg Latency: %v\n", m.TotalLatency/time.Duration(m.RequestCount))
	fmt.Printf("  Last Used: %v\n", m.LastUsed)
}

Metrics include:

  • Request count per provider
  • Error count per provider
  • Total latency per provider
  • Last usage timestamp per provider

Request Context

The router builds a RequestContext for each request, which routing strategies use to make decisions:

type RequestContext struct {
	Messages     []core.Message  // The messages being sent
	MessageCount int             // Number of messages
	TotalTokens  int             // Estimated token count
	HasToolCalls bool            // Whether request involves tool calls
	Priority     string          // "low", "medium", "high"
	Complexity   string          // "simple", "moderate", "complex"
	UserMetadata map[string]any  // Custom metadata
}

Complexity is automatically inferred:

  • "complex": >10,000 tokens or has tool calls
  • "simple": <1,000 tokens and no tool calls
  • "moderate": everything else

Authentication

The package supports multiple authentication methods:

1. Explicit API key:

provider.WithAPIKey("sk-...")

2. Environment variables:

ANTHROPIC_API_KEY  // For Anthropic
OPENAI_API_KEY     // For OpenAI
GITHUB_TOKEN       // For GitHub Copilot

3. GitHub CLI (for Copilot):

gh auth token

Ollama doesn't require authentication.

Resource Cleanup

Always call cleanup functions to release resources:

// Single provider
model, cleanup, err := provider.NewProvider(ctx, provider.ProviderOpenAI, ...)
if err != nil {
	return err
}
defer cleanup()

// Router
router, err := provider.NewRouter(ctx, entries, strategy)
if err != nil {
	return err
}
defer router.Cleanup()

For most providers, cleanup is a no-op. For GitHub Copilot, cleanup stops the CLI server process.

Thread Safety

All components are thread-safe and support concurrent usage:

  • Multiple goroutines can invoke the same provider or router concurrently
  • Metrics updates are atomic
  • Routing strategy state is protected by mutexes

Error Handling

The package provides detailed error types:

err := provider.NewProviderError(providerType, name, operation, cause)
err := provider.NewRoutingError(operation, cause)
err := provider.NewFallbackError(failedProvider, attemptedProviders, cause)

Common errors:

  • ErrUnknownProvider: Invalid provider type
  • ErrProviderNotFound: Provider name not found in router
  • ErrNoProvidersAvailable: Router has no providers
  • ErrNoFallbackAvailable: No fallback provider available
  • ErrRouterClosed: Router has been cleaned up

Complete Example

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/LucaLanziani/langchain-go/core"
	"github.com/LucaLanziani/langchain-go/provider"
)

func main() {
	ctx := context.Background()

	// Create router with multiple providers
	router, err := provider.NewRouter(ctx,
		[]provider.ProviderEntry{
			{
				Name:         "fast",
				ProviderType: provider.ProviderOpenAI,
				Options: []provider.ProviderOption{
					provider.WithModel("gpt-3.5-turbo"),
					provider.WithTemperature(0.7),
				},
				Weight: 3,
			},
			{
				Name:         "smart",
				ProviderType: provider.ProviderAnthropic,
				Options: []provider.ProviderOption{
					provider.WithModel("claude-3-opus-20240229"),
					provider.WithMaxTokens(4096),
				},
				Weight: 1,
			},
		},
		provider.NewWeightedStrategy(map[string]int{
			"fast":  3,
			"smart": 1,
		}),
		provider.WithFallback(&provider.SequentialFallback{
			Order: []string{"fast", "smart"},
		}),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer router.Cleanup()

	// Use router like any ChatModel
	messages := []core.Message{
		core.NewHumanMessage("What is the capital of France?"),
	}

	response, err := router.Invoke(ctx, messages)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(response.GetContent())

	// Check metrics
	metrics := router.GetMetrics()
	for name, m := range metrics {
		fmt.Printf("%s: %d requests, %d errors\n", name, m.RequestCount, m.ErrorCount)
	}
}

Backward Compatibility

The package maintains full backward compatibility with existing provider-specific constructors:

// Still works
model := anthropic.New(anthropic.WithModelName("claude-3-opus-20240229"))
model := openai.New(openai.WithModelName("gpt-4o"))
model := ollama.New(ollama.WithModel("llama2"))
model, _ := copilot.New(ctx, copilot.WithModelName("gpt-4o"))

The unified interface is an addition, not a replacement.

Index

Constants

View Source
const (
	// Version is the current version of the provider package
	Version = "1.0.0"
)

Version information

Variables

View Source
var (
	// ErrUnknownProvider is returned when an invalid provider type is specified
	ErrUnknownProvider = errors.New("unknown provider type")

	// ErrInvalidConfig is returned when provider configuration is invalid
	ErrInvalidConfig = errors.New("invalid provider configuration")

	// ErrDuplicateProviderName is returned when router entries have duplicate names
	ErrDuplicateProviderName = errors.New("duplicate provider name in router entries")

	// ErrEmptyProviderList is returned when router is created with no providers
	ErrEmptyProviderList = errors.New("router requires at least one provider")

	// ErrProviderNotFound is returned when a requested provider doesn't exist
	ErrProviderNotFound = errors.New("provider not found")

	// ErrNoFallbackAvailable is returned when fallback is needed but no providers are available
	ErrNoFallbackAvailable = errors.New("no fallback provider available")

	// ErrMaxRetriesExceeded is returned when all retry attempts have been exhausted
	ErrMaxRetriesExceeded = errors.New("maximum retry attempts exceeded")

	// ErrInvalidProviderFromLLM is returned when LLM routing returns an invalid provider name
	ErrInvalidProviderFromLLM = errors.New("LLM returned invalid provider name")

	// ErrMissingRequiredField is returned when a required configuration field is missing
	ErrMissingRequiredField = errors.New("missing required configuration field")

	// ErrInvalidFieldValue is returned when a configuration field has an invalid value
	ErrInvalidFieldValue = errors.New("invalid configuration field value")

	// ErrAuthenticationFailed is returned when provider authentication fails
	ErrAuthenticationFailed = errors.New("provider authentication failed")

	// ErrProviderInitialization is returned when provider initialization fails
	ErrProviderInitialization = errors.New("provider initialization failed")

	// ErrRouterClosed is returned when operations are attempted on a closed router
	ErrRouterClosed = errors.New("router has been closed")

	// ErrNoProvidersAvailable is returned when no providers are available for routing
	ErrNoProvidersAvailable = errors.New("no providers available")
)

Sentinel errors for provider operations

Functions

func NewFallbackError

func NewFallbackError(failedProvider string, attemptedFallbacks []string, err error) error

NewFallbackError creates a new fallback error

func NewFallbackErrorWithStrategy

func NewFallbackErrorWithStrategy(failedProvider string, attemptedFallbacks []string, fallbackStrategy string, err error) error

NewFallbackErrorWithStrategy creates a new fallback error with strategy information

func NewProviderError

func NewProviderError(providerType ProviderType, providerName, operation string, err error) error

NewProviderError creates a new provider error with context

func NewProviderErrorWithContext

func NewProviderErrorWithContext(providerType ProviderType, providerName, operation string, err error, context map[string]string) error

NewProviderErrorWithContext creates a new provider error with additional context

func NewRoutingError

func NewRoutingError(strategy string, err error) error

NewRoutingError creates a new routing error

func NewRoutingErrorWithContext

func NewRoutingErrorWithContext(strategy string, availableProviders []string, requestComplexity string, err error) error

NewRoutingErrorWithContext creates a new routing error with additional context

func NewValidationError

func NewValidationError(field string, value any, message string) error

NewValidationError creates a new validation error

Types

type BatchError

type BatchError struct {
	FailedItems map[int]error
}

BatchError reports per-item failures from Router.Batch while preserving partial results.

func (*BatchError) Error

func (e *BatchError) Error() string

func (*BatchError) Unwrap

func (e *BatchError) Unwrap() error

type CleanupFunc

type CleanupFunc func() error

CleanupFunc releases provider resources (e.g., Copilot CLI server)

func NewProvider

func NewProvider(ctx context.Context, providerType ProviderType, opts ...ProviderOption) (llms.ChatModel, CleanupFunc, error)

NewProvider creates a ChatModel for the specified provider type with unified configuration. Returns the created model, a cleanup function, and an error if creation fails.

The cleanup function must be called when the model is no longer needed to release resources. For most providers (Anthropic, OpenAI, Ollama), cleanup is a no-op. For GitHub Copilot, cleanup stops the CLI server process.

Example:

model, cleanup, err := provider.NewProvider(ctx, provider.ProviderOpenAI,
    provider.WithModel("gpt-4o"),
    provider.WithTemperature(0.7),
    provider.WithAPIKey("sk-..."),
)
if err != nil {
    return err
}
defer cleanup()

type CustomStrategy

type CustomStrategy struct {
	SelectFunc    func(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)
	OnSuccessFunc func(ctx context.Context, providerName string, latency time.Duration)
	OnErrorFunc   func(ctx context.Context, providerName string, err error)
}

CustomStrategy allows user-defined routing logic

func (*CustomStrategy) OnError

func (s *CustomStrategy) OnError(ctx context.Context, providerName string, err error)

OnError calls the user-provided error callback if defined. Panics are recovered and logged but don't propagate.

func (*CustomStrategy) OnSuccess

func (s *CustomStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess calls the user-provided success callback if defined. Panics are recovered and logged but don't propagate.

func (*CustomStrategy) SelectProvider

func (s *CustomStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (providerName string, err error)

SelectProvider executes the user-provided selection function. Panics are recovered and returned as errors.

type FallbackError

type FallbackError struct {
	FailedProvider     string
	AttemptedFallbacks []string
	FallbackStrategy   string
	Err                error
}

FallbackError wraps errors that occur during fallback attempts

func (*FallbackError) Error

func (e *FallbackError) Error() string

func (*FallbackError) Unwrap

func (e *FallbackError) Unwrap() error

type FallbackStrategy

type FallbackStrategy interface {
	// GetFallbackProvider returns next provider to try after failure
	GetFallbackProvider(ctx context.Context, failedProvider string, providers map[string]llms.ChatModel) (string, error)

	// ShouldRetry determines if request should be retried
	ShouldRetry(err error, attemptCount int) bool
}

FallbackStrategy determines fallback behavior when primary provider fails

type LLMRoutingStrategy

type LLMRoutingStrategy struct {
	// contains filtered or unexported fields
}

LLMRoutingStrategy uses an LLM to make routing decisions

func (*LLMRoutingStrategy) OnError

func (s *LLMRoutingStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for LLMRoutingStrategy. The LLM makes routing decisions based on request characteristics, not historical performance.

func (*LLMRoutingStrategy) OnSuccess

func (s *LLMRoutingStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for LLMRoutingStrategy. The LLM makes routing decisions based on request characteristics, not historical performance.

func (*LLMRoutingStrategy) SelectProvider

func (s *LLMRoutingStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider uses an LLM to analyze the request and select the most appropriate provider. It caches routing decisions for similar requests to minimize LLM calls.

type LoadBalancedStrategy

type LoadBalancedStrategy struct {
	// contains filtered or unexported fields
}

LoadBalancedStrategy routes based on current load and latency

func NewLoadBalancedStrategy

func NewLoadBalancedStrategy(metrics *RouterMetrics) *LoadBalancedStrategy

NewLoadBalancedStrategy creates a new LoadBalancedStrategy.

func (*LoadBalancedStrategy) OnError

func (s *LoadBalancedStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for LoadBalancedStrategy. Metrics are updated by the router, so no additional action needed.

func (*LoadBalancedStrategy) OnSuccess

func (s *LoadBalancedStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for LoadBalancedStrategy. Metrics are updated by the router, so no additional action needed.

func (*LoadBalancedStrategy) SelectProvider

func (s *LoadBalancedStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider returns the provider with the best score. Score is calculated based on latency, error rate, and load.

type NoFallback

type NoFallback struct{}

NoFallback never retries or falls back

func (*NoFallback) GetFallbackProvider

func (n *NoFallback) GetFallbackProvider(ctx context.Context, failedProvider string, providers map[string]llms.ChatModel) (string, error)

GetFallbackProvider always returns an error (no fallback)

func (*NoFallback) ShouldRetry

func (n *NoFallback) ShouldRetry(err error, attemptCount int) bool

ShouldRetry always returns false (never retry)

type ProviderConfig

type ProviderConfig struct {
	// Common fields (applicable to all providers)
	Model       string
	Temperature *float64
	MaxTokens   *int
	TopP        *float64
	Stop        []string

	// Authentication
	APIKey string // Anthropic, OpenAI, GitHub Copilot (Ollama doesn't need auth)

	// Base URLs
	BaseURL string // Anthropic, OpenAI, Ollama

	// Provider-specific fields
	ProviderSpecific map[string]any
}

ProviderConfig holds unified configuration for all providers

type ProviderEntry

type ProviderEntry struct {
	Name         string           // Unique identifier (e.g., "fast-openai", "smart-anthropic")
	ProviderType ProviderType     // Type of provider
	Options      []ProviderOption // Configuration options
	Weight       int              // Weight for weighted routing (default: 1)
	Tags         []string         // Tags for categorization (e.g., "fast", "cheap", "smart")
}

ProviderEntry defines a provider configuration for the router

type ProviderError

type ProviderError struct {
	ProviderType ProviderType
	ProviderName string
	Operation    string
	Err          error
	// Additional context for debugging (never includes sensitive data)
	Context map[string]string
}

ProviderError wraps errors with provider context

func (*ProviderError) Error

func (e *ProviderError) Error() string

func (*ProviderError) Unwrap

func (e *ProviderError) Unwrap() error

type ProviderMetrics

type ProviderMetrics struct {
	RequestCount   int64
	ErrorCount     int64
	CancelledCount int64
	TotalLatency   time.Duration
	LastUsed       time.Time
}

ProviderMetrics holds metrics for a single provider

type ProviderOption

type ProviderOption func(*ProviderConfig)

ProviderOption configures the unified provider

func WithAPIKey

func WithAPIKey(apiKey string) ProviderOption

WithAPIKey sets the API key for authentication

func WithAnthropicVersion

func WithAnthropicVersion(version string) ProviderOption

WithAnthropicVersion sets the Anthropic API version

func WithBaseURL

func WithBaseURL(baseURL string) ProviderOption

WithBaseURL sets the base URL for the provider API

func WithCLIPath

func WithCLIPath(cliPath string) ProviderOption

WithCLIPath sets the path to the GitHub Copilot CLI executable

func WithFormat

func WithFormat(format string) ProviderOption

WithFormat sets the response format for Ollama Currently supports "json" for JSON-formatted responses

func WithKeepAlive

func WithKeepAlive(keepAlive string) ProviderOption

WithKeepAlive sets the keep_alive duration for Ollama models Controls how long the model stays loaded in memory Examples: "5m", "10m", "-1" (keep forever), "0" (unload immediately)

func WithLogLevel

func WithLogLevel(logLevel string) ProviderOption

WithLogLevel sets the log level for GitHub Copilot CLI Valid values: "debug", "info", "warn", "error"

func WithMaxTokens

func WithMaxTokens(maxTokens int) ProviderOption

WithMaxTokens sets the maximum number of tokens to generate

func WithModel

func WithModel(model string) ProviderOption

WithModel sets the model name for the provider

func WithNumCtx

func WithNumCtx(numCtx int) ProviderOption

WithNumCtx sets the context window size for Ollama models Determines how many tokens the model can consider

func WithOrganization

func WithOrganization(organization string) ProviderOption

WithOrganization sets the OpenAI organization ID

func WithProviderSpecific

func WithProviderSpecific(key string, value any) ProviderOption

WithProviderSpecific adds a provider-specific configuration option

func WithStop

func WithStop(stop []string) ProviderOption

WithStop sets the stop sequences

func WithTemperature

func WithTemperature(temperature float64) ProviderOption

WithTemperature sets the temperature parameter (0.0 to 2.0)

func WithTools

func WithTools(tools ...tools.Tool) ProviderOption

WithTools sets the tools available to GitHub Copilot

func WithTopK

func WithTopK(topK int) ProviderOption

WithTopK sets the top-k sampling parameter for Ollama Limits the next token selection to the K most likely tokens

func WithTopP

func WithTopP(topP float64) ProviderOption

WithTopP sets the top-p sampling parameter (0.0 to 1.0)

type ProviderStats

type ProviderStats struct {
	ProviderName   string        // Name of the provider
	RequestCount   int64         // Total number of requests
	ErrorCount     int64         // Total number of errors
	CancelledCount int64         // Total number of cancelled requests
	SuccessCount   int64         // Total number of successful requests
	TotalLatency   time.Duration // Cumulative latency
	AverageLatency time.Duration // Average latency per request
	ErrorRate      float64       // Error rate (0.0 to 1.0)
	CancelledRate  float64       // Cancelled rate (0.0 to 1.0)
	SuccessRate    float64       // Success rate (0.0 to 1.0)
	LastUsed       time.Time     // Last usage timestamp
}

ProviderStats contains computed statistics for a single provider

type ProviderType

type ProviderType string

ProviderType identifies which LLM provider to use

const (
	ProviderAnthropic     ProviderType = "anthropic"
	ProviderGitHubCopilot ProviderType = "github-copilot"
	ProviderOllama        ProviderType = "ollama"
	ProviderOpenAI        ProviderType = "openai"
)

type RequestContext

type RequestContext struct {
	Messages     []core.Message
	MessageCount int
	TotalTokens  int // Estimated
	HasToolCalls bool
	Priority     string // "low", "medium", "high"
	Complexity   string // "simple", "moderate", "complex"
	UserMetadata map[string]any
}

RequestContext provides metadata about a request for routing decisions

type RoundRobinStrategy

type RoundRobinStrategy struct {
	// contains filtered or unexported fields
}

RoundRobinStrategy distributes requests evenly across providers

func (*RoundRobinStrategy) OnError

func (s *RoundRobinStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for RoundRobinStrategy.

func (*RoundRobinStrategy) OnSuccess

func (s *RoundRobinStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for RoundRobinStrategy.

func (*RoundRobinStrategy) SelectProvider

func (s *RoundRobinStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider returns providers in round-robin order. The distribution is guaranteed to be even across all providers over time.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router manages multiple providers and routes requests between them Implements llms.ChatModel interface for transparent usage

func NewRouter

func NewRouter(ctx context.Context, entries []ProviderEntry, strategy RoutingStrategy, opts ...RouterOption) (*Router, error)

NewRouter creates a router that manages multiple providers. It validates that all provider entries have unique names and creates all providers using the factory. If any provider fails to initialize, all successfully created providers are cleaned up before returning an error.

The router implements the llms.ChatModel interface, allowing it to be used transparently in place of a single provider.

Example:

router, err := provider.NewRouter(ctx,
	[]provider.ProviderEntry{
		{Name: "openai", ProviderType: provider.ProviderOpenAI, Options: []provider.ProviderOption{provider.WithModel("gpt-4o")}},
		{Name: "anthropic", ProviderType: provider.ProviderAnthropic, Options: []provider.ProviderOption{provider.WithModel("claude-3-opus")}},
	},
	&provider.SimpleStrategy{ProviderName: "openai"},
)
if err != nil {
	return err
}
defer router.Cleanup()

func (*Router) Batch

func (r *Router) Batch(ctx context.Context, inputs [][]core.Message, opts ...core.Option) ([]*core.AIMessage, error)

Batch implements the core.Runnable interface. It processes multiple message sets in parallel using the routing strategy.

func (*Router) BindTools

func (r *Router) BindTools(tools ...llms.ToolDefinition) llms.ChatModel

BindTools implements the llms.ChatModel interface. It binds tools to all providers managed by the router.

func (*Router) Cleanup

func (r *Router) Cleanup() error

Cleanup releases all resources held by the router and its providers. It calls the cleanup function for every provider it manages.

Cleanup is idempotent - it can be called multiple times safely. If called while requests are in flight, those requests may fail.

Returns the first error encountered during cleanup, but continues cleaning up remaining providers.

func (*Router) Generate

func (r *Router) Generate(ctx context.Context, messages []core.Message, opts ...core.Option) (*llms.ChatResult, error)

Generate implements the llms.ChatModel interface. It selects a provider using the routing strategy and generates a response.

func (*Router) GetMetrics

func (r *Router) GetMetrics() map[string]ProviderMetrics

GetMetrics returns a copy of the current routing metrics. Returns nil if the router has been cleaned up.

func (*Router) GetName

func (r *Router) GetName() string

GetName implements the core.Runnable interface.

func (*Router) GetProvider

func (r *Router) GetProvider(name string) llms.ChatModel

GetProvider returns the ChatModel for a specific provider by name. Returns nil if the provider doesn't exist or the router has been cleaned up.

func (*Router) Invoke

func (r *Router) Invoke(ctx context.Context, messages []core.Message, opts ...core.Option) (*core.AIMessage, error)

Invoke implements the core.Runnable interface. It selects a provider using the routing strategy and invokes it.

func (*Router) ListProviders

func (r *Router) ListProviders() []string

ListProviders returns the names of all providers managed by this router. Returns nil if the router has been cleaned up.

func (*Router) Stream

func (r *Router) Stream(ctx context.Context, messages []core.Message, opts ...core.Option) (*core.StreamIterator[*core.AIMessage], error)

Stream implements the core.Runnable interface. It selects a provider using the routing strategy and streams from it.

func (*Router) WithStructuredOutput

func (r *Router) WithStructuredOutput(schema map[string]any) llms.ChatModel

WithStructuredOutput implements the llms.ChatModel interface. It configures structured output for all providers managed by the router.

type RouterConfig

type RouterConfig struct {
	FallbackStrategy FallbackStrategy
	EnableMetrics    bool
	MaxRetries       int
	RetryDelay       time.Duration
}

RouterConfig holds router configuration

type RouterMetrics

type RouterMetrics struct {
	RequestCount   map[string]int64         // Requests per provider
	ErrorCount     map[string]int64         // Errors per provider
	CancelledCount map[string]int64         // Cancelled streams per provider
	TotalLatency   map[string]time.Duration // Total latency per provider
	LastUsed       map[string]time.Time     // Last usage timestamp
	// contains filtered or unexported fields
}

RouterMetrics tracks routing statistics

func (*RouterMetrics) GetAllStats

func (m *RouterMetrics) GetAllStats() map[string]*ProviderStats

GetAllStats returns computed statistics for all providers. Returns an empty map if no providers have been tracked.

func (*RouterMetrics) GetStats

func (m *RouterMetrics) GetStats(providerName string) *ProviderStats

GetStats returns computed statistics for a specific provider. Returns nil if the provider doesn't exist in the metrics.

func (*RouterMetrics) Reset

func (m *RouterMetrics) Reset(providerName string)

Reset clears all metrics for a specific provider. This is useful for resetting statistics without recreating the router.

func (*RouterMetrics) ResetAll

func (m *RouterMetrics) ResetAll()

ResetAll clears all metrics for all providers.

type RouterOption

type RouterOption func(*RouterConfig)

RouterOption configures the router

type RoutingError

type RoutingError struct {
	Strategy           string
	AvailableProviders []string
	RequestComplexity  string
	Err                error
}

RoutingError wraps errors that occur during request routing

func (*RoutingError) Error

func (e *RoutingError) Error() string

func (*RoutingError) Unwrap

func (e *RoutingError) Unwrap() error

type RoutingRule

type RoutingRule struct {
	Name      string
	Condition func(RequestContext) bool
	Provider  string
	Priority  int // Higher priority rules evaluated first
}

RoutingRule defines a condition and target provider

type RoutingStrategy

type RoutingStrategy interface {
	// SelectProvider chooses a provider for the given request
	SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

	// OnSuccess is called after a successful request
	OnSuccess(ctx context.Context, providerName string, latency time.Duration)

	// OnError is called after a failed request
	OnError(ctx context.Context, providerName string, err error)
}

RoutingStrategy determines which provider to use for a request

type RuleBasedStrategy

type RuleBasedStrategy struct {
	// contains filtered or unexported fields
}

RuleBasedStrategy routes based on request characteristics

func NewRuleBasedStrategy

func NewRuleBasedStrategy(rules []RoutingRule, defaultProvider string) *RuleBasedStrategy

NewRuleBasedStrategy creates a new RuleBasedStrategy. Rules are automatically sorted by priority (highest first).

func (*RuleBasedStrategy) AddRule

func (s *RuleBasedStrategy) AddRule(rule RoutingRule)

AddRule adds a new rule to the strategy. Rules are automatically re-sorted by priority.

func (*RuleBasedStrategy) GetRules

func (s *RuleBasedStrategy) GetRules() []RoutingRule

GetRules returns a copy of all rules.

func (*RuleBasedStrategy) OnError

func (s *RuleBasedStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for RuleBasedStrategy.

func (*RuleBasedStrategy) OnSuccess

func (s *RuleBasedStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for RuleBasedStrategy.

func (*RuleBasedStrategy) RemoveRule

func (s *RuleBasedStrategy) RemoveRule(name string)

RemoveRule removes a rule by name.

func (*RuleBasedStrategy) SelectProvider

func (s *RuleBasedStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider evaluates rules in priority order and returns the first match. If no rules match, returns the default provider.

type SequentialFallback

type SequentialFallback struct {
	Order []string
}

SequentialFallback tries providers in order

func (*SequentialFallback) GetFallbackProvider

func (s *SequentialFallback) GetFallbackProvider(ctx context.Context, failedProvider string, providers map[string]llms.ChatModel) (string, error)

GetFallbackProvider returns the next provider in the configured order Never returns the failed provider

func (*SequentialFallback) ShouldRetry

func (s *SequentialFallback) ShouldRetry(err error, attemptCount int) bool

ShouldRetry returns true if there are more providers to try

type SimpleStrategy

type SimpleStrategy struct {
	ProviderName string
}

SimpleStrategy always routes to a specific provider

func (*SimpleStrategy) OnError

func (s *SimpleStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for SimpleStrategy.

func (*SimpleStrategy) OnSuccess

func (s *SimpleStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for SimpleStrategy.

func (*SimpleStrategy) SelectProvider

func (s *SimpleStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider returns the configured provider name.

type SmartFallback

type SmartFallback struct {
	// contains filtered or unexported fields
}

SmartFallback uses metrics to choose best fallback

func (*SmartFallback) GetFallbackProvider

func (s *SmartFallback) GetFallbackProvider(ctx context.Context, failedProvider string, providers map[string]llms.ChatModel) (string, error)

GetFallbackProvider selects the best alternative provider based on metrics Never returns the failed provider

func (*SmartFallback) ShouldRetry

func (s *SmartFallback) ShouldRetry(err error, attemptCount int) bool

ShouldRetry returns true if the error is retryable and attempt count is reasonable

type ValidationError

type ValidationError struct {
	Field   string
	Value   any
	Message string
}

ValidationError represents a configuration validation error

func (*ValidationError) Error

func (e *ValidationError) Error() string

type WeightedStrategy

type WeightedStrategy struct {
	// contains filtered or unexported fields
}

WeightedStrategy routes based on provider weights

func NewWeightedStrategy

func NewWeightedStrategy(weights map[string]int) *WeightedStrategy

NewWeightedStrategy creates a new WeightedStrategy with the given weights. If a provider is not in the weights map, it defaults to weight 1.

func (*WeightedStrategy) GetWeight

func (s *WeightedStrategy) GetWeight(providerName string) int

GetWeight returns the weight for a provider.

func (*WeightedStrategy) OnError

func (s *WeightedStrategy) OnError(ctx context.Context, providerName string, err error)

OnError is a no-op for WeightedStrategy.

func (*WeightedStrategy) OnSuccess

func (s *WeightedStrategy) OnSuccess(ctx context.Context, providerName string, latency time.Duration)

OnSuccess is a no-op for WeightedStrategy.

func (*WeightedStrategy) SelectProvider

func (s *WeightedStrategy) SelectProvider(ctx context.Context, reqCtx RequestContext, providers map[string]llms.ChatModel) (string, error)

SelectProvider returns a provider based on weighted random selection. The probability of selecting a provider is proportional to its weight.

func (*WeightedStrategy) SetWeight

func (s *WeightedStrategy) SetWeight(providerName string, weight int)

SetWeight updates the weight for a provider. This allows dynamic adjustment of routing weights.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL