cost

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package cost tracks per-turn token usage and dollar cost across providers. The Tracker is process-local, thread-safe, and consumed by both the TUI status bar (for live session total) and the cost-monitor pane (for the historical breakdown view).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddLifetime

func AddLifetime(in, out int)

AddLifetime bumps persisted totals and writes the file atomically. I/O errors are swallowed: a missing or unwritable home should never crash a turn, and on next start the counter just stays at the last successful sum.

func AppendUsage added in v0.1.1

func AppendUsage(r UsageRecord)

AppendUsage appends one usage line. Unlike the lifetime counter this log is append-only — a single O_APPEND write of a short line is atomic on local filesystems, so a crash mid-write can at worst leave one trailing partial line, which the reader skips. I/O errors are swallowed: a missing or unwritable home must never crash a turn.

func FormatLifetimeTokens

func FormatLifetimeTokens(total int64) string

FormatLifetimeTokens compacts a token count for banner display: thousands as K, millions as M, billions as B. Two significant digits below 10, one digit above so the column doesn't grow as totals climb.

func LifetimeTotals

func LifetimeTotals() (in, out int64)

LifetimeTotals returns persisted input/output token totals across every bee session that ever called AddLifetime.

func ResetLifetimeForTest

func ResetLifetimeForTest()

ResetLifetimeForTest clears the cached load so the next call re-reads from disk. Test-only; production never hot-reloads.

func ResetUsageForTest added in v0.1.1

func ResetUsageForTest()

ResetUsageForTest removes the usage log so a test starts from empty. Test- only; resolves the same path AppendUsage writes to.

func SortedKeys

func SortedKeys[V any](m map[string]V) []string

SortedKeys returns map keys sorted alphabetically — convenience for deterministic rendering in the TUI pane.

Types

type Event

type Event struct {
	Time     time.Time
	Provider string
	Model    string
	Input    int
	Output   int
	USD      float64
}

Event is a single usage record produced after a provider stream finishes.

type Price

type Price struct {
	InputPerM  float64
	OutputPerM float64
}

Price is per-million-token rates for one model.

func Lookup

func Lookup(provider, model string) (Price, bool)

Lookup returns pricing for (provider, model). Tries the most specific key first (provider+model), then bare model, then a stripped path-suffix (openrouter returns "vendor/model" ids). Returns false when nothing matches — caller treats that as zero-cost.

func SetPrice

func SetPrice(model string, p Price) Price

SetPrice overrides a model's pricing in the active table. Returns the previous value so a caller can restore it. Useful for tests and for surfacing a /price command later.

type Summary

type Summary struct {
	Calls  int
	Input  int
	Output int
	USD    float64
}

Summary aggregates Events along some dimension.

type Tracker

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

Tracker is the in-memory store. Append-only; never persisted.

func New

func New() *Tracker

New returns an empty tracker.

func (*Tracker) ByModel

func (t *Tracker) ByModel() map[string]Summary

ByModel groups events by model id.

func (*Tracker) ByProvider

func (t *Tracker) ByProvider() map[string]Summary

ByProvider groups events by provider name.

func (*Tracker) Events

func (t *Tracker) Events() []Event

Events returns a snapshot copy of every recorded event.

func (*Tracker) Filter

func (t *Tracker) Filter(provider, model string) []Event

Filter narrows events by provider and/or model. Empty string = no filter on that dimension.

func (*Tracker) LastInput

func (t *Tracker) LastInput() int

LastInput returns the InputTokens of the most recent event, or 0 when the tracker is empty. Used by the TUI to estimate current context fill — each turn re-sends the full conversation so the latest input count approximates live context usage.

func (*Tracker) Record

func (t *Tracker) Record(provider, model string, in, out int) Event

Record computes cost from the active pricing table and appends an event. Unknown models fall back to zero-cost so unpriced local models still log token totals without polluting the dollar figure.

func (*Tracker) Reset

func (t *Tracker) Reset()

Reset drops every recorded event so a fresh session starts at zero. Used by /new and /clear to bring the context-fill indicator back to 0%.

func (*Tracker) SetEstimatedInput

func (t *Tracker) SetEstimatedInput(n int)

SetEstimatedInput stores an override that LastInput returns until the next Record call overwrites it. /compact uses this so the context-fill indicator drops to the post-compact estimate immediately, instead of staying frozen at the prior turn's input until the next assistant reply.

func (*Tracker) Total

func (t *Tracker) Total() Summary

Total returns the rollup of every recorded event.

type UsageRecord added in v0.1.1

type UsageRecord struct {
	Time         time.Time `json:"t"` // UTC, turn completion
	Provider     string    `json:"provider"`
	Model        string    `json:"model"`
	Input        int       `json:"in"`
	Output       int       `json:"out"`
	Cached       int       `json:"cached,omitempty"`   // cached input tokens, if reported
	USD          float64   `json:"usd,omitempty"`      // cost for this turn
	CostReported bool      `json:"reported,omitempty"` // true => provider $, false => static estimate
}

UsageRecord is one completed-turn usage line in the append-only usage log. One JSON object per line. Optionals carry omitempty so lines stay small.

func ReadUsage added in v0.1.1

func ReadUsage() ([]UsageRecord, error)

ReadUsage loads and parses the whole usage log once. Returns (nil, nil) when the file is absent so callers degrade gracefully. Unparseable lines (e.g. a partial trailing line from a crash) are skipped. Past the soft cap only the tail is read.

type UsageWindow added in v0.1.1

type UsageWindow struct {
	Total      Summary
	ByProvider map[string]Summary
	ByModel    map[string]Summary
	Series     []float64 // per-bucket token totals (oldest→newest) for a sparkline
	Estimated  bool      // true if any included record's cost was a static estimate
}

UsageWindow is the rollup for one time horizon.

func Aggregate added in v0.1.1

func Aggregate(recs []UsageRecord, window time.Duration, now time.Time, buckets int) UsageWindow

Aggregate rolls records into one window: a record is included when window <= 0 (all-time) or its age is within [0, window]. buckets controls Series resolution; pass 0 to skip the series.

func UsageOverview added in v0.1.1

func UsageOverview() (day, week, month, all UsageWindow, err error)

UsageOverview reads the log once and returns the four standard windows: last 24h, last 7d, last 30d, all-time.

Jump to

Keyboard shortcuts

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