Help us shape the future of Go! Take the 2026 Go Developer Survey

ai

package
v0.36.21 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package ai hosts the hot-swappable LLM provider adapters (OpenAI, Anthropic, Google Gemini) used across Rivolt: weekly digest, trip planning, charging strategy, and anomaly explanations.

The code in this file is provider-agnostic. Domain features (digest, planner, coach) live in their own files and build on top of Provider.

Anthropic Claude Messages API provider.

Docs: https://docs.anthropic.com/en/api/messages

Google Gemini generateContent API provider.

Docs: https://ai.google.dev/api/generate-content

Model listing helpers — one per provider. Each returns the set of model IDs that can serve generateContent / chat completions, so the UI can offer a dropdown instead of asking the operator to type a model name.

These are plain functions (not methods on *Provider) because the settings UI needs to list models even when the selected model would otherwise be invalid — we don't want to construct a full provider just to list.

OpenAI Chat Completions provider. No SDK — one tiny HTTP call keeps the dependency surface small and makes auditing trivial.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComputeCost

func ComputeCost(provider, model string, inTokens, outTokens int64) float64

ComputeCost returns the USD cost of a call using real token counts and the provider's published per-1M-token price. Unknown models fall back to a conservative rate so the dashboard shows *something*.

func ListAnthropicModels

func ListAnthropicModels(ctx context.Context, apiKey string) ([]string, error)

ListAnthropicModels returns every model the Anthropic Messages API advertises. All of them support messages, so no client-side filtering.

func ListGeminiModels

func ListGeminiModels(ctx context.Context, apiKey string) ([]string, error)

ListGeminiModels returns the Gemini models that support generateContent, with the "models/" prefix stripped. Gemma and preview-only variants are included too — the user can pick, we don't gatekeep.

func ListOpenAIModels

func ListOpenAIModels(ctx context.Context, apiKey string) ([]string, error)

ListOpenAIModels returns the subset of OpenAI models usable with chat completions. We filter client-side since /v1/models returns every model including embeddings, moderation, TTS, etc.

func SplitModelName

func SplitModelName(name string) (provider, model string)

SplitModelName decomposes a Provider.Name() result (e.g. "anthropic:claude-haiku-4-5") into provider and model. Unknown shapes return (name, "").

Types

type Analyzer

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

Analyzer wraps a Provider. It exists so call sites can hot-swap the backing provider without plumbing the raw Provider through every handler. Settings manager owns the single *Analyzer instance and rebuilds it when the operator changes API key / provider / model.

func NewAnalyzer

func NewAnalyzer(p Provider) *Analyzer

NewAnalyzer returns an analyzer backed by p. p must be non-nil; the settings manager guards against that before calling.

func (*Analyzer) Complete

func (a *Analyzer) Complete(ctx context.Context, system, user string) (string, TokenUsage, error)

Complete is a convenience passthrough so domain code doesn't have to reach into Provider directly.

func (*Analyzer) ModelName

func (a *Analyzer) ModelName() string

ModelName is the "provider:model" short identifier used in logs.

func (*Analyzer) Provider

func (a *Analyzer) Provider() Provider

Provider returns the underlying Provider so callers that need full control (custom prompts, streaming) can reach through.

type AnthropicConfig

type AnthropicConfig struct {
	APIKey   string // required
	Model    string // default "claude-3-5-haiku-latest"
	Endpoint string
	Version  string // x-api-key header version, default "2023-06-01"
	Timeout  time.Duration
}

AnthropicConfig configures the provider. Zero values pick sensible defaults.

type AnthropicProvider

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

AnthropicProvider calls the Anthropic Messages API.

func NewAnthropic

func NewAnthropic(cfg AnthropicConfig) (*AnthropicProvider, error)

NewAnthropic constructs a provider. Returns an error if no API key is set.

func (*AnthropicProvider) Complete

func (p *AnthropicProvider) Complete(ctx context.Context, system, user string) (string, TokenUsage, error)

Complete sends a system+user prompt pair and returns the assistant text along with real token usage parsed from the Anthropic response.

func (*AnthropicProvider) Name

func (p *AnthropicProvider) Name() string

Name reports a stable identifier for cache keying.

type CostBreak

type CostBreak struct {
	Calls        int     `json:"calls"`
	InputTokens  int64   `json:"input_tokens"`
	OutputTokens int64   `json:"output_tokens"`
	CostUSD      float64 `json:"cost_usd"`
	LastUsedUnix int64   `json:"last_used_unix,omitempty"`
}

CostBreak is the per-slice rollup shown in the dashboard.

type GeminiConfig

type GeminiConfig struct {
	APIKey   string // required
	Model    string // default "gemini-1.5-flash"
	Endpoint string // v1beta base URL; default official endpoint
	Timeout  time.Duration
}

GeminiConfig configures the provider.

type GeminiProvider

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

GeminiProvider calls the Google Generative Language API.

func NewGemini

func NewGemini(cfg GeminiConfig) (*GeminiProvider, error)

NewGemini constructs a provider. Returns an error if no API key is set.

func (*GeminiProvider) Complete

func (p *GeminiProvider) Complete(ctx context.Context, system, user string) (string, TokenUsage, error)

Complete sends the prompt pair and returns the assistant text along with real token usage from the response.

Gemini has no separate "system" role; we fold it into the request as system_instruction which is the documented equivalent.

func (*GeminiProvider) Name

func (p *GeminiProvider) Name() string

Name reports a stable identifier for cache keying.

type OpenAIConfig

type OpenAIConfig struct {
	APIKey   string // required
	Model    string // default "gpt-4o-mini"
	Endpoint string // default official OpenAI chat endpoint
	Timeout  time.Duration
}

OpenAIConfig configures the provider. Zero values pick sensible defaults.

type OpenAIProvider

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

OpenAIProvider calls the OpenAI Chat Completions API.

func NewOpenAI

func NewOpenAI(cfg OpenAIConfig) (*OpenAIProvider, error)

NewOpenAI constructs a provider. Returns an error if no API key is set.

func (*OpenAIProvider) Complete

func (p *OpenAIProvider) Complete(ctx context.Context, system, user string) (string, TokenUsage, error)

Complete sends a system+user prompt pair and returns the assistant text along with real token usage from the response.

func (*OpenAIProvider) Name

func (p *OpenAIProvider) Name() string

Name reports a stable identifier for cache keying.

type Provider

type Provider interface {
	// Complete sends a system+user prompt pair and returns the assistant
	// text along with real token usage parsed from the provider response.
	// Implementations MUST return usage whenever the API gives it to them;
	// a zero-valued TokenUsage is only acceptable when the upstream
	// response omitted the counts (fall back to zeros, never estimate).
	Complete(ctx context.Context, system, user string) (string, TokenUsage, error)
	// Name returns a short identifier (e.g. "openai:gpt-4o-mini") used
	// for cache keys and usage accounting. Changing model invalidates
	// downstream caches automatically.
	Name() string
}

Provider is the minimal contract every LLM backend must implement.

type Record

type Record struct {
	Time         time.Time
	Provider     string // openai, anthropic, gemini
	Model        string // gpt-4o-mini, claude-haiku-4-5, ...
	Feature      string // analyze, coach, compare, digest, ask, name, transcribe, image
	InputTokens  int64
	OutputTokens int64
	DurationMs   int64
	ShotID       string
	OK           bool
	Err          string
}

Record is the event we log for each LLM call.

type Recorder

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

Recorder persists AI call metadata to SQLite.

func NewRecorder

func NewRecorder(db *sql.DB) (*Recorder, error)

NewRecorder wires a Recorder to an already-open *sql.DB (we reuse the shots database to avoid a second file).

func (*Recorder) Record

func (r *Recorder) Record(ctx context.Context, rec Record)

Record stores a single call. Failures in the recorder are logged but never bubble up — we don't want telemetry to break user-facing flows.

func (*Recorder) Summarize

func (r *Recorder) Summarize(ctx context.Context, days, recent int) (*UsageSummary, error)

Summarize returns rollups for the last `days` days plus the N most recent raw records. `days<=0` means "all time".

type TokenUsage

type TokenUsage struct {
	InputTokens  int64 `json:"input_tokens"`
	OutputTokens int64 `json:"output_tokens"`
}

TokenUsage is the real input/output token count reported by a provider for a single call. Zero values mean the provider didn't report counts.

type UsageSummary

type UsageSummary struct {
	Since        time.Time            `json:"since"`
	TotalCalls   int                  `json:"total_calls"`
	TotalCostUSD float64              `json:"total_cost_usd"`
	ByProvider   map[string]CostBreak `json:"by_provider"`
	ByFeature    map[string]CostBreak `json:"by_feature"`
	ByModel      map[string]CostBreak `json:"by_model"`
	Recent       []Record             `json:"recent"` // newest first
}

UsageSummary aggregates recent activity for the dashboard.

Jump to

Keyboard shortcuts

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