package providers import ( "context" "encoding/json" "git.gobha.me/xcaliber/chat-switchboard/models" ) // ── 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 provider_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 config JSONB } // ── Request / Response Types ──────────────── // Message represents a chat message in the conversation. type Message struct { Role string `json:"role"` // user, assistant, system, tool Content string `json:"content"` // Tool calling fields (assistant → tool_calls, tool → tool_call_id) ToolCalls []ToolCall `json:"tool_calls,omitempty"` // set when assistant requests tools ToolCallID string `json:"tool_call_id,omitempty"` // set for role="tool" result messages Name string `json:"name,omitempty"` // tool name for role="tool" } // ToolCall represents a function call requested by the LLM. type ToolCall struct { ID string `json:"id"` Type string `json:"type"` // "function" Function FunctionCall `json:"function"` } // FunctionCall is the function name and JSON arguments. type FunctionCall struct { Name string `json:"name"` Arguments string `json:"arguments"` } // ToolDef describes a tool available to the LLM. type ToolDef struct { Type string `json:"type"` // "function" Function FunctionDef `json:"function"` } // FunctionDef is the schema for a tool function. type FunctionDef struct { Name string `json:"name"` Description string `json:"description"` Parameters json.RawMessage `json:"parameters"` } // 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"` Tools []ToolDef `json:"tools,omitempty"` // available tools for function calling } // 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"` ToolCalls []ToolCall `json:"tool_calls,omitempty"` // set when finish_reason is "tool_calls" } // StreamEvent is a single chunk from a streaming response. type StreamEvent struct { Delta string `json:"delta,omitempty"` Reasoning string `json:"reasoning,omitempty"` Done bool `json:"done,omitempty"` FinishReason string `json:"finish_reason,omitempty"` ToolCalls []ToolCall `json:"tool_calls,omitempty"` Model string `json:"model,omitempty"` 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 models.ModelCapabilities `json:"capabilities"` Pricing *models.ModelPricing `json:"pricing,omitempty"` }