cost

package
v0.392.0 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package cost tracks Anthropic token usage and running dollar cost per PromptZero session, and implements the simple "consecutive errors → offline" heuristic that flips the observability offline banner.

Pricer is a read-only rate table: model name → USD per million tokens (input/output split). PromptZero ships with built-in rates for the current Claude lineup; operators can override or extend the table via config.

Tracker accumulates tokens and stream errors. When three consecutive streams fail within a 60s window, Tracker flips to offline and invokes the Offline hook; a successful stream clears the error run and flips back online. The three-strikes rule keeps transient network hiccups from flipping the banner on every stutter.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultRates

func DefaultRates() map[string]Rate

DefaultRates returns a copy of the built-in rate table. Current Claude lineup as of late-2025: Opus 4.7 $15/$75, Sonnet 4.6 $3/$15, Haiku 4.5 $0.80/$4. Values should track Anthropic's public pricing page; adjust via config override when it drifts.

Types

type Pricer

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

Pricer owns the rate table. Lookup is case-insensitive and falls through on unknown models to (0, 0) so the Tracker still records token counts even when the rate isn't known.

func NewPricer

func NewPricer(overrides map[string]Rate) *Pricer

NewPricer seeds a Pricer with DefaultRates plus any overrides. Keys are normalized (trimmed, lower-cased) so "Claude-Opus-4-7" and "claude-opus-4-7" resolve to the same row.

func (*Pricer) Cost

func (p *Pricer) Cost(model string, inTokens, outTokens int64) float64

Cost computes USD for (input, output) token counts against the model's rates. Zero rates produce zero cost.

func (*Pricer) CostWithCache added in v0.3.0

func (p *Pricer) CostWithCache(model string, inTokens, outTokens, cacheReadTokens, cacheCreationTokens int64) float64

CostWithCache is Cost plus prompt-cache read and creation tokens. Cache reads are billed at 0.1x the normal input rate; cache creations at 1.25x. The multipliers match Anthropic's published pricing as of late 2025; if they drift, this is the only place to update.

func (*Pricer) Rate

func (p *Pricer) Rate(model string) (Rate, bool)

Rate returns the per-million-token rates for the given model. Unknown models return zero rates (and ok=false); callers typically still record the token counts with zero cost.

type Rate

type Rate struct {
	InputPerMTok  float64
	OutputPerMTok float64
}

Rate is one model's price schedule. Values are USD per million tokens.

type Snapshot

type Snapshot struct {
	Model               string
	InputTokens         int64
	OutputTokens        int64
	CacheReadTokens     int64
	CacheCreationTokens int64
	TotalUSD            float64
	Offline             bool
	// BudgetUSD is the configured session cap; 0 means no budget.
	// /cost and /status render the spent/cap pair when non-zero.
	BudgetUSD float64
}

Snapshot is a point-in-time copy of the Tracker's accumulated state.

func (Snapshot) CacheHitRate added in v0.3.0

func (s Snapshot) CacheHitRate() float64

CacheHitRate returns the fraction of prompt-cacheable input tokens that landed on an existing cache (vs. paid full-price for cache creation). Returns 0 when neither counter has moved yet so fresh sessions don't render a divide-by-zero. Intended for /stats and dashboard display.

func (Snapshot) Format

func (s Snapshot) Format() string

Format returns the single-line human summary used by /cost and /status.

type Tracker

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

Tracker accumulates token counts, dollar cost, and stream error streaks. It is safe for concurrent use. A zero-value Tracker is NOT usable — call NewTracker.

func NewTracker

func NewTracker(p *Pricer, model string, onOffline func(bool)) *Tracker

NewTracker builds a Tracker bound to a specific model. The offline hook is invoked (with the new state) on every transition — pass nil to disable. Model can be changed later via SetModel when the user picks a new default mid-session.

func (*Tracker) AddUsage

func (t *Tracker) AddUsage(inTokens, outTokens int64)

AddUsage records one response's input/output token counts and bumps the running USD total. Any successful usage record also clears the consecutive-error run and flips the tracker back online if it was offline. Prefer AddUsageFull for callers that have cache token counters — this wrapper ignores them.

func (*Tracker) AddUsageFull added in v0.3.0

func (t *Tracker) AddUsageFull(inTokens, outTokens, cacheReadTokens, cacheCreationTokens int64)

AddUsageFull is the complete version of AddUsage that also records prompt-cache read / creation tokens. Cache-read tokens are billed at ~10 % of the normal input rate (Anthropic's current published number); cache-creation tokens are billed at ~125 % to amortise the cache write. Model rates default to uncached input pricing if no cache rate is configured, so the dollar line is always conservative.

Pricing uses the Tracker's configured model. Callers that know the per-call model (e.g. agent.Usage.Model from a tier-routed turn) should use AddUsageFullForModel so persona-defined tier overrides (claude-haiku for the classify tier, etc.) are priced correctly.

func (*Tracker) AddUsageFullForModel added in v0.195.0

func (t *Tracker) AddUsageFullForModel(model string, inTokens, outTokens, cacheReadTokens, cacheCreationTokens int64)

AddUsageFullForModel is AddUsageFull with an explicit per-call model for pricing. When model is "" the Tracker's configured model is used (matches AddUsageFull behaviour). When model is set, the per-call model wins over t.model for the price calc — token counters and the displayed Snapshot.Model stay tied to the tracker's primary model, so the dashboard shows the user-configured base model while the bill reflects actual tier routing.

Pre-fix, every persona that routed the plan tier to a cheaper model (Haiku for read-only defender personas, Sonnet for plan-tier downshift) silently still got billed at the operator's --model rate, often overstating cost 5x.

func (*Tracker) BudgetExceeded added in v0.21.0

func (t *Tracker) BudgetExceeded() bool

BudgetExceeded reports whether the session has crossed the configured 100% cap. Returns false when no budget is set. Used by the agent's pre-dispatch check to refuse new turns once the cap is exhausted.

func (*Tracker) RecordStreamError

func (t *Tracker) RecordStreamError()

RecordStreamError notifies the tracker that one Messages.NewStreaming call failed. Three failures inside errRunWindow flip offline.

func (*Tracker) SetBudget added in v0.21.0

func (t *Tracker) SetBudget(usdCap float64, onWarn, onHit func(spent, cap float64))

SetBudget configures a session USD cap and the callbacks that fire at the 80%-warn and 100%-cap thresholds. usdCap == 0 disables the budget entirely (default). Either callback may be nil.

The 80% threshold fires once per session; the 100% threshold fires once. Re-entering thresholds after a budget bump (e.g. operator raises the cap with /budget set) requires resetting the flags via SetBudget — passing usdCap >= current spend resets warned/hit automatically.

func (*Tracker) SetModel

func (t *Tracker) SetModel(model string)

SetModel updates the tracker's active model. Past usage stays attributed to the prior model's cost — only future AddUsage calls pick up the new rate.

func (*Tracker) Snapshot

func (t *Tracker) Snapshot() Snapshot

Snapshot returns the current state for the /cost REPL command and the /debug view.

func (*Tracker) UpdateBudgetCap added in v0.23.0

func (t *Tracker) UpdateBudgetCap(usdCap float64)

UpdateBudgetCap changes the configured USD cap without touching the warn/hit callbacks (which were wired once at setup time). When the new cap clears the current spend the warned/hit flags reset so a future re-cross fires a fresh notification — matching SetBudget's "operator bumps the cap" behaviour. Setting cap to 0 disables the budget gate entirely. Used by the /budget REPL command.

Jump to

Keyboard shortcuts

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