router

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

README

Router

The router package adapts gateway requests to the pure route planner and the attempt executor. It does not own model capabilities, prices, context limits, or provider offerings. Starmap owns those facts through one immutable routable snapshot.

Routing behavior

  • A single model selects matching provider offerings from the snapshot.
  • A models array sets explicit model order and fallback order.
  • openrouter/auto lets the planner consider any routable model in the snapshot. In a mixed array, explicit models stay ahead of the automatic fallback set.
  • Provider order, only, and ignore rules are request policy.
  • Tenant model and provider restrictions are hard constraints.
  • Measured latency, Starmap price facts, required capabilities, context size, and provider affinity determine the stable order within one model rank.
  • The executor owns the total retry and fallback budget for streaming and non-streaming calls.

Ownership

  • internal/catalog publishes the generation-consistent Starmap snapshot.
  • internal/routing plans immutable attempts without network or mutable state.
  • internal/availability owns runtime offering health.
  • internal/execution runs the plan within one budget.
  • internal/providers/connectors adapts each provider transport.

Run the package contracts with:

go test ./internal/router ./internal/routing

Documentation

Overview

Package router provides model routing and fallback capabilities for the Starport gateway.

Package router provides model routing and fallback capabilities for the Starport gateway. It implements OpenRouter-compatible routing with provider preferences, health tracking, latency-based routing, cost optimization, and sticky sessions for conversation continuity.

Index

Constants

View Source
const (
	// AutoModelID is the special model ID for automatic routing
	AutoModelID = "openrouter/auto"
)

Variables

View Source
var (
	// ErrNoModelsAvailable is returned when no models can be used
	ErrNoModelsAvailable = errors.New("no models available for routing")
	// ErrAllModelsFailed is returned when all models in the chain failed
	ErrAllModelsFailed = errors.New("all models failed")
)

Functions

This section is empty.

Types

type APIKeyConfig

type APIKeyConfig struct {
	// Allowed providers for this API key
	AllowedProviders []string

	// Allowed models for this API key
	AllowedModels []string

	// Model-specific overrides
	ModelOverrides map[string]string

	// Rate limit tier
	RateLimitTier string

	// CredentialStrategy selects request-bound operator and tenant credential order.
	CredentialStrategy byok.Strategy
}

APIKeyConfig contains API key specific routing configuration

type Config

type Config struct {
	// Latency tracking configuration
	LatencyAlpha      float64 // EMA smoothing factor (0-1)
	LatencyWindowSize int     // Samples before EMA kicks in

	// Cost optimization
	EnableCostOptimization bool

	// Sticky sessions
	EnableStickySessions bool
	SessionTTL           time.Duration

	// Execution owns the one total retry and fallback budget.
	Execution execution.Config

	// Availability owns exact offering circuit state.
	Availability availability.Config
}

Config contains configuration for the router

type EMALatencyTracker

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

EMALatencyTracker implements LatencyTracker using exponential moving average

func (*EMALatencyTracker) GetAllLatencies

func (t *EMALatencyTracker) GetAllLatencies() map[string]time.Duration

GetAllLatencies returns latencies for all tracked providers

func (*EMALatencyTracker) GetLatency

func (t *EMALatencyTracker) GetLatency(provider string) time.Duration

GetLatency returns the current EMA latency for a provider

func (*EMALatencyTracker) RecordLatency

func (t *EMALatencyTracker) RecordLatency(provider string, latency time.Duration)

RecordLatency records a latency measurement for a provider

func (*EMALatencyTracker) Reset

func (t *EMALatencyTracker) Reset()

Reset clears all latency data

type EmbeddingRequest added in v1.0.2

type EmbeddingRequest struct {
	*connectors.EmbeddingsRequest
	APIKeyConfig *APIKeyConfig
	TenantID     string
}

EmbeddingRequest contains one provider-neutral embedding request plus tenant routing and credential policy.

type EmbeddingResponse added in v1.0.2

type EmbeddingResponse struct {
	Response        inference.EmbeddingResponse
	ModelUsed       string
	ProviderUsed    string
	Attempts        int
	Metadata        *Metadata
	CatalogSnapshot *runtimecatalog.RoutableSnapshot
}

EmbeddingResponse wraps one embedding result with route evidence.

type LatencyTracker

type LatencyTracker interface {
	// RecordLatency records a latency measurement for a provider
	RecordLatency(provider string, latency time.Duration)

	// GetLatency returns the current EMA latency for a provider
	GetLatency(provider string) time.Duration

	// GetAllLatencies returns latencies for all tracked providers
	GetAllLatencies() map[string]time.Duration

	// Reset clears all latency data
	Reset()
}

LatencyTracker tracks provider latencies using exponential moving average (EMA)

func NewLatencyTracker

func NewLatencyTracker(alpha float64, windowSize int) LatencyTracker

NewLatencyTracker creates a new EMA-based latency tracker

type Metadata

type Metadata struct {
	// Models that were tried
	ModelsAttempted []ModelAttempt `json:"models_attempted"`

	// Total routing time
	RoutingDuration time.Duration `json:"routing_duration_ms"`

	// Reason for final model selection
	SelectionReason string `json:"selection_reason"`
}

Metadata contains detailed routing information

type ModelAttempt

type ModelAttempt struct {
	Model    string        `json:"model"`
	Provider string        `json:"provider"`
	Error    string        `json:"error,omitempty"`
	Duration time.Duration `json:"duration_ms"`
	Status   string        `json:"status"` // "success", "failed", "skipped"
}

ModelAttempt records an attempt to use a specific model

type ModelRouter

type ModelRouter interface {
	// SelectModel chooses the best model based on the request and routing strategy
	// Returns the selected model ID and the connector to use
	SelectModel(ctx context.Context, req *Request) (modelID string, connector connectors.Connector, err error)

	// RouteWithFallback attempts to route a request through multiple models with fallback logic
	// Returns the response and which model was actually used
	RouteWithFallback(ctx context.Context, req *Request) (*Response, error)

	// RouteStream executes the same immutable route plan and budget for streaming.
	RouteStream(ctx context.Context, req *Request) (execution.ManagedStream, error)

	// RouteEmbeddings executes one embedding request through the same route,
	// credential, availability, and total-attempt policies as chat requests.
	RouteEmbeddings(ctx context.Context, req *EmbeddingRequest) (*EmbeddingResponse, error)
}

ModelRouter handles model selection, fallback logic, and provider routing

func New

func New(registry connectors.Registry, opts ...Option) ModelRouter

New creates a new model router with all features enabled by default

type Option

type Option func(*modelRouter)

Option configures the transitional router composition.

func WithAvailability

func WithAvailability(tracker *availability.Tracker) Option

WithAvailability supplies the one runtime offering availability owner.

func WithCatalog

func WithCatalog(catalogPlane *runtimecatalog.ControlPlane) Option

WithCatalog supplies the shared generation-consistent routable snapshot.

func WithExecutionConfig

func WithExecutionConfig(config execution.Config) Option

WithExecutionConfig replaces the total attempt budget.

func WithUserCredentials added in v1.0.2

func WithUserCredentials(resolver UserCredentialResolver) Option

WithUserCredentials supplies the tenant-scoped inference credential plane.

type ProviderPreferences

type ProviderPreferences struct {
	// Try providers in this order
	Order []string `json:"order,omitempty"`

	// Only use these providers
	Only []string `json:"only,omitempty"`

	// Never use these providers
	Ignore []string `json:"ignore,omitempty"`

	// Allow fallback to other providers not in order list
	AllowFallbacks bool `json:"allow_fallbacks,omitempty"`
}

ProviderPreferences controls which providers can be used

type Request

type Request struct {
	// Original chat request
	*connectors.ChatRequest

	// Models to try in order (fallback chain)
	Models []string

	// Provider routing preferences
	ProviderPreferences *ProviderPreferences

	// API key configuration (for provider restrictions)
	APIKeyConfig *APIKeyConfig

	// TenantID selects the exact user-scoped provider credential record.
	TenantID string

	// Request metadata for routing decisions
	Metadata *RequestMetadata

	// PrepareAttempt optionally adjusts the provider request for the selected
	// model immediately before invoking the connector.
	PrepareAttempt func(route routing.Route, req *connectors.ChatRequest) *connectors.ChatRequest
}

Request contains the original request plus routing preferences

type RequestMetadata

type RequestMetadata struct {
	// Estimated tokens in the request
	EstimatedTokens int

	// Required features (e.g., "vision", "function_calling")
	RequiredFeatures []string

	// Conversation ID for sticky routing
	ConversationID string

	// User preferences
	UserPreferences map[string]any
}

RequestMetadata contains information for routing decisions

type Response

type Response struct {
	// The actual response from the model
	*connectors.ChatResponse

	// Which model was actually used
	ModelUsed string `json:"model_used"`

	// Provider that handled the request
	ProviderUsed string `json:"provider_used"`

	// Number of attempts made
	Attempts int `json:"attempts"`

	// Routing metadata
	Metadata *Metadata `json:"metadata,omitempty"`

	// CatalogSnapshot is the exact leased runtime generation that produced the
	// response.
	CatalogSnapshot *runtimecatalog.RoutableSnapshot `json:"-"`
}

Response wraps the chat response with routing metadata

type StickyProviderSessionManager

type StickyProviderSessionManager interface {
	// GetProvider returns the provider for a conversation, if any
	GetProvider(conversationID string) (string, bool)

	// SetProvider sets the provider for a conversation
	SetProvider(conversationID string, provider string)

	// RemoveSession removes a conversation's sticky session
	RemoveSession(conversationID string)

	// CleanupExpired removes expired sessions
	CleanupExpired()
}

StickyProviderSessionManager manages conversation-to-provider mappings

func NewStickyProviderSessionManager

func NewStickyProviderSessionManager(ttl time.Duration) StickyProviderSessionManager

NewStickyProviderSessionManager creates a new sticky session manager

type UserCredentialResolver added in v1.0.2

type UserCredentialResolver interface {
	ResolveUserMaterial(context.Context, string, catalogs.Provider) (credentials.Material, error)
}

UserCredentialResolver resolves one exact tenant record against the provider contract retained by the request's runtime generation.

Jump to

Keyboard shortcuts

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