usage

package
v0.1.457 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package usage keeps the token count of every call the gateway serves, so magpie can show what each agent and model consumed and roughly what it cost. Records go to one JSON-lines file next to providers.json; nothing leaves the machine.

Index

Constants

This section is empty.

Variables

View Source
var Agents func() []Known

Agents lists the agents magpie knows. Package agent sets it from each agent's own description, so they are listed in one place only.

View Source
var CSVHeader = []string{"time", "agent", "requested_model", "provider", "host", "model", "served_model", "swapped",
	"effort", "input_tokens", "output_tokens", "cache_write_tokens", "cache_read_tokens", "reasoning_tokens",
	"cost_usd", "duration_ms", "ttft_ms", "status", "error", "session", "kind"}

CSVHeader is the ledger's columns, as WriteCSV writes them.

View Source
var Periods = []Period{Today, Week, Month, All}

Periods lists the windows in order.

Functions

func AgentOf

func AgentOf(ua string) string

AgentOf names the agent behind a client User-Agent. Known agents map to their magpie id; anything else keeps its product name.

func Append

func Append(r Record)

Append writes one record. Errors are swallowed: accounting must never break a call.

func FormatCost added in v0.1.404

func FormatCost(amountUSD float64, currency string, rate float64) string

FormatCost renders a list-price cost, kept in USD everywhere it's stored, as the CLI and TUI show it: at amountUSD's own price when currency isn't "cny", else converted at rate (CNY per one USD, from internal/fx; a rate of 0 or below also falls back to USD, a stale or missing rate being no reason to hide the number). Whole dollars or yuan above 100, cents above 1, else thousandths, so a fraction of a cent still shows as something.

func LastSeen added in v0.1.91

func LastSeen(agent string) time.Time

LastSeen is when a request from the agent last reached the gateway: this process's own, else the newest in the log's last stretch. Zero if none.

func Ledger added in v0.1.408

func Ledger(p Period, f Filter) (rows []Row, sum Totals, agents []string)

Ledger is the calls of a period that the filter keeps, newest first, with their sum, and the agents that made any call in the period (their ids, for a filter to offer).

func Path

func Path() string

Path is the log file: ~/.config/magpie/usage.jsonl (XDG-aware).

func Saw added in v0.1.91

func Saw(agent string)

Saw notes a request from an agent arriving now.

func Swapped added in v0.1.408

func Swapped(sent, served string) bool

Swapped reports whether served is another model than sent: not the same name, however dated, pinned or prefixed. A vendor's "auto" (Copilot's, Cursor's) asked it to pick, so whichever answers wasn't swapped in.

func Vias added in v0.1.284

func Vias(since time.Time) map[string][]Via

Vias is what the gateway sent each session's calls to since a time, by agent id and the session's id ("codex|<id>"), the most calls first.

func WriteCSV added in v0.1.408

func WriteCSV(w io.Writer, rows []Row) error

WriteCSV writes rows as CSV, a header first: times in RFC 3339 with their offset, the cost in USD at list price (empty when unknown), error "true" for a call answered with a status of 400 or more.

Types

type Filter added in v0.1.408

type Filter struct {
	Agent  string
	Failed bool
	Query  string
}

Filter narrows the ledger: to one agent (its id, as AgentOf gives it), to the failed calls, and to the rows whose models, provider, host or session hold Query (any case).

type Group

type Group struct {
	ID       string `json:"id"`
	Provider string `json:"provider,omitempty"` // models only
	Model    string `json:"model,omitempty"`
	// Host is where the calls went, when the provider's id has gone to
	// more than one place, or elsewhere than the provider goes now: its
	// calls are then told apart by it, not summed under the id.
	Host string `json:"host,omitempty"`
	// Agent is the agent a session is of (sessions only).
	Agent string `json:"agent,omitempty"`
	Totals
}

Group is the share of one agent or model.

type Known added in v0.1.43

type Known struct {
	ID    string
	Names []string // its id and aliases, which a record may already carry
	UA    []string // what its User-Agent begins with
}

Known is an agent as its requests name it.

type Period

type Period string

Period is a window of time to sum over.

const (
	Today Period = "today"
	Week  Period = "7d"
	Month Period = "30d"
	All   Period = "all"
)

func (Period) Since added in v0.1.408

func (p Period) Since(now time.Time) time.Time

Since is when the period began, as of now; zero for all.

type Point

type Point struct {
	Label string    `json:"label"`
	Time  time.Time `json:"time"`
	Totals
}

Point is one bar of the timeline.

type Record

type Record struct {
	Time     time.Time `json:"t"`
	Agent    string    `json:"agent"` // magpie agent id, or the client's product name
	Provider string    `json:"provider"`
	Host     string    `json:"host,omitempty"` // where the call went: provider.Where then
	Model    string    `json:"model"`          // the provider's model id
	// Requested is the model id the agent asked for (a magpie alias, a
	// routing group, provider/model…), and Served the model the vendor's
	// reply says answered, when it named one: a ledger to set beside the
	// vendor's own bill. Neither is in a record written before they were.
	Requested  string `json:"req,omitempty"`
	Served     string `json:"served,omitempty"`
	Input      int    `json:"in"`
	Output     int    `json:"out"`
	CacheRead  int    `json:"cache_read,omitempty"`
	CacheWrite int    `json:"cache_write,omitempty"`
	Reasoning  int    `json:"reasoning,omitempty"`
	// Effort is the reasoning the model was asked for — a routing group's
	// pick for the turn, or the agent's own — as it takes it; "" for none
	Effort string `json:"effort,omitempty"`
	Millis int64  `json:"ms"`
	// TTFT: ms from the request to its reply's first content — text,
	// reasoning or a tool call — and FirstText to its first text, counted
	// as Millis is, so Millis-TTFT is how long the reply took to write;
	// none for a reply that wasn't streamed (#196)
	TTFT      int64 `json:"ttft_ms,omitempty"`
	FirstText int64 `json:"first_text_ms,omitempty"`
	Status    int   `json:"status"`
	// Session is the conversation the call was part of, as its agent names
	// it (X-Magpie-Session, or the session header Claude Code, Codex or
	// OpenCode sends): several sessions on one model told apart
	Session string `json:"session,omitempty"`
	// Kind is what the agent made the call for when it isn't a turn of
	// the conversation: a Codex subagent's (review, compact, guardian…)
	Kind string `json:"kind,omitempty"`
}

Record is one call.

func Load

func Load(since time.Time) []Record

Load reads every record since a time (zero means all), oldest first.

type Row added in v0.1.408

type Row struct {
	Record
	// Cost is the call's list price in USD, when its model's is known
	// (Priced); Swapped: the reply named another model than Model
	Cost    float64 `json:"cost"`
	Priced  bool    `json:"priced"`
	Swapped bool    `json:"swapped,omitempty"`
}

Row is one call as the ledger lists it.

type Summary

type Summary struct {
	Period Period    `json:"period"`
	Since  time.Time `json:"since"`
	Totals
	Bucket string  `json:"bucket"` // hour | day | week
	Series []Point `json:"series"`
	Agents []Group `json:"agents"`
	Models []Group `json:"models"`
	// Sessions are the calls that named their session, by session.
	Sessions []Group `json:"sessions"`
}

Summary is a period, summed up.

func Summarize

func Summarize(p Period) Summary

Summarize sums the log over a period, as of now.

type Totals

type Totals struct {
	Calls      int     `json:"calls"`
	Errors     int     `json:"errors"`
	Input      int     `json:"input"`
	Output     int     `json:"output"`
	CacheRead  int     `json:"cache_read"`
	CacheWrite int     `json:"cache_write"`
	Reasoning  int     `json:"reasoning"`
	Cost       float64 `json:"cost"`     // USD at list prices, for the priced calls
	Unpriced   int     `json:"unpriced"` // calls with tokens but no known price
	// Timed: the answered calls whose first token was timed (streamed),
	// TTFT the sum of their ttft_ms; DecodeMs the time from it to the end
	// of those that wrote any, over which DecodeOut tokens came: their
	// mean wait, and how fast they wrote (#196)
	Timed     int   `json:"timed,omitempty"`
	TTFT      int64 `json:"ttft_ms,omitempty"`
	DecodeMs  int64 `json:"decode_ms,omitempty"`
	DecodeOut int   `json:"decode_out,omitempty"`
}

Totals is a sum of calls.

func (Totals) MeanTTFT added in v0.1.392

func (t Totals) MeanTTFT() int64

MeanTTFT is the mean ms to the first token of the timed calls, 0 for none.

func (Totals) Speed added in v0.1.392

func (t Totals) Speed() float64

Speed is how fast the timed calls wrote, in tokens a second after their first: 0 for none.

func (Totals) Tokens

func (t Totals) Tokens() int

Tokens is what went in and out, excluding cache traffic.

type Via added in v0.1.284

type Via struct {
	Provider string    `json:"provider"`
	Model    string    `json:"model"`
	Effort   string    `json:"effort,omitempty"`
	Calls    int       `json:"calls"`
	Tokens   int       `json:"tokens"` // in and out, as Totals counts them
	Last     time.Time `json:"last"`
}

Via is where the gateway sent a session's calls: one model at one reasoning effort, how often and how much.

Jump to

Keyboard shortcuts

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