package providers import ( "context" ) // ── Provider Interface ────────────────────── // Provider is the contract for LLM API adapters. type Provider interface { // ID returns the provider identifier (e.g. "openai", "anthropic"). ID() string // ChatCompletion sends a non-streaming request and returns the full response. ChatCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (*CompletionResponse, error) // StreamCompletion sends a streaming request and returns a channel of events. // The channel is closed when the stream ends. Errors are sent as StreamEvents. StreamCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (<-chan StreamEvent, error) // ListModels returns available models from this provider. ListModels(ctx context.Context, cfg ProviderConfig) ([]Model, error) } // ── Configuration ─────────────────────────── // ProviderConfig holds credentials and endpoint for a configured provider. // Populated from the api_configs table at call time. type ProviderConfig struct { Endpoint string APIKey string CustomHeaders map[string]string // Extra HTTP headers (e.g. OpenRouter HTTP-Referer) Settings map[string]interface{} // Provider-specific settings from provider_settings JSONB } // ── Request / Response Types ──────────────── // Message represents a chat message in the conversation. type Message struct { Role string `json:"role"` // user, assistant, system Content string `json:"content"` } // CompletionRequest is the normalized request sent to any provider. type CompletionRequest struct { Model string `json:"model"` Messages []Message `json:"messages"` MaxTokens int `json:"max_tokens,omitempty"` Temperature *float64 `json:"temperature,omitempty"` TopP *float64 `json:"top_p,omitempty"` Stream bool `json:"stream,omitempty"` } // CompletionResponse is the normalized non-streaming response. type CompletionResponse struct { Content string `json:"content"` Model string `json:"model"` FinishReason string `json:"finish_reason"` InputTokens int `json:"input_tokens"` OutputTokens int `json:"output_tokens"` } // StreamEvent is a single chunk from a streaming response. type StreamEvent struct { // Delta is the incremental text content (empty for non-content events). Delta string `json:"delta,omitempty"` // Done is true when the stream is complete. Done bool `json:"done,omitempty"` // FinishReason is set on the final event. FinishReason string `json:"finish_reason,omitempty"` // Model echoes back the model used. Model string `json:"model,omitempty"` // Error is set if the stream encountered an error. Error error `json:"-"` } // Model represents an available model from a provider, with capabilities. type Model struct { ID string `json:"id"` Name string `json:"name,omitempty"` OwnedBy string `json:"owned_by,omitempty"` Capabilities ModelCapabilities `json:"capabilities"` Pricing *ModelPricing `json:"pricing,omitempty"` } // ModelPricing holds per-million-token costs. type ModelPricing struct { InputPerM float64 `json:"input_per_m,omitempty"` OutputPerM float64 `json:"output_per_m,omitempty"` }