llmtier

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package llmtier gives the learning pipelines their model access: an explicit Cheap/Strong generator pair (plan §cost control) behind the multi-backend llmgen seam, gated by a persistent daily spend ledger. Every pipeline call goes through Tier.Generate, so no learning code can bypass the caps.

Index

Constants

This section is empty.

Variables

View Source
var ErrBackendUnavailable = errors.New("llmtier: learning backend unavailable")

ErrBackendUnavailable reports the learning backend could not be reached in a way retrying this run won't fix: the claude CLI is logged out, or the API key is missing/invalid. Workers stop the run and keep jobs queued (like ErrCapped) — and, crucially, Generate does NOT fold such a failure into the daily cap: it spent nothing and every queued job would fail identically, so counting it would let a logged-out CLI burn the whole daily_call_cap and block learning even after the user logs back in.

View Source
var ErrCapped = errors.New("llmtier: daily learning cap reached")

ErrCapped reports today's spend cap is reached. Workers treat it as "stop now, keep everything queued" — the queue drains after midnight UTC.

Functions

func IsStop added in v0.2.0

func IsStop(err error) bool

IsStop reports errors on which a worker should halt the current run and leave its jobs queued (never park them): the daily cap is reached, or the backend is unavailable. Both are transient with respect to the job itself.

Types

type DaySpend

type DaySpend struct {
	Calls      int     `json:"calls"`
	Prompt     int     `json:"prompt_tokens"`
	Completion int     `json:"completion_tokens"`
	USD        float64 `json:"usd"`
}

DaySpend is one UTC day's usage bucket.

type Ledger

type Ledger struct {
	Days map[string]DaySpend `json:"days"`
	// contains filtered or unexported fields
}

Ledger is the persistent daily spend record (state/spend.json). Its methods are safe for concurrent use so a --no-cap parallel drain can record spend from several mining goroutines at once.

func LoadLedger

func LoadLedger(stateDir string) *Ledger

LoadLedger reads the ledger; missing or corrupt files start empty (worst case today's caps reset — bounded by one day's caps, never unbounded).

func (*Ledger) Allow

func (l *Ledger) Allow(now time.Time, usdCap float64, callCap int) error

Allow returns ErrCapped (wrapped with the reason) when today's bucket is at either cap. Caps ≤ 0 mean "no cap of that kind".

func (*Ledger) Record

func (l *Ledger) Record(now time.Time, usage llmgen.Usage, usd float64)

Record folds one call into today's bucket (in memory; Save persists).

func (*Ledger) Save

func (l *Ledger) Save() error

Save writes the ledger atomically, pruning buckets past retention. The lock is held across the (small, local) file write so concurrent Saves can't interleave temp-file writes or lose an update; the slow LLM call in Tier.Generate happens outside any ledger lock.

type Tier

type Tier struct {
	Cheap  llmgen.Generator
	Strong llmgen.Generator
	// contains filtered or unexported fields
}

Tier is the resolved Cheap/Strong pair plus its spend gate.

func NewTier

func NewTier(cheap, strong llmgen.Generator, stateDir string, usdCap float64, callCap int, priced bool) *Tier

NewTier assembles a tier directly. Resolve is the config-driven path; this exists for tests and pipelines with custom backends.

func Resolve

func Resolve(lc config.LearnConfig, ollamaEndpoint, stateDir string) (*Tier, string, error)

Resolve builds the tier from config, mirroring the import backend policy: "auto" prefers the strongest thing the user already has and never errors — a nil Tier with a reason means learning quietly cannot run. Explicit providers DO error when their prerequisite is missing.

func (*Tier) Generate

func (t *Tier) Generate(ctx context.Context, strong bool, system, user, name string, schema map[string]any, out any) (llmgen.Usage, error)

Generate runs one capped structured call on the chosen tier. Usage is recorded even for failed calls — the user paid for every attempt — EXCEPT deterministic backend-unavailable failures (auth/config), which spent nothing and would otherwise let identical retries drain the cap (see isBackendUnavailable / ErrBackendUnavailable). A cap hit returns ErrCapped before any model call; the caller leaves its work queued.

Jump to

Keyboard shortcuts

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