gateway

package
v0.1.1273 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 95 Imported by: 0

Documentation

Overview

Package gateway is the local LLM endpoint agents talk to. It serves the wire APIs coding agents speak — OpenAI Chat Completions, OpenAI Responses, Anthropic Messages and Google Gemini — and forwards each call to whichever provider serves the requested model, translating between the APIs when the provider does not speak the one the agent used.

Index

Constants

View Source
const (
	PartSystem  = "system"  // the agent's own prompt: system, developer and harness messages
	PartTools   = "tools"   // tool definitions
	PartMemory  = "memory"  // instruction files, skills, reminders
	PartFiles   = "files"   // files and images the tools read in
	PartResults = "results" // the tools' other output
	PartChat    = "chat"    // what the user and the model said, the model's calls
)

The kinds of a prompt's parts, in the order they are shown.

View Source
const (
	AgentHeader = "X-Magpie-Agent"
	ViaHeader   = "X-Magpie-Via"
)

A request passed on to another computer's magpie (a Remote magpie provider) goes as magpie's own, with magpie's User-Agent and the other magpie's key, so that magpie knew it only as "magpie" (Jorben on Discord). It now names the agent it came from (AgentHeader) and the computer (ViaHeader), and the other magpie keeps them in its usage, as "Claude Code · via <computer>". They are a label and nothing more: what magpie does with the request — the models an agent is shown, its stand-ins, a routing group's rules — still goes by who sent it, and they are taken only from a magpie's request (its User-Agent), one a client on the network could send only with the key anyway, and could name itself any agent by its User-Agent as well. No vendor is ever sent them: they come off every request as it arrives, and go on only to a remote magpie.

View Source
const (
	SearcherGone   = "gone"    // no such provider any more
	SearcherOff    = "off"     // turned off, or signed out
	SearcherCant   = "cant"    // it can't search the web by itself
	SearcherNoneOf = "nomodel" // it lists no model to search with
)

Why the searcher Settings names isn't used, and magpie picks one itself.

View Source
const (
	TLSCertEnv = "MAGPIE_TLS_CERT"
	TLSKeyEnv  = "MAGPIE_TLS_KEY"
)

TLSCertEnv and TLSKeyEnv name the PEM certificate (its chain after it) and private key files the flags set.

View Source
const AccountHeader = "X-Magpie-Account"

AccountHeader pins a request to one of a subscription's accounts, by its user (an email, a login) or its id in the routing trace: only it is tried, and when it can't take the request the caller is told why rather than another account answering — a probe of one account needs that one. It goes no further than magpie.

View Source
const AllowIPsEnv = "MAGPIE_ALLOW_IPS"

AllowIPsEnv names the environment variable that sets the list, in place of Settings' (for Docker and `magpie web`).

View Source
const AlphaSearchPath = "/alpha/search"

AlphaSearchPath is where Codex's own web search, its web.run tool, goes: "alpha/search" under the model provider's base URL, so /v1/alpha/search on magpie's provider and CodexPath+"/alpha/search" when Codex is signed in to ChatGPT. Codex offers web.run since 0.143 for a provider that sends x-openai-actor-authorization, as magpie's does, on a model whose catalog entry says use_responses_lite, as a ChatGPT account's do in magpie (codexcat copies Codex's own entry). Unanswered, the 404 ended the turn: Codex takes any failure of web.run as fatal (anton on Discord).

View Source
const ArchiveHeader = "X-Magpie-Archive-Id"

ArchiveHeader carries a call's archive id on its response.

View Source
const CodexCatalogPath = "/v1/codex/models"

CodexCatalogPath is Codex's model list in its own shape, for a Codex that names magpie its model_provider (base_url <gateway>/v1) on another computer, with a gateway key (#1281): its model_catalog_url. /v1/models stays OpenAI's list, which Codex can't read, and CodexPath's list is the ChatGPT backend's, for a Codex signed in to ChatGPT here.

View Source
const CodexPath = "/backend-api/codex"

CodexPath is where Codex's built-in OpenAI provider reaches magpie, as its `openai_base_url`. Codex keeps its own sign-in and sends what it would send the ChatGPT backend: a request for one of its own models goes on there as it came, one for a magpie model (a catalog id, provider/model) is served like any other, and the model list is OpenAI's with magpie's added. Ending in /backend-api/codex keeps Codex treating it as that backend.

View Source
const DefaultAddr = "127.0.0.1:3425"

DefaultAddr is where the gateway listens unless Settings' port or MAGPIE_ADDR says otherwise.

View Source
const DrawAgent = "magpie-image/1"

DrawAgent is the User-Agent magpie's generate_image tool adds to its own.

View Source
const PromptKept = promptBodies

PromptKept is how many requests' text the trace keeps.

View Source
const RouterAgent = "magpie-router/1"

RouterAgent is the User-Agent magpie's own classifier calls carry.

View Source
const ScienceID = "claude-science"

ScienceID is Claude Science's agent id.

View Source
const SearchAgent = "magpie-search/1"

SearchAgent is the User-Agent of the searches magpie makes for a model.

View Source
const SearchMCPPath = "/mcp/magpie/web-search"

SearchMCPPath is where the web search MCP server is served. It has two segments under /mcp/, so it can't hide a signed-in server's /mcp/{name}.

View Source
const SearchingHeader = "X-Magpie-Searching"

SearchingHeader marks a request a magpie made to search for another model, to a remote magpie, which then searches only by the model itself.

View Source
const SessionHeader = "X-Magpie-Session"

SessionHeader names the session a call is part of, for the usage log to tell several sessions on one model apart; without it, the session an agent names itself in sessionHeaders is taken.

View Source
const Token = "magpie"

Token is the bearer token agents are told to use. The gateway only listens on loopback and accepts anything, but agents insist on one.

View Source
const ToolsMCPPath = "/mcp/magpie/tools"

ToolsMCPPath is where the plugin tools MCP server is served.

View Source
const VisionAgent = "magpie-vision/1"

VisionAgent is the User-Agent of the descriptions magpie asks for.

View Source
const VisionMCPPath = "/mcp/magpie/vision"

VisionMCPPath is where the image recognition MCP server is served.

Variables

View Source
var (
	ImageStall   = time.Minute
	ImageLongest = 5 * time.Minute
)

ImageStall is how long an image being downloaded may send nothing before the download is given up, and ImageLongest how long it may take in all. A slow download goes on while it moves: a 4K PNG is 10 MB and more, and a cap on the whole of it (generate_image's was 2 minutes) lost one that was still coming (#1576).

View Source
var ArchiveBucket func() (Putter, bool)

ArchiveBucket is the bucket the archive goes to, and false when there is none (sync is off, or to a WebDAV folder): set by main to the S3 sync's.

View Source
var CodexOwnOnly func() bool

CodexOwnOnly reports whether the Codex asking for its model list at CodexPath reaches magpie for account failover alone, not connected to it (agent.CodexOwnOnly): it is then handed only its own models (#1385). Set by main; nil, every Codex gets magpie's models too.

View Source
var DesktopTierNames = []string{"opus", "sonnet", "haiku", "fable"}

Claude Desktop's Code tab runs Claude Code with ANTHROPIC_DEFAULT_<TIER>_MODEL set to "" for every tier, unless the gateway's /v1/models tags a model with anthropic_family_tier (shortnameIdentityOverrides in its app.asar, 2.7032: the first so tagged, or the one also is_family_default). Untagged, a subagent on "sonnet" or "haiku" asked for Claude Code's own claude-sonnet-… and that, unserved, went to the chat's model: every subagent ran on it, whatever its tier (WilianWeng on Discord). The user picks a model per tier in magpie; a Claude model magpie serves stands in for its own tier while its tier has none picked.

View Source
var Handover bool

Handover lets another process listen on the same address beside this one, for `make dev`: a restarted backend takes the gateway's port up before the one before it lets go, and that one finishes the streams it has instead of cutting them. Set before ListenAndServe; off, a second magpie can't bind the port, which is how it learns one already serves.

View Source
var StandIn func(agent, model string) string

StandIn is the model an agent is set to use in place of one it named that magpie doesn't serve it: Claude Code asks for claude-haiku-… by name for its small tasks, whatever its haiku tier is set to, and that goes to the tier's model rather than to some provider that happens to list the name. "" leaves the model as asked. Set by main.

View Source
var TurnDone func(TurnEnd)

TurnDone is told of each such turn; set by the app, which notifies. Nil (magpie serve, the CLI) has turns not followed at all.

View Source
var Version = "dev"

Version is set by main.

View Source
var WhileServing []func(context.Context)

WhileServing is work only the magpie serving the gateway does, begun once it is bound and ended with it: one of the magpies running, never two at once.

View Source
var Window bool

Window says this process shows the routing of the gateway it serves: the app's window (a tray's too, when opened) or magpie web's page, and not magpie serve, which has none. Set by the gui.

Functions

func AdaptiveThinking added in v0.1.317

func AdaptiveThinking(model string) bool

AdaptiveThinking is adaptiveOnly for agents told how to ask a model: a Claude that takes thinking.type=adaptive and an effort, never a budget.

func Addr

func Addr() string

Addr is the listen address: MAGPIE_ADDR, else Settings' port on loopback (settings.GatewayAddr).

func AllowGuard added in v0.1.1214

func AllowGuard(next http.Handler) http.Handler

AllowGuard refuses a request from an address the allow list leaves out, 403, before anything else looks at it: the page `magpie web` serves.

func AllowIPs added in v0.1.1214

func AllowIPs() (list []string, fromEnv bool)

AllowIPs is the allow list in force, as written, and whether MAGPIE_ALLOW_IPS set it. Empty: no list, every address let in.

func AllowedFrom added in v0.1.1214

func AllowedFrom(a netip.Addr) bool

AllowedFrom: a request from a may reach magpie under the allow list — there is none, a is this computer's, or a is in it.

func ArchiveError added in v0.1.577

func ArchiveError() (string, time.Time)

ArchiveError is the last upload's failure, and when; "" once one after it went.

func ArchiveName added in v0.1.577

func ArchiveName(date, id string) (string, bool)

ArchiveName is where the archive keeps the call named "<date>/<id>", under the bucket's magpie folder; false for a name not of that shape, which is never one magpie made.

func AutoDrawer added in v0.1.338

func AutoDrawer() string

AutoDrawer is the model magpie draws with when the Settings name none: a ChatGPT account's, which its plan pays for, else the cheapest of the models the API keys set up can draw with, the newest of those whose price isn't known. "" when none can.

func AutoModeReviewed added in v0.1.1213

func AutoModeReviewed(p provider.Provider, model string) bool

AutoModeReviewed reports whether a request for model on p can have its actions reviewed by Anthropic for Claude Code's auto mode: the Claude subscription (the bridge hands the review to Claude Code's own binary), a Claude model (Anthropic's API, a relay in front of it, Bedrock's or Vertex's names for it), or anything on Anthropic's own API. No other vendor runs Anthropic's classifier, and magpie answers none on its behalf.

func AutoSearcher added in v0.1.672

func AutoSearcher() string

AutoSearcher names the provider and model magpie picks to search with when Settings names none, "" when none can.

func AutoVideomaker added in v0.1.544

func AutoVideomaker() string

AutoVideomaker is the model a request that names none makes its video with: the first model of the first provider that makes any. "" when none can.

func AutoVision added in v0.1.333

func AutoVision() string

AutoVision is the model magpie picks to describe images when the Settings name none: a small model that sees, of the models the user enabled on the providers switched on (smallModel) — a Claude account's, a Codex account's, the cheapest of an API key's, another account's. One with allowance left goes before one whose every account or key is out of it (smallReady), whatever their order: the one out is picked only when every model that sees is, so that agents are still told images are described (provider.Described), and askVisionWith says when it is back instead of asking (#1801). "" when no model sees.

func ByStrength added in v0.1.783

func ByStrength(efforts []string) []string

ByStrength is efforts weakest first, in effortRank's order; a level it doesn't know keeps its place among the others of its kind, after them.

func CanReadSearchQuota added in v0.1.1231

func CanReadSearchQuota(a provider.SearchAPI) bool

CanReadSearchQuota is whether magpie can read what a search API's keys have left: Tavily's, with a key.

func CanSearch added in v0.1.1045

func CanSearch() bool

CanSearch is canSearch for the agents' rows: whether a web_search server tool asked of any model here is answered.

func CheckTLS added in v0.1.1232

func CheckTLS() error

CheckTLS says why the files set can't be served: only one of the two, or a pair that doesn't load. nil with neither set.

func ClassifierFailure added in v0.1.1226

func ClassifierFailure(model string) (why string, at time.Time, ok bool)

ClassifierFailure is why model, a routing group's classifier, couldn't say which intent or effort a turn is the last time it was asked, and when; ok is false once it answers, and before it is asked. The Routing page says it on the group's card (#1929, versun): a classifier that fails at every turn otherwise only showed in each request's own details, while its group's rules with an intent quietly never matched.

func ContainerAddrs added in v0.1.553

func ContainerAddrs() bool

ContainerAddrs: the addresses magpie finds for itself are a container's, which other machines can't reach, and MAGPIE_PUBLIC_URL doesn't say the host's.

func DesktopCatalogID added in v0.1.685

func DesktopCatalogID(id string) string

DesktopCatalogID is the catalog id of a model as Claude Desktop names it: one of its aliases or the catalog id itself.

func DesktopID added in v0.1.592

func DesktopID(e provider.Entry) string

DesktopID is the id Claude Desktop is shown e by, and its Code tab hands Claude Code (claudeLooking).

func DesktopListed1M added in v0.1.1154

func DesktopListed1M(e provider.Entry) bool

DesktopListed1M says Claude Desktop is shown e by its "[1m]" id, which its Code tab hands Claude Code, so a session on it has the 1M window.

func DesktopTiers added in v0.1.685

func DesktopTiers() map[string]string

DesktopTiers is the catalog id picked for each of Claude Desktop's tiers.

func Drawer added in v0.1.1119

func Drawer() string

Drawer is the model a request that names none draws with (drawer), as provider/model: "" when image generation is off or no provider draws.

func DrawerMissing added in v0.1.1118

func DrawerMissing() string

DrawerMissing is the model Settings › Models › Image generation names when magpie can't find it any more, so that AutoDrawer's draws in its place, as VisionMissing is Image recognition's. "" when none is named, it is off, or it resolves.

func Drawers added in v0.1.338

func Drawers(p provider.Provider) []catalog.Model

Drawers are the models a provider can draw with: its catalogs' models that make images, those its own model list names that do, those of its own picks named for images, and those the user said draw (#1399), less those they said make videos; a ChatGPT account's GPT Image, a Grok subscription's Grok Imagine, a WorkBuddy plan's those its config lists.

func FetchImage added in v0.1.1184

func FetchImage(ctx context.Context, c *http.Client, url string) ([]byte, string, error)

FetchImage downloads the image at url with c: its bytes, and its type — what the bytes are, over what the server says. It gives up when nothing comes for ImageStall or it has taken ImageLongest, and says which, and how much had come.

func History added in v0.1.341

func History(day string) (days []HistoryDay, routes []Route, cut bool)

History is the days kept, newest first, and the routes of day, oldest first — its latest historyMax, and whether there were more.

func HistoryDir added in v0.1.341

func HistoryDir() string

HistoryDir is where the days are kept: ~/.config/magpie/routing.

func InContainer added in v0.1.1132

func InContainer() bool

InContainer: this magpie runs in a container (Docker, Podman, a Kubernetes pod), whose image is what gets updated, not its binary.

func KeepsOut added in v0.1.1214

func KeepsOut(list []string, r *http.Request) (string, bool)

KeepsOut: the allow list list would refuse r, a request that came in from elsewhere; it names r's address.

func LANURLs added in v0.1.168

func LANURLs() []string

LANURLs are the addresses other machines on the network reach the gateway at: MAGPIE_PUBLIC_URL when set, else one per IPv4 address this computer has there.

func ListedDrawer added in v0.1.1217

func ListedDrawer(ref string) string

ListedDrawer is the listed image model a picked one (provider/model) stands for: a ChatGPT account's gpt-image-2.5, or any other GPT Image name, is its one GPT Image, as its backend draws the same for any name (#1865). ref itself otherwise, and when its provider isn't found. The pick itself is kept as it was saved, and draws as before.

func Listen added in v0.1.291

func Listen(addr string) (net.Listener, error)

Listen listens on addr, beside another process when Handover is on.

func ModelEfforts added in v0.1.1226

func ModelEfforts(model string) []string

ModelEfforts are the reasoning levels model ("<provider>/<model>") has, weakest first, for Settings to offer beside it; none for one whose levels aren't known, or a routing group.

func NamedSearchModel added in v0.1.1213

func NamedSearchModel() string

NamedSearchModel is the model the searcher Settings names searches with, as "<provider>/<model>": what an agent's own web search row asks, so a search goes to the searcher the user picked rather than first to the agent's model (dsh, 我只会玩单机 on Discord). "" when Settings names none, provider search is off, the one named can't be used, or it searches with no model (a Kimi Code plan's search service).

func OnNetwork added in v0.1.1151

func OnNetwork() bool

OnNetwork: MAGPIE_ADDR puts the gateway beyond loopback (0.0.0.0 in the Docker image, a server's or one interface's address), so it is reached from other machines, and from a container's host, whether or not it is shared from Settings. Such callers need an enabled gateway key, as they do while it is shared: nothing that reaches it from elsewhere is let in on any key.

func Port added in v0.1.168

func Port() string

Port is the gateway's port.

func PublicClient added in v0.1.1272

func PublicClient() *http.Client

PublicClient is publicClient, for a download outside the gateway of a URL magpie didn't choose (generate_image's of a vendor's image).

func PublicHost added in v0.1.553

func PublicHost() string

PublicHost is MAGPIE_PUBLIC_URL's host, "" when it isn't set.

func PublicURL added in v0.1.591

func PublicURL() string

PublicURL is MAGPIE_PUBLIC_URL, with a scheme; "" when it isn't set.

func RelaysSaidToSearch added in v0.1.672

func RelaysSaidToSearch() []provider.Provider

RelaysSaidToSearch are the providers on that are said to search by themselves but are not asked for another model unless Settings names them (#359).

func Running

func Running() bool

Running reports whether a gateway answers at the address.

func SavedURL added in v0.1.950

func SavedURL() string

SavedURL is URL by Settings alone, MAGPIE_ADDR left aside: where the installed magpie, whose settings these are, is reached.

func Scheme added in v0.1.1232

func Scheme() string

Scheme is the gateway's scheme for other computers: https with TLS on.

func SearchEffortNow added in v0.1.1226

func SearchEffortNow() string

SearchEffortNow is the level the searcher in use is asked at, when one is picked in Settings.

func SearchEfforts added in v0.1.1226

func SearchEfforts() []string

SearchEfforts are the levels of the model that searches now: none for a Kimi Code plan's search service, which has no model.

func Searcher added in v0.1.587

func Searcher() string

Searcher names the provider and model magpie searches with for a model that can't, "" when none can.

func SearcherUnused added in v0.1.672

func SearcherUnused() string

SearcherUnused is why the searcher Settings names isn't used (one of the Searcher* reasons), "" when it is or none is named.

func ServeTLS added in v0.1.1232

func ServeTLS(ln net.Listener) (net.Listener, error)

ServeTLS wraps ln to serve TLS, with plain HTTP for this computer's own connections, when the files are set; ln as it is otherwise.

func Serving added in v0.1.191

func Serving() (running, window bool)

Serving asks the address what answers there: whether a magpie gateway does, and whether the magpie serving it has a window its routing can be watched in (#110).

func SetDesktopTier added in v0.1.685

func SetDesktopTier(tier, id string) error

SetDesktopTier picks the model (a catalog id) Claude Desktop runs a tier on; "" takes the pick away.

func SetTLS added in v0.1.1232

func SetTLS(cert, key string) error

SetTLS sets the files the flags name, as absolute paths (a service starts in another folder), after checking them as CheckTLS does.

func TLSFiles added in v0.1.1232

func TLSFiles() (cert, key string)

TLSFiles are the certificate and key files set, "" for none.

func TLSOn added in v0.1.1232

func TLSOn() bool

TLSOn: the gateway serves other computers over HTTPS.

func TLSSummary added in v0.1.1232

func TLSSummary() string

TLSSummary says what the certificate served now is for and until when, for the serve banner: "" with TLS off or a pair that doesn't load.

func Taken added in v0.1.1231

func Taken() bool

Taken reports whether anything accepts connections at the gateway's address, whether or not it answers ServedBy's question in time: a magpie busy starting, or slow on a small server, still holds the port.

func ThinksOnlyWhenAsked added in v0.1.771

func ThinksOnlyWhenAsked(model string) bool

ThinksOnlyWhenAsked is a model that takes thinking turned off on the Messages API whatever its levels: one of Anthropic's own (anthropicModel, or a relay's opus-5.5). Another vendor's model there takes it off only when none is among its levels; without it, it always thinks, and GLM-5.3 turns thinking disabled away (#699).

func TokenFor added in v0.1.174

func TokenFor(agent string) string

TokenFor is the token an agent that says nothing of itself in its User-Agent is told to use, so the gateway still knows it: Alma's requests go out as the AI SDK's ("ai-sdk/openai/…"), with nothing of Alma's own.

func ToolNames added in v0.1.1257

func ToolNames(pts []plugin.PluginTools) map[string]map[string]string

ToolNames are the names the plugin tools MCP server gives pts' tools, by spec and the tool's own name, as the Plugins page shows them.

func TurnFolder added in v0.1.1191

func TurnFolder(dir string) string

TurnFolder is the last part of a folder, for a notification.

func URL

func URL() string

URL is the base URL agents use, e.g. http://127.0.0.1:3425: a gateway listening on every interface is reached here on loopback.

func VendorPicksDrawer added in v0.1.1217

func VendorPicksDrawer(p provider.Provider) bool

VendorPicksDrawer is whether p's vendor picks the image model itself, whichever is named: a ChatGPT account's images backend (#1865).

func Videomakers added in v0.1.544

func Videomakers(p provider.Provider) []catalog.Model

Videomakers are the models a provider can make videos with: a Grok subscription's, another magpie's, a preset plan's models when magpie implements that vendor's video API, and those a provider's own model list marks as video models (customVideomakers).

func VisionEffortNow added in v0.1.1226

func VisionEffortNow() string

VisionEffortNow is the level the Image recognition model in use is asked at when one is picked in Settings ("" when none is): the picked one fitted to the model's levels, for the row to show.

func VisionEfforts added in v0.1.1226

func VisionEfforts() []string

VisionEfforts are the levels of the model that describes images now.

func VisionMissing added in v0.1.1118

func VisionMissing() string

VisionMissing is the model Settings › Models › Image recognition names when magpie can't find it any more, so that AutoVision's describes in its place. "" when none is named, Vision is off, or it resolves.

Types

type Active added in v0.1.1241

type Active struct {
	ID       int64     `json:"id"`
	Agent    string    `json:"agent"`
	Model    string    `json:"model,omitempty"`
	Provider string    `json:"provider,omitempty"`
	Session  string    `json:"session,omitempty"`
	Started  time.Time `json:"started"`
	Millis   int64     `json:"ms"`
	Phase    string    `json:"phase,omitempty"`
	Route    int64     `json:"route,omitempty"` // its routing trace's id
}

Active is one agent request in flight, as /v1/magpie/concurrency lists it for a status bar's hover (#2132, bigbitbox): which agent asked, for which model, since when, and where it stands. It holds no prompt, reply or key. Model and Provider are the routing trace's, once the request has been routed; Phase is said only when the gateway knows it: "slot" while it waits in a key's or account's queue (MaxConcurrency), "rpm" while it waits for room in the minute (MaxRPM), "upstream" while a try is out at the vendor (the request sent, or its reply streaming). A request served another way (a subscription bridge, a title helper) has none.

type Affinity added in v0.1.38

type Affinity struct {
	Mode       string    `json:"mode"`             // the provider's or group's: "", session, turn, off
	Turn       int       `json:"turn"`             // the user's turns in the conversation so far
	Within     bool      `json:"within,omitempty"` // the agent sending tool results back: mid-turn
	Last       string    `json:"last,omitempty"`   // who answered the conversation last
	LastTurn   int       `json:"lastTurn,omitempty"`
	At         time.Time `json:"at,omitempty"`         // when
	CacheRead  int       `json:"cacheRead,omitempty"`  // tokens that answer read from the vendor's cache
	CacheWrite int       `json:"cacheWrite,omitempty"` // and wrote to it, or was sent where none is
	Kept       bool      `json:"kept,omitempty"`       // Last was put first for it
	// Why it was kept — "session", "turn", "cache" — or not: "off", "first"
	// (nobody has answered it yet), "new-turn", "no-cache" (the vendor
	// read and wrote too little of its cache to keep, or was sent too
	// little for a cache it keeps without saying so), "cold" (too long
	// ago), "resting", "spent", "gone" (no longer one to route to).
	Why string `json:"why"`
}

Affinity is what the trace tells of a request's conversation and whether it stayed with who answered it last.

type ArchivePart added in v0.1.577

type ArchivePart struct {
	Method  string              `json:"method,omitempty"`
	Path    string              `json:"path,omitempty"`
	Status  int                 `json:"status,omitempty"`
	Headers map[string][]string `json:"headers"`
	Body    string              `json:"body"`
	// Size is the whole body's, in bytes, as the gateway had it, before
	// its secrets were taken out; none in an archive from before #447
	Size int64 `json:"size,omitempty"`
	// Truncated: only the start of the body is kept — its first
	// RequestArchiveMaxMB, or, in an archive from before #447 (no Size),
	// its first 256 KB
	Truncated bool `json:"truncated,omitempty"`
}

ArchivePart is one way of a call: the request, or the response.

type Archived added in v0.1.577

type Archived struct {
	ID       string      `json:"id"`   // <date>/<id>
	Call     Call        `json:"call"` // as Recent calls has it, its bodies below
	Request  ArchivePart `json:"request"`
	Response ArchivePart `json:"response"`
}

Archived is a call as the archive keeps it.

type AutoReset added in v0.1.507

type AutoReset struct {
	Who   string `json:"who"`
	Text  string `json:"text"`
	Agent string `json:"agent,omitempty"` // the account's agent, as Account.Agent has it
}

AutoReset is a Codex reset spent by itself, on Who's account. (Claude's resets were taken out in 9bf6d4352 and aren't coming back: reading or spending one means magpie calling Anthropic with the account's token, #1972.)

type Busy added in v0.1.672

type Busy struct {
	Requests int       `json:"requests"`
	Tools    int       `json:"tools"`
	Last     time.Time `json:"-"`
}

Busy is what a restart of the magpie serving the gateway would cut short (#577): the agents' requests in flight — a reply streaming, an image being made — and the turns of Claude Code run through the subscription bridge waiting on their caller's tool results, whose Claude Code lives only in this process. A request in flight is one that does work (not a GET: the model lists, the info another magpie asks for every 15 s); the bridge's own helper calls are not counted apart, a turn waiting on them being in Tools. Last is when the last counted request ended, so a caller can tell a tool chain's gap — the agent running a tool between two requests — from the end of its turn.

func (Busy) Any added in v0.1.672

func (b Busy) Any() bool

Any is whether there is anything in flight.

type Call

type Call struct {
	// ID numbers the call in the Recent-calls ring, from 1, for the page
	// to ask for its bodies by (the ring's summary leaves them out, #1521)
	ID uint64 `json:"id,omitempty"`
	// Route: the Routing page's request (Route.ID) this call is, for it
	// to ask for the call's bodies by while the ring still has them
	Route int64     `json:"route,omitempty"`
	Time  time.Time `json:"time"`
	Agent string    `json:"agent"`         // who called, from the client's User-Agent
	Via   string    `json:"via,omitempty"` // the computer a remote magpie's request came from (AgentHeader)
	// Kind: what the agent made the call for, when it isn't its turn —
	// a Codex subagent's (callKind) — "" for a turn
	Kind string `json:"kind,omitempty"`
	// For: the request a call of magpie's own (a web search) was made for
	For      *CallFor          `json:"for,omitempty"`
	Model    string            `json:"model"`
	Provider string            `json:"provider"`
	From     provider.Protocol `json:"from"`
	To       provider.Protocol `json:"to"`
	Status   int               `json:"status"`
	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, when
	// it was streamed (#196)
	TTFT      int64 `json:"ttft,omitempty"`
	FirstText int64 `json:"firstText,omitempty"`
	// FirstReasoning is the start of paced visible reasoning, absent for hidden reasoning.
	FirstReasoning  int64 `json:"firstReasoning,omitempty"`
	ReasoningHidden bool  `json:"reasoningHidden,omitempty"`
	// Flow: the ms its content took to come, from where its speed is
	// counted (firstToken.flowMs): next to none for a reply that came in
	// a burst, so it tells no speed
	Flow              int64  `json:"flow,omitempty"`
	Error             string `json:"error,omitempty"`
	Fallback          string `json:"fallback,omitempty"` // providers that failed first, and why
	Usage             Usage  `json:"usage"`
	RequestBody       string `json:"requestBody,omitempty"`
	ResponseBody      string `json:"responseBody,omitempty"`
	RequestTruncated  bool   `json:"requestTruncated,omitempty"`
	ResponseTruncated bool   `json:"responseTruncated,omitempty"`
	// Archive: "<date>/<id>", where the request archive keeps the call,
	// when it was on (archive.go); wire what it keeps besides
	Archive string `json:"archive,omitempty"`
	// contains filtered or unexported fields
}

Call is one request the gateway handled, for the status views.

type CallFor added in v0.1.490

type CallFor struct {
	Agent string `json:"agent"`
	Model string `json:"model"`
	// Unknown, on an image's description, is that the model was counted
	// text-only because nothing magpie knows says whether it sees images
	// (blindTo), not because its list or the user says it takes text only.
	// The Routing view says which, so a user whose model does see knows
	// to say so (#1287).
	Unknown bool `json:"unknown,omitempty"`
	// Missing, on an image's description, is the Image recognition model
	// the user picked in Settings that magpie can't find any more: the
	// model that described is the one magpie picks in its place
	// (VisionMissing), and the Routing view names both.
	Missing string `json:"missing,omitempty"`
	// MCP, on a web search or an image's description, is that the agent
	// called magpie's MCP server (SearchMCPPath, VisionMCPPath) itself, for
	// no model of magpie's.
	MCP bool `json:"mcp,omitempty"`
	// Instead, on a web search, is the searcher asked first that failed
	// or found nothing (Why, NothingFound): the searcher that did search
	// was the next one magpie tried in its place, and the Routing view
	// says so. Picked is that the first was the one picked in Settings.
	// A fallback that said nothing read as magpie ignoring the pick
	// (Gearclickist on Discord: Grok picked, Codex's model searched).
	// NotSearched is that the first answered without searching at all
	// (errNotSearched), apart from searching and naming no page.
	Instead      string `json:"instead,omitempty"`
	Why          string `json:"why,omitempty"`
	NothingFound bool   `json:"nothingFound,omitempty"`
	NotSearched  bool   `json:"notSearched,omitempty"`
	Picked       bool   `json:"picked,omitempty"`
}

CallFor is the request a call magpie made on its own was made for: its agent, and the model that agent asked for.

type Classified added in v0.1.95

type Classified struct {
	By      string   `json:"by"`               // the classifier model
	Intents []string `json:"intents"`          // what it chose among
	Intent  string   `json:"intent,omitempty"` // what it said the message is; "" for none
	After   string   `json:"after,omitempty"`  // what it said the turn before was, which it was told
	Effort  string   `json:"effort,omitempty"` // the reasoning it said the turn wants
	Score   float64  `json:"score,omitempty"`  // how hard it took the turn to be, 0 (low) to 3 (xhigh)
	Sure    float64  `json:"sure,omitempty"`   // how confident it was of the intent, 0 to 1
	Cached  bool     `json:"cached,omitempty"` // said before, for the same message
	Ms      int      `json:"ms,omitempty"`     // how long asking it took
	Error   string   `json:"error,omitempty"`  // why it couldn't say: no intent matches then, unless Fallback
	// Fallback: "previous" when it couldn't say and the turn keeps the
	// intent the turn before had (After), rather than none
	Fallback string `json:"fallback,omitempty"`

	// AfterEffort: the reasoning picked for the turn before, which it was told
	AfterEffort string `json:"afterEffort,omitempty"`
}

Classified is what the classifier was asked as a turn began, and said.

type Event

type Event struct {
	Kind   EventKind
	Status int // upstream HTTP status for KError, when known
	Text   string
	ID     string
	Name   string
	MsgID  string
	Model  string
	Stop   string // stop | length | tool | filter
	// Code: for KError, the source error or safety-filter code (rate_limit,
	// server_error, bio_policy, content_filter…); RequestID: the vendor's id for the
	// request the event is of, when it is known by then
	Code             string
	RequestID        string
	Usage            Usage
	Hits             []Hit
	SafeguardResults json.RawMessage
	// StopDetails: Anthropic's stop_details, what its classifier said of
	// a refusal (#1768), carried to the client as it came
	StopDetails json.RawMessage

	// Wait: for KError, how long the vendor said to wait before asking
	// again, when it said; sent on as Retry-After
	Wait time.Duration
	// Said: for KError, the vendor's own error as {"error":{…}}, when it
	// said the request itself is at fault; its code and param go to a
	// client answered whole (writeVendorError)
	Said json.RawMessage
}

Event is one thing a streaming reply said.

type EventKind

type EventKind int

EventKind is what a streamed event carries.

const (
	KStart     EventKind = iota // MsgID, Model, Usage (input side)
	KText                       // Text
	KThink                      // Text (reasoning)
	KSig                        // Text (thinking signature)
	KToolStart                  // ID, Name
	KToolArgs                   // Text (partial JSON of the arguments)
	KStop                       // Stop
	KUsage                      // Usage
	KError                      // Text
	KSearch                     // Text (the query), Hits: a web search run for the model
	KImage                      // Name (media type), Text (base64): an image the model made
	// KThinkStart: a new block of reasoning begins (Anthropic's thinking
	// block, a Responses reasoning item, ID its id): what follows is not
	// the one before's, even with nothing between them
	KThinkStart
	// KSealed: Text is reasoning the upstream sealed, whole as its API
	// wrote it, Name that API (Part.Sealed): Anthropic's redacted_thinking
	// block, a Responses reasoning item as it was done
	KSealed
	// KTextSig: Text is Gemini's thoughtSignature on the text before it
	KTextSig
	// KAlive: nothing of the reply, only that its provider is still heard
	// from (a keepalive, an event with nothing for the client) after
	// keepaliveGap of nothing else: a reply read in rounds (searchReply)
	// keeps its client alive with it as a translated stream does (#2316)
	KAlive
)

type Format added in v0.1.1110

type Format struct {
	// Type is "json_schema" (Schema holds the schema the answer fits) or
	// "json_object" (any JSON object).
	Type string
	// Name and Description are json_schema's, as OpenAI's APIs take them;
	// Name is "response" where the client's API has none.
	Name, Description string
	Schema            json.RawMessage
	// Strict is the client's strict, nil when it said none.
	Strict *bool
	// contains filtered or unexported fields
}

Format is the shape a client asked the answer to come in (structured output), read from whichever API it spoke: Responses' text.format, Chat's response_format, Anthropic's output_config.format, Gemini's generationConfig.responseMimeType with its schema. Each API it is built for again asks for it in its own words; one that can't is told it in the system prompt (inSystem).

type GroupRef added in v0.1.38

type GroupRef struct {
	ID       string   `json:"id"`
	Name     string   `json:"name"`
	Routing  string   `json:"routing"`
	Affinity string   `json:"affinity"`
	Auto     bool     `json:"auto,omitempty"`
	Sink     bool     `json:"sink,omitempty"` // provider.Group.Sink, as it applies
	Members  []string `json:"members"`        // those ready, as provider/model[:effort fixed on it]
	// Subs: the groups in the group, at any depth, outermost first
	Subs []SubGroup `json:"subs,omitempty"`
	// Via: for each of Members, the groups in the group it is of, as
	// "fast>cheap" ("" for the group's own), when it has groups in it
	Via []string `json:"via,omitempty"`
	// Fast: those of Members sent in their vendor's fast mode
	Fast []string `json:"fast,omitempty"`
	// Paused: the models a pause rule left out of the request, so not in
	// Members (provider.PausedOut)
	Paused []provider.Paused `json:"paused,omitempty"`
}

GroupRef is the routing group a request asked for.

type HistoryDay added in v0.1.341

type HistoryDay struct {
	Day      string `json:"day"`
	Requests int    `json:"requests"`
}

HistoryDay is a kept day, and how many requests it had.

type Hit added in v0.1.149

type Hit struct {
	Title string `json:"title"`
	URL   string `json:"url"`
	// PageAge is how old the search said the page is, "" when it didn't
	PageAge string `json:"page_age,omitempty"`
}

Hit is a page a web search found.

type Kind

type Kind string

Kind is what a part of a message holds.

const (
	Text       Kind = "text"
	Image      Kind = "image"
	File       Kind = "file"
	ToolCall   Kind = "tool_call"
	ToolResult Kind = "tool_result"
	Thinking   Kind = "thinking"
	Search     Kind = "web_search" // a web search run for the model: its query and hits
)

type Lane added in v0.1.633

type Lane struct {
	Busy    int `json:"busy"`
	Waiting int `json:"waiting"`
	Limit   int `json:"limit"`
}

Lane is how a key's or account's requests stand: out at the vendor, and waiting their turn.

type Message

type Message struct {
	Role  string // user | assistant
	Parts []Part
}

Message is one turn.

type NestedRule added in v0.1.102

type NestedRule struct {
	Group string   `json:"group"`
	Name  string   `json:"name"`
	Rule  *RuleHit `json:"rule"`
}

NestedRule is a group in the group's rules, as they decided.

type Part

type Part struct {
	Kind Kind
	Text string // text, thinking, or a tool result's output

	// image or file
	MediaType string
	Data      string // base64
	URL       string

	// tool_call
	ID   string
	Name string
	Args json.RawMessage // a JSON object

	// tool_result
	CallID     string
	IsError    bool
	Images     []Part         // the images the tool returned beside its text
	Standalone map[string]any // native Responses notification with no call ID

	// thinking: its signature (Anthropic's, or a Gemini thought's). On a
	// tool call, and on text, Gemini's thoughtSignature: a tool call's
	// comes only from Google, as gemini_signature.go carries it, and
	// text's only from a Gemini API (#1445)
	Signature string
	// thinking an upstream sealed, as its API wrote it: Anthropic's
	// redacted_thinking block, a Responses reasoning item with its id,
	// summary and encrypted_content. Only that API's builder, encoder and
	// renderer write it, byte for byte; to any other it is reasoning with
	// no text, or Text's (#1445). SealedBy is the API (sealAnthropic,
	// sealResponses).
	Sealed   json.RawMessage
	SealedBy string

	// web_search: Text is the query
	Hits []Hit
	// contains filtered or unexported fields
}

Part is one block of a message.

type Prompt added in v0.1.1107

type Prompt struct {
	Window int `json:"window,omitempty"` // the context window of the model that answered, when known
	// Tokens: the prompt, as the vendor counted it when Counted, the parts
	// scaled to it; estimated from the body before that
	Tokens  int  `json:"tokens"`
	Counted bool `json:"counted,omitempty"`
	// Held: the request named a previous response, whose turns the vendor
	// holds; they are in Tokens once counted, as the conversation
	Held  bool         `json:"held,omitempty"`
	Turns int          `json:"turns,omitempty"` // the user's turns in it
	Parts []PromptPart `json:"parts"`
}

Prompt is a request's prompt, part by part.

type PromptEntry added in v0.1.1169

type PromptEntry struct {
	Name   string        `json:"name"`
	Tag    string        `json:"tag,omitempty"`
	N      int           `json:"n,omitempty"`
	Tokens int           `json:"tokens"`
	Pieces []PromptPiece `json:"pieces,omitempty"`
}

PromptEntry is one item of a prompt's part with its text: the card's item, unfolded — every turn and every tool, not the latest or largest promptItems.

type PromptItem added in v0.1.1107

type PromptItem struct {
	Name   string `json:"name"`
	Tag    string `json:"tag,omitempty"` // what it is: mcp, user, project, skills, reminder, image, read, shell, turn…
	N      int    `json:"n,omitempty"`   // how many it gathers: an MCP server's tools, a tool's results
	Tokens int    `json:"tokens"`
}

PromptItem is one thing in a part: a tool, an MCP server's tools, an instruction file, a file read, a turn.

type PromptPart added in v0.1.1107

type PromptPart struct {
	Kind   string       `json:"kind"`
	Tokens int          `json:"tokens"`
	Items  []PromptItem `json:"items,omitempty"` // largest first, promptItems at most
}

PromptPart is one kind of what a prompt holds.

type PromptPiece added in v0.1.1169

type PromptPiece struct {
	// Role: system, user, assistant, thinking, call, result, tool, image,
	// sealed; "" for text that is the item itself (an instruction file)
	Role string `json:"role,omitempty"`
	Name string `json:"name,omitempty"` // the tool called or defined
	Text string `json:"text,omitempty"`
	Size int    `json:"size,omitempty"` // a sealed piece's bytes
	// contains filtered or unexported fields
}

PromptPiece is a stretch of an item's text as the request sent it: a message, a tool's definition, a call and its input, what a tool answered. An image or sealed reasoning is only named, with its size.

type PromptText added in v0.1.1169

type PromptText struct {
	ID    int64         `json:"id"`
	Kind  string        `json:"kind"`
	Items []PromptEntry `json:"items"`
	// Kept is how many requests' text is kept, for the GUI to say so
	Kept int `json:"kept"`
}

PromptText is a part of a request's prompt, item by item, with the text when an item is asked for.

type Putter added in v0.1.577

type Putter interface {
	Put(ctx context.Context, name string, data []byte) error
}

Putter is a bucket the archive is written to.

type Request

type Request struct {
	Model      string
	System     string
	Messages   []Message
	Tools      []Tool
	ToolChoice string // "" | auto | none | required | name:<tool>
	MaxTokens  int
	Temp       *float64
	TopP       *float64
	Stop       []string
	Stream     bool
	Effort     string // low | medium | high | xhigh | max, when the client asked
	Thinking   bool   // the client asked for visible reasoning
	// ThinkOff is the client turning reasoning off: effort "none" (which
	// Effort reads as low, for vendors with no way to turn it off) or an
	// Anthropic request with thinking disabled.
	ThinkOff  bool
	Parallel  *bool // parallel tool calls allowed
	WebSearch bool  // the client offered its provider's own web search
	Fast      bool  // the client asked for priority processing: service_tier priority (Codex's Fast mode)
	// Ultrafast is Codex's Ultrafast (service_tier "ultrafast"), which a
	// ChatGPT account on a plan with it offers on its models; Fast is set
	// with it, so where there is no Ultrafast the request goes fast
	Ultrafast bool
	// Tier is the service_tier the client sent, as it sent it. It goes on
	// as it is to a provider the user added by its address (OwnTier):
	// a relay of theirs may serve Fast and Ultrafast where magpie can't
	// tell (hsiangron on X: both were left out)
	Tier string
	// OwnTier is set for such a provider (gateway.go, as each attempt is
	// built); one that turns the field away is asked again without it
	// (optionalFields)
	OwnTier bool
	// CacheKey is the client's prompt_cache_key (Codex sends its thread's
	// id), which OpenAI, and relays in front of it, route a conversation by
	// to where its prompt is cached.
	CacheKey string
	// Include is a Responses client's include, the extra output it asked
	// for (Codex's reasoning.encrypted_content), which a Responses upstream
	// is asked for too: a relay may refuse a request without it (#315).
	Include []string
	// ClientMetadata and Text are a Responses client's client_metadata
	// (Codex's installation and session ids, which a relay may check, #374)
	// and text (its verbosity), which go on as they were sent when the
	// request is built again for a Responses upstream; no other API takes
	// them. text's format is read into Format.
	ClientMetadata json.RawMessage
	Text           json.RawMessage
	// AccessPrograms is a client's access_programs, the program a request
	// asks the model under (OpenAI's Daybreak: {"cyber":"daybreak_blue"}),
	// which Codex CLI sends the ChatGPT backend on every turn it picked one
	// for (codex-rs's ResponsesApiRequest.access_programs). It goes on as it
	// was sent, null and all, when the request is built again for a
	// Responses upstream, whose answer to a value it doesn't take
	// (invalid_access_program) is the client's to read; no other API takes
	// it (magpie-releases#18).
	AccessPrograms json.RawMessage
	// Metadata is an Anthropic client's metadata (Claude Code's user_id),
	// which goes on as it was sent when the request is built again for an
	// Anthropic upstream: a relay that serves only Claude Code turns a
	// request without it away (#359).
	Metadata json.RawMessage
	// Safeguards are the caller's safety context, opaque to the gateway.
	Safeguards    json.RawMessage
	SafeguardBeta string
	// Format is the shape the client asked the answer in (structured
	// output: format.go), nil for plain text. Text, a Responses client's,
	// holds it no more: it is asked for again in the upstream's own words.
	Format *Format
	// FormatTold is set when Format was told in the system prompt instead
	// (inSystem): the client still wants the answer as JSON.
	FormatTold bool
	// GeminiCompat is the upstream being Gemini's OpenAI-compatible API
	// (AI Studio's, or a proxy in front of it on this machine or the LAN),
	// which gives the model's thoughts only when asked in thinking_config.
	GeminiCompat bool
	// OffLevel is the level such an API is asked to think at when the
	// client turned reasoning off: Gemini 3 can't stop thinking, and thinks
	// least at minimal, or at its lowest level where it has no minimal or
	// turned minimal away (geminiLevels). "" is minimal.
	OffLevel string
	// Resume is set on a request built to go on with a reply the client
	// already has part of (continuation.go): its last message is that
	// part, an assistant message the model goes on from, not a turn
	// answered.
	Resume bool
	// LastIsTurn is set on a request from a client whose API reads a
	// conversation ending with the assistant's message as a turn already
	// said, to answer after (OpenAI's Chat and Responses), not one to go
	// on from (Anthropic's prefill): to a model that takes no prefill it
	// is asked with a user turn after it (prefill.go).
	LastIsTurn bool
	// Namespaced are the tools a Responses client offered inside a
	// namespace, by the flat name the model is offered them under.
	Namespaced map[string]nsTool
	// Grok is set when the model asked is one of Grok's, whose calls'
	// arguments reach the client with their zero fractions dropped
	// (grok_integral.go).
	Grok bool
	// contains filtered or unexported fields
}

Request is a call to a model, whichever API it arrived in.

type Rest added in v0.1.38

type Rest struct {
	Why    string    `json:"why"`    // failCredit, failQuota, failRate, failOther
	Status int       `json:"status"` // what it answered
	Until  time.Time `json:"until"`
	// By is what set how long: "credit" (half an hour), "retry-after" (the
	// vendor's own headers), "resets" (the time Claude Code gave), "window"
	// (the allowance window it filled renews), "quota" (no word of when),
	// "cooldown" (a minute), "backoff" (longer each time it fails again,
	// or is rate limited again as soon as it is back), "restricted" (the
	// vendor restricted the account: two hours, or until lifted by hand),
	// "off" (no rest: its provider is set not to rest after an unknown
	// failure, provider.RestCapOff).
	By       string `json:"by"`
	Failures int    `json:"failures,omitempty"` // in a row, for a backoff
	// Key is what it rests by, for the app to lift the rest (Unrest)
	Key string `json:"key,omitempty"`
	// Model: the one model resting, when the account or key still
	// answers its others (a pooled allowance, a model it doesn't serve);
	// "" for the account or key as a whole. The app shows the rest on
	// that model's rows only (#1960: Antigravity's Claude & GPT pool used
	// up showed gemini-3.8-flash, in a pool of its own, as out too).
	Model string `json:"model,omitempty"`
	// Link: where the vendor said to verify the account, for failVerify
	Link string `json:"link,omitempty"`
	// contains filtered or unexported fields
}

Rest is why a candidate sits out after a failure, and until when.

func RestOf added in v0.1.930

func RestOf(key string) (Rest, bool)

RestOf is why what rests by key — a provider's id, or its id#key — is passed over now, while it is.

type Result

type Result struct {
	ID               string
	Model            string
	Parts            []Part
	Stop             string
	Usage            Usage
	SafeguardResults json.RawMessage
	StopDetails      json.RawMessage
}

Result is a whole reply, for non-streaming clients.

type Route added in v0.1.38

type Route struct {
	Seq           int64        `json:"seq"` // the trace's count when it last changed
	ID            int64        `json:"id"`
	Time          time.Time    `json:"time"`
	Agent         string       `json:"agent"`
	ParentSession string       `json:"parentSession,omitempty"` // title helper's explicit originating chat; does not affect routing
	Session       string       `json:"session,omitempty"`       // the client's session id, never inferred from its model or account
	TitleLink     *TitleLink   `json:"titleLink,omitempty"`     // digests only; display evidence, never account affinity
	ParentMatched bool         `json:"parentMatched,omitempty"` // parent inferred for this view, not supplied by Codex
	Usage         []RouteUsage `json:"usage,omitempty"`         // token tiers of billable tries; priced when read
	Kind          string       `json:"kind,omitempty"`          // what the call is for, as Call's
	For           *CallFor     `json:"for,omitempty"`           // the request it was made for, as Call's
	Model         string       `json:"model"`                   // as the agent asked
	Effort        string       `json:"effort,omitempty"`        // the reasoning the agent asked for; "" for none
	Tier          string       `json:"tier,omitempty"`          // the service tier the agent asked for (bodyTier); "" for none
	Provider      string       `json:"provider"`                // the provider the model resolved to
	Group         *GroupRef    `json:"group,omitempty"`         // the routing group the agent asked for
	Rule          *RuleHit     `json:"rule,omitempty"`          // the group's rules for it, when it has any
	SealedTask    bool         `json:"sealedTask,omitempty"`    // only ChatGPT accounts can read this subagent's task
	LeadAccount   string       `json:"leadAccount,omitempty"`   // the parent account put first for a sealed task
	// Subagent is a Codex or Claude Desktop subagent's request put on
	// the model set for its subagents, or kept on the one asked for and why
	Subagent *SubagentPick `json:"subagent,omitempty"`
	// Sub: the Claude Code subagent the request is of (subagentOf), whose
	// session header is its conversation's; "" for the conversation's own
	Sub string `json:"sub,omitempty"`
	// SubagentEffort is Desktop's configured effort. Tries keep the actual
	// level after member overrides and fitting to the model.
	SubagentEffort string `json:"subagentEffort,omitempty"`
	// SubagentID is the Claude Code subagent whose turn this is
	// (subagentTurnOf), the id the ledger's Subagent keeps too. Claude Code
	// names no kind for it, so Kind stays empty and the Routing page tags
	// it as Codex's subagents are.
	SubagentID string `json:"subagentId,omitempty"`
	// Nested: the rules of the groups in the group, down the way to the
	// one that went first, each as it decided
	Nested   []NestedRule `json:"nested,omitempty"`
	Affinity *Affinity    `json:"affinity,omitempty"` // its conversation, and whether it stayed put
	Pinned   string       `json:"pinned,omitempty"`   // the account AccountHeader named: only it was tried
	Order    []Weighed    `json:"order"`              // who was to try it, first first
	Left     []Weighed    `json:"left,omitempty"`
	Tries    []Try        `json:"tries"`
	Done     bool         `json:"done"`
	Status   int          `json:"status,omitempty"`
	Error    string       `json:"error,omitempty"`
	Millis   int64        `json:"ms,omitempty"`
	Tokens   int          `json:"tokens,omitempty"`
	Output   int          `json:"out,omitempty"` // of Tokens, the reply's
	// Reasoning: of Output, the reply's reasoning, which its speed leaves
	// out (usage.DecodeOf)
	Reasoning int `json:"reasoning,omitempty"`
	// TTFT: ms from the request to its reply's first content (text,
	// reasoning or a tool call), FirstText to its first text, as Millis
	// counts: streamed replies only (#196)
	TTFT      int64 `json:"ttft,omitempty"`
	FirstText int64 `json:"firstText,omitempty"`
	// FirstReasoning is the start of paced visible reasoning, absent for hidden reasoning.
	FirstReasoning  int64 `json:"firstReasoning,omitempty"`
	ReasoningHidden bool  `json:"reasoningHidden,omitempty"`
	// Flow: the ms its content took to come (Call.Flow)
	Flow int64 `json:"flow,omitempty"`
	// Sent: ms from the request to its answering try's request written
	// to the vendor, and of it Own magpie's, Retried the tries that
	// failed first, Queued waiting for a slot, as the usage record has
	// them (Record.Sent); the rest of Sent is connecting and sending
	Sent    int64 `json:"sent,omitempty"`
	Own     int64 `json:"own,omitempty"`
	Retried int64 `json:"retried,omitempty"`
	Queued  int64 `json:"queued,omitempty"`
	// Served: the model the reply says answered, as the last try has it;
	// Swapped: another than the one that try asked for; Routed: that try
	// asked another magpie's routing group, and Served is its member
	Served  string `json:"served,omitempty"`
	Swapped bool   `json:"swapped,omitempty"`
	Routed  bool   `json:"routed,omitempty"`
	// Upstream: the provider an aggregator said answered behind it
	Upstream string `json:"upstream,omitempty"`
	// Prompt: what the prompt held, part by part, and the window it went
	// into (prompt.go)
	Prompt *Prompt `json:"prompt,omitempty"`
	// Conv: the conversation a request without a session id is part of,
	// as a digest of its first user turn (conversationID)
	Conv string `json:"conv,omitempty"`
	// Folder: the last two levels of the folder its agent says it works
	// in (shortFolder), never the whole path; a request that says none
	// takes its session's, as said last (#1068)
	Folder string `json:"folder,omitempty"`
	// Archive: "<date>/<id>", where the request archive keeps the call,
	// when it was on (Call.Archive), for the page to read its bodies back
	// once the recent calls have let them go
	Archive string `json:"archive,omitempty"`
	// contains filtered or unexported fields
}

Route is one request's way through routing.

func HistoryRoute added in v0.1.572

func HistoryRoute(id int64, day time.Time) (Route, bool)

HistoryRoute searches the request's day and its neighbours (the browser and gateway may use different time zones), without holding up history writes.

type RouteTry added in v0.1.578

type RouteTry struct {
	Model  string `json:"model"` // provider/model
	Effort string `json:"effort,omitempty"`
	// Tier: the service tier it went out at; TierServed: the one its
	// reply said it ran at
	Tier       string `json:"tier,omitempty"`
	TierServed string `json:"tier_served,omitempty"`
	Done       bool   `json:"done"`
	Status     int    `json:"status,omitempty"`
	Fail       string `json:"fail,omitempty"` // why it failed, as the trace tells it
	Millis     int64  `json:"ms,omitempty"`
}

RouteTry is one member trying the request: each failed one was fallen over from.

type RouteUsage added in v0.1.591

type RouteUsage struct {
	Provider   string `json:"provider"`
	Model      string `json:"model"`
	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"`
}

RouteUsage is one billable attempt's pricing inputs, kept in routing history. Its JSON keys also read the earlier history that stored full usage records.

func (RouteUsage) PricingRecord added in v0.1.591

func (u RouteUsage) PricingRecord() usage.Record

PricingRecord lets the routing view reuse the ledger's effective prices.

type RuleHit added in v0.1.94

type RuleHit struct {
	N    int      `json:"n"`             // the rule, from 1; 0 when none matched
	Use  string   `json:"use,omitempty"` // the member it puts first
	When []string `json:"when,omitempty"`
	Held bool     `json:"held,omitempty"` // decided when the turn began
	// Waits: the turn began before magpie saw it (or its rule was changed
	// since), so no rule moves it; the next turn is looked at afresh
	Waits bool `json:"waits,omitempty"`
	// Grown: within the turn the conversation grew past what the model it
	// was on can take, so the rules were looked at again — the one time a
	// turn moves
	Grown  bool   `json:"grown,omitempty"`
	Turn   int    `json:"turn"`             // the user's turns so far
	Tokens int    `json:"tokens"`           // how long the request was taken to be
	Images bool   `json:"images,omitempty"` // it carries an image
	Effort string `json:"effort,omitempty"` // the reasoning asked for: a level, or "on"
	// Folder: the working folder the agent said, looked at when a rule
	// is by folder; "" when it said none
	Folder string `json:"folder,omitempty"`
	// Unready: the member the rule names has nobody to take it now, and
	// the group routes the request as it would without the rule.
	Unready bool `json:"unready,omitempty"`
	// Then: the members the rules after it that match too send to, which
	// the request fails over to, in turn, before the group's others (#112)
	Then []string `json:"then,omitempty"`
	// Instead: the one of Then that went first, Use having nobody ready
	Instead string `json:"instead,omitempty"`
	// Classified: the group's classifier was asked which intent the
	// turn's first message is
	Classified *Classified `json:"classified,omitempty"`
	// Pick: the reasoning the group's decision model picked for the turn,
	// which its requests ask their model for (provider.EffortAuto)
	Pick string `json:"pick,omitempty"`
	// Wanted: the reasoning the decision model picked for the turn when
	// the conversation kept a higher one (Pick) for the vendor's cache of
	// it (#617) — sent instead where the change goes as an effort update
	// that keeps the cache (takesEffortUpdates)
	Wanted string `json:"wanted,omitempty"`
	// Compact: the request is the agent compacting its conversation, looked
	// at on its own; Small, the members of rules it matched that take less
	// than it is long, passed over
	Compact bool     `json:"compact,omitempty"`
	Small   []string `json:"small,omitempty"`
	// Bare: the group has no rules, only its effort picked
	Bare bool `json:"bare,omitempty"`
}

RuleHit is what the trace tells of a group's rules for a request.

type SearchFailure added in v0.1.1216

type SearchFailure struct {
	Searcher     string // "<provider>/<model>", or "<provider>"
	Why          string // the error, when it neither found nothing nor didn't search
	NothingFound bool   // it searched and named no page
	NotSearched  bool   // it answered without searching (errNotSearched)
	At           time.Time
}

SearchFailure is a search the searcher Settings names didn't make: why, and when.

func SearcherFailed added in v0.1.1216

func SearcherFailed() (SearchFailure, bool)

SearcherFailed is the last search the searcher Settings names now didn't make, since it last searched; ok false when there is none.

type SearchKeyQuota added in v0.1.1231

type SearchKeyQuota struct {
	Key string `json:"key"` // masked (provider.MaskSearchKey)
	// Known: Used and Limit were read. Unlimited: read, and the key and
	// its plan have no limit (Used is what the key has used).
	Known     bool  `json:"known"`
	Unlimited bool  `json:"unlimited,omitempty"`
	Used      int64 `json:"used"`
	Limit     int64 `json:"limit"`
	// Of is what Limit is the limit of: "key", a limit set on the key
	// itself, or "plan", its account's plan (which every key of the
	// account spends)
	Of   string `json:"of,omitempty"`
	Plan string `json:"plan,omitempty"` // the plan's name
	// PaygoLeft is the pay-as-you-go credit still there past the plan's
	// limit, 0 when there is none
	PaygoLeft int64 `json:"paygoLeft,omitempty"`
	// UsedUp: Used reached Limit, with no pay-as-you-go credit left
	UsedUp bool `json:"usedUp,omitempty"`
	// Err is why it couldn't be read: Known is false
	Err string `json:"err,omitempty"`
	// Resting is why searches ask the key last now (searchKeyOrder), and
	// RestUntil until when; "" when they don't
	Resting   string    `json:"resting,omitempty"`
	RestUntil time.Time `json:"restUntil,omitzero"`
}

SearchKeyQuota is what one key of a search API has used of its limit.

func SearchQuotas added in v0.1.1231

func SearchQuotas(ctx context.Context, a provider.SearchAPI, fresh bool) []SearchKeyQuota

SearchQuotas reads what each of a search API's keys has left, in the order of its keys, nil for an API magpie can't ask (CanReadSearchQuota). A read newer than searchQuotaKeep is used again unless fresh is set. A key it finds used up rests (a search asks it last); one with credit that rests for being out of it wakes.

type SearcherChoice added in v0.1.672

type SearcherChoice struct {
	Provider provider.Provider
	Small    string // the model it searches with when none is named
	Models   []catalog.Model

	ManualOnly bool // a relay said to search, which only Settings may name
	// Service is a Kimi Code plan, which searches by its search service,
	// with no model (and no Small or Models)
	Service bool
	// Own is a Google sign-in, whose Gemini searches for the provider's
	// own models first, whoever is named (ownSearcher)
	Own bool
	// contains filtered or unexported fields
}

SearcherChoice is a provider Settings' Searcher may name.

func Searchers added in v0.1.672

func Searchers() []SearcherChoice

Searchers are the providers Settings' Searcher may name: those magpie would pick, then relays said to search, each with the model it would search with.

type Served added in v0.1.638

type Served struct {
	Running bool   // a magpie gateway answers
	Window  bool   // its routing can be watched in its window (#110)
	Version string // its version; "" from one that doesn't say
}

Served is what the magpie answering at the gateway's address says of itself.

func ServedBy added in v0.1.638

func ServedBy() Served

ServedBy asks the address which magpie answers there. Another magpie can keep the port after this one is updated (a magpie serve left running, a second copy, one that didn't quit), and every agent's request is then still that one's to send: in #506 a Factory 403 came worded as v0.1.550 and earlier word it to two people whose magpie said v0.1.630, so none of the fixes since reached their requests. Its version tells it apart.

type Server

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

Server is the gateway.

func New

func New() *Server

New makes a gateway.

func (*Server) Active added in v0.1.1241

func (s *Server) Active() []Active

Active lists the agent requests in flight now, the oldest first; empty, never nil, when there are none.

func (*Server) Busy added in v0.1.672

func (s *Server) Busy() Busy

Busy says what is in flight at the gateway now.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler routes the client APIs.

func (*Server) Lanes added in v0.1.633

func (s *Server) Lanes() map[string]Lane

Lanes is how each key or account with requests out or waiting under a limit stands, by its who (provider, provider#key, provider@account).

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe runs the gateway until ctx ends, and returns once the requests in flight then have finished: within 2s, or, handing over, as long as a stream takes. A bind error means another magpie is already serving, which is fine for the caller to ignore.

func (*Server) PromptText added in v0.1.1169

func (s *Server) PromptText(id int64, kind string, withText bool) (PromptText, bool)

PromptText is the part kind of request id's prompt, item by item, in the card's order: the turns oldest first, the rest largest first. Each entry's text is there when withText; false when the request's body is no longer kept, or its prompt can't be read.

func (*Server) Recent

func (s *Server) Recent() []Call

Recent lists the last calls, newest first.

func (*Server) RecentCall added in v0.1.1172

func (s *Server) RecentCall(id uint64) (Call, bool)

RecentCall is the call numbered id while it is still in the ring.

func (*Server) Relisten added in v0.1.168

func (s *Server) Relisten() error

Relisten moves the gateway to where settings now say it listens — onto the network or back to loopback, or to another port. Requests in flight finish.

func (*Server) ResolveTitleParents added in v0.1.840

func (s *Server) ResolveTitleParents(rows []Route) []Route

ResolveTitleParents checks completed title replies against actual Codex name writes. It operates on copies for the GUI only, never on gateway routing. An explicit parent wins. Missing, conflicting or old evidence fails closed.

func (*Server) RouteCall added in v0.1.1265

func (s *Server) RouteCall(route int64) (Call, bool)

RouteCall is the call the Routing page's request route was, while it is still in the ring.

func (*Server) Trace added in v0.1.38

func (s *Server) Trace(ctx context.Context, after int64, wait time.Duration) TraceState

Trace is the routes changed after seq, oldest first. With none, it waits up to wait for one.

func (*Server) Unrest added in v0.1.304

func (s *Server) Unrest(key string) bool

Unrest lifts the rest of what rests by key — an account just verified with its vendor, say — so the next request asks it again. False when it wasn't resting.

func (*Server) UnrestAll added in v0.1.1220

func (s *Server) UnrestAll(key string) int

UnrestAll lifts every rest of what rests by key: its own and each of its models' (restID, key/model). A key whose value was replaced (#1869) is asked again for all of them. It returns how many it lifted.

type SessionRoute added in v0.1.578

type SessionRoute struct {
	ID          int64        `json:"id"`
	Time        time.Time    `json:"time"`
	Kind        string       `json:"kind,omitempty"`         // a side call's: a title, a subagent…
	Asked       string       `json:"asked"`                  // the model as the agent asked
	AskedEffort string       `json:"asked_effort,omitempty"` // the reasoning it asked for
	AskedTier   string       `json:"asked_tier,omitempty"`   // the service tier it asked for
	Group       string       `json:"group,omitempty"`        // the routing group's id, when it asked one
	Rule        *RuleHit     `json:"rule,omitempty"`         // the group's rules, as the Routing page has them
	Nested      []NestedRule `json:"nested,omitempty"`
	// Model and Effort: the try under way, or the last, as provider/model
	// and the reasoning it was sent at
	Model  string `json:"model,omitempty"`
	Effort string `json:"effort,omitempty"`
	// Tier and TierServed: the service tier that try went out at, and the
	// one its reply said it ran at, when it said one (#1784)
	Tier       string     `json:"tier,omitempty"`
	TierServed string     `json:"tier_served,omitempty"`
	Served     string     `json:"served,omitempty"` // the model the reply says answered
	Tries      []RouteTry `json:"tries"`
	Done       bool       `json:"done"`
	Status     int        `json:"status,omitempty"`
	Error      string     `json:"error,omitempty"`
	Millis     int64      `json:"ms,omitempty"`
	TTFT       int64      `json:"ttft_ms,omitempty"`
}

SessionRoute is a session's latest request as routing has it so far.

type SubGroup added in v0.1.102

type SubGroup struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Routing string `json:"routing"`
	In      string `json:"in"`              // the group it is in
	Rules   int    `json:"rules,omitempty"` // how many rules it has
}

SubGroup is a routing group in the group a request asked for.

type SubagentPick added in v0.1.1142

type SubagentPick struct {
	Asked string `json:"asked"`
	To    string `json:"to"`
	Kept  string `json:"kept,omitempty"`
}

SubagentPick is a subagent's request put on the model the user set for its agent's subagents, in place of the one its lead asked for: Codex's (provider.CodexSubagentModel, willz on Discord) or Claude Desktop's (provider.DesktopSubagentModel). Kept says why it went on the model asked for instead, "" when it was put on To.

func (*SubagentPick) Moved added in v0.1.1142

func (p *SubagentPick) Moved() bool

Moved says the request went on To.

type TitleLink struct {
	Scope  string `json:"scope"`
	Prompt string `json:"prompt"`
	Reply  string `json:"reply,omitempty"`
}

TitleLink contains only fingerprints. Native request IDs and account affinity are never changed by an inferred display association.

type Tool

type Tool struct {
	Name        string
	Description string
	Schema      json.RawMessage // JSON schema of the arguments
	Strict      bool            // the client asked for its arguments held to the schema
}

Tool is a function the model may call.

type Totals added in v0.1.38

type Totals struct {
	Requests int `json:"requests"` // answered, one way or the other
	Rerouted int `json:"rerouted"` // tries that failed and handed the request on
	Errors   int `json:"errors"`   // requests whose agent got an error
}

Totals count the requests routed since the gateway started.

type TraceState added in v0.1.38

type TraceState struct {
	Seq    int64   `json:"seq"`
	Routes []Route `json:"routes"`
	Totals Totals  `json:"totals"`
}

TraceState is the routes changed since a seq, and the totals.

type Try added in v0.1.38

type Try struct {
	ID     string `json:"id"`
	Model  string `json:"model,omitempty"`  // the model it was asked for: a group's members may share a provider's keys
	Effort string `json:"effort,omitempty"` // the reasoning it was sent at, fitted to its model's levels; "" for none
	Picked bool   `json:"picked,omitempty"` // Effort is the turn's pick, in place of the agent's
	// Fixed: the effort the group's member it went to is fixed at, which
	// Effort is (fitted to the model's levels) whatever was asked
	Fixed  string    `json:"fixed,omitempty"`
	Fast   bool      `json:"fast,omitempty"` // sent in its vendor's fast mode, as the group's member it went to is
	Start  time.Time `json:"start"`
	Done   bool      `json:"done"`
	Status int       `json:"status,omitempty"`
	Millis int64     `json:"ms,omitempty"`
	// TTFT: ms from Start to its reply's first content, FirstText to its
	// first text, when it streamed any (#196)
	TTFT      int64 `json:"ttft,omitempty"`
	FirstText int64 `json:"firstText,omitempty"`
	// FirstReasoning is the start of paced visible reasoning, absent for hidden reasoning.
	FirstReasoning  int64 `json:"firstReasoning,omitempty"`
	ReasoningHidden bool  `json:"reasoningHidden,omitempty"`
	// Flow: the ms its content took to come (Call.Flow)
	Flow int64 `json:"flow,omitempty"`
	// Served: the model its reply said answered, when it named one;
	// Swapped: another model than Model, not just its dated name; Routed:
	// Model is another magpie's routing group, and Served the member it
	// routed to (usage.GroupRouted)
	Served  string `json:"served,omitempty"`
	Swapped bool   `json:"swapped,omitempty"`
	Routed  bool   `json:"routed,omitempty"`
	// Upstream: the provider an aggregator said answered behind it
	// (OpenRouter's DeepInfra, Novita …)
	Upstream string `json:"upstream,omitempty"`
	// Tier: the service tier it went out at, once a fast pick or an
	// account without Ultrafast had changed it; TierServed: the one its
	// reply said it ran at, when it said one (#1784)
	Tier       string `json:"tier,omitempty"`
	TierServed string `json:"tierServed,omitempty"`
	Fail       string `json:"fail,omitempty"` // why it failed, as rest tells it
	Error      string `json:"error,omitempty"`
	Rest       *Rest  `json:"rest,omitempty"`  // how long it now sits out; none when it was the last to try
	Again      int64  `json:"again,omitempty"` // ms waited before it was tried again, the last one left
	// Replan: every member had failed in a way that passes, so after
	// Again the Replan of them that may answer by then were asked again,
	// in turn, within the group's Patience (seconds) for the request
	// (#1418)
	Replan   int `json:"replan,omitempty"`
	Patience int `json:"patience,omitempty"`
	// Gone: the agent canceled the request in the pause Again was to be
	// waited, so nobody was asked again (#1894: the Routing page's story
	// otherwise ended on "tried again in 1s", a retry that never came)
	Gone bool `json:"gone,omitempty"`
	// Earlier: the last try, its allowance run out, whose error the agent
	// wasn't told: it got the first failure before it that wasn't an
	// allowance's (Discord, waroy). Whether a try went on is the next
	// try in Tries, which is appended only as it is asked (#2281)
	Earlier bool `json:"earlier,omitempty"`
	// Queued: ms it waited for one of its key's or account's slots, the
	// provider's MaxConcurrency out already (concurrency.go)
	Queued int64 `json:"queued,omitempty"`
	// Net: where its time went up to its reply's first byte (TryNet)
	Net *TryNet `json:"net,omitempty"`
	// Reset: its week used up and nobody else left, one of the account's
	// Codex resets was spent by itself (the user's setting) — on Who, and
	// what spending it did — and the request asked again
	Reset *AutoReset `json:"reset,omitempty"`
	// Auto: the models Copilot's Auto picked for it, in turn — where each
	// pick came from and Copilot's refusal of it — Model being "auto"
	Auto []provider.AutoPick `json:"auto,omitempty"`
}

Try is one candidate trying the request.

type TryNet added in v0.1.1260

type TryNet struct {
	// Own: magpie's, from the try's Start to its request going out, the
	// queue for a slot (Try.Queued) left out
	Own float64 `json:"own,omitempty"`
	// Before: requests made on the way before the last one, from the
	// first's going out to the last's (a token refreshed, a request
	// asked again); Asks counts them all, the last one too
	Before float64 `json:"before,omitempty"`
	Asks   int     `json:"asks,omitempty"`
	// Pool: waiting for a connection that wasn't dialed for it, the
	// client's limit per host out; DNS, Connect and TLS are a new
	// connection's; Reused: an open connection carried it, none of the
	// three spent
	Pool    float64 `json:"pool,omitempty"`
	DNS     float64 `json:"dns,omitempty"`
	Connect float64 `json:"connect,omitempty"`
	TLS     float64 `json:"tls,omitempty"`
	Reused  bool    `json:"reused,omitempty"`
	// Send: writing the request, headers and body, on the connection
	Send float64 `json:"send,omitempty"`
	// Wait: the vendor's, from the request written to its reply's first
	// byte (its headers)
	Wait float64 `json:"wait,omitempty"`
	// Head: from the try's Start to that first byte, which the try's TTFT
	// (to the reply's first content) is counted from too
	Head float64 `json:"head,omitempty"`
}

TryNet is where a try's time went up to its reply's first byte, as Go's HTTP client saw the request that went out to the vendor last (a sign-in refreshed or a request asked again on the way are Before): what was magpie's, the network's and the vendor's, so a slow turn says whose it was (Discord, Magic_zero: "网关连接提供商和回复到agent的速度 有点慢"). Each is in ms, to a tenth; absent for a try whose request went out some other way (a plugin's own fetch, an agent's app).

type TurnEnd added in v0.1.1191

type TurnEnd struct {
	Agent   string // magpie's id for it: claude, codex, opencode …
	Session string // the agent's session id, "" when it sends none
	Folder  string // the folder it says it works in, "" when it doesn't
	Took    time.Duration
}

TurnEnd is a turn that ran at least as long as Settings' TurnDoneAlert.

type Usage

type Usage struct {
	Input      int `json:"input"`
	Output     int `json:"output"`
	CacheRead  int `json:"cache_read"`
	CacheWrite int `json:"cache_write"`
	// CacheWrite1h is how many of the CacheWrite tokens were written to
	// be kept for an hour, which Anthropic bills at 2× input where a
	// 5-minute write is 1.25×, when its usage says so (cache_creation's
	// ephemeral_1h_input_tokens)
	CacheWrite1h int `json:"cache_write_1h,omitempty"`

	Reasoning int `json:"reasoning"`
	// Served: the model the vendor's reply says answered, when it named
	// one — which may not be the one it was asked for
	Served string `json:"served,omitempty"`
	// Upstream: the provider an aggregator says answered behind it
	// (OpenRouter's "provider": DeepInfra, Novita …), when it says one
	Upstream string `json:"upstream,omitempty"`
	// RequestID: the id the vendor gave the request, from its reply's
	// headers (Claude Code's own for a subscription); ErrType: what a
	// failed request's error body called the error
	RequestID string `json:"request_id,omitempty"`
	// ResponseID is the final client response ID, independent of request headers.
	ResponseID string `json:"response_id,omitempty"`
	ErrType    string `json:"err_type,omitempty"`
	// Stop is why the upstream said its reply ended, in its own words
	// (stop_reason, finish_reason, a Responses status): "" when it said
	// none, as a stream that just stops does (upstreamStop)
	Stop string `json:"stop,omitempty"`
	// Tier is the service tier the reply says it ran at (upstreamTier),
	// "" when it says none
	Tier string `json:"tier,omitempty"`
	// Deferred is what the reply counted of earlier requests of its
	// conversation, which their own replies couldn't (cUsage's
	// MagpieDeferred): billed with this one, never told as its prompt
	Deferred *Usage `json:"deferred,omitempty"`
	// Credits is what the reply said the request cost in its plan's own
	// credits, nil when it said none: WorkBuddy's usage.credit, the
	// figure its app shows on each reply as "Credits Consumed" (#2512)
	Credits *float64 `json:"credits,omitempty"`
	// contains filtered or unexported fields
}

Usage counts tokens.

type Weighed added in v0.1.38

type Weighed struct {
	ID       string  `json:"id"` // what rests after a failure
	Provider string  `json:"provider"`
	Name     string  `json:"name"` // the provider's
	Icon     string  `json:"icon,omitempty"`
	Preset   string  `json:"preset,omitempty"`
	Who      string  `json:"who,omitempty"` // the account, or the key's name or its masked self
	Kind     string  `json:"kind"`          // "account", "key", or "provider" when it has one
	Agent    string  `json:"agent,omitempty"`
	Plan     string  `json:"plan,omitempty"`
	Model    string  `json:"model"`
	Fixed    string  `json:"fixed,omitempty"` // the effort the group's member it is of is fixed at
	Fast     bool    `json:"fast,omitempty"`  // the group's member it is of is sent fast
	Routing  string  `json:"routing"`         // its provider's: "", order, rotate, usage
	Fallback bool    `json:"fallback,omitempty"`
	Shared   bool    `json:"shared,omitempty"` // its provider has more than one on
	Known    bool    `json:"known,omitempty"`  // the vendor said what the account has left
	Learns   bool    `json:"learns,omitempty"` // not known, but its answer will tell
	Used     float64 `json:"used"`             // share of the allowance counting the model, used
	// Amount of Limit in Unit: the count that share is of, when the
	// vendor counts it so (WorkBuddy's credits, #659)
	Amount   float64           `json:"amount,omitempty"`
	Limit    float64           `json:"limit,omitempty"`
	Unit     string            `json:"unit,omitempty"`
	Renews   []time.Time       `json:"renews,omitempty"` // when those windows renew, the biggest first
	Pace     float64           `json:"pace,omitempty"`   // remaining allowance per hour until its window resets
	Due      *time.Time        `json:"due,omitempty"`    // when the allowance window used for pace resets
	Tokens   float64           `json:"tokens,omitempty"` // least used: tokens it served lately
	Turn     bool              `json:"turn,omitempty"`   // in turn: it was this one's turn
	Fit      int               `json:"fit,omitempty"`    // keyFit
	Speaks   provider.Protocol `json:"speaks,omitempty"` // a key made for one protocol only
	Rest     *Rest             `json:"rest,omitempty"`   // resting after a failure, when the request came
	Unlisted bool              `json:"unlisted,omitempty"`
	// DueBy: "reset" when Due is when an auto-used Codex reset about to
	// run out starts the windows again, sooner than they renew (#717)
	DueBy string `json:"dueBy,omitempty"`
	// Restarts: when that reset starts them again, set when it is sooner
	// than its biggest window renews — Smart goes by it then (#718)
	Restarts *time.Time `json:"restarts,omitempty"`
	// Barred: left out as the user set it not to serve the model, its
	// own list of models leaving it out (#474)
	Barred bool `json:"barred,omitempty"`
	// Held: left out as the gateway key asking may not use its account or
	// key (#905)
	Held bool `json:"held,omitempty"`
	// Capped: left out as held at the usage cap the user set on the
	// account, this cap in percent; Used is then its fullest window's
	// share, CapBack when the last window at or past it renews
	Capped  int        `json:"capped,omitempty"`
	CapBack *time.Time `json:"capBack,omitempty"`
	// NoCredits: held at 100% (Capped), a Codex account the user set not
	// to spend its credits once its allowance is used up
	NoCredits bool `json:"noCredits,omitempty"`
	// Rank: its place in its provider's own list of accounts or keys, the
	// order the provider's page shows and a drag sets (#217); routing may
	// weigh them in another
	Rank int `json:"rank,omitempty"`
	// Aside: a key made for another protocol than the keys routed over,
	// tried only after them
	Aside bool `json:"aside,omitempty"`
	// NoURL: its keys are all set to this protocol, which its provider has
	// no URL for, so it was tried on the URLs it has (#1702)
	NoURL provider.Protocol `json:"noURL,omitempty"`
	// Via: the groups in the group it is of, outermost first, when it is
	// of a group in the group asked for
	Via []string `json:"via,omitempty"`
	// UsedRenews: when the window Used is the share of renews, apart
	// from Renews' biggest first: a row says the two together, so of one
	// window, a Factory account's week and not its month (#1778)
	UsedRenews *time.Time `json:"usedRenews,omitempty"`
	// Sunk: when it was rate limited with quota left, sending it to the
	// back of an order that sinks (sink.go); nil when it didn't, or the
	// order doesn't sink
	Sunk *time.Time `json:"sunk,omitempty"`
}

Weighed is one account or key as routing weighed it.

Source Files

Jump to

Keyboard shortcuts

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