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 ¶
- func DefaultRates() map[string]Rate
- type Pricer
- type Rate
- type Snapshot
- type Tracker
- func (t *Tracker) AddUsage(inTokens, outTokens int64)
- func (t *Tracker) AddUsageFull(inTokens, outTokens, cacheReadTokens, cacheCreationTokens int64)
- func (t *Tracker) BudgetExceeded() bool
- func (t *Tracker) RecordStreamError()
- func (t *Tracker) SetBudget(usdCap float64, onWarn, onHit func(spent, cap float64))
- func (t *Tracker) SetModel(model string)
- func (t *Tracker) Snapshot() Snapshot
- func (t *Tracker) UpdateBudgetCap(usdCap float64)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultRates ¶
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 ¶
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 ¶
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.
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
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.
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 ¶
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 ¶
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
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.
func (*Tracker) BudgetExceeded ¶ added in v0.21.0
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
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 ¶
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 ¶
Snapshot returns the current state for the /cost REPL command and the /debug view.
func (*Tracker) UpdateBudgetCap ¶ added in v0.23.0
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.