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 ¶
- Variables
- func AgentOf(ua string) string
- func Append(r Record)
- func FormatCost(amountUSD float64, currency string, rate float64) string
- func LastSeen(agent string) time.Time
- func Ledger(p Period, f Filter) (rows []Row, sum Totals, agents []string)
- func Path() string
- func Saw(agent string)
- func Swapped(sent, served string) bool
- func Vias(since time.Time) map[string][]Via
- func WriteCSV(w io.Writer, rows []Row) error
- type Filter
- type Group
- type Known
- type Period
- type Point
- type Record
- type Row
- type Summary
- type Totals
- type Via
Constants ¶
This section is empty.
Variables ¶
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.
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.
Periods lists the windows in order.
Functions ¶
func AgentOf ¶
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
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
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
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 Swapped ¶ added in v0.1.408
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.
Types ¶
type Filter ¶ added in v0.1.408
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 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.
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.
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
MeanTTFT is the mean ms to the first token of the timed calls, 0 for none.
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.