Help us shape the future of Go! Take the 2026 Go Developer Survey

provider

package
v0.1.1407 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 82 Imported by: 0

Documentation

Overview

Package provider holds the model vendors magpie can reach: where each one lives, which protocols it speaks, the API key the user typed in, and which of its models should show up in the agents' pickers.

Provider keys are never read from environment variables. A provider is exactly what the user entered, kept in ~/.config/magpie/providers.json (mode 0600).

Index

Constants

View Source
const (
	MinCap = 1
	MaxCap = 99
)

MinCap and MaxCap bound an account's cap, in percent: none is no cap.

View Source
const (
	AuthBoth    = ""                  // x-api-key and Authorization: Bearer, the default
	AuthXAPIKey = catalog.AuthXAPIKey // x-api-key alone
	AuthBearer  = catalog.AuthBearer  // Authorization: Bearer alone
)

The headers a third-party Anthropic API's key goes in (Provider.AuthHeader).

View Source
const (
	SplitGranted = "Granted"
	SplitTopUp   = "Topped up"
)

Split labels: what a balance is made of, each a key the GUI words in the user's language (the TUI and CLI say it in English).

View Source
const (
	ResetCaseWeek     = "week"
	ResetCaseExpiring = "expiring"
)

The two times an account the user lets spend its resets by itself spends one, each of which can be on alone (#2078): its week used up and no other account left (AutoUseCodexReset), and the one about to run out unused (SpendExpiringCodexResets).

View Source
const (
	ResetUsedWeek     = "week"
	ResetUsedExpiring = "expiring"
	ResetUsedByHand   = "hand"
)

Why a reset was used: by itself as the account's week was used up and no other account could answer (AutoUseCodexReset), by itself as it was about to run out unused (SpendExpiringCodexResets), or by hand from the Usage page, the panel or the CLI (UseCodexReset).

View Source
const (
	MaxLimit      = 1000
	MaxQueueLimit = 10000
	MaxQueueWait  = 3600
)

MaxLimit bounds a limit on requests at once; MaxQueueLimit how many may wait, MaxQueueWait how long one waits, in seconds.

View Source
const (
	CloudflareJev       = "typesafe/jev"
	CloudflareClefModel = "@cf/cloudflare/clef"
	CloudflareClefFlash = "@cf/cloudflare/clef-flash"
)
View Source
const (
	ViaSystemOne  = "systemone"
	ViaVercel     = "vercel"
	ViaVercelEval = "vercel-eval"
	ViaCloudflare = "cloudflare"
)

The ways a decision API is asked, by where it is (DecideVia): TypeSafe's own System One; Vercel's AI Gateway, at its TypeSafe API (System One's questions and answers, with its own name for Jev) or, where an older setup points, at the AI SDK's evaluation models (a boolean for a noul and probabilities for a confidence); or Workers AI (System One's questions and answers, in Cloudflare's envelope and at an account's address).

View Source
const (
	DetectMax  = 30
	DetectWide = 8
)

A detection of many models asks at most DetectMax of them, DetectWide requests at a time, each waiting detectWait for its answer.

View Source
const (
	AffinitySession = "session"
	AffinityTurn    = "turn"
	AffinityOff     = "off"
	// AffinityStrict keeps a conversation on the key or account that
	// answered it whatever happens: resting, all but used up or past the
	// usage cap set on it, it is still the one asked, and its error goes
	// to the agent rather than the conversation to another. A usage cap
	// still keeps new conversations off it.
	AffinityStrict = "strict"
)
View Source
const (
	PatienceOff     = -1
	PatienceDefault = 60
	PatienceLongest = 240
)

PatienceOff, PatienceDefault and PatienceLongest are a group's Patience: none, the seconds a group waits that hasn't set it, and the most it may.

View Source
const (
	ShareMark    = "routing-group"
	ShareVersion = 1
)

A routing group shared as text (laincatx on X): one group's routing, rules and members, copied from one magpie and pasted into another. It says what it is (ShareMark) and in which format (ShareVersion), so a magpie can tell it from any other text and one made by a newer magpie from one it can read.

View Source
const (
	// TemplateSmart sends a turn the classifier judges hard to the
	// strongest model and one it judges easy to a cheap one; a compaction
	// goes to the cheap one too.
	TemplateSmart = "smart"
	// TemplateThrifty sends everything to a cheap model first, and to the
	// strongest when the agent asks for high reasoning or every cheap one
	// fails.
	TemplateThrifty = "thrifty"
	// TemplateSteady is the strongest model of each of up to three
	// providers, in order, so one vendor down or out of quota doesn't stop
	// the agent.
	TemplateSteady = "steady"
)
View Source
const (
	IntentHard = "a hard task: designing, debugging, a change across several files, or planning"
	IntentEasy = "an easy task: a quick question, a small edit, a lookup, or running a command"
)

The intents TemplateSmart's classifier chooses between. Hard comes first, so a turn the classifier can't place stays on the strong model, the group's first.

View Source
const (
	NeedProvider  = "provider"
	NeedProviders = "providers"
	NeedCheap     = "cheap"
)
View Source
const (
	MoveMoving = "moving" // under way, or cut short (put back at the next try)
	MovePlugin = "plugin" // the plugin has the id
	MovedBack  = "back"   // moved back to the built-in by an older magpie: moved again by itself
	MoveFailed = "failed" // the last try failed: the built-in carries on
	// MoveRemoved is a moved one whose plugin the user removed: its
	// accounts stay with the plugin's sign-ins, and the plugin installed
	// again has it at once (HandOver). Nothing installs it by itself.
	MoveRemoved = "removed"
)

A migration's states.

View Source
const (
	MiniMaxCodeID       = "minimax-code"
	MiniMaxCodeGlobalID = "minimax-code-global"
)

MiniMaxCodeID is the MiniMax Code plugin's provider (the China site), MiniMaxCodeGlobalID its international site's.

View Source
const (
	KindImage = "image"
	KindVideo = "video"
)

What a model makes, as the user says it (shen-joe, #1399): a provider set up with a base URL tells magpie its image and video models by its own model list ("kind": "image" or "video") or, for images, by a model's name. A relay whose list says neither — most don't — leaves a video model making nothing, and an image model with an odd name drawing nothing. The user can say so of one model instead, kept in settings' ModelKinds by "<provider id>/<model id>" as a model's name is: an image model is drawn with at the images API under the provider's base, a video model asked at its videos API, as one its list marks is (gateway's Drawers and customVideomakers).

View Source
const (
	SuffixOn  = "on"
	SuffixOwn = "own"
	SuffixOff = "off"
)

The ways the agents' lists name models (SuffixMode): every name with its provider's after it, as by default; all but the names the user gave models (#92); or none (#335).

View Source
const (
	PartnerShown  = "shown"  // the add sheet listed it
	PartnerOpened = "opened" // its row was opened
	PartnerKeys   = "keys"   // its key page was opened
	PartnerAdded  = "added"  // a provider was added from it
)

What is counted for a partner.

View Source
const (
	WorkDirHeader = "X-Magpie-Work-Dir"
	WorkGitHeader = "X-Magpie-Work-Git"
)

WorkDirHeader and WorkGitHeader tell a plugin's fetch where the agent that asked works, as the agent says it in its request: the folder, percent-encoded (decodeURIComponent reads it), and "yes" or "no" for whether it is in a git repository. Each is left off when it isn't known. The plugin host takes them off whatever the plugin sends on (host.js), so they reach no vendor as headers.

View Source
const (
	Ordered   = "order"
	Rotate    = "rotate"
	LeastUsed = "usage"
	Pace      = "pace"
	// Weighted spreads a provider's requests over its keys by each key's
	// weight (KeyAccount.Weight, #841), smoothly: 3 and 1 go a, a, b, a…
	Weighted = "weight"
	// FreeFirst spends what costs nothing first: the models its vendor
	// serves at no cost to the subscription's allowance or credits, before
	// the ones that spend it (routes.FreeFirst).
	FreeFirst = "free"
)

The routings besides the default, smart, in order.

View Source
const (
	SearchPickTurns = ""      // in turn, each search the next key
	SearchPickOrder = "order" // the first until it is refused
)

How a search picks among a search API's keys (SearchAPI.Pick).

View Source
const (
	ClientCodex      = "codex"
	ClientClaudeCode = "claude-code"
)

The clients a test can be asked as.

View Source
const (
	HoldsLow        = "low"     // under HoldsFloor used
	HoldsNoClock    = "clock"   // no reset clock, so no known start
	HoldsBeforeLog  = "log"     // began before magpie's log does
	HoldsNoneRouted = "none"    // magpie routed nothing it counts in it
	HoldsCredits    = "credits" // a call in it may have been paid from credits
)

Why a window's whole isn't told (QuotaWindow.HoldsWhy), for the GUI to say "not enough data" and why rather than leave it out (#2045).

View Source
const (
	CheckinClaimed    = "claimed"    // claimed by magpie
	CheckinDone       = "done"       // in already, pressed in WorkBuddy or before
	CheckinIneligible = "ineligible" // the account can't take part
	CheckinInactive   = "inactive"   // no event running, or it has ended
	CheckinFailed     = "failed"     // no answer; tried again later that day
	// CheckinCaptcha is a plugin's check-in the vendor asked a captcha
	// of: the user checks in in its own app, magpie never solves one
	CheckinCaptcha = "captcha"
	// CheckinOwnApp is a check-in the user is to do in the vendor's own
	// app: an answer for the day. WorkBuddy's check-in answered 401 while
	// the sign-in works; Trae CN refused the claim with 9074, which says
	// so in its own words (#1920), not that only its app is paid
	CheckinOwnApp = "own-app"
)

What came of a day's check-in, WorkBuddyCheckin.Outcome.

View Source
const AntigravityRisk = "Google may suspend an Antigravity account it sees used outside Antigravity. Use one you can afford to lose."

AntigravityRisk is what magpie says before an Antigravity account is added.

View Source
const Auto = "auto"

Auto is the word that takes one part of a spec back to the vendor's list and models.dev.

View Source
const AutoFallback = "fallback"

AutoFallback is an Auto pick that is the model the account may pick by hand, Copilot having no Auto session to give it (copilotAutoFallback).

View Source
const AutoPrefix = "auto/"

AutoPrefix starts the id agents are given for a group magpie found: "auto/<model>".

View Source
const AzurePreset = "azure"

AzurePreset is the preset's id.

View Source
const BailianDecision = "decision-model-preview"

BailianDecision is Alibaba Cloud Bailian's decision model, asked on the same System One API as Jev (#647).

View Source
const BlockedHint = "the provider's network firewall blocked requests from this IP; wait a while, or switch to another network or proxy"

BlockedHint is what a vendor's edge firewall blocking magpie's address means, in plain words: Alibaba Cloud's (ESA, in front of zcode.z.ai) answers a 405 HTML page, "Sorry, your request has been blocked due to unusual activity", linking errors.aliyun.com. Nothing in the request is at fault and magpie changes nothing about it: the address is.

View Source
const ChatGPTAPIID = "chatgpt-api"

ChatGPTAPIID is the subscription's id, as a provider and in logins.json.

View Source
const ClaudeRisk = "" /* 228-byte string literal not displayed */

ClaudeRisk is what magpie says before a Claude account is added, as the window does.

View Source
const ClineVersion = "3.5.54"

ClineVersion is the Cline desktop release magpie says it is to the Cline API.

View Source
const CodexDaemonRestart = "codex app-server daemon restart"

CodexDaemonRestart is the command that restarts Codex's app-server, for the user to run themselves.

View Source
const CommandCodeGoHint = "" /* 204-byte string literal not displayed */

CommandCodeGoHint says where a Go plan's key works.

View Source
const CommandCodeMaxOutput = 200_000

CommandCodeMaxOutput is the most max_tokens Command Code takes at /alpha/generate, for any model: more is refused ("Too big: expected number to be <=200000 at params.max_tokens"). models.dev gives some of its models more (DeepSeek V4's 384000, MiniMax M3's 512000).

View Source
const CommandCodePlanID = "commandcode-plan"

CommandCodePlanID is the subscription's id, and its sign-in's.

View Source
const ContextSmallest = -1

ContextSmallest is a group's Context when agents are told the window of its smallest member.

View Source
const ConversationHeader = "X-Magpie-Conversation"

ConversationHeader carries the conversation a request belongs to, to a plugin's chat.headers hook as its session; it goes no further.

View Source
const CopilotAuto = "auto"

CopilotAuto is the model id that has Copilot pick the model.

View Source
const DecidersHeader = "X-Magpie-Deciders"

DecidersHeader asks a magpie's model list for its decision models too.

View Source
const DrawersHeader = "X-Magpie-Drawers"

DrawersHeader asks a magpie's model list for its image models as well.

View Source
const EffortAuto = "auto"

EffortAuto is a group whose classifier picks each turn's reasoning effort (Group.Effort).

View Source
const FastWord = "fast"

FastWord is the last part of a member typed to be sent fast.

View Source
const FlatSep = "~"

FlatSep stands for each slash of a catalog id in its flat spelling.

MiniMax Code takes a SubAgent's model only as "<provider>/<model>" with one slash in the whole (/^[^/\s]+\/[^/\s]+$/, #1387), and its provider for magpie is "custom_provider:magpie", so a model under it can't hold a slash: "bb-codex/gpt-6.1-sol" is written there as "bb-codex~gpt-6.1-sol", and the gateway takes that back to the catalog id (Unflat). A tilde is in no id a provider was seen to serve but OpenRouter's "~anthropic/…" latest-aliases, which flatten to "openrouter~~anthropic~…", still one entry's.

View Source
const FreshPace = 100 / (7 * 24.0)

FreshPace is the pace of an account with a whole week ahead of it: what one not known counts as.

View Source
const GrokFastTimes = 2

GrokFastTimes is how many times its model's price xAI sells a Grok model's fast variant at (grokFastPrice).

View Source
const GroupPrefix = "group/"

GroupPrefix starts a group's id in the catalog: "group/<id>".

View Source
const HoldsFloor = 5.0

HoldsFloor is the least share used a window's whole is reckoned from: below it a percent the vendor rounds is too coarse to scale up.

View Source
const JevLatest = "jev-latest"

JevLatest is the Jev a decision provider is asked with when the user picked none: TypeSafe's latest stable one.

View Source
const KeyHeldCode = "gateway_key_held"

KeyHeldCode is the error code a gateway answers a key held to a budget, models or accounts with, where its own accounts would be told (#1981): the key is someone else's to use, and is told its own limit alone.

View Source
const KiloVersion = "7.8.3"

KiloVersion is the Kilo CLI release magpie says it is to the Kilo Gateway.

View Source
const MLXServePreset = "mlx-serve"

MLXServePreset is the MLX-Serve preset's id.

View Source
const Manual = "manual"

Manual is a group's routing when the user picks which member it uses, as CC Switch has one provider on at a time (#317): every request goes to the member picked (Group.Pick), over its own keys or accounts; the others, and the rules, wait until another is picked or the group is routed otherwise. The pick is changed on the group's card, in a click.

View Source
const MaxAccountName = 64

MaxAccountName bounds an account's name, in characters.

View Source
const MaxIcon = 1 << 20

MaxIcon is the largest picture magpie keeps for a provider.

View Source
const MaxIntent = 200

MaxIntent is how long an intent may be, in characters.

View Source
const MaxKeyWeight = 1000

MaxKeyWeight is the most a key's weight can be.

View Source
const MaxPartners = 12

MaxPartners is the most partners listed; the rest of a longer list are left out.

View Source
const MaxQuotaRest = 8 * 24 * 60

MaxQuotaRest bounds QuotaRest, in minutes: eight days, a week's window and a day over, the longest the gateway rests anyone out of quota.

View Source
const MaxRPMLimit = 10000

MaxRPMLimit bounds a limit on requests a minute.

View Source
const MiMoID = "mimo-app"

MiMoID is the MiMo subscription's id, as a provider and in logins.json.

View Source
const MinRefreshEvery = 10 * time.Minute

MinRefreshEvery is the shortest RefreshEvery: a vendor's list changes over days, and asking it each minute only spends its rate limit.

View Source
const OMLXPreset = "omlx"

OMLXPreset is the oMLX preset's id.

View Source
const OpenCodeAnonymousKey = "public"

OpenCodeAnonymousKey is the key OpenCode asks Zen with when no one is signed in to it, which Zen's free models answer.

View Source
const OpenCodeConsole = "https://opencode.ai/console"

OpenCodeConsole is where OpenCode shows a workspace's credits: the Credits card on the console's Overview, to its owners and admins.

View Source
const OpenCodeStub = "Not available in this session. Never call this tool."

OpenCodeStub describes a tool offered only for Zen's free tier to see, which the client doesn't have.

View Source
const OpenCodeUserAgent = "opencode/" + OpenCodeVersion + " ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14"

OpenCodeUserAgent is the User-Agent OpenCode 1.19.0 sends, its ai-sdk and Bun included, as captured from the real client.

View Source
const OpenCodeVersion = "1.19.0"

OpenCodeVersion is the OpenCode release magpie says it is to OpenCode's gateway. Zen's free tier turns away anything older than 1.18.0 (426 "OpenCode 1.18.0 or newer is required to use the free tier").

View Source
const OpenRouterJev = "~typesafe/jev-latest"

Cloudflare's own decision models on Workers AI (ARNO on Discord): Clef and Clef Flash answer System One's questions as Jev does, but each is run at its own address (…/ai/run/@cf/cloudflare/clef) and takes the request as it is, its model named "clef" or "clef-flash", where Jev is a run of typesafe/jev with the questions as its input. OpenRouterJev is Jev as OpenRouter names it, the latest one.

View Source
const PartnersURL = "https://usemagpie.ai/api/partners"

PartnersURL is where the list is kept; MAGPIE_PARTNERS moves it, and MAGPIE_PARTNERS=off keeps to none.

View Source
const PricesHeader = "X-Magpie-Prices"

PricesHeader asks a magpie's model list for what each model costs there ("magpie_price"): a magpie that doesn't send it is told nothing more than before.

View Source
const QoderCNID = qoder.CNProviderKey

QoderCNID is the Qoder CN subscription's id, the same as Qoder CN's agent.

View Source
const RegexpPrefix = "re:"

RegexpPrefix starts a member that is a regular expression over the whole "provider/model" id, in any case as a glob is: "re:openrouter/.*:(free|beta)". "(?-i)" in it makes case matter from there on: "re:(?-i)openrouter/.*:FREE".

View Source
const RemoteCardsPath = "/v1/magpie/quotas/cards"

RemoteCardsPath is the gateway's answer of its kept cards.

View Source
const RemoteKeyLimitPath = "/v1/magpie/limit"

RemoteKeyLimitPath is the gateway's answer of the calling key's limit.

View Source
const RemoteMagpiePreset = "remote-magpie"

RemoteMagpiePreset is the preset's id.

View Source
const RemoteRefreshPath = "/v1/magpie/quotas/refresh"

RemoteRefreshPath has the gateway read a card (?provider=, &user=) again, or every card when no provider is named, then answer as RemoteCardsPath.

View Source
const RestCapOff = -1

RestCapOff is RestCap set to off (`magpie provider rest-cap <id> off`): a key or account of the provider that fails without saying why — a relay's or an account pool's 5xx, a dropped connection — doesn't rest at all, and is asked again by the next request as if it hadn't failed (Kismet Alan on Discord: an aggregator's unknown errors fail now and then, and the next request often goes through). What the vendor said plainly still rests it as ever: out of quota or credit, rate limited, its key refused (401, 403), its model not served, its window full.

View Source
const (

	// SIWCUsageURL is where a ChatGPT account's usage is shown
	SIWCUsageURL = "https://chatgpt.com/settings/usage"
)
View Source
const Scheme = "magpie"

Scheme is the URL scheme magpie registers with the system.

View Source
const SessionPlaceholder = "${sessionId}"

SessionPlaceholder is what a string value of extraBody writes for the conversation's id.

View Source
const SignInHeader = "X-Magpie-Sign-In"

SignInHeader is how a plugin says what its answer means for the account's sign-in, whatever its status, so it can answer with the status its built-in did: "expired" marks the account lapsed, as a built-in whose vendor refused the sign-in marked it, though the status be a 502; "kept" leaves the account as it is, as a built-in answering a 401 of the vendor's without its sign-in refused did; "renewed" clears the mark, as a built-in whose sign-in renewed took it off whatever the request then met. Without it a 401 marks the account and a success clears the mark.

View Source
const SpentShare = 98

SpentShare is the share of an allowance past which an account is all but used up: Smart routing keeps it for when no other can take a request, and the agent signed in to it is signed in to another.

View Source
const TraeCNID = "trae-cn"

TraeCNID is the Trae CN plugin's provider.

View Source
const TraeRefusedWords = "Trae CN refused this check-in (9074: too many taking part); check in in the Trae CN app"

TraeRefusedWords is what an account Trae CN refused a claim 9074 is told, in the TUI and CLI (the GUI says it in each language): what Trae did, and where the check-in can still be done.

View Source
const UnknownRuleWord = "unknown "

UnknownRuleWord starts the error for a word ParseRule doesn't know.

View Source
const VertexPreset = "google-vertex"

VertexPreset is the preset's id.

View Source
const VideomakersHeader = "X-Magpie-Videomakers"

VideomakersHeader asks a magpie's model list for its video models as well: a magpie that doesn't send it would take grok-imagine-video, whose id says "imagine", for an image model.

View Source
const WBRestrictedHint = "" /* 152-byte string literal not displayed */

WBRestrictedHint is what magpie adds to WorkBuddy's 403 code 11140 "request illegal" (#1849), whose displayMsg says "Your account has been restricted due to unusual activity": the account, not the request, is out until WorkBuddy lifts the restriction, which its appeal asks for. The gateway reads it as the account restricted (failRestricted), the plugin adds the same words, and the Routing page says it apart.

View Source
const WorkBuddyAIID = "workbuddy-ai"

WorkBuddyAIID is WorkBuddy AI's subscription, the international build's.

View Source
const WorkspaceID = "{WorkspaceId}"

WorkspaceID stands in a decision API's address for the user's Bailian workspace id (#647), which the editor and `workspace=` fill in.

View Source
const YouFreeSearch = "https://api.you.com/v1/agents/search"

YouFreeSearch is You.com's search that takes no key (#1626): 100 searches a day for each address, then 429. With a key, You.com is asked at its Base, ydc-index.io, instead.

Variables

View Source
var (
	ZCodeZaiBase      = "https://api.z.ai/api/anthropic"
	ZCodeBigModelBase = "https://open.bigmodel.cn/api/anthropic"
)

Where ZCode's coding plan and its sign-in are; vars so tests can point them elsewhere.

Affinities are how long a conversation stays with the key or account that answered it: "" auto, as long as what the vendor cached of it is worth keeping; for the whole session; within a turn only, free to move when the user speaks again; never; or strictly: for the whole session, never moved to another key or account however it answers (#1797).

View Source
var AllBuilt atomic.Int64

AllBuilt counts the times All built the list anew, for tests.

AuthChoices are the values Provider.AuthHeader takes.

View Source
var ClaudeHandedOver func(user string)

forgetClaudeDir removes a saved account's config directory altogether. ClaudeHandedOver is told of a saved Claude account switched in to Claude Code itself, whose directory forgetClaudeDir has just removed: a Claude Code still running there (the gateway's, waiting for its conversation's next turn) holds the refresh token that is Claude Code's own now, and a refresh of it there would leave Claude Code's copy refused, the account signed out (0xAncientTwo on X). The gateway sets it.

View Source
var CodexBase = "https://chatgpt.com/backend-api/codex"

CodexBase is where a ChatGPT account's Codex requests go; a var so tests can point it elsewhere.

View Source
var CopilotTokenURL = "https://api.github.com/copilot_internal/v2/token"

CopilotTokenURL trades the GitHub OAuth token for a short-lived Copilot session token; a var so tests can point it elsewhere.

View Source
var CopilotUserURL = "https://api.github.com/copilot_internal/user"

CopilotUserURL says where an account's Copilot API is; a var so tests can point it elsewhere.

View Source
var CopilotWSLHomes func() []string

CopilotWSLHomes, set by internal/agent, are the homes, as magpie opens them, of the WSL distros that run now: magpie on Windows finds a Copilot CLI signed in inside one (#723, jia2). nil, or none, off Windows. A stopped distro isn't in it: reading its files would start it.

View Source
var CursorExecutable = func() string {
	for _, name := range []string{"cursor-agent", "agent"} {
		if p, err := proc.LookPath(name); err == nil && (name == "cursor-agent" || isCursorAgent(p)) {
			return p
		}
	}
	home, _ := os.UserHomeDir()
	for _, p := range append([]string{filepath.Join(home, ".local", "bin", "cursor-agent")}, proc.SystemDirs("/usr/local/bin/cursor-agent", "/opt/homebrew/bin/cursor-agent")...) {
		if st, err := os.Stat(p); err == nil && !st.IsDir() {
			return p
		}
	}
	return ""
}

CursorExecutable finds the cursor-agent CLI; a var so tests can fake it.

View Source
var Described func() bool

Described is set by the gateway: whether an image sent to a model that can't see is described to it by one that can (Settings › Vision). Agents are then told every model takes images; told a model is text-only, they turn the user's image away before magpie is asked (Codex: "does not support image input").

View Source
var DevinExecutable = func() string {
	if p, err := proc.LookPath("devin"); err == nil {
		return p
	}
	home, _ := os.UserHomeDir()
	for _, p := range append([]string{filepath.Join(home, ".local", "bin", "devin")}, proc.SystemDirs("/usr/local/bin/devin", "/opt/homebrew/bin/devin")...) {
		if st, err := os.Stat(p); err == nil && !st.IsDir() {
			return p
		}
	}
	return ""
}

DevinExecutable finds the devin CLI; a var so tests can fake it.

View Source
var Efforts = []string{"low", "medium", "high", "xhigh", "max"}

Efforts are the reasoning levels a rule can ask for, lowest first.

View Source
var ErrNoURL = errors.New("type the base URL first")

ErrNoURL is a detection with no URL to ask at.

View Source
var ErrSIWCSignIn = errors.New("the ChatGPT sign-in has expired — sign in again")

ErrSIWCSignIn is an account OpenAI no longer refreshes: it must be signed in again.

View Source
var ErrUnreadable = errors.New("providers.json can't be read")

ErrUnreadable is a providers.json that is there but can't be read or decoded: never an empty catalog, to list as none, back up or write over.

View Source
var ExtraBodyReserved = []string{"model", "stream", "messages", "input", "contents", "system", "systemInstruction", "system_instruction", "instructions", "tools"}

ExtraBodyReserved are the fields extraBody can't set: the model and whether to stream, which magpie decides for routing and reads the reply by, and the conversation itself — its messages, input or contents, its system prompt and instructions, its tools.

View Source
var GitHubUserURL = "https://api.github.com/user"

GitHubUserURL says whose a GitHub token is; a var so tests can point it elsewhere.

View Source
var GrokBase = "https://cli-chat-proxy.grok.com/v1"

GrokBase is the CLI's backend; a var so tests can point it elsewhere.

View Source
var GrokExecutable = func() string {
	home, _ := os.UserHomeDir()
	path := append(filepath.SplitList(os.Getenv("PATH")), registryPath()...)
	for _, c := range grokCandidates(runtime.GOOS, home, GrokHome(), appdir.Getenv("GROK_BIN_DIR"), path) {
		if isFile(c.path) && (c.own || isGrokBuild(c.path)) {
			return c.path
		}
	}
	return ""
}

GrokExecutable finds the Grok Build CLI; a var so tests can fake it.

View Source
var KiroExecutable = func() string {
	if p, err := proc.LookPath("kiro-cli"); err == nil {
		return p
	}
	home, _ := os.UserHomeDir()
	for _, p := range append([]string{filepath.Join(home, ".local", "bin", "kiro-cli")}, proc.SystemDirs(
		"/Applications/Kiro CLI.app/Contents/MacOS/kiro-cli", "/usr/local/bin/kiro-cli", "/opt/homebrew/bin/kiro-cli")...) {
		if st, err := os.Stat(p); err == nil && !st.IsDir() {
			return p
		}
	}
	return ""
}

KiroExecutable finds kiro-cli, which refreshes its own sign-in; a var so tests can fake it. The installer puts it in ~/.local/bin, and on macOS inside Kiro CLI.app as well.

View Source
var Levels = []string{"none", "minimal", "low", "medium", "high", "xhigh", "max"}

Levels are the reasoning levels a model whose own aren't known can be given.

View Source
var MemberEfforts = []string{"none", "minimal", "low", "medium", "high", "xhigh", "max"}

MemberEfforts are the levels a group's member may be fixed at, lowest first: the words agents and vendors use for reasoning effort.

View Source
var OpenCodeToolSchemas = map[string]string{
	"bash": `{"type":"object","properties":{"command":{"type":"string","description":"The command to execute"},"timeout":{"type":"integer","description":"Optional timeout in milliseconds"},"workdir":{"type":"string","description":"The working directory to run the command in"}},"required":["command"]}`,
	"read": `{"type":"object","properties":{"filePath":{"type":"string","description":"The absolute path to the file or directory to read"},"offset":{"type":"integer","description":"The line number to start reading from (1-indexed)"},"limit":{"type":"integer","description":"The maximum number of lines to read"}},"required":["filePath"]}`,
}

OpenCodeToolSchemas are the parameters OpenCode itself gives bash and read (1.19.0, as it sent them to Zen). Since mid-October 2026 Zen's free tier answers 403 FreeTierError when either is offered with no parameters, as magpie's stubs were ({"type":"object","properties":{}}); one property is enough, and these are OpenCode's own.

View Source
var OpenCodeTools = []string{"bash", "read"}

OpenCodeTools are the tools Zen's free tier wants offered, by name.

Protocols in the order magpie prefers them when it has to translate.

View Source
var ReckonHolds func(qs []SubscriptionQuota, now time.Time) []SubscriptionQuota

ReckonHolds is usage.WithWindowHolds, which package usage sets: it reads the usage log, which this package can't import. QuotaReport, KeptQuotaReport and RefreshReport tell each window's whole by it, as the Usage page does (#2333); nil, where usage isn't linked in, leaves it out.

View Source
var SearchVendors = []SearchVendor{
	{ID: "tavily", Name: "Tavily", Base: "https://api.tavily.com", KeysURL: "https://app.tavily.com/home"},
	{ID: "brave", Name: "Brave Search", Base: "https://api.search.brave.com", KeysURL: "https://api-dashboard.search.brave.com/app/keys"},
	{ID: "exa", Name: "Exa", Base: "https://api.exa.ai", KeysURL: "https://dashboard.exa.ai/api-keys"},
	{ID: "firecrawl", Name: "Firecrawl", Base: "https://api.firecrawl.dev", KeysURL: "https://www.firecrawl.dev/app/api-keys"},
	{ID: "you", Name: "You.com", Base: "https://ydc-index.io", KeysURL: "https://you.com/platform", KeyOptional: true},
	{ID: "deepseek", Name: "DeepSeek", Base: "https://api.deepseek.com", KeysURL: "https://platform.deepseek.com/api_keys"},
	{ID: "searxng", Name: "SearXNG", KeyOptional: true},
}

SearchVendors are the search APIs magpie can ask, in the order offered.

View Source
var TemplateIDs = map[string]string{TemplateSmart: "smart-split", TemplateThrifty: "cheap-first", TemplateSteady: "never-stuck"}

TemplateIDs are the ids agents pick a template's group as, before a number when one is in use.

TemplateKinds are the templates, in the order they are offered.

View Source
var TemplateNames = map[string]string{
	TemplateSmart:   "Hard to strong, easy to cheap",
	TemplateThrifty: "Cheap first",
	TemplateSteady:  "Never stuck",
}

TemplateNames are the templates' names in English, which the GUI says in the user's language.

View Source
var Weekdays = []string{"sun", "mon", "tue", "wed", "thu", "fri", "sat"}

Weekdays are the days a TimeWindow names, as time.Weekday counts them.

Functions

func APIError

func APIError(b []byte, fallback string) string

APIError pulls the human message out of an error body when there is one. A firewall's block page is put in plain words (BlockedHint); Google's "verify your account" refusal also says what to do about it, with the link it gave.

func AccessKeyVendor added in v0.1.1182

func AccessKeyVendor(p Provider) string

AccessKeyVendor is whose account access key p's plan is read with: "volcengine" (Ark's Coding and Agent Plans), "tencent" (Token Plan 企业版), or "" for none.

func AccountCapOf added in v0.1.809

func AccountCapOf(id, user string) int

AccountCapOf is AccountCap of the provider id, 0 when there is none.

func AccountModelsOf added in v0.1.610

func AccountModelsOf(id, ref string) (string, []string, error)

AccountModelsOf is the models the account or key ref of the provider id alone serves, and the account or key as AccountModels knows it; no models when it serves all the provider's.

func AccountNameOf added in v0.1.1172

func AccountNameOf(id, user string) string

AccountNameOf is the name the user gave the account user of the subscription id, "" when none.

func AccountNames added in v0.1.1076

func AccountNames() map[string]string

AccountNames maps every account and key a gateway key may name (#905), "<provider>/<id>", to how it is shown, "<provider>/<user>", an account by the name the user gave it (AccountShown); what no provider has now maps to itself.

func AccountShownOf added in v0.1.1326

func AccountShownOf(id, user string) string

AccountShownOf is AccountShown for the account user of the provider id.

func Add added in v0.1.50

func Add(p Provider) (string, error)

Add saves a provider the user just added, beside those already here: an id in use — the preset's, or the one its name slugs to — moves on to the next free one (anthropic-2), and a name in use gets the same number, so a second key of a vendor, or one key for another workspace, is a provider of its own rather than one replacing the first. It answers the id saved.

func AddCopy added in v0.1.455

func AddCopy(p Provider, from string) (string, error)

AddCopy adds p, a copy the user made of the provider from (#268), beside it: what the form doesn't carry — the keys, the balance token, how requests spread over the keys, where they fall back to — is from's where p leaves it out. The same key on the same host is taken, the copy being asked for (another model list, another endpoint). A signed-in account is never copied: its sign-in is the agent's.

func AddKey added in v0.1.14

func AddKey(id, name, key string, proto Protocol) error

AddKey saves one more key for a provider, on: it takes requests after the ones before it. It becomes the first when the provider has none.

func AddKeys added in v0.1.930

func AddKeys(id string, keys []string, proto Protocol) (added, had int, err error)

AddKeys saves several keys at once, on, after the ones the provider has, with the protocol given: those it has already are passed over. added is how many were new, had how many it had.

func AddPlugin added in v0.1.1232

func AddPlugin(ctx context.Context, spec string) (plugin.Entry, error)

AddPlugin installs the plugin spec, as plugin.Add does, and puts back what was set aside of it when it was last removed.

func AddPlugins added in v0.1.1225

func AddPlugins(ctx context.Context, es []plugin.Entry) (added []string, failed map[string]error)

AddPlugins installs the plugins another computer has (Carried) that aren't here, the way Settings → Plugins adds one, and hands each a deprecated built-in it serves (HandOver). It never takes a plugin away or changes one already here: a plugin removed on one computer stays on the others. It returns the specs added and why the others couldn't be.

func AddressOf added in v0.1.1224

func AddressOf(urls ...string) string

AddressOf is the address the URLs are at, the origin of the first one set, for an editor to start from; "" when none is.

func Adopt added in v0.1.642

func Adopt(ctx context.Context, id string) error

Adopt puts the built-in id onto its plugin before any account of it is signed in: the plugin installed, and the subscription signs in through it from now on, as a moved one does. One with accounts is moved instead, and one whose plugin the user removed is the plugin's again.

func AgentEffort added in v0.1.1084

func AgentEffort(agent string) string

AgentEffort is the effort agent's requests are asked for, "" for none.

func AgentUser added in v0.1.683

func AgentUser(agent string) string

AgentUser is who an agent is signed in to itself, as its own files say, for an agent whose vendor a plugin serves too; "" when not known.

func Allowances added in v0.1.29

func Allowances(agent string) map[string]Allowance

Allowances is each of an agent's accounts' allowance by user, as last known, asked for again in the background when that was over a minute ago. Only the very first ask waits, and not for long. An account missing is one not known yet.

func AntigravityBase added in v0.1.299

func AntigravityBase(id string) (base, effort string, ok bool)

AntigravityBase is the model magpie offers for one of Antigravity's ids at a level ("gemini-3.7-flash-low" is gemini-3.7-flash at low), and that level; ok is false for an id that is itself a model magpie offers, or that no family has. Picks and agents' models saved before the families were one model still name these ids.

func AntigravitySentID added in v0.1.560

func AntigravitySentID(model, effort string) string

AntigravitySentID is the id a request for model goes out under at that effort on an Antigravity account: the variant of the family the effort picks, at the level of that family nearest the effort asked for; with no effort asked for, the family's own default. One of the family's own variant ids — an id a pick or an agent's model list kept from before the families were one model — goes as it is when no effort is asked for, and at the level the effort picks otherwise, since the effort the client asks for wins, as it does for the family. Any other id goes as it is.

The gateway sends the envelope under this and the ledger judges what the vendor answered against it, so there is one of it rather than one each: a reply naming the id a call went out under is that model answering, and read against the family instead every level of it reads as another model having swapped in, in the routing view and in the ledger alike.

func AntigravityVariants added in v0.1.299

func AntigravityVariants(model string) (map[string]string, bool)

AntigravityVariants are Antigravity's ids a model magpie offers stands for, by level, "" the default; ok is false for a model that stands for none, which goes to Antigravity as it is.

func AnyPriceKey added in v0.1.581

func AnyPriceKey(model string) string

AnyPriceKey is the key a price for a model from any provider is stored at: its id lower-cased, the way a session's bare model is looked up.

func ApplyImage added in v0.1.413

func ApplyImage(pid, model string, images bool, known *bool) (bool, *bool)

ApplyImage is what magpie tells of model: the user's answer when they gave one, else images as the vendor's list has it (known is that list's explicit answer, nil when it didn't say).

func ArrangeSearchAPIs added in v0.1.1258

func ArrangeSearchAPIs(order []string) error

ArrangeSearchAPIs puts the search APIs in the order of the vendors named (#2286), the order they are tried in. One not named keeps its place after them; a name of none set up is refused, so an order sent from a page drawn before one was removed changes nothing.

func AskClaudeUsage added in v0.1.558

func AskClaudeUsage()

AskClaudeUsage is the user asking to see Claude's usage — opening the Usage page, refreshing it, `magpie quota` — so Claude Code's /usage is run at once rather than when the next unasked reading is due (claudeUsageWait); the next SubscriptionUsage waits for it.

func AskUsage added in v0.1.791

func AskUsage()

AskUsage has the next SubscriptionUsage wait for a new reading rather than hand back the last one, as AskClaudeUsage does, without having Claude Code's /usage run: magpie quota wait reads again each time it wakes, and only a wait for Claude needs Claude read.

func Asked added in v0.1.1169

func Asked(ctx context.Context) context.Context

Asked is ctx for a read the user asked for: the Usage page opened or refreshed, a card's refresh, `magpie quota`, `magpie accounts`.

func AuthHeaders

func AuthHeaders(p Provider, proto Protocol) map[string]string

AuthHeaders is how a request to the vendor proves who it is. Anthropic's own API wants x-api-key alone, and so does Bedrock's, which turns away a request with both (#176); other compatible vendors take either, so both. Azure OpenAI takes a key in api-key alone: a Bearer there is an Entra ID token, and the key sent as one is turned away.

func AutoGroupID added in v0.1.603

func AutoGroupID(model string) string

AutoGroupID is the id of the group magpie finds for a model, however a vendor spells it: "auto-claude-opus-5-5" for claude-opus-5.5.

func AutoGroupOf added in v0.1.673

func AutoGroupOf(pid, model string) string

AutoGroupOf is the id of the group magpie finds for a provider's model: AutoGroupID of the model the user said it is the same as (settings' ModelSameAs), else of its own id.

func AutoGroupsOn added in v0.1.603

func AutoGroupsOn() bool

AutoGroupsOn reports whether magpie finds groups on its own: a model more than one provider serves is a group of them (autoGroups). It is on until the user turns it off.

func AutoRefsOn added in v0.1.1294

func AutoRefsOn() bool

AutoRefsOn is autoRefsOn, for the packages that spell a group's id.

func AutoResetWords added in v0.1.1234

func AutoResetWords(user string) string

AutoResetWords says in a few words when user spends one by itself, for the CLI and TUI: "" when it never does.

func AutoResets added in v0.1.514

func AutoResets(agent, user string) bool

AutoResets says whether agent's account user spends its resets by itself at either time; only a Codex account does.

func AutoResetsWeek added in v0.1.1234

func AutoResetsWeek(agent, user string) bool

AutoResetsWeek says whether agent's account user spends a reset by itself once its week is used up and no other account can answer.

func AutoStandIn added in v0.1.603

func AutoStandIn(id string) (string, bool)

AutoStandIn is the model a request for a group magpie found goes to while such groups are off (SetAutoGroups): its model, from the first provider that serves it, as "provider/model". An agent set to the group, or a session begun on it, keeps working, on one provider. ok is false for any other id, a group the user has of that id, or while found groups are on.

func AwaitAllowance added in v0.1.1164

func AwaitAllowance(ctx context.Context, agent, user string) bool

AwaitAllowance has agent's accounts read again unless a reading is out, and waits, till ctx ends, for one that knows user: after a reset is spent, routing then counts the account's windows started again, rather than not known and behind the rest till a later request reads them (#1491). A reading out already, begun before the reset, doesn't count it, so another is asked for; three at most. It says whether user is known now.

func AzureBase added in v0.1.419

func AzureBase(raw string) (string, bool)

AzureBase is the v1 API base of the resource an endpoint names, as it was pasted from the portal or another app — the bare resource (https://r.openai.azure.com), …/openai, …/openai/v1, a classic deployment's URL with its api-version, or only the resource's name — and ok false when it names no Azure resource.

func AzureHost added in v0.1.419

func AzureHost(host string) bool

AzureHost reports whether host is an Azure OpenAI resource's.

func BackAt added in v0.1.791

func BackAt(q SubscriptionQuota, now time.Time) time.Time

BackAt is when a used-up account has room again: when the last of the windows that stop it (usedUp's) starts again, a window's seconds to go counted from now. Zero when one of them doesn't say.

func Balance added in v0.1.37

func Balance(ctx context.Context, p Provider) (amount string, ok bool, err error)

Balance asks the vendor what is left on the provider's key in use. ok is false when there is no way to ask it. A key given limits and no quota of its own has what its fullest window has left: what it can spend now.

func BalanceNumber added in v0.1.540

func BalanceNumber(s string) (float64, bool)

BalanceNumber is the amount a balance as a vendor tells it holds: "$12.34", "¥1,024.50", "CNY 8", "12.3k credits". A share ("45%"), or text with no number, is none.

func BalanceQuery added in v0.1.1235

func BalanceQuery(p Provider) (balanceURL, field string)

BalanceQuery is the Balance URL and field the provider's balance is asked at, which differ from the saved ones for an account query left without its token (keyQueryOf).

func BareDisabled added in v0.1.1219

func BareDisabled(id string) (string, bool)

BareDisabled reports whether a bare id (no provider in it) is the id of a model of a provider that is on and the user disabled, and the pattern that did: the catalog leaves it out, so Resolve doesn't find it.

func BareModelIDs added in v0.1.1226

func BareModelIDs() bool

BareModelIDs says whether /v1/models lists models by their bare ids too.

func BoundCallID added in v0.1.887

func BoundCallID(id string) string

BoundCallID is a call's id as the ChatGPT backend takes one: as it is when it fits its 64 characters, else the sha256 of it (trimmed, as calls and their outputs are paired), 64 hex characters. Foreign providers can join two ids into one longer than that (#732, congee949: 86 and 87); the same id gives the same hash on every request, so a call and its output stay paired, and two ids that differ are never cut down alike.

func BuiltinRetired added in v0.1.1282

func BuiltinRetired(id string) bool

BuiltinRetired is whether magpie's built-in id is retired: its plugin serves it, and the built-in serves nothing, moved or not. One whose accounts haven't moved yet (a failed install, an account the plugin turned away) is listed by MoveCandidates with why, until it moves. The built-ins are retired one by one, each with its code (the owner, 10-16: 陆续把内置 Provider下线掉), so this is the set retired so far.

func CCSwitchSkillOrigin added in v0.1.83

func CCSwitchSkillOrigin(dir string) (repo, branch string, ok bool)

CCSwitchSkillOrigin is the GitHub repository (owner/name) and branch CC Switch installed the skill in its folder dir from, as its database records it.

func CCSwitchSkillsDir added in v0.1.83

func CCSwitchSkillsDir() string

CCSwitchSkillsDir is the folder CC Switch keeps the skills it installs in.

func CanFast added in v0.1.577

func CanFast(p Provider, model string) bool

CanFast reports whether model, as p serves it, has a fast mode magpie can ask for: a ChatGPT account's GPT models (Codex's Fast), Cursor's models with a -fast one, an OpenAI key's GPT and o-series models on its Responses API (priority processing), an Anthropic key's Opus models with fast mode, and a plugin's models it says are served at priority. A Claude subscription runs Claude Code itself, and a cloud (Bedrock, Vertex) refuses the field, so neither is. A provider the user added by its address (AddedByAddress) is asked for priority on a GPT model it serves on an OpenAI API, when the user switches it fast themselves (#1615): it is sent service_tier "priority" there, as Codex's own Fast already is (#1234), and one that turns the field away is asked again without it and not sent it again (the gateway's optional fields).

func CanUltra added in v0.1.1270

func CanUltra(p Provider, model string) bool

CanUltra reports whether a fast pick of model on p can be sent as Ultrafast: a ChatGPT model that one of Codex's accounts lists the tier on (Account.Tiers), or a plugin's model, with fast mode, that the plugin says its vendor serves at ultrafast (serviceTiers, #2514). A list that doesn't say tiers offers none.

func CancelSignIn added in v0.1.14

func CancelSignIn(id string)

CancelSignIn stops waiting for the browser.

func CanonicalRef added in v0.1.1294

func CanonicalRef(ref string) string

CanonicalRef is ref as magpie keeps it: a found group's auto/<model> as group/auto-<slug>, an effort after it (":high") and Claude Code's [1m] mark kept; any other ref as it is. The gateway takes a request's model back to it before key limits, routing and the usage log see it, so the two ids of one group are one.

func Carried added in v0.1.1225

func Carried(keys bool) []plugin.Entry

Carried is the plugins a backup or a sync carries: those added from npm or a git repository, on or off as the user left them, with their options: without keys, those whose names look like a key are left out, as a provider's secret headers are. A plugin added from a file or folder is this computer's alone, and a plugin's sign-ins (plugin-auth.json) stay here, as a subscription's do.

func Changed added in v0.1.705

func Changed()

Changed drops what is held: a provider, an account, a plugin or a setting was written.

func CheckQueue added in v0.1.1009

func CheckQueue(limit, wait int) error

CheckQueue says what is wrong with a queue's bound or wait, nil when nothing is.

func CheckRPM added in v0.1.1119

func CheckRPM(n int) error

CheckRPM says what is wrong with a limit on requests a minute, nil when nothing is.

func CheckinDay added in v0.1.778

func CheckinDay(t time.Time) string

CheckinDay is the day (Beijing, "2006-01-02") WorkBuddy's check-in counts t in: a WorkBuddyCheckin of that Day is today's.

func ClaudeCodeMovedOff added in v0.1.648

func ClaudeCodeMovedOff(user string) bool

ClaudeCodeMovedOff says Claude Code itself is signed in to another account than user now: what a Claude Code run in its own home says of the account it is on is no longer user's. false when it can't be told. Named from its profile, the account is told by its whole name: a Team seat and a personal plan of one email ("me@x.com · Acme", "me@x.com") are two accounts, and one's usage isn't the other's (netfishx on X).

func ClaudeDashed added in v0.1.1163

func ClaudeDashed(id string) string

ClaudeDashed is id with each dot of a Claude model's version a dash: relay/claude-opus-4.6-us[1m] is relay/claude-opus-4-6-us[1m]. Any other id is as it is.

func ClaudeFast added in v0.1.577

func ClaudeFast(model string) bool

ClaudeFast reports whether a Claude model has fast mode.

func ClaudeGroup added in v0.1.1219

func ClaudeGroup(id string) bool

ClaudeGroup says a model id (as CompactSet takes it) is a routing group whose every member is one of Anthropic's Claude models, by the name it is listed under or the one the vendor is asked for. Claude Code runs such a group as it runs a Claude model, to its own window, so it isn't handed magpie's default compaction window (#1741: a group of Claude [1m] models was told 272000, its id's last part not starting with "claude"). A group with any other member, or none, isn't.

func ClaudeInWSL added in v0.1.834

func ClaudeInWSL() string

ClaudeInWSL is the WSL distro the gateway runs Claude Code in, when there is none on Windows itself and one was found there; "" otherwise. It never waits on WSL: until a look has been made, one starts and "" comes back.

func ClaudeLoginVersion added in v0.1.788

func ClaudeLoginVersion(user string) string

ClaudeLoginVersion is the credential the saved Claude account user has now, which a run started on it goes by (NoteClaudeSignInFailure).

func ClaudeModel added in v0.1.1309

func ClaudeModel(model string) bool

ClaudeModel is claudeModel for another package: whether model, after any vendor prefix, is one of Anthropic's Claude models by its name.

func ClaudeRead added in v0.1.1163

func ClaudeRead(ref string) string

ClaudeRead is a model read back from Claude Code's settings as magpie serves it: a dashed spelling ClaudeSpelled wrote taken back to the served id, anything else as it is. A model of a provider switched off since is taken back too, so magpie still knows it for its own and moves the agent off it (Reseat).

func ClaudeSignInRequired added in v0.1.788

func ClaudeSignInRequired(message string) bool

ClaudeSignInRequired says message is Claude Code's, or magpie's, word that a Claude sign-in is gone and has to be made again: not a failure of the moment, as a network error or another Claude Code holding the refresh is ("Failed to refresh OAuth token: another Claude Code process is refreshing it").

func ClaudeSpelled added in v0.1.1163

func ClaudeSpelled(ref string) string

ClaudeSpelled is ref (a served id, with an effort and [1m] mark or not) as Claude Code is given it: dashed (ClaudeDashed) when that spelling comes back to this id (ClaudeUndashed), else as it is.

func ClaudeUndashed added in v0.1.1163

func ClaudeUndashed(ref string) (string, bool)

ClaudeUndashed is the served id (a provider's model or a routing group) whose dashed spelling (ClaudeDashed) ref is, its effort and [1m] mark kept, when ref is no served id as it is and exactly one served id is so spelled. An id served as it is spelled always wins.

func ClaudeWarmed added in v0.1.223

func ClaudeWarmed() map[string]time.Time

ClaudeWarmed is when magpie last started a window of each Claude account, by user as kept (lower-cased).

func CleanAutoInclude added in v0.1.1234

func CleanAutoInclude(in []string) ([]string, error)

CleanAutoInclude are AutoInclude's patterns as they are kept: trimmed, each once, every one one magpie can read. A pattern is a glob with * in it (any run of characters, in any case: "gpt-*", "*claude*") or a regular expression after "re:" that matches the whole id.

func CleanLevels added in v0.1.477

func CleanLevels(in []string) ([]string, error)

CleanLevels are the reasoning levels a group names for itself (Group.Levels) as they are kept: lowercase, each once, lowest first. Only the levels magpie knows are taken.

func CleanPatterns added in v0.1.826

func CleanPatterns(in []string) ([]string, error)

CleanPatterns are a group's patterns as they are kept: trimmed, each once, every one one magpie can read.

func ClineClient added in v0.1.630

func ClineClient(h http.Header)

ClineClient makes a request to the Cline API carry the desktop app's headers.

func Closest added in v0.1.1148

func Closest(asked string, n int) []string

Closest lists up to n catalog ids nearest to asked, nearest first: a model whose display name holds asked's words before one whose id does, and the provider's id or name counting only alongside. Nothing when no model's name or id shares a word with it.

func CloudflareClef added in v0.1.859

func CloudflareClef(model string) bool

CloudflareClef reports whether model is one of Cloudflare's Clef models.

func CodexAPIKeySignedIn added in v0.1.1083

func CodexAPIKeySignedIn() bool

CodexAPIKeySignedIn says Codex itself is signed in with an OpenAI API key rather than a ChatGPT account (auth.json's auth_mode): its sign-in is a key's, and spends no account a gateway key's list governs.

func CodexAccountModel added in v0.1.1195

func CodexAccountModel(id string) bool

CodexAccountModel says id names a model of a ChatGPT account's, served now or not: codex/<model>, or one of a provider that is a ChatGPT account.

func CodexAppOut added in v0.1.1381

func CodexAppOut() string

CodexAppOut is the ChatGPT account of a Codex app that was open when that account ran out and hasn't been opened again since, "" for none: it sends nothing till it is (the agent package's AppOut says whether magpie is Codex's provider for it, which the app needs too).

func CodexAppReopenOnce added in v0.1.1381

func CodexAppReopenOnce() bool

CodexAppReopenOnce is whether the Codex app CodexAppOut names may be reopened by magpie: true once for each time the account runs out, so a reopen that didn't take is never tried again.

func CodexAppReopenTried added in v0.1.1381

func CodexAppReopenTried() bool

CodexAppReopenTried is whether magpie tried reopening the Codex app CodexAppOut names already, which it doesn't do twice.

func CodexAppStale added in v0.1.1155

func CodexAppStale() string

CodexAppStale answers the account the Codex desktop app is still signed in to when Codex has been switched to another since the app opened, "" when it isn't open or is on the account Codex is. The app shows that account's limits, and once they are spent won't send in any thread, until it is quit and opened again.

func CodexAutoReset added in v0.1.507

func CodexAutoReset(user string) bool

CodexAutoReset says whether the Codex account user spends a reset by itself at either time.

func CodexAutoResetWhen added in v0.1.1234

func CodexAutoResetWhen(user string) (week, expiring bool)

CodexAutoResetWhen says at which of those times the Codex account user spends a reset by itself: both unless the user kept it to one.

func CodexCatalog added in v0.1.1118

func CodexCatalog(shown []Entry) []catalog.Model

CodexCatalog is shown as a Codex that names magpie its model_provider is handed it from GET /v1/codex/models (#1281): every model, a ChatGPT account's own among them, since that Codex reaches them through magpie's /v1 by magpie's id, not through the ChatGPT backend's list.

func CodexCompressed added in v0.1.1206

func CodexCompressed(req *http.Request, body []byte) int

CodexCompressed sends req's body, body, zstd-compressed as Codex's own client sends it, when req is a turn to the ChatGPT backend (CodexBase/responses), and as it is otherwise. It is called once the body is final and signed, and returns the bytes that go on the wire. The body is still the plain body everywhere magpie keeps or shows it.

func CodexCredits added in v0.1.1080

func CodexCredits(user string) bool

CodexCredits says whether the Codex account user spends its credits once a usage window is used up: true unless the user turned it off.

func CodexDaemonStale added in v0.1.368

func CodexDaemonStale() string

CodexDaemonStale answers the account Codex's app-server is still signed in to when Codex has been switched to another since it started, "" when it isn't running or is on the account Codex is.

func CodexHome added in v0.1.1151

func CodexHome() string

CodexHome is the Codex home magpie wires and signs Codex in through.

func CodexKeychainForTest added in v0.1.1258

func CodexKeychainForTest(find func(service, account string) ([]byte, error)) (restore func())

CodexKeychainForTest has Codex's keychain item read through find (no item: fs.ErrNotExist) on every system, until restore.

func CodexListTag added in v0.1.460

func CodexListTag() string

CodexListTag names the list Codex is handed, for its ETag: magpie's models, the account's own taken out of it, the order they are in, the windows set on them, the auto-review model, and whether its OpenAI models say multi-agent V1 (settings.CodexAgentsV1), so any of them changing has Codex ask for the list again.

func CodexListed added in v0.1.54

func CodexListed() []catalog.Model

CodexListed is the catalog as a Codex signed in to ChatGPT is handed it, after the backend's own models: all but a ChatGPT account's in magpie, which the backend lists already. A group answers for its first member but is not that provider's.

func CodexMayBeUsedUp added in v0.1.1381

func CodexMayBeUsedUp(user string)

CodexMayBeUsedUp is a reply's word that user's ChatGPT account may be out (usage_limit_reached, or a window heard at 100%): for the account Codex is signed in to, its allowance is read again at once, at most every codexRecheckEvery, and a change told as the five-minute look tells it (noteCodexUsedUp).

func CodexNativeHidden added in v0.1.460

func CodexNativeHidden() map[string]bool

CodexNativeHidden is the ChatGPT account's own model slugs the user took out of Codex's list (HiddenModels), or didn't pick for it when it is shown only the models picked (PickedModels): the backend lists them, and the gateway drops them from its /models answer as it does the ones not picked.

func CodexNativePicked added in v0.1.292

func CodexNativePicked() (map[string]bool, bool)

CodexNativePicked is the set of the ChatGPT account's own model slugs the user kept, and whether they narrowed that list at all. The backend lists every model the account can reach; when the user has picked among them on the codex provider, the gateway keeps its /models answer to those (see codexModels). Not narrowed — the account's list is left whole.

A provider switched off picks nothing, as it serves no agent anything (Provider.Off): its picks are kept for when it is switched on again and are not a narrowing now.

func CodexNativeUnlisted added in v0.1.1218

func CodexNativeUnlisted() (all bool, slugs map[string]bool)

CodexNativeUnlisted is the ChatGPT account's own models kept out of the lists agents see, which the backend lists to Codex all the same: every one (all) when the codex provider serves only through routing groups (Provider.Unlisted), and by slug those a routing group keeps out of the lists (Group.Unlists). The gateway drops them from its /models answer as it does the ones hidden; Codex then reaches them only through its groups (#1602). A provider switched off keeps none out: it serves nothing, and its setting is kept for when it is switched on again.

func CodexNativeWindow added in v0.1.757

func CodexNativeWindow(restore bool) func(slug string) (n, most int, ok bool)

CodexNativeWindow is the context window Codex is handed for one of the ChatGPT account's own models, by the backend's slug, and the most it may be raised to (0: as the entry says): the window the user set on the codex provider (Provider.ContextOf), as /v1/models says it (#674). ok is false for a model the user set none for, whose entry keeps the backend's window — unless restore, for an entry not fresh from the backend: Codex's models_cache.json keeps what magpie last handed it, a window since taken away among it, so such an entry takes the account's own list's again.

func CodexOrder added in v0.1.952

func CodexOrder() (map[string]int, bool)

CodexOrder is where each model of Codex's list goes when the user put them in an order of their own on the Agents page (#855), by the slug Codex knows it by — a ChatGPT account's own by its bare one, as the backend lists it — and whether they did. A model it doesn't name keeps its place after them.

func CodexOwn added in v0.1.952

func CodexOwn(e Entry) bool

CodexOwn reports whether e is one of a ChatGPT account's own models, which the ChatGPT backend lists to Codex by its bare slug (e.Model).

func CodexOwnListTag added in v0.1.1138

func CodexOwnListTag() string

CodexOwnListTag names the list a Codex that reaches magpie for account failover alone is handed, its own models without magpie's (#1385). Neither it nor CodexListTag's is a part of the other, so Codex asks again when it moves from one list to the other; a V1 list's mark stays in front.

func CodexSignIn added in v0.1.1258

func CodexSignIn(dir string) (b []byte, ok bool)

CodexSignIn is the sign-in Codex goes by under its home dir, from wherever its config.toml has it kept (readCodexLogin); ok is false for none, or one magpie couldn't read. Agents' wiring reads it here.

func CodexSignedIn added in v0.1.507

func CodexSignedIn() (string, bool)

CodexSignedIn is the ChatGPT account Codex is signed in to now.

func CodexSignedInAccount added in v0.1.1258

func CodexSignedInAccount() string

CodexSignedInAccount is the ChatGPT account id (chatgpt-account-id) Codex's auth.json is signed in to now; "" when it is signed in to none, on an API key, or can't be read.

func CodexSubagentModel added in v0.1.1142

func CodexSubagentModel() string

CodexSubagentModel is the model Codex's subagents are put on, "" for the one the lead asks for.

func CodexSubagentUnserved added in v0.1.1142

func CodexSubagentUnserved(id string) string

CodexSubagentUnserved says why Codex's subagents can't be put on id now, "" when magpie serves it.

func CodexTiers added in v0.1.1172

func CodexTiers(m *catalog.Model, e Entry, members func(id string) []Member)

CodexTiers sets on m what Codex is offered on e's service tiers (codexcat.Entries turns them into the entry's service_tiers): one source for every list Codex is handed, the gateway's and the models.json file magpie writes for a Codex CLI that names magpie its provider (#1530).

func CodexTokenURLForTest added in v0.1.1152

func CodexTokenURLForTest(u string) func()

CodexTokenURLForTest points ChatGPT's token endpoint at a test server, for the CLI's tests; the func it returns puts it back.

func CodexTurnURL added in v0.1.1349

func CodexTurnURL(u *url.URL) bool

CodexTurnURL says whether u is CodexBase's /responses, where Codex sends a turn.

func CodexUsedUp added in v0.1.44

func CodexUsedUp(ctx context.Context) bool

CodexUsedUp reports whether the ChatGPT account Codex is signed in to is out for the Codex app, which then sends nothing for it (codexHeld): out of its allowance with no credits to go on with. A window at 100% with credits left isn't (the Codex app keeps sending, and the backend answers). False when that isn't known.

func CodexUsedUpKnown added in v0.1.1225

func CodexUsedUpKnown() bool

CodexUsedUpKnown is CodexUsedUp over what was read already, asking no one and waiting for no one. False when nothing was read yet, which is CodexUsedUp's own answer for an account it can't tell about.

For a caller on a path that must not do I/O: agent.SyncCatalog runs inside a write's own request (a routing group's Save), and the reading there is one the vendor is asked for over the network — a save waited 1.1s of the miss of its minute's cache. Nothing is lost by not asking: KeepOnAnAccountWithRoom reads it every loginSwitchEvery and noteCodexUsedUp tells the catalog when the answer changes, which is what the sync is reacting to, and the Usage page and routing read it as the user looks at them.

func CodexWarmAtOf added in v0.1.1080

func CodexWarmAtOf(user string) (string, bool)

CodexWarmAtOf is user's own time of day to start its 5-hour window at, "off" for none; false when it follows settings' CodexWarmAts.

func CodexWarmed added in v0.1.182

func CodexWarmed() map[string]time.Time

CodexWarmed is when magpie last started a window of each ChatGPT account, by user as kept (lower-cased).

func CodexWindow added in v0.1.1280

func CodexWindow(user, slug string) int

CodexWindow is the context window Codex works in for one of its own models, by the backend's slug, for a request to the ChatGPT backend or OpenAI's API that Codex sent through magpie: the window the user set on the codex provider, else the one the account's own list gives (user, "" for any), else magpie's Codex subscription's, else Codex CLI's models_cache.json's; 0 when none says. models.dev's input limit for the same id is OpenAI's API's (gpt-5.5's 922K), not the window Codex holds a conversation to (272K): netube on Discord saw Routing say 922K for a Codex Plus account.

func CodexZstdForTests added in v0.1.1206

func CodexZstdForTests(on bool) (restore func())

CodexZstdForTests sets whether turns to the ChatGPT backend go compressed, for a test, and returns what puts it back.

func CompactFor added in v0.1.1214

func CompactFor(s settings.Settings, e Entry, find func(string) (Group, []Member, bool)) int

CompactFor is where Codex compacts a conversation on e (catalog.Model's Compact): the threshold the user set on it or its provider (CompactSet), else, when its window is one the user typed (Entry.WindowSet) and no size of theirs is typed in Settings, that whole window (#1809: a group set to 500K was told Codex as magpie's default 272K, which Codex runs to 95% of). magpie's default gives way to a window the user typed as it does to one they set in Claude Code (#876); a threshold they typed still comes first. 0 leaves it to settings.Compact. It takes the settings and the group finder from its caller: an agent's list is built for hundreds of models at magpie's start, and reading both again for each is what EffectivePriceIn saves the same loop.

func CompactSet added in v0.1.979

func CompactSet(id string) int

CompactSet is the threshold the user set on a model, by its catalog id ("provider/model", magpie/ and a [1m] mark taken off), or on its provider; for a group, the smallest its models have, so none of them outgrows its own. 0 when none is set: settings.Compact then answers.

func CompactsOf added in v0.1.979

func CompactsOf(providerID string) map[string]int

CompactsOf is the thresholds the user set on a provider's models, by model id, "*" for all of them: what its editor's Compact at shows.

func Confidence added in v0.1.862

func Confidence(ps map[string]any) float64

Confidence is how sure a set of probabilities is of its likeliest, as System One gives it: 0 with every option as likely, 1 with one certain (its 0.87 of three options is 0.8).

func CopilotAccountName added in v0.1.1108

func CopilotAccountName(login, host string) string

CopilotAccountName is how a Copilot account is known in magpie: its GitHub login on github.com (host ""), "<login>@<name>.ghe.com" on an enterprise's (#1220). One login on two hosts is two accounts, each with its own token, plan and usage, so the name every list, switch, card and routing setting goes by carries the host. A GitHub login never has an @.

func CopilotHost added in v0.1.795

func CopilotHost(s string) (string, error)

CopilotHost is where a Copilot account signs in, from what a user typed ("acme.ghe.com", "https://acme.ghe.com/", "github.com"): "" for github.com, "<name>.ghe.com" for an enterprise on GHE.com. Nothing else is taken, so a GitHub token is never sent to a host of the user's choosing.

func CopilotRefusal added in v0.1.914

func CopilotRefusal(body []byte) bool

CopilotRefusal is Copilot saying the account may not call the model it was asked for, which Auto, having picked it, picks another for.

func CountPartner added in v0.1.1126

func CountPartner(what string, ids ...string)

CountPartner counts what for each of the partners ids, today.

func CursorBase added in v0.1.297

func CursorBase(id string) (base, effort string, ok bool)

CursorBase is the model magpie offers for one of Cursor's ids at an effort ("grok-4.7-low" is grok-4.7 at low, "grok-4.7-low-fast" grok-4.7-fast at low), and that effort; ok is false for an id that is itself a model magpie offers, or that no family has. Picks and agents' models saved before the families were one model still name these ids.

func CursorVariants added in v0.1.268

func CursorVariants(model string) (map[string]string, bool)

CursorVariants are Cursor's ids a model magpie offers stands for, by effort, "" the default; ok is false for a model that stands for none, which goes to Cursor as it is.

func DecideAnswer added in v0.1.862

func DecideAnswer(via string, b []byte) []byte

DecideAnswer is a gateway's answer as System One gives it: out of Cloudflare's envelope, or, from Vercel's evaluation models (its TypeSafe API answers as System One does), a boolean's probability as a noul, a confidence from the probabilities where there is none, and its usage named as System One names it.

func DecideAsk added in v0.1.862

func DecideAsk(via, model string, body []byte) []byte

DecideAsk is a System One request (body) as via takes it: Vercel's TypeSafe API takes it as it is; its evaluation models name the model in a header and ask a noul as a boolean; Workers AI takes the state and questions as the input of a run of the model, and a Clef there takes the request as it is, its model named as Clef names itself.

func DecideRouteStatus added in v0.1.411

func DecideRouteStatus(err error) int

DecideRouteStatus is the HTTP status a System One request gets for err from RouteDecider: 400 when the model is named badly, 404 when magpie has no such Jev provider.

func DecisionGroup added in v0.1.1170

func DecisionGroup(ms []Member) bool

DecisionGroup reports whether ms, a group's models as they resolve now, are decision models, every one: the group answers System One, not a conversation.

func DeclareSearch added in v0.1.1142

func DeclareSearch(body []byte, lite bool) []byte

DeclareSearch is body with the web_search tool declared when its input replays a web search and nothing declares the tool, or body as it was. lite says the request goes as Codex's Responses Lite, whose tools are an additional_tools input item: the backend refuses a web_search among a Lite request's tools (400 "only supports function tools, custom tools, and client-executed tool search").

func Delete

func Delete(id string) error

Delete removes a provider. An account, a built-in's or a plugin's, is only hidden from magpie (its accounts and model picks kept, shown again from Hidden or by signing in); signing out is each account's Remove.

func DeleteGroup added in v0.1.38

func DeleteGroup(id string) error

DeleteGroup removes a group of the user's; one magpie found is hidden, to come back with ShowGroup. A group another has in it, or classifies with, stays until it is taken out of that one.

func DeleteGroups added in v0.1.912

func DeleteGroups(ids []string) error

DeleteGroups removes several groups at once, as DeleteGroup does each (lc on Discord: they could only be removed one at a time). It is all or none: refused, before any is removed, when one isn't there or a group left holds one as a member or classifier; one held only by another of them goes after it.

func DesktopSubagentEffort added in v0.1.1243

func DesktopSubagentEffort() string

DesktopSubagentEffort is the effort set for Desktop's subagent turns, independent of their model. Empty leaves each request's effort alone.

func DesktopSubagentModel added in v0.1.1234

func DesktopSubagentModel() string

DesktopSubagentModel is the model Desktop's subagents are put on, "" for the one the lead asks for. A provider renamed since it was set is named by its new id (RenamedRef), as a profile's model is.

func DesktopSubagentUnserved added in v0.1.1234

func DesktopSubagentUnserved(id string) string

DesktopSubagentUnserved says why Desktop's subagents can't be put on id now, "" when magpie serves that exact model or routing group. Resolve isn't enough: it takes any model name under a provider that is on, and the subagent would go to the vendor for a model it lacks.

func DetectBase added in v0.1.663

func DetectBase(base string, proto Protocol) string

DetectBase is base as proto takes it: an endpoint pasted whole (…/v1/chat/ completions, …/models/gemini-2.5-pro:generateContent) cut to its base, then the root for Anthropic, which adds /v1/messages itself, …/v1 for OpenAI's two when base is a bare host, and for Gemini's the …/v1beta beside a …/v1 or on a bare host (GeminiBase) — the editor's respellURL, in Go.

func DevinAuth added in v0.1.175

func DevinAuth() (key, server string, err error)

DevinAuth is the key the CLI signed in with and the server its API is on, read from credentials.toml; WINDSURF_API_SERVER_URL moves the server, as it does the CLI's.

func DevinAuthAt added in v0.1.386

func DevinAuthAt(home string) (key, server string, err error)

DevinAuthAt is DevinAuth for the account signed in in home, "" for the CLI's own.

func DevinCredentialsPath added in v0.1.45

func DevinCredentialsPath() string

DevinCredentialsPath is where the CLI keeps its sign-in.

func DevinNoWait added in v0.1.424

func DevinNoWait(ctx context.Context) context.Context

DevinNoWait marks a context whose caller must not wait on the devin CLI: the window's state, drawn after every click. DevinFamilies then answers with what it knows (or an error while nothing is known) and asks the CLI in the background, so the next state has it.

func DevinOffered added in v0.1.380

func DevinOffered(families []DevinFamily) []catalog.Model

DevinOffered is Devin's list as an agent's picker offers it: each family one model with the efforts its variants are at, as the provider lists it (devinModels), and Adaptive and Fusion — which Devin's own agent runs, though the API doesn't serve them — as the one model each.

func DevinPick added in v0.1.380

func DevinPick(families []DevinFamily, model, effort string) string

DevinPick is the id to give Devin's config for a model and effort picked as magpie offers them (DevinSplit the other way round): a family's variant at the effort, or the nearest it has; the family's own id with no effort, so that it keeps following the family's default; a fast run's variant at the effort, or at the family's default one. Any other id goes as it is.

func DevinSplit added in v0.1.380

func DevinSplit(families []DevinFamily, id string) (model, effort string)

DevinSplit is an id Devin's config holds taken apart as magpie offers it: the model (a family, or a family's fast run) and the effort the id is at. A family's own id is at none — it follows the family's default — and an id no family has at an effort (glm-5-2-1m, one Devin no longer lists) is itself, at none.

func DevinVariant added in v0.1.175

func DevinVariant(ctx context.Context, model, effort string) string

DevinVariant is the model to ask Devin's API for: a family's name follows its newest model, which the API takes only as one of its variants — the one at the effort asked for, or at the nearest effort the family has; with none asked, the family's default. A family's fast run (claude-opus-5-5-fast) is likewise its fast variant at that effort (claude-opus-5-5-high-fast). A variant's own id (swe-2-medium, one an agent was set to) goes as it is, whatever effort is asked: its id is the effort it runs at.

func DisableModels added in v0.1.1219

func DisableModels(pats ...string) error

DisableModels adds patterns to the disabled list.

func DisabledBy added in v0.1.1219

func DisabledBy(pat, pid, model string) bool

DisabledBy reports whether the one pattern pat disables pid's model.

func DisabledHits added in v0.1.1219

func DisabledHits(pat string) []string

DisabledHits are the providers' models, on and listed, that pat turns off now, as "<provider>/<model>".

func DisabledModels added in v0.1.1219

func DisabledModels() []string

DisabledModels are the patterns the user disabled, as saved.

func DisabledUnknown added in v0.1.1219

func DisabledUnknown() bool

DisabledUnknown reports that settings.json can't be read and no list was read before it: the gateway then refuses every model, since any of them may be one the user disabled.

func DismissCodexApp added in v0.1.1155

func DismissCodexApp()

DismissCodexApp stops saying the Codex app is on another account.

func DismissCodexDaemon added in v0.1.368

func DismissCodexDaemon()

DismissCodexDaemon stops saying the app-server is on another account.

func DropContext added in v0.1.532

func DropContext(p Provider, model string) (bool, error)

DropContext takes a window off one of a provider's models and reports whether there was one there to take away, as DropModelPrice and DropModelOutput do: a removal over a window that is not there leaves the provider in the state it was already in, but only the caller can tell the user so, and a ✓ over a window that was never set says there was one. Nothing is saved in that case, and so the agents are not told either — a provider saved over a window that did not change rewrites every agent's model lists for nothing, which is the one round the removal itself earns.

Save is what tells the agents here (store), so it is the save, and not a Touched of its own, that has to happen exactly once.

func DropModelOutput added in v0.1.532

func DropModelOutput(id string) (string, bool, error)

DropModelOutput takes a user's reply limit away under the key it is stored at, and hands that key back, so a caller left without a provider to name it by can still say which entry it cleared. It does not ask whether the provider is still there: a reply limit outlives the provider it was set for, and that provider can be deleted — the entry then sits in the settings answering for a model nothing serves, and a removal that resolved the provider first would leave the user no way to take it away, the file being the only other place it is in. Which key that is comes from the spelling as given before anything is looked up (outputKeyOf), so that a provider which has since taken the name of one that is gone is not the one the entry is cleared under. A key holding no limit is no error: there is nothing there to take away, which is the state the entry is left in either way, and writing it out again would rewrite the settings and every agent's model lists over a limit that did not change.

It reports whether there was a limit there to take away, as DropModelPrice does, and by neither saving nor telling the agents when there was none: only the caller can put that to the user, and a ✓ over a limit that was never set says the model had one.

func DropModelPrice added in v0.1.504

func DropModelPrice(key string) (bool, error)

DropModelPrice takes a user's price away under the key it is stored at, without asking whether the provider is still there, and reports whether there was one there to take away. A price outlives the provider it was set for: that provider can be deleted, and `magpie model prices` still lists the price and usage is still counted at it, so a removal that resolved the provider first would leave the user no way to take it away. Which of the keys a price is ever kept under this one is, is PriceKey's to say.

A key holding no price is still no error — there is nothing there to take away, which is the state it is left in either way — but saying so is what tells a mistyped id from a price that was cleared: `magpie model price -- reset` over a price still in the file would have the user believe it gone.

func DropUpstreamName added in v0.1.560

func DropUpstreamName(key string) (bool, error)

DropUpstreamName takes a name off under the key it is stored at, and says whether there was one to take. A name outlives the provider it was given for: that provider can be deleted, and the name is then in force for whichever provider takes that id next — its requests would go out renamed to a vendor that never heard of it, and nothing would say so — so a removal that resolved the provider first would leave the user no way to take away the one name doing that. A key holding no name is not an error: there is nothing there to take away, which is the state it is left in either way, and false says so to a caller that has something else to say.

Which key a ref is taken at is wireKey's: the name comes off from where it is really kept, rather than from under whichever provider the ref names now.

func EdgeBlocked added in v0.1.570

func EdgeBlocked(b []byte) bool

EdgeBlocked says whether an error body is a firewall's block page rather than the vendor's API answering, or one already put in plain words.

func EffectivePrice added in v0.1.504

func EffectivePrice(providerID, model string) (catalog.Price, bool)

EffectivePrice is what a call to a provider's model costs the user: the price they set for that model, or for every model of that provider, or for that model from any provider (settings' ModelPrices), else the provider's own list price, else its maker's, else the maker's of the model the user said it is the same as (SamePriceIn), each at the provider's price rate (PriceRate). The second return is false only when no price is known at all, which is not the same as a price of zero: that one is set, deliberately.

A price here is the provider's tariff, not the model's: the same model through two relays is two prices, and neither is what models.dev lists.

func EffectivePriceIn added in v0.1.504

func EffectivePriceIn(s settings.Settings, providerID, model string) (catalog.Price, bool)

EffectivePriceIn is EffectivePrice at the settings given, for a caller pricing a whole list of models at one read of the file rather than one read per model: every model of that list is priced at the same copy, so the list is one snapshot of the prices rather than a reading per row, and a price changed while it is read takes effect in the next call.

func EffortFamily added in v0.1.603

func EffortFamily(id string) string

EffortFamily is the model an id with an effort word after it is a level of ("gemini-3.8-flash-medium" is gemini-3.8-flash), and the id itself when it has none.

func EffortsOf added in v0.1.137

func EffortsOf(m catalog.Model) []string

EffortsOf is the reasoning levels one of a provider's listed models has, before any the user left out.

func EnableModels added in v0.1.1219

func EnableModels(pats ...string) (missing []string, err error)

EnableModels takes patterns off the disabled list (ignoring case); it says which of them weren't on it.

func EntryPriceIn added in v0.1.1131

func EntryPriceIn(st settings.Settings, find func(string) (Group, []Member, bool), e Entry) (catalog.Price, bool)

EntryPriceIn is what a call to an entry of the catalog costs the user, as the usage pages count it: its model's EffectivePriceIn, or a group's when every member costs the same, none in a fast mode, since which of them answers isn't known beforehand. find is GroupFinder's.

func ErrorType added in v0.1.579

func ErrorType(b []byte) string

ErrorType is the kind of error a vendor's body names — the error's type (rate_limit_error, usage_limit_reached), else its code — or "" when it names none: what to set beside the status when a request failed.

func ExtraBodyOK added in v0.1.1191

func ExtraBodyOK(e ExtraBody) string

ExtraBodyOK says what is wrong with an extraBody, "" when nothing is.

func FactoryBaseForTest added in v0.1.685

func FactoryBaseForTest(api, eu string) func()

FactoryBaseForTest points Factory's API at api, and its EU region at eu, until the returned function runs. A provider built after the call uses them. Tests outside this package use it.

func Families added in v0.1.111

func Families() []string

Families are the families providers and groups are tagged with, sorted.

func FastPicks added in v0.1.1077

func FastPicks(agent string) []string

FastPicks are the entries agent's requests for are sent fast, read once for a list of them all.

func FaviconFor added in v0.1.186

func FaviconFor(ctx context.Context, base, name string) (string, error)

FaviconFor finds the site behind a provider's base URL and keeps its icon like a picture picked by hand (#12). The API's own host is asked first, then the domains it sits under (api.deepseek.com, then deepseek.com), since an API host seldom has a page of its own. On each, the home page's <link rel="icon"> pictures come before /favicon.ico. Only public https hosts are reached, as for an import link's icon.

A new-api or one-api site names its logo only in /api/status, which its page's script reads to set the tab's icon; the page itself names none, or the panel's own /logo.png, and its /favicon.ico is the panel's too, the same on every such site (wiixdede on X: every relay got new-api's icon). Its logo is taken from there, or one its page was given by hand, and one with neither gets name's first letters on a tile.

func FetchIcon added in v0.1.21

func FetchIcon(ctx context.Context, rawURL string) (string, error)

FetchIcon downloads the picture an import link named and keeps it like any other, returning the Icon value that points at it. It runs when the user confirms the import, never at parse time; the URL is re-checked here so a crafted request can't point magpie at anything but a public https picture, and the read stops one byte past MaxIcon so a huge body is refused rather than buffered. The picture is asked for through usemagpie.ai's icon proxy, so its host never sees the user's IP.

func FetchNew added in v0.1.402

func FetchNew(timeout time.Duration) (missing bool)

FetchNew asks each signed-in account whose vendor list magpie hasn't fetched yet for it, each for at most timeout. Start-up does this for the accounts there then; an account signed in while magpie runs (in magpie or in the agent's own app) otherwise showed magpie's built-in list, fewer models than the vendor serves, until Refresh was clicked (#204). One that fails is asked again after newFetchRetry, not each time. It reports whether an account is left without its list (one that failed, or that failed less than newFetchRetry ago), for a caller with no page to ask again from (the terminal, magpie serve) to try once more later.

func FetchNewBehind added in v0.1.651

func FetchNewBehind(timeout time.Duration)

FetchNewBehind is FetchNew in the background, started at once unless one started so is still running: for the Providers page, which waited on it (#541: ten seconds and more of placeholders, an account at a time and behind start-up's own run). FetchingNew says when it is done.

func FetchNewSoon added in v0.1.591

func FetchNewSoon(timeout time.Duration)

FetchNewSoon is FetchNew in the background, for a page that shouldn't wait on vendors (the panel, whose model picker otherwise kept an account's fallback list until the Providers page was opened). It does nothing while one runs or within newSoonEvery of the last.

func FetchingNew added in v0.1.651

func FetchingNew() bool

FetchingNew reports whether a FetchNew is under way (start-up's, or one started behind a page): accounts' lists may be on their way still. One started behind a page counts from its start, while it still picks the accounts due: a page whose FetchNewBehind found it so returned at once, and was told none was on its way until the one picking counted itself.

func FileError added in v0.1.587

func FileError() error

FileError is why providers.json can't be read, nil when it can or isn't there: for what lists the providers to say so, not "none yet".

func FindGroup added in v0.1.38

func FindGroup(id string) (Group, []Member, bool)

FindGroup looks a group up by its catalog id ("group/<id>") and resolves its members; one not ready now is left out.

func FirstLogin added in v0.1.1226

func FirstLogin(agent string) string

FirstLogin is the account of an agent's first in the gateway's order, as InUseLogin, by the order alone: the one the agent is signed in to unless it is paused, else the first other one on; kept signed in to one of the user's choosing, the first on in the order (#1957). An account spent is still named, so a list that names it isn't rewritten each time an allowance is read. "" when the agent has none, or is none whose own sign-in is paused for its others (Claude Code's and Codex's).

func FlatID added in v0.1.1137

func FlatID(id string) string

FlatID is a catalog id with no slash in it.

func FlatName added in v0.1.572

func FlatName(namespace, name string) string

FlatName is the name a namespaced tool is offered to a model under, which takes one flat name: namespace__name, as Codex names an MCP server's tools. A name longer than the 64 characters APIs allow is cut and made unique by a hash of the whole.

func Flattened added in v0.1.1137

func Flattened() map[string]string

Flattened maps each served id that can be spelled flat, and taken back by Unflat, to that spelling; an id two served ids flatten to alike is left out, as is one already without a slash.

func FlushServed added in v0.1.1291

func FlushServed()

FlushServed writes what NoteServed noted and hasn't written yet: the gateway calls it as it ends.

func FolderUnder added in v0.1.1180

func FolderUnder(folder, root string) bool

FolderUnder reports whether folder is root or a folder inside it: at a path's boundary, so /a/b is not under /a/bc. An unknown folder ("") is under none.

func ForgetAccount added in v0.1.770

func ForgetAccount(id string) error

ForgetAccount signs a subscription's accounts out of magpie for good, the way past a removal (#694: a removed Qoder came back with its old account each time it was added back, and nothing took it away). A plugin's sign-ins leave plugin-auth.json (the plugin host's signOut when one runs, else under plugin-auth.json.lock) and logins.json, and a moved built-in's backup of them goes too, so moving back doesn't bring them either; a built-in's saved accounts go as each account's Remove takes them. An agent's own sign-in, which magpie only reads, is hidden as Remove hides it. Signing in again starts afresh.

func ForgetAccounts added in v0.1.362

func ForgetAccounts()

ForgetAccounts makes the next look at the accounts read them afresh, for a caller that changed a sign-in behind magpie's back (a test's home).

func ForgetBalances added in v0.1.90

func ForgetBalances()

ForgetBalances has the next KeyBalances ask again, after a provider's key or balance token changed.

func ForgetCopilotForTest added in v0.1.1077

func ForgetCopilotForTest()

ForgetCopilotForTest drops what magpie keeps of each Copilot account for the process's life — its session (and the API endpoint it named), Auto's session, the models it was refused, may pick or saw — so a test run again (-count) asks the fake GitHub it serves rather than the last run's.

func ForgetKeptCardsForTest added in v0.1.1120

func ForgetKeptCardsForTest()

ForgetKeptCardsForTest has the cards kept on disk (quotas.json) read again from the home a test has set: they are read once per process.

func ForgetLogin added in v0.1.11

func ForgetLogin(agent, user string) error

ForgetLogin drops a remembered account. The one an agent is signed in to now can't be forgotten while it has another to be signed in to; it would only be remembered again (SignedInError). Codex is signed in to another of its accounts first (nextOnForget), and its last one is signed out instead, as `codex logout` does (mamba on Discord: a single Codex account couldn't be removed at all).

func ForgetPlanQuotas added in v0.1.1142

func ForgetPlanQuotas()

ForgetPlanQuotas has the next PlanQuotas ask again, after what a plan's windows are read with changed (a Volcengine or Tencent Cloud access key).

func ForgetRemoteCardsForTest added in v0.1.1078

func ForgetRemoteCardsForTest()

ForgetRemoteCardsForTest drops the remote magpies' cards kept here, for a test run again (-count) to ask its own fake remote afresh.

func FreeID added in v0.1.399

func FreeID(id string) string

FreeID is id, or id-2, id-3… whichever no provider or subscription has.

func GateGroups added in v0.1.1248

func GateGroups(refresh func()) (stop func())

GateGroups makes the user's own groups wait on ServeGroups until stop: the gateway calls it as it starts serving. refresh, when not nil, is asked to bring the plugins up to date when a lookup gated finds a group of the user's own (served).

func GeminiBase added in v0.1.1125

func GeminiBase(u string) string

GeminiBase is the base a Gemini URL is kept as: trimmed, an endpoint or the model list pasted whole cut back to the base, and a bare host given Google's version (/v1beta), as the Gemini API's SDKs add it.

func GeminiPath added in v0.1.1125

func GeminiPath(model string, stream bool) string

GeminiPath is the path under a Gemini base model is asked at: streamed as server-sent events (alt=sse) when stream, else one JSON reply.

func GitOnDisk added in v0.1.1191

func GitOnDisk(dir string) string

GitOnDisk says whether dir, a folder on this computer, is in a git repository: a .git in it or in a folder above it. "" when dir isn't a folder here (an agent on another computer, through a shared magpie): unknown, never "no".

func GitSaid added in v0.1.1191

func GitSaid(text string) string

GitSaid is the last "yes" or "no" an agent's text says of its folder being in a git repository, "" when it says neither.

func GrokBuildFast added in v0.1.1258

func GrokBuildFast(id string) (string, bool)

GrokBuildFast is the Grok model id is Grok Build's fast variant of (grok-4.7-build-fast is grok-4.7's), and whether it is one: for a Grok CLI session, which names it bare, priced as grokFastPrice prices it.

func GrokHome added in v0.1.22

func GrokHome() string

GrokHome is where the CLI keeps its sign-in and settings.

func GrokUser added in v0.1.22

func GrokUser(home string) (string, bool)

GrokUser is who the grok with this home is signed in to.

func GroupFinder added in v0.1.133

func GroupFinder() func(id string) (Group, []Member, bool)

GroupFinder is FindGroup for looking up many: every provider's models are read once, when the first group is looked up, not again for each.

func GroupFor added in v0.1.136

func GroupFor(id string) (string, bool)

GroupFor is the group a model's id without a provider in it names, as "group/<id>": the group of that id, else the group of that model however a vendor spells it ("grok-4.7" is the group grok-4-7 or auto-grok-4-7). A request for the model is the group's then, as it would be for the group's own id; failing those, the group whose name it is (groupNamed); ok is false when no group has it. An id with a provider in it ("a/m") names that provider's model, never a group.

func GroupIDOf added in v0.1.1083

func GroupIDOf(ref string) (string, bool)

GroupIDOf is the group id a ref names ("group/<id>", or a found group's "auto/<model>": CanonicalRef), with spaces and the [1m] mark Claude Code puts on a 1M window taken off, as an agent's own settings carry it. ok is false for a ref that isn't a group's.

func GroupMember added in v0.1.136

func GroupMember(g Group, in string) (string, error)

GroupMember is the group's member a typed model names: its id, its model id without the provider, or the model's last name — each with the effort fixed on the member ("m:high") or, when only one member is of that model, without it.

func GroupSlug added in v0.1.1078

func GroupSlug(name string) string

GroupSlug derives a group's own id from a name as Slug does, the dots kept: "GPT 6.1 Sol" → "gpt-6.1-sol", so an agent sending group/<id> sends the model's name as harnesses that price or tune by it read it (#968). A run of dots is one, and none starts or ends it. The ids magpie finds (auto-…) stay Slug's, so no id saved before changes.

func GroupsServed added in v0.1.1248

func GroupsServed() bool

GroupsServed says whether the user's own groups are served here now.

func HandOver added in v0.1.661

func HandOver(ctx context.Context, accounts bool) map[string]error

HandOver gives each deprecated built-in whose plugin the user has installed, at the version its move needs, and which that plugin serves, its id, so one subscription is never listed twice: the built-in, and the plugin's under "<id>-plugin" (ARNO on Discord: Qoder CN twice once the Qoder plugin's 0.2.0 served it, as nothing gave it the id). One with no accounts is the plugin's at once, as Adopt makes it; with accounts too, one that has some is moved (Move: each tried through the plugin, all put back on any failure, the built-in carrying on). One the plugin has accounts of its own for already is left as it is, since its models are in use as <id>-plugin's and the id changing would leave agents asking for a provider gone; the add sheet lists it once regardless. One moved whose plugin the user removed is the plugin's again once they install it, its accounts still with the plugin, and a failed move waits retryWait. No plugin is installed for it: the user's own install is what says to.

func HasMiniMax added in v0.1.910

func HasMiniMax() bool

HasMiniMax says whether a MiniMax Code account is signed in, on either site.

func HasPluginCheckin added in v0.1.1085

func HasPluginCheckin() bool

HasPluginCheckin says whether a plugin that checks in is signed in.

func HasQoder added in v0.1.1077

func HasQoder() bool

HasQoder says whether a Qoder account of the plugin is signed in, on either site.

func HasTrae added in v0.1.784

func HasTrae() bool

HasTrae says whether a Trae CN account is signed in.

func HasUpstreamName added in v0.1.560

func HasUpstreamName(key string) bool

HasUpstreamName reports whether a name is kept under exactly the key it is given, the provider's part spelled as it is. No other spelling of the provider is tried: a caller deciding whether to remove a name by this key has to know that this key is the one a name is kept under, which is the one question wireKey's order is about.

A key spelled as an agent spells one — with magpie/ in front of it, and the spaces a ref is typed with — is that same key, as it is for a removal (DropUpstreamName): a name kept under it is there whichever way it is spelled, and a check that answered for one spelling only would say a name was not kept where it is. The one caller has had that prefix taken off already (splitModelRef), so nothing depends on it yet.

func HasWorkBuddy added in v0.1.356

func HasWorkBuddy() bool

HasWorkBuddy says whether a WorkBuddy (China) account is signed in.

func HeldSettings added in v0.1.908

func HeldSettings() settings.Settings

HeldSettings is the settings as heldSettings reads them, for a look outside the package made many times in one request.

func HiddenModels added in v0.1.460

func HiddenModels(agent string) map[string]bool

HiddenModels are the ids of the entries taken out of agent's lists, a found group saved by its old id, group/auto-<slug>, by the one it is listed by now (PublicRef).

func Hold added in v0.1.705

func Hold() (release func())

Hold keeps the catalog built once until release is called, for a request that only reads; a write meanwhile (Changed) drops it.

func HostOf

func HostOf(u string) string

HostOf pulls the host out of a URL, for display.

func IDDisabled added in v0.1.1219

func IDDisabled(id string) (string, bool)

IDDisabled reports whether a model id as asked ("<provider>/<model>" or a bare id) is one the user disabled, and the pattern that did.

func IDs

func IDs() []string

IDs lists the catalog ids, for error messages.

func IconDir added in v0.1.10

func IconDir() string

IconDir is where pictures given to providers are kept.

func IconFile added in v0.1.10

func IconFile(name string) string

IconFile is the path of a stored picture, for a name as StoreIcon made it; "" for anything else, so a request can't reach outside the folder.

func IconForCatalog

func IconForCatalog(catalogID string) string

IconForCatalog names the logo of the vendor behind a models.dev provider id, or "" when no preset covers it.

func ImageOverride added in v0.1.413

func ImageOverride(pid, model string) (bool, bool)

ImageOverride is the user's answer for whether pid's model takes images.

func ImageOverrideIn added in v0.1.1093

func ImageOverrideIn(s settings.Settings, pid, model string) (bool, bool)

ImageOverrideIn is ImageOverride from settings s already read: a list of many models reads them once, not for each (lml on Discord, Windows).

func ImportFromApps added in v0.1.25

func ImportFromApps(picks []AppPick) ([]string, error)

ImportFromApps adds what the user picked, reading the sources again so keys never pass through the window. It answers the names added.

func InUseLogin added in v0.1.504

func InUseLogin(agent string) string

InUseLogin is the account of an agent's the gateway goes to first: the one the agent is signed in to, unless it is paused or has used its allowance up — then the next one on that still has room — else the first other one on; "" when the agent has none. Kept signed in to one of the user's choosing, it is the first in the order that is in use.

func InstallPluginCLI added in v0.1.1241

func InstallPluginCLI(ctx context.Context, id string) error

InstallPluginCLI installs the CLI PluginCLIMissing names, with its vendor's installer or, where that can't run, as it installs it.

func Intents added in v0.1.95

func Intents(rules []Rule, q RuleRequest) []string

Intents are the intents the classifier is to choose among for q: those of the rules that match it but for their intent, up to the first that matches outright (a rule after it could never be the first to match). None when no rule before that one has an intent — the classifier then isn't asked. Each is given once, as the first rule has it.

func IsDecider added in v0.1.142

func IsDecider(id string) bool

IsDecider reports whether a classifier ("provider/model") is a decision provider's model.

func IsFastPick added in v0.1.1077

func IsFastPick(agent, id string) bool

IsFastPick reports whether agent's requests for the entry id ("<provider>/<model>") are sent fast.

func IsGroupRef added in v0.1.1294

func IsGroupRef(ref string) bool

IsGroupRef reports whether ref names a routing group: group/<id>, or a found group's auto/<model>.

func IsPattern added in v0.1.826

func IsPattern(s string) bool

IsPattern reports whether a member as typed is a pattern rather than a model's id: a regular expression ("re:…") or a glob with "*" in it. No vendor's model id has a "*" in it, so a glob can't be taken for one.

func IsRemoteCard added in v0.1.1078

func IsRemoteCard(id string) bool

IsRemoteCard is whether id is a card this magpie has from a remote magpie, or the card standing for the remote itself.

func IsUltraPick added in v0.1.1270

func IsUltraPick(agent, id string) bool

IsUltraPick reports whether agent's requests for the entry id are sent as Ultrafast where the account offers it.

func KeepClaudeWindowsWarm added in v0.1.223

func KeepClaudeWindowsWarm(ctx context.Context, send func(ctx context.Context, configDir string) error)

KeepClaudeWindowsWarm starts the Claude accounts' windows as they reset, while settings say to, each with one request send makes.

func KeepCodexWindowsWarm added in v0.1.182

func KeepCodexWindowsWarm(ctx context.Context)

KeepCodexWindowsWarm starts the ChatGPT accounts' windows as they reset, while settings say to, two minutes after it starts and every codexWarmEvery after that, until ctx ends.

func KeepListsFresh added in v0.1.1234

func KeepListsFresh(ctx context.Context)

KeepListsFresh fetches the list of each provider of the user's own that has a RefreshEvery once its list is that old, run by the magpie serving the gateway (`magpie serve`, the app).

func KeepLoginsAlive added in v0.1.75

func KeepLoginsAlive(ctx context.Context)

KeepLoginsAlive renews the saved sign-ins that are due, a minute after it starts and every hour after that — a computer that slept through a day catches up within the hour of waking — until ctx ends.

func KeepMiniMaxCheckedIn added in v0.1.910

func KeepMiniMaxCheckedIn(ctx context.Context)

KeepMiniMaxCheckedIn checks the MiniMax Code accounts in each day while settings say to, as KeepTraeCheckedIn does Trae CN's.

func KeepOnAnAccountWithRoom added in v0.1.402

func KeepOnAnAccountWithRoom(ctx context.Context)

KeepOnAnAccountWithRoom runs SwitchWhenSpent for Codex and Claude Code a minute after it starts and every loginSwitchEvery after that, until ctx ends, and keeps Claude Code's proxy that of its account (SyncClaudeProxyEnv).

func KeepPartnersFresh added in v0.1.1343

func KeepPartnersFresh(ctx context.Context)

KeepPartnersFresh fetches the partner list when the magpie serving the gateway starts, and again whenever it is due (every hour, ten minutes after a failed fetch), whether or not a page asks for it, so a partner added reaches an app left running within the hour, and the list kept on disk is fresh for the next start.

func KeepPluginsCheckedIn added in v0.1.1085

func KeepPluginsCheckedIn(ctx context.Context)

KeepPluginsCheckedIn checks the plugins' accounts in each day, each provider's while settings say to, as KeepWorkBuddyCheckedIn does WorkBuddy's.

func KeepPluginsListed added in v0.1.1167

func KeepPluginsListed(ctx context.Context)

KeepPluginsListed lists the plugins' models again every relistEvery, in the magpie serving the gateway, and drops the picks of models gone from them.

func KeepQoderCheckedIn added in v0.1.1077

func KeepQoderCheckedIn(ctx context.Context)

KeepQoderCheckedIn checks the Qoder accounts in each day while settings say to, as KeepTraeCheckedIn does Trae CN's.

func KeepResetsFromRunningOut added in v0.1.701

func KeepResetsFromRunningOut(ctx context.Context)

KeepResetsFromRunningOut spends the Codex resets about to run out unused (SpendExpiringCodexResets), three minutes after it starts and every resetExpiryClose after that, until ctx ends.

func KeepRetiringMoved added in v0.1.506

func KeepRetiringMoved(ctx context.Context)

KeepRetiringMoved moves the built-ins being retired, and hands over those whose plugin the user installed (HandOver), run by the magpie serving the gateway (one magpie, never two at once): a little after it starts, then every hour, so a failed move is tried again once retryWait has gone; a retired built-in's failed move brings the next run forward to when it is due. It also keeps each moved built-in's plugin up to date.

func KeepTraeCheckedIn added in v0.1.784

func KeepTraeCheckedIn(ctx context.Context)

KeepTraeCheckedIn checks the Trae CN accounts in each day while settings say to, as KeepWorkBuddyCheckedIn does WorkBuddy's.

func KeepWorkBuddyCheckedIn added in v0.1.356

func KeepWorkBuddyCheckedIn(ctx context.Context)

KeepWorkBuddyCheckedIn checks the WorkBuddy accounts in each day while settings say to: two minutes after it starts, every wbCheckinEvery after that, and as the Beijing day turns, until ctx ends.

func KeyAllowanceID added in v0.1.1086

func KeyAllowanceID(p Provider) string

KeyAllowanceID is what OnRenewed's hooks are told, as the user of agent "", of a key whose own windows magpie reads; empty for any other.

func KeyID added in v0.1.14

func KeyID(key string) string

KeyID is the fingerprint a key is named by, in lists and in the gateway.

func KeyOf added in v0.1.1164

func KeyOf(id, keyRef string) (string, error)

KeyOf is one of a provider's keys, by its id (keyID), for the editor to show or copy: a provider of several keys has a row for each, and each row copies its own (#1480).

func KeysListed added in v0.1.1265

func KeysListed() int64

KeysListed is how many times a provider's keys on have been listed in this process: a test counts them, not the time a page or request took, to say they are listed once and not once a key (@NetRozee on X).

func KiloClient added in v0.1.635

func KiloClient(h http.Header, key, session string)

KiloClient makes a request to the Kilo Gateway carry what the Kilo CLI sends it (Kilo-Org/kilocode packages/opencode/src/session/llm/request.ts and kilocode/const.ts, packages/kilo-gateway/src/headers.ts): Kilo Code's attribution and User-Agent, the editor it runs in, its mode, and the session as the task, which the gateway keys its prompt cache on. session names the conversation, made into one of the CLI's ids (ses_…) as for OpenCode; none leaves the session headers out. A provider with no key sends no Authorization at all: the gateway answers a free model to a caller with no credential as anonymous (by IP, 200 requests an hour), and refuses a bearer it can't verify with 401 (Kilo-Org/cloud web-shared/src/lib/tokens.ts, ai-gateway/handlers/llm-proxy.ts). Kilo's clients still send "Bearer anonymous", which the gateway reads as none only until no released client sends it, so it is not copied here.

func KimiCodeSearch added in v0.1.779

func KimiCodeSearch(p Provider) string

KimiCodeSearch is where a Kimi Code plan's key searches the web, as kimi-cli's SearchWeb does (auth/platforms.py: the plan's search_url is its base_url, /coding/v1, with /search), "" for a provider that isn't a Kimi Code plan with a key.

func KnownFace added in v0.1.1234

func KnownFace(id string) (name, icon string)

KnownFace is the name and icon magpie knows the provider id by while it isn't set up: a built-in subscription signed out of, or with account discovery off ("claude" is Claude Code), or a preset's removed since. The usage log keeps the id of every provider a call went to, and the Usage page names those by this rather than by the bare id (@ByronVon1 on X: "claude" in the Provider filter). "" for an id magpie doesn't know, such as a custom provider removed since.

func Labels added in v0.1.516

func Labels(es []Entry) []string

Labels are how an agent's list names each of es, in order: as Label, or, when the user wants names plain (settings' PlainNames, #335), by the name alone — but for two or more the list would call the same, as a routing group found for a model is called with that model left in the list, which keep their provider's after it to tell them apart. With their own names plain (PlainOwnNames, #92), a name the user gave — a model's, or a routing group's they made (#868: "· routing group" was what an agent's narrow menu cut off) — is that name just as they wrote it, but for two the list would call the same, and the rest keep Label's.

func LastServed added in v0.1.664

func LastServed() map[string]time.Time

LastServed is when each ServedID last answered: what this process noted and what the file holds, whichever gateway wrote it.

func LearnAuthHeader added in v0.1.1211

func LearnAuthHeader(id, only string)

LearnAuthHeader keeps only as the header provider id's key goes in, when it sends both still: one the user picked is theirs.

func LearnZhipuCoding added in v0.1.1224

func LearnZhipuCoding(p Provider, from string)

LearnZhipuCoding moves provider p, whose key the pay-as-you-go endpoint from refused and the GLM Coding Plan's served, to the plan's endpoints: its OpenAI URL, and the plan's Responses URL when it has none (the zhipu and zai presets' Coding Plan region). Only a provider with that one key still at from is moved: one with other keys may hold pay-as-you-go keys too, and one the user has moved since is theirs. Each of its requests is then asked again at the plan's endpoint as this one was.

func LetGo added in v0.1.1400

func LetGo(req *http.Request)

LetGo lets go of the bytes SetBody gave req once it was answered and nothing will ask it again; a body SetBody didn't give is left as it is.

func ListHeader added in v0.1.1030

func ListHeader(name string) bool

ListHeader is a header whose value is a comma-separated list the request has its own of, which a provider's header of the same name adds to: anthropic-beta, the betas an agent asks on each request.

func ListedWindow added in v0.1.816

func ListedWindow(m catalog.Model) int

ListedWindow is the window a provider's model takes before the user says one: its vendor's list's, else the one models.dev gives a model of its id. A vendor models.dev doesn't list (a custom provider, a proxy, a plugin whose list says none, as Cline's) serves models it knows from others, under the vendor's prefix too: cline-free/mimo-v2.6-flash is mimo-v2.6-flash. A window the vendor lists under catalog.LeastWindow (512, H20 on Discord) is no window: models.dev's answers, else none, and the agent's default.

func ListsRead added in v0.1.1265

func ListsRead() int64

ListsRead is how many times a provider's saved lists have been asked for whole in this process: a test counts them to say a request reads them once, not once a key (@NetRozee on X).

func LocalAddresses added in v0.1.1091

func LocalAddresses(bases ...string) bool

LocalAddresses says every non-empty base URL among bases is on this machine or the local network (localhost, *.local, a loopback or private IP), and there is at least one.

func LoginID added in v0.1.1076

func LoginID(agent, user string) string

LoginID is the stable id of an agent's account known by its name (#905): the login's, kept through renames, or one made of the name for an account whose logins haven't been written since — and for an agent that keeps its accounts elsewhere, made of the name always.

func LoginUsage added in v0.1.14

func LoginUsage(ctx context.Context, agent string) map[string]SubscriptionQuota

LoginUsage is the allowance used by each of an agent's accounts, by user. What was read less than a minute ago, here or for the Usage page, comes from the cache; the rest is asked for at once, as long as ctx allows.

func LoginUsageVia added in v0.1.778

func LoginUsageVia(f func(ctx context.Context, agent string) map[string]SubscriptionQuota)

LoginUsageVia has tests stand in for LoginUsage's readings. It returns once no reading is still running through the one it replaces, and none starts through it after.

func MakerPrice added in v0.1.411

func MakerPrice(model string) (catalog.Price, bool)

MakerPrice is a model's list price as the first vendor among the presets that makes the models it serves lists it; for a call whose provider has gone since.

func MantleBase added in v0.1.1270

func MantleBase(base, model string, other bool) string

MantleBase is the base a request for model goes to on Mantle's chat completions or Responses API, given a Mantle provider's base for it (IsBedrockMantle): one ending /v1 or /openai/v1 goes at whichever of the two serves the model, or at the other when other is set (the model was refused at the first, so the gateway learned its prefix). A base ending otherwise, one the user typed, is given back as it is.

func Mask

func Mask(s string) string

Mask hides all but the ends of a secret.

func MaskSearchKey added in v0.1.1231

func MaskSearchKey(k string) string

MaskSearchKey is one search API key as shown: as Mask, but a Tavily key keeps its whole "tvly-" tag (tvly-…abcd), which says what it is and nothing secret of it.

func MatchRule added in v0.1.94

func MatchRule(rules []Rule, q RuleRequest) int

MatchRule is the first of rules the request matches, -1 for none.

func MemberEffort added in v0.1.379

func MemberEffort(id string) (model, effort string)

MemberEffort splits a group's member into the model it names and the effort fixed on it ("" for none): "a/m:high" is a/m at high, unless a has a model "m:high" of its own. A group in the group ("group/<id>") takes none; one typed with one comes back split, for SaveGroup to refuse.

func MemberFast added in v0.1.577

func MemberFast(id string) (member string, fast bool)

MemberFast splits a member typed with ":fast" after it into the member and true: "a/m:high:fast" is a/m:high, fast, unless a has a model "m:high:fast" of its own.

func MemberGroups added in v0.1.572

func MemberGroups() map[string][]string

MemberGroups are the routing groups each model is in, as "group/<id>", by the model's "provider/model" id; a member fixed at an effort counts as its model, and a group removed is none. A provider kept for routing groups (Provider.Unlisted) reaches agents through these alone: a model of it in none of them is used by nothing.

func MergeList added in v0.1.1030

func MergeList(h http.Header, name, add string)

MergeList writes name in h as the items h has under it, in any case, followed by those of add: comma-separated, each once, empty ones left out, under name as written.

func MergeName added in v0.1.673

func MergeName(model string) string

MergeName is the name the groups magpie finds merge a model by, when the user said nothing of it: its id as vendors agree on it (sameModel).

func MergeQuotaHistory added in v0.1.722

func MergeQuotaHistory(data []byte, now time.Time) error

MergeQuotaHistory merges another computer's history (as QuotaHistoryData gave it there) into this one's.

func Mirror added in v0.1.76

func Mirror(ps []Provider, gs []Group) error

Mirror makes the providers and groups exactly these, as sync brings them from another computer: one not among them goes, one that came without keys keeps the keys it has here, and an access key or balance token it came without is kept too (KeepSecrets).

func MirrorGroupOrder added in v0.1.843

func MirrorGroupOrder(order []string) error

MirrorGroupOrder makes the groups' order the one another computer has, as sync brings it, the way MirrorOrder does the providers': its ids first, then the ones named here alone. None leaves the order here as it is.

func MirrorOrder added in v0.1.638

func MirrorOrder(order []string) error

MirrorOrder makes the providers' order the one another computer has, as sync brings it: its ids first, as it has them, then the ones named here alone (a signed-in account only this computer has), in the order they have here. None, as from a magpie before the order was synced or one never arranged, leaves the order here as it is.

func MirrorSearchAPIs added in v0.1.587

func MirrorSearchAPIs(as []SearchAPI) error

MirrorSearchAPIs makes the search APIs exactly these, as sync brings them; one that came without a key keeps the key it has here.

func ModelDisabled added in v0.1.1219

func ModelDisabled(pid, model string) (string, bool)

ModelDisabled reports whether the user disabled pid's model, and the pattern that did. A list nobody knows (DisabledUnknown) disables none here: the gateway asks DisabledUnknown itself.

func ModelListsHeld added in v0.1.1209

func ModelListsHeld(ls map[string]ModelList) bool

ModelListsHeld reports whether every list in ls is the one its agent has now: SetModelLists would change none of them.

func ModelName added in v0.1.137

func ModelName(pid, model string) (string, bool)

ModelName is the name the user gave a provider's model, if any.

func ModelOff added in v0.1.1130

func ModelOff(agent string) func(id string) bool

ModelOff reports whether agent's lists leave an entry out by the picks made one model at a time: every one not picked, when it is shown only the models picked for it, else the ones taken out (HiddenModels).

func ModelOrder added in v0.1.952

func ModelOrder(agent string) []string

ModelOrder is the order the user put agent's models in (OrderedModels), by entry id, a found group by the id it is listed by now (PublicRef); none when they never did.

func Movable added in v0.1.506

func Movable(id string) bool

Movable is whether the built-in id has a plugin it can move to.

func MovableIDs added in v0.1.628

func MovableIDs() []string

MovableIDs are the built-ins that have a plugin to move to, by id: the page marks them deprecated, moved or not.

func Move added in v0.1.506

func Move(ctx context.Context, id string) error

Move puts the built-in id's accounts onto its plugin (see above). An error leaves the built-in as it was.

func MovePackage added in v0.1.506

func MovePackage(id string) string

MovePackage is the plugin the built-in id moves to.

func MoveRetiring added in v0.1.506

func MoveRetiring(ctx context.Context) map[string]error

MoveRetiring moves the built-ins being retired that have accounts, at start-up: once, or again retryWait after one failed. One an older magpie moved back is moved again: there is no way back, as the built-in is going. One whose plugin the user removed waits for them to install it.

func Moved added in v0.1.506

func Moved(id string) bool

Moved is whether the built-in id's accounts are its plugin's now.

func MovedOnto added in v0.1.538

func MovedOnto(name string) []string

MovedOnto are the built-ins moved onto the plugin named (its spec or package name).

func NamedGroups added in v0.1.1248

func NamedGroups() (int, error)

NamedGroups counts the user's own groups in providers.json, served or not; a file that can't be read is an error, not none.

func NextLogin added in v0.1.402

func NextLogin(ctx context.Context, agent string) (from, to string, back, ok bool)

NextLogin is the account agent should be signed in to instead of the one it is on: the account magpie moved it off, once that has room again (back); else, when the one it is on is spent, the first of its other accounts that are on in magpie, in the order they were saved, whose allowance is known and not spent. ok is false when the agent should stay.

func NextResetAt added in v0.1.1230

func NextResetAt(s string, now time.Time) (time.Time, bool)

NextResetAt is the first time after now that the time of day s names comes round; ok is false when s names none.

func NotSignedIn added in v0.1.1225

func NotSignedIn(ps []Provider) []string

NotSignedIn is the subscriptions among ps (as a backup or a sync brings them: their model picks and settings alone) that no account here is signed in to: they are listed once one is, and are to be signed in to on this computer. A subscription the user removed from magpie is not one.

func NoteClaudeLimits added in v0.1.199

func NoteClaudeLimits(user string, ls []ClaudeLimit)

NoteClaudeLimits keeps what Claude Code said of user's allowance as it answered, in place of the windows of the same names last read, and has routing weigh the account by it.

func NoteClaudeSignInFailure added in v0.1.788

func NoteClaudeSignInFailure(user, version, message string)

NoteClaudeSignInFailure keeps a run's refusal on the saved Claude account user, when the run started on the credential the account still has (version): one started on an older credential says nothing of this one. The run's own error stays in the request's trace.

func NoteCodexLimits added in v0.1.1118

func NoteCodexLimits(agent, user string, heard []CodexLimit)

NoteCodexLimits keeps what a reply said of agent's account user (agent as its usage is read, Account.UsageAgent) in place of the windows of the same span last read, for routing (Allowances) and the Usage page alike. An account not read yet is left to its reading: a reply names only the windows it counts, which isn't the whole of the account.

func NoteExpiredSignIn added in v0.1.1335

func NoteExpiredSignIn(ctx context.Context, a *Account, req *http.Request)

NoteExpiredSignIn renews the ChatGPT sign-in of a, whose request req the backend answered 401 token expired while the token had time left by its exp, so the next request goes with a new one. The request itself isn't sent again here; the routing loop passes over it as an auth failure. A refresh refused marks a saved account lapsed (savedRefreshFailed).

func NoteRevokedSignIn added in v0.1.1213

func NoteRevokedSignIn(ctx context.Context, a *Account, req *http.Request)

NoteRevokedSignIn keeps that the vendor revoked the credential req went to account a with. A saved ChatGPT account is refreshed first, as Codex does on a 401: a refresh that goes through is a new sign-in, and the account isn't marked.

func NoteServed added in v0.1.664

func NoteServed(p Provider, at time.Time)

NoteServed records that p just answered a request, at at. The file follows within servedFlushAfter (FlushServed): this process's LastServed has it at once.

func NoticePartners added in v0.1.1126

func NoticePartners(ids ...string)

NoticePartners keeps that the user has been shown the partners ids, so they are no longer new. It is kept whether or not they are counted.

func ObjectRoot added in v0.1.718

func ObjectRoot(ps map[string]any) bool

ObjectRoot makes a tool's input schema a plain object at the root, with no anyOf, oneOf or allOf there: Grok's backend wants one, and so do Anthropic's models behind Factory ("input_schema does not support oneOf, allOf, or anyOf at the top level", #646). allOf's branches are all merged, properties and required alike. Of anyOf's and oneOf's object branches the properties are merged, a field each of them requires stays required, and the other branches go. A branch that is a union itself, as zod writes a discriminated union inside another (Codex desktop's automation_update, #1271), is folded the same way first, so its fields are kept; a field the branches give different schemas takes any of them. It reports whether it changed anything.

func OffersUltra added in v0.1.733

func OffersUltra(model string) bool

OffersUltra reports whether Codex offers its Ultra on the model, by the id a vendor serves it under: openai/gpt-6.1-sol on a relay, a dated snapshot.

func OnAccountIDs added in v0.1.399

func OnAccountIDs() []string

OnAccountIDs are the user's own providers saved on a subscription's id, which hide that subscription once it is signed in (All lists the one saved): made before the id was a subscription's, as a WorkBuddy key was before WorkBuddy's plan was one. MoveOffAccountIDs moves them.

func OnPlugins added in v0.1.506

func OnPlugins() []string

OnPlugins are the built-ins moved onto their plugins.

func OnRenewed added in v0.1.289

func OnRenewed(f func(agent, user string))

OnRenewed has f told when an account's usage windows were started again (a Codex reset spent), or a reading of them (Allowances) finds one it was full in full no more, so what sat out waiting for them can come back; agent is the one its usage is read under (Account.UsageAgent). And, as agent "" and the key's KeyAllowanceID, when a reading of a key's own windows finds one it was full in full no more: its limit raised in its panel, or its usage reset.

func OnServedMoved added in v0.1.1169

func OnServedMoved(f func())

OnServedMoved sets what is told when a provider's requests are answered by another of its accounts or keys than the one that answered before, or when the user signs an agent in to another account (SwitchLogin): the menu bar following the account in use reads it again then, rather than minutes later (#1516). It is called after NoteServed lets go of its lock and must not block; nil tells nothing.

func OnSubscriptionUsage added in v0.1.247

func OnSubscriptionUsage(f func())

OnSubscriptionUsage sets what is told when a refresh has landed, for what shows a stale copy meanwhile (the menu bar's text) to read the new one; nil tells nothing. It is held atomically: a refresh runs in the background and may be under way while it is set (#1023).

func OnlyPicks added in v0.1.1225

func OnlyPicks(p Provider) bool

OnlyPicks is whether p, as providers.json keeps it, is a subscription's model picks and settings alone, with no endpoint or key of its own: it is signed in to, never given a key.

func OpenCodeClient added in v0.1.615

func OpenCodeClient(h http.Header, session string)

OpenCodeClient makes a request to OpenCode's gateway (Zen or Go) carry what OpenCode itself sends there (packages/core/src/session/ model-request.ts): its User-Agent, the session in x-opencode-session and x-opencode-session-id, the turn in x-opencode-request, and x-opencode-client and x-opencode-project. OpenCode 1.19.0 sends Zen no x-session-affinity or X-Session-Id (captured from the real client), and since mid-October 2026 Zen's free tier answers 403 FreeTierError to a request carrying x-session-affinity, so neither goes. Zen's free models are served to no one else ("OpenCode's free tier can only be used from within OpenCode"), and Zen reads the session id as OpenCode lays one out (openCodeSession). session names the conversation, whose turns keep one session id, which Zen routes and caches by.

func OpenCodeFreeURL added in v0.1.1243

func OpenCodeFreeURL(u string) string

OpenCodeFreeURL is where a request to Zen's free tier goes, given the URL it would go to at Zen (https://opencode.ai/zen/v1/…, or under the root for Messages): the same path under the inference API's root, which models.dev gives OpenCode as Zen's URL since October 2026 and OpenCode 1.19.0 asks. Since mid-October 2026 Zen answers a free model at /zen/v1 with 403 FreeTierError even when the request is OpenCode's own, word for word, and the same request at /inference/v1 with 200. Any other URL, Go's (/zen/go) among them, is u.

func OpenCodeSession added in v0.1.1258

func OpenCodeSession(h http.Header, u string)

OpenCodeSession names a session on a request to OpenCode's gateway that names none yet: since September 2026 it answers every request without x-opencode-session 400 "Request is missing x-opencode-session and cannot be routed efficiently" (luci on Discord). A call that is no conversation's turn — a model list, a System One decision, a key check — gets a session of its own, as OpenCode gives its own stateless calls one (packages/core/src/generate.ts: "Gateways require session attribution even for a stateless call"). A turn's is named before this, by OpenCodeClient, and stays; so does one the user set on the provider. Sign calls it, so every signed request has it.

func OpenCodeURL added in v0.1.1258

func OpenCodeURL(u string) bool

OpenCodeURL says whether u is at OpenCode's gateway (Zen, Go or the inference API): opencode.ai or a name under it, whatever port the URL gives. What goes there is judged by the URL it goes to, not by the provider's first base (IsOpenCode), so a custom provider whose URL names a port, or one with only some of its endpoints there, is asked as OpenCode asks too.

func OpenReadOnly added in v0.1.92

func OpenReadOnly(path string) (*sql.DB, error)

OpenReadOnly opens another app's SQLite database without writing to it.

func OutputWithin added in v0.1.1144

func OutputWithin(window, output int) int

OutputWithin is a reply limit as it is published beside a window: kept within it. models.dev lists some models' output above the window their vendor's own list gives (Grok's grok-4.7: 500000 against the 256000 its backend says, #1438; deepseek-chat's 384000 against 128000, #338), and a client that reads both sizes its replies past what the window holds. An unknown window or output is left as it is. Every place that hands out the pair uses it — the agents' files, the gateway's model lists, the GUI and the CLI — while a request is still lowered only to the model's own limit (Entry.Output, withMaxOutput).

func OutputsOf added in v0.1.876

func OutputsOf(providerID string) map[string]int

OutputsOf is the reply limits the user set on a provider's models, by model id, "*" for all of them: what its editor's Max output shows.

func OwnFast added in v0.1.1191

func OwnFast(p Provider, model string) bool

OwnFast reports whether model has a fast mode only as the user's own provider may serve it (#1615): a GPT model on a provider they added by its address, on an OpenAI API, which magpie can't tell serves priority and asks for it all the same when the user switches it fast. Not where CanFast knows the vendor's (OpenAI's own API).

func OwnModelsHidden added in v0.1.1198

func OwnModelsHidden(agent string) bool

OwnModelsHidden reports whether agent's pickers leave out the models it reaches on its own, offering magpie's alone (#1642).

func ParseCap added in v0.1.809

func ParseCap(s string) (int, error)

ParseCap reads a cap as the CLI takes it: "70", "70%", or off (none, 0, -) for no cap.

func ParseDay added in v0.1.570

func ParseDay(s string) (string, bool)

ParseDay reads a day of the week, "mon" or "Monday", as Weekdays has it.

func ParseDays added in v0.1.570

func ParseDays(v string) ([]string, error)

ParseDays reads days of the week: "mon-fri", "sat,sun", "mon,wed-fri"; a range may run past Sunday (fri-mon).

func ParseLimit added in v0.1.1009

func ParseLimit(s string) (*int, error)

ParseLimit reads a limit as the CLI takes it: a whole number, 0 or off for no limit, default for the provider's (nil).

func ParseRefreshEvery added in v0.1.1234

func ParseRefreshEvery(s string) (time.Duration, error)

ParseRefreshEvery reads a RefreshEvery as typed: a Go duration ("30m", "6h") or a number of days ("1d"); "", "off", "never" or "0" for none.

func ParseTokens added in v0.1.136

func ParseTokens(v string) (int, error)

ParseTokens reads 200000, 200k, 1.5m.

func ParseVision added in v0.1.1360

func ParseVision(v string) (*bool, error)

ParseVision is a typed vision answer: true or false, nil for auto.

func PartnerCountsSent added in v0.1.1126

func PartnerCountsSent(now time.Time)

PartnerCountsSent forgets the days that were sent: those before now's.

func PartnerNoticed added in v0.1.1126

func PartnerNoticed(id string) bool

PartnerNoticed reports whether the user has been shown the partner id.

func PastePluginCallback added in v0.1.1091

func PastePluginCallback(ctx context.Context, page, raw string) (next string, err error)

PastePluginCallback is pluginCallback for the command line, which runs a plugin's sign-in itself: page is the address the sign-in opened.

func Path

func Path() string

Path is the file the user's providers live in.

func PatternMatches added in v0.1.826

func PatternMatches(pattern, id string) bool

PatternMatches reports whether a pattern matches a "provider/model" id.

func PausedOut added in v0.1.1155

func PausedOut(g Group, ms []Member, agent, folder string, at time.Time) (kept []Member, paused []Paused)

PausedOut leaves out of ms the models a pause rule holds for now, for a request from agent working in folder ("" when it didn't say, or wasn't read: see PausesByFolder): the group's own, or those of a group in it on the way to them. A rule naming a group in the group pauses every model of it.

func PausesByFolder added in v0.1.1191

func PausesByFolder(g Group, ms []Member) bool

PausesByFolder reports whether a pause rule of g, or of a group in it on the way to one of ms, holds by folder: the request's folder is then read before the pauses are looked at.

func PickGroup added in v0.1.1272

func PickGroup(id, pick string) error

PickGroup sends every request to a Manual group of the user's to its member pick from the next request on (#317), as its card's radios do, from wherever the user switches it: the tray panel (#2489) too. Nothing else of the group changes, and only a Manual group can be switched so.

func PickedModels added in v0.1.1130

func PickedModels(agent string) (map[string]bool, bool)

PickedModels are the only entries agent's lists show, by id (a found group by the id it is listed by now, PublicRef), and whether it is shown only those (#1337): a model not among them, one that came after the user switched to it among them, is not shown.

func PlanTerm added in v0.1.209

func PlanTerm(until *time.Time, renew string) string

PlanTerm says when a plan's paid time ends, "renews Oct 18", "expires Oct 18" or "until Oct 18" when the vendor doesn't say which; "" when it isn't known.

func PluginAPIKey added in v0.1.479

func PluginAPIKey(ctx context.Context, id string, method int, inputs map[string]string, key string) (string, error)

PluginAPIKey signs in to a plugin's provider with a key, as its "api" method does, beside the accounts signed in already; it gives the provider's magpie id.

func PluginCLIMissing added in v0.1.1241

func PluginCLIMissing(id string) string

PluginCLIMissing is the name of the vendor CLI a plugin's sign-in runs through and this machine lacks (Grok Build for Grok's), "" when there is none to install. The command line's sign-in installs it first, as StartPluginSignIn does; without it, `magpie plugin login grok` in Docker said "install Grok Build first: curl … | bash", which the image has no curl to run (#2223).

func PluginCheckinOn added in v0.1.1085

func PluginCheckinOn(s settings.Settings, id string) bool

PluginCheckinOn says whether a plugin provider's accounts are checked in each day: as the user set it for the provider, else as the built-in check-in of its vendor is set, which the plugin took over.

func PluginID added in v0.1.479

func PluginID(id string) string

PluginID is the id magpie gives the provider OpenCode calls id: the same, unless a preset or a built-in subscription has it (google, openai, anthropic), or a provider of the user's own made before the plugin was installed (zenmux, #867), or "auto" or "group", which start the ids of routing groups, when it is id-plugin — but for a built-in moved onto the plugin, whose id the plugin has now.

func PluginIcon added in v0.1.553

func PluginIcon(pp plugin.Provider) string

PluginIcon is the icon a plugin's provider shows: the picture its plugin gives it (the auth hook's icon, or package.json's magpie.icon), kept as a picture given by hand is, else the one the plugin market gives it.

func PluginListError added in v0.1.1001

func PluginListError(pp plugin.Provider, key string) string

PluginListError is why the plugin couldn't list the account at key's models, "" when it did or kept the list it had: what it shows instead is its short defaults (Cursor's Auto alone).

func PluginOf added in v0.1.479

func PluginOf(id string) (plugin.Provider, bool)

PluginOf is the plugin provider magpie's provider id is, when it is one.

func PluginOwnIcon added in v0.1.1161

func PluginOwnIcon(said string) string

PluginOwnIcon is the Icon value of a picture a plugin gave (a data:image URI or an https URL), "" while there is none to show: an agent a plugin adds shows it as a provider's does.

func PluginPastesCallback added in v0.1.1091

func PluginPastesCallback(id, page string) bool

PluginPastesCallback says whether a plugin's sign-in that opened page can be finished from the address its browser ends on.

func PluginRouting added in v0.1.1257

func PluginRouting(routing string) bool

PluginRouting says whether routing is one a plugin serves, "<plugin>/<name>" (a JS gateway plugin's strategies). providers.json keeps one as saved, served now or not: one no plugin serves is tried in its listed order.

func PluginServes added in v0.1.1282

func PluginServes(id string) bool

PluginServes is whether the built-in id's subscription is its plugin's to serve, and magpie's built-in code serves none of it: moved onto its plugin, or retired.

func PluginSignedIn added in v0.1.1098

func PluginSignedIn(saved plugin.Saved) string

PluginSignedIn finishes a sign-in to a plugin's provider that magpie doesn't follow, a key or the command line's own, once the plugin has saved the account: as for one it follows (pluginDone), the account's lapsed mark goes and, removed from magpie, it comes back. It gives the provider's magpie id.

func PluginTiers added in v0.1.1269

func PluginTiers(p Provider, model string) []string

PluginTiers are the service tiers p's plugin says its vendor serves model at (m.serviceTiers, #2514): none for a provider not a plugin's, or a model it doesn't list.

func PriceKey added in v0.1.504

func PriceKey(pid, model string) (string, bool)

PriceKey is the key a price for pid's model is stored at, and whether the provider naming that key is still there at all.

The spelling that was given comes first, because a price outlives the provider it was set for and nothing rewrites the key when that provider goes: "b/vendor/m" can still be where a price is held while a provider of some other id answers to "b" as its display name. Resolving that name first would take the second provider's price away instead — none is stored under it, so nothing would change, the caller would be told it had, and the price the user meant would stay in the file to be counted at. Only where nothing is stored under the spelling is the provider looked for, by the id it has or the one it was renamed from: that is where SetModelPrice keeps a price set through a display name, and the same resolution EffectivePrice reads it back under.

func PriceRateOK added in v0.1.901

func PriceRateOK(r float64) string

PriceRateOK says what is wrong with a provider's price rate, "" when nothing: from 0 (none) to 1000, in steps of 0.001.

func PricedName added in v0.1.418

func PricedName(model string) string

PricedName is the catalog ID used for a list-price estimate. Prefer a directly listed model before falling back to a documented alias.

func PricedNameFor added in v0.1.1134

func PricedNameFor(providerID, model string) string

PricedNameFor is PricedName for a call to that provider: a Kimi Code membership's k3 is priced as the API's kimi-k3 (kimiCodeAPI).

func ProbeClaudeVia added in v0.1.551

func ProbeClaudeVia(f func(ctx context.Context, configDir, model string) error)

ProbeClaudeVia sets how a Claude account's test runs Claude Code.

func ProbeTranslatedVia added in v0.1.1158

func ProbeTranslatedVia(f func(ctx context.Context, p Provider, proto Protocol, model string) (int, error))

ProbeTranslatedVia sets how a model only the gateway can ask is tested.

func ProxyOf added in v0.1.418

func ProxyOf(id string) string

ProxyOf is the own proxy of the provider or signed-in account with id, "" when it follows the global one.

func ProxyOfLogin added in v0.1.427

func ProxyOfLogin(id, user string) string

ProxyOfLogin is the proxy requests made on behalf of the account user of the subscription id go through (gakki: one Codex account through one proxy, another through another): the account's own, or else the subscription's (ProxyOf); "" follows the global one.

func PublicRef added in v0.1.1294

func PublicRef(ref string) string

PublicRef is the id agents are given for ref: a found group's group/auto-<slug> as its auto/<model> (Group.Ref), its effort and [1m] mark kept; any other ref as it is, a found group magpie has none of now too.

func QuietAccount added in v0.1.204

func QuietAccount(id string) error

QuietAccount stops reminding the user of an account they removed: its "Add it back" line goes, and it is offered only from the Add sheet.

func QuotaHistoryData added in v0.1.722

func QuotaHistoryData() []byte

QuotaHistoryData is this computer's history as kept, for the usage sync to share.

func QuotaHistorySince added in v0.1.722

func QuotaHistorySince(days string, now time.Time) time.Time

QuotaHistorySince is the start of a range days long (as a query gives it) to now: all that is kept when not a number of days.

func ReadAllCards added in v0.1.1078

func ReadAllCards(ctx context.Context)

ReadAllCards has every card read again, the page's Refresh asked by another magpie whose card of this one's said nothing was read yet.

func Reasonless added in v0.1.1231

func Reasonless(pid, model string) bool

Reasonless reports whether the user said pid's model takes no reasoning ask (SetModelReasonless).

func RefreshUsage added in v0.1.935

func RefreshUsage(ctx context.Context, provider, user string)

RefreshUsage reads the card of provider (of account user, "" for every account it has) again, whether a subscription's, a plan's or a key's balance, and keeps it with the others, which aren't asked. The next Quotas has it.

func RemoveKey added in v0.1.14

func RemoveKey(id, keyRef string) error

RemoveKey forgets a key. The last key in use stays: turn another on first.

func RemoveKeys added in v0.1.1029

func RemoveKeys(id string, refs []string) (removed int, err error)

RemoveKeys forgets several keys at once (361 on Discord: hundreds of keys, some dead): those named that it has. The first key, when it is among them, gives its place to the next one on that stays. One key in use always stays: removing every key in use is refused.

func RemovePlugin added in v0.1.538

func RemovePlugin(ctx context.Context, name string) error

RemovePlugin removes the plugin named and sets aside the model picks of its providers it leaves in providers.json (plugin_left.go). A built-in moved onto it isn't moved back, as the built-in is going: it is MoveRemoved, its accounts kept with the plugin's sign-ins for when the plugin is installed again.

func RemoveSearchAPI added in v0.1.587

func RemoveSearchAPI(vendor string) error

RemoveSearchAPI takes the vendor's search API away.

func RemovedGroups added in v0.1.92

func RemovedGroups() []string

RemovedGroups are the found groups the user removed, whether or not magpie finds them now: each is a record in providers.json ({"id", "hidden": true}) that keeps it removed when two providers serve its model again.

func Rename added in v0.1.125

func Rename(from, to string) error

Rename gives a provider another id, the one its models are picked by (<id>/<model>). What magpie keeps that names it by id follows: the routing groups it is in and their rules and classifiers, the other providers' fallbacks, which agents are shown it, and its StepFun sign-in. The old id stays with it (Was), so an agent still running on a config that names it the old way reaches it, and its usage so far is counted with it; the agents' own files are the agent package's to rewrite (agent.RenameProvider). A signed-in account keeps the id of its agent.

func RenameGroup added in v0.1.105

func RenameGroup(from, to string) error

RenameGroup gives a group another id, the one agents pick it by (group/<id>). A group magpie found becomes the user's under the new id, the found one kept removed so it doesn't come back beside it. The groups that have it in them, and their rules, name it by the new id.

func RenameKey added in v0.1.14

func RenameKey(id, keyRef, name string) error

RenameKey names one of a provider's keys, "Personal", "Team".

func Renamed added in v0.1.125

func Renamed() map[string]string

Renamed maps the ids providers had to the ones they have now.

func RenamedRef added in v0.1.125

func RenamedRef(ref string) string

RenamedRef is ref with the provider it names by an id the provider had named by the id it has now.

func ReplaceKey added in v0.1.1220

func ReplaceKey(id, keyRef, key string) (was, now string, err error)

ReplaceKey puts a new value in place of one of a provider's keys (#1869: a key rotated at the vendor or the relay). The key keeps its name, its place, its protocol and weight, whether it is on, and what was set for it by its fingerprint: the models it serves, its proxy, its concurrency. It returns the key's fingerprint before and after; the same value pasted again changes nothing and returns the same one twice.

func RepoIcons added in v0.1.1147

func RepoIcons(said []string, wait time.Duration) []string

RepoIcons are the Icon values of the pictures plugins not installed yet give in their package.json (repositories tagged magpie-plugin), checked and kept as an installed plugin's are: "" where there is none to show. An https picture not fetched before is waited for up to wait, so the list's first answer has it (yetone: 非官方插件显示不出来 logo); one slower than that shows the next time the list is asked.

func ResetClock added in v0.1.211

func ResetClock(at, now time.Time) string

ResetClock is when a window starts again, on the clock: "14:30" today, "tomorrow 09:00", "Wed 14:30" within the week, else "Oct 3 14:30".

func ResetModelSpec added in v0.1.1360

func ResetModelSpec(ref string) ([]string, error)

ResetModelSpec takes every spec the user gave a provider's model away — its window, reply limit, vision answer and levels — leaving it to the vendor's list and models.dev again. "provider/*" takes away the window and reply limit given every model of the provider. It reports what it took away, by part ("context", "output", "vision", "reasoning"). A provider that has gone still has its settings' parts taken away, under the key as typed: a spec outlives the provider it was set for, and `magpie model specs` still lists it.

func RestartCodexDaemon added in v0.1.368

func RestartCodexDaemon(ctx context.Context) error

RestartCodexDaemon has Codex restart its app-server, which reads the sign-in again: `codex app-server daemon restart`, run with the codex CLI magpie finds and the Codex home it signs Codex in through. Codex 0.162's sessions attached to it reconnect to the new one, a turn running is let finish first (for up to a minute); an older Codex's are ended.

func Restore added in v0.1.28

func Restore(ps []Provider) (added, replaced int, err error)

Restore puts providers from a backup in. Each replaces the one here with its id; one that came without keys keeps the keys already here, and one without an access key or balance token keeps those (KeepSecrets). It returns how many were new and how many replaced one here.

func RestoreGroups added in v0.1.76

func RestoreGroups(gs []Group) error

RestoreGroups puts groups from a backup in, each replacing the one here with its id.

func RestoreSearchAPIs added in v0.1.587

func RestoreSearchAPIs(as []SearchAPI) error

RestoreSearchAPIs puts search APIs from a backup in, each replacing the one of its vendor here; one that came without a key keeps the key here. They are asked in the backup's order, switched on or off as they were there (#2286), and one only here is asked after them.

func Retire added in v0.1.1148

func Retire(pid, model string)

Retire notes that provider pid's vendor said model is retired: it leaves the lists, and the agents' lists are written again.

func Retired added in v0.1.1148

func Retired(pid, model string) bool

Retired says whether provider pid's vendor said model is retired, within retiredFor.

func RetryCodexKeychain added in v0.1.1261

func RetryCodexKeychain() error

RetryCodexKeychain is Try again beside a sign-in the keychain didn't give (#2367): Codex's item is read once, now, past a refusal or a prompt with no answer kept (a fresh read), and what it gets is kept in their place. It gives what that read gave: errKeychainWaiting while the prompt is up (joining it, never a second one), its answer kept when it comes.

func RetryOneAuth added in v0.1.1211

func RetryOneAuth(p Provider, req *http.Request, res *http.Response, do func(*http.Request) (*http.Response, error)) (*http.Response, error)

RetryOneAuth hands on res, the answer to req, which p signed for its Anthropic API; or, when the vendor refused it for carrying the key in both x-api-key and Authorization (catalog.BothAuthRefused), the answer to req asked again with each alone, x-api-key first, and remembers for p the one it took (LearnAuthHeader). do sends a request as req was sent.

func RetryZhipuCoding added in v0.1.1224

func RetryZhipuCoding(p Provider, req *http.Request, res *http.Response, do func(*http.Request) (*http.Response, error)) (*http.Response, error)

RetryZhipuCoding hands on res, the answer to req; or, when req went to Zhipu's or Z.ai's pay-as-you-go OpenAI API and was refused for want of a balance (1113), the answer to req asked again at the GLM Coding Plan's endpoint when that one serves it — remembering it for p (LearnZhipuCoding) — else res with what to change added to its message. do sends a request as req was sent.

func RevokedAccount added in v0.1.1213

func RevokedAccount(a *Account) bool

RevokedAccount says the account's revoked sign-in is marked here: one of the built-in subscriptions that keep no mark of their own.

func RevokedSignIn added in v0.1.1213

func RevokedSignIn(a *Account, req *http.Request) (why string, ok bool)

RevokedSignIn is why the request req, signed for account a, isn't sent: its vendor revoked the credential it carries. ok is false otherwise.

func Routings added in v0.1.1247

func Routings() ([]string, error)

Routings is the routing of each provider and group providers.json sets one for, read from the file alone: for what asks often (the rotation plugin's InUse), without building the catalog and reading every sign-in.

func RuleWords added in v0.1.136

func RuleWords(line string) []string

RuleWords splits a typed line into its words, a "quoted" part in one: intent="a quick question".

func SIWCForTest added in v0.1.1058

func SIWCForTest(issuer, api string) func()

SIWCForTest points the sign-in and the API at test servers.

func SamePriceIn added in v0.1.1258

func SamePriceIn(s settings.Settings, providerID, model string) (catalog.Price, bool)

SamePriceIn is the maker's list price of the model the user said providerID's model is the same as (settings' ModelSameAs, #2344): for an id of the provider's own that no list prices, as WorkBuddy's kimi-k3-1 or a plugin's qfmodel. It is the last place a price is looked for, after the user's own, the provider's list and the model's maker's by its own id, and is never another provider's tariff. MakerPrice reads the id as any vendor spells it, with its prefix ("moonshotai/kimi-k3") or not.

func SameRef added in v0.1.1294

func SameRef(a, b string) bool

SameRef reports whether a and b name the same model or group, a found group by either of its ids.

func Save

func Save(p Provider) error

Save adds or replaces a provider.

func SaveGroup added in v0.1.38

func SaveGroup(g Group) error

SaveGroup adds or replaces a group of the user's. Changing one magpie found makes it the user's.

func SaveStepFunPaste added in v0.1.389

func SaveStepFunPaste(ctx context.Context, id, site, text string) error

SaveStepFunPaste keeps the session the user pasted for the provider id, whose platform is site: what the bookmarklet copied, or the Oasis-Token cookie as the browser's developer tools show it (the access token, three dots, the refresh one).

func SaveStepFunSession added in v0.1.389

func SaveStepFunSession(ctx context.Context, id, site, access, refresh, webID string) error

SaveStepFunSession keeps the session the sign-in page ended in, once the platform has taken it: a page that isn't signed in yet has an anonymous one, which is refused here. It is the provider id's alone; site is the provider's platform.

func SawClient added in v0.1.1158

func SawClient(client string, h http.Header)

SawClient notes the headers the gateway let go on as client sent them, for a test asked as client to ask with.

func SawCodexClient added in v0.1.441

func SawCodexClient(h http.Header)

SawCodexClient notes the version a Codex client's request says it is — its `version` header, else the one in its User-Agent (codex_cli_rs/0.159.0, Codex Desktop/0.159.0) — when the request is Codex's (it names an originator, or its User-Agent is codex_…).

func SearchAPIsSet added in v0.1.1253

func SearchAPIsSet() (int, error)

SearchAPIsSet counts the search APIs that can be asked; a providers.json that can't be read is an error, not none.

func SeatNameOf added in v0.1.1172

func SeatNameOf(id, user string) string

SeatNameOf is the name of the key plan the account user of the subscription id was found to stand in for, "" when none: the plan's provider as it is named now, and its key's name when it has several.

func SecretHeader added in v0.1.1214

func SecretHeader(name string) bool

SecretHeader reports whether a header or an environment variable by that name looks like it holds a key: what a backup without keys leaves empty.

func SentNameIn added in v0.1.560

func SentNameIn(wires map[string]string, pid, model, effort string) string

SentNameIn is the name a call on the provider's model goes out under at that effort: the name the vendor would be asked for now, which is the one magpie knows the model by unless the user gave one. It is UpstreamNameAs for the id that call asks for, which is not the model magpie knows everywhere: on an Antigravity account it is the variant of it that effort picks, so a name given for the provider asks for each level by its own id, and a ledger reading a record back reads the vendor's reply against the name that really went out — the same one the gateway sent — rather than against the family it is one level of.

The effort is the one the gateway sent, already fitted to the model's own levels, which is what a record keeps of it, so a level of the model's own is one of its variants and goes out as that one. An effort that is no level of the family names the same id the gateway asked for all the same: the level of the family's own nearest (AntigravitySentID), which is where the envelope went out.

It is SentNameOnIn for the caller that has nothing but the id — a record in the ledger, which keeps the id the call went out on and nothing else. A provider that is an account is built with that account's own id as its own (googleProvider and the rest of the account providers), so the id says which account it was, and a provider of the user's own is no account's whatever its id is. A record's provider need not even be signed in now, which is why nothing here goes looking for the account behind the id: the id a call went out on is all a record has and all it can be read by.

func SentNameOnIn added in v0.1.560

func SentNameOnIn(wires map[string]string, pid, account, model, effort string) string

SentNameOnIn is SentNameIn for a caller holding the provider itself, and so the account behind it: the call goes out on that account, and it is the account the id the effort picks is a question about. A provider's id is that account's own id today (googleProvider and the rest of the account providers build each one with it), so passing the id for the account reads the same — but the two are one id by construction rather than by rule, and a provider of the user's own has no account at all whatever its id is. So the route, which is holding the provider, asks about the account and lets the gateway's dispatch (codeAssistID, on the same agent) be the one rule.

func ServeGroups added in v0.1.1248

func ServeGroups() (remove func())

ServeGroups serves the user's own groups until remove: plugins/groups calls it while it is on.

func ServedID added in v0.1.664

func ServedID(p Provider) string

ServedID names who answers for p, as its Quota is found by: an account by its agent and user ("codex@a@b.c"), a key by its provider and the key's id ("deepseek#k1a2b3c"), else the provider.

func ServedSignIn added in v0.1.1213

func ServedSignIn(a *Account)

ServedSignIn notes a request account a's vendor served: a mark of a revoked sign-in it has is gone, as the account was signed in again or its sign-in refreshed.

func ServesModel added in v0.1.560

func ServesModel(p Provider, model string) bool

ServesModel is whether the provider really serves model, listed or exposed: the question SetUpstreamName asks before it keeps a name for one, and the same one, since a name given for a model the provider does not serve is a request magpie would never send it. It is the answer a caller told to take a name off needs as well: a model the provider has nothing like is not asked for by any name, so reporting which one is in force for it would say magpie asks for a model it does not know.

func SetAccountCap added in v0.1.809

func SetAccountCap(id, ref string, cap int) error

SetAccountCap caps the account ref of the subscription id at cap percent of its windows; 0 lifts the cap.

func SetAccountConcurrency added in v0.1.1009

func SetAccountConcurrency(id, ref string, limit *int) error

SetAccountConcurrency gives the account or key ref of the provider id its own limit on requests at once, 0 for none; nil gives it the provider's again.

func SetAccountModels added in v0.1.610

func SetAccountModels(id, ref string, models []string) error

SetAccountModels gives the account or key ref of the provider id the models it alone serves; none gives it every model the provider has again.

func SetAccountName added in v0.1.1172

func SetAccountName(id, ref, name string) error

SetAccountName names the account ref of the subscription id; "" takes the name off.

func SetAccountOrder added in v0.1.605

func SetAccountOrder(id string, order []string) error

SetAccountOrder changes the order used by routing, not just its presentation. The first enabled account becomes first through the same switch used by Make first, unless the agent is kept signed in to another (KeepLoginAs). Disabled accounts can be moved, but never silently enabled by a drag.

func SetAffinity added in v0.1.38

func SetAffinity(id, affinity string) error

SetAffinity changes how long a provider's conversations stay with the key or account that answered them.

func SetAgentEffort added in v0.1.1084

func SetAgentEffort(agent, level string) error

SetAgentEffort asks agent's requests for level, one of MemberEfforts; "" asks for none, leaving each request's own.

func SetAutoGroups added in v0.1.603

func SetAutoGroups(on bool) error

SetAutoGroups turns the groups magpie finds on its own on or off, all of them at once (蓝猫 on Discord: they could only be removed one by one). Off, none is listed or served; the groups the user made or changed, one found included, stay, and so do the records of those removed, so that on again brings back the found groups as they were. A found group one of the user's has in it, or classifies with, keeps them on until it is taken out, as DeleteGroup keeps it: the user's group would lose it unsaid.

func SetAutoInclude added in v0.1.1234

func SetAutoInclude(id string, rules []string) ([]string, error)

SetAutoInclude sets the provider's rules, and takes the models its list has now that they match into its picks; none clears them. It answers the models taken.

func SetBareModelIDs added in v0.1.1226

func SetBareModelIDs(on bool) error

SetBareModelIDs turns settings.BareModelIDs on or off. The list is built for each request, so the next one has the bare ids, or goes without them; no agent's file names a model by one, so none is written again.

func SetBody added in v0.1.1400

func SetBody(req *http.Request, b []byte)

SetBody makes b req's body, as NewRequest would from a bytes.Reader, read again by GetBody for a retry or a redirect until LetGo.

func SetCodexAgentsV1 added in v0.1.715

func SetCodexAgentsV1(on bool) error

SetCodexAgentsV1 turns settings.CodexAgentsV1 on or off, and has Codex's lists written and asked for again.

func SetCodexAsyncCompact added in v0.1.1277

func SetCodexAsyncCompact(on bool, percent int) error

SetCodexAsyncCompact sets Codex's background compaction (settings.CodexAsyncCompact) and the share of a model's window it starts at, 1–100 or 0 for Codex's own, and has Codex's config written again.

func SetCodexAutoReset added in v0.1.507

func SetCodexAutoReset(user string, on bool) error

SetCodexAutoReset turns that on or off for user, at both times.

func SetCodexAutoResetCase added in v0.1.1234

func SetCodexAutoResetCase(user, when string, on bool) error

SetCodexAutoResetCase turns one of the two times (ResetCaseWeek or ResetCaseExpiring) on or off for user, the other kept as it is.

func SetCodexAutoReview added in v0.1.1062

func SetCodexAutoReview(id string) error

SetCodexAutoReview sets settings.CodexAutoReview, the model Codex's auto-review runs on ("" for Codex's own pick), and has Codex's lists written and asked for again.

func SetCodexCredits added in v0.1.1080

func SetCodexCredits(user string, on bool) error

SetCodexCredits turns that on or off for user.

func SetCodexSubagentModel added in v0.1.1142

func SetCodexSubagentModel(id string) error

SetCodexSubagentModel puts Codex's subagents on id, a model or routing group of magpie's (provider/model, group/<id>); "" leaves them on the model their lead asks for. One magpie doesn't serve now is kept all the same — a backup or profile put back on a computer whose providers differ, or an account signed in again later — and the gateway leaves subagents on the model asked for until it is served, saying why in the route trace. One of Codex's own bare names is refused: it names no model of magpie's to put the request on.

func SetCodexWarmAt added in v0.1.1080

func SetCodexWarmAt(user, at string) error

SetCodexWarmAt gives user a time of day of its own ("06:00"), none ("off"), or, "", has it follow settings' CodexWarmAts again.

func SetCompactAt added in v0.1.979

func SetCompactAt(n int) error

SetCompactAt has every model without a threshold of its own compacted at n tokens, Full window turned off; 0 is the working window again (settings.WorkingWindow).

func SetContext added in v0.1.532

func SetContext(p Provider, model string, n int) error

SetContext is how long a request one of a provider's models takes, in tokens, over what the vendor's list and models.dev say; 0 takes the user's away, which DropContext does, and "*" is every model of that provider. As with a reply limit, setting one has to name a model the provider serves, and a removal may name one it no longer does.

This is the provider's own Contexts, kept as the one value both the gateway advertises and the routing rules read — a context is a routing input, not only a number agents are shown: at 95% of a held member's window a request moves to a member that takes more (internal/gateway/rules.go). Saving it tells the agents (catalog.Touched), as for any change of the catalog: a window is a number they keep in files of their own — Pi's contextWindow, OpenCode's limit — and read at start-up, so a session already running keeps the window it began with while the gateway's own /models is right at once.

func SetDesktopSubagentEffort added in v0.1.1243

func SetDesktopSubagentEffort(level string) error

SetDesktopSubagentEffort sets a level the gateway fits to the model each subagent reaches. It survives model changes; "" clears the pick.

func SetDesktopSubagentModel added in v0.1.1234

func SetDesktopSubagentModel(id string) error

SetDesktopSubagentModel puts Desktop's subagent turns on id, a model or routing group of magpie's (provider/model, group/<id>); "" leaves them on the model their lead asks for. One magpie doesn't serve now is kept all the same, as Codex's subagent model is, so a backup or profile put back on a computer whose providers differ still applies; the gateway leaves subagents on the model asked for until it is served. A bare name is refused: it names no model of magpie's.

func SetDisabledModels added in v0.1.1219

func SetDisabledModels(list []string) error

SetDisabledModels saves the disabled list whole.

func SetFastPick added in v0.1.1077

func SetFastPick(agent, id string, fast bool) error

SetFastPick sends agent's requests for the entry id fast, or not. Only a model with a fast mode magpie can ask for (CanFast) is switched on.

func SetFastTier added in v0.1.1270

func SetFastTier(agent, id, tier string) error

SetFastTier sends agent's requests for the entry id at tier: "" the usual speed, "priority" fast, "ultrafast" Ultrafast where the account offers it (CanUltra), priority where it doesn't.

func SetFullContext added in v0.1.836

func SetFullContext(on bool) error

SetFullContext turns settings.FullContext on or off: Codex and Claude Code are told a model's whole window, or the working one, again.

func SetGoogleProject added in v0.1.63

func SetGoogleProject(agent, user, project string) error

SetGoogleProject names the Google Cloud project an account's requests go to, "" to let Code Assist pick; Code Assist Standard and Enterprise need one.

func SetGroupOrder added in v0.1.843

func SetGroupOrder(ids []string) error

SetGroupOrder saves the order the routing groups are listed in, by id. Every id must be a group's, once; the ones left out follow those named, as they are now, and the whole order is kept, so a group made or found later goes after them all.

func SetHiddenModels added in v0.1.460

func SetHiddenModels(agent string, ids []string) error

SetHiddenModels takes these entries out of agent's lists, and puts back every other; none shows it every model its visibility gives it. The agents that keep the models in files of their own are told.

func SetKeepLogin added in v0.1.641

func SetKeepLogin(id string, keep bool) error

SetKeepLogin keeps Codex or Claude Code signed in to the account the user made first (Provider.KeepLogin), or lets magpie move it on again. Either way it is no longer kept on one of the user's choosing (KeepLoginAs): it is signed in to the first again.

func SetKeepLoginAs added in v0.1.672

func SetKeepLoginAs(id, user string) error

SetKeepLoginAs keeps Codex or Claude Code signed in to user, one of its saved accounts, and signs it in to it now; the order the gateway tries the accounts in stays as it was, the first still first.

func SetKeyOn added in v0.1.14

func SetKeyOn(id, keyRef string, on bool) error

SetKeyOn turns a key on or off. The last key that's on stays on.

func SetKeyProtocol added in v0.1.15

func SetKeyProtocol(id, keyRef string, proto Protocol) error

SetKeyProtocol says which one protocol a key works with; empty is any.

func SetKeyWeight added in v0.1.933

func SetKeyWeight(id, keyRef string, weight int) error

SetKeyWeight sets a key's share of the requests under Weighted routing; 0 takes it back to the default, 1.

func SetLoginOn added in v0.1.14

func SetLoginOn(agent, user string, on bool) error

SetLoginOn puts a saved account in use beside the agent's own, or takes it out. The account the agent is signed in to is always in use.

func SetModelAPI added in v0.1.663

func SetModelAPI(ref, api string) error

SetModelAPI says which one of a provider's APIs a model is asked on — chat, responses, anthropic or gemini — for a relay whose one key serves some of its models on one and others on another (01huadalang on Discord: 有的供应商 一个 api 里有很多模型但是不同协议); "" leaves it to the vendor's list and the URLs the provider has, as before. It must be an API the provider has a URL for: a preset's or a subscription's as well as a custom provider's, when it has more than one (01huadalang: OpenCode Go's deepseek-v4.1-flash answers on Responses too, and magpie asked it on chat alone).

func SetModelCompacts added in v0.1.979

func SetModelCompacts(providerID string, cs map[string]int) error

SetModelCompacts makes a provider's thresholds cs, by model id, "*" for all of them, as its editor's Compact at says: those it leaves out are taken away, and every one set or changed has to be a model the provider serves, as for a reply limit (SetModelOutputs); one sent back as it is for a model the provider no longer lists is kept, not refused (#3305). Codex's and Claude Code's lists are written again when anything changed.

func SetModelEfforts added in v0.1.137

func SetModelEfforts(ref string, efforts []string) error

SetModelEfforts keeps only these of a provider's model's reasoning levels in the lists magpie hands out; none, or all it has, offers them all again. They must be levels the model has — or, for a model whose levels aren't known, any of Levels, which it is given; none takes them away.

func SetModelImage added in v0.1.413

func SetModelImage(ref string, images *bool) error

SetModelImage says whether a provider's model takes images, in place of what its vendor's list says. nil gives that answer back.

func SetModelKind added in v0.1.1225

func SetModelKind(ref, kind string) error

SetModelKind says what a provider's model, spelt "provider/model", makes: KindImage, KindVideo, or "" to leave it to its vendor's list and name.

func SetModelLists added in v0.1.1133

func SetModelLists(ls map[string]ModelList) ([]string, error)

SetModelLists puts each agent's model list back as it was kept, exactly, and tells the agents that keep the models in files of their own once, as a pick made by hand does (catalog.Touched). A model of a provider renamed since is the same model by its new id. It returns the agents whose list changed, sorted.

func SetModelName added in v0.1.137

func SetModelName(ref, name string) error

SetModelName names a provider's model, spelled "provider/model"; an empty name gives it back its own. The agents that keep the models in files of their own are told (catalog.Touched), as for any other change of the catalog.

func SetModelOrder added in v0.1.952

func SetModelOrder(agent string, ids []string) error

SetModelOrder lists agent's models in this order, by entry id: the ones it names first, as it names them, then every other as before; none puts them back in magpie's own order. Only agent's lists follow it.

func SetModelOutput added in v0.1.532

func SetModelOutput(id string, n int) error

SetModelOutput is the most a reply of a provider's model may hold, in tokens, over what the vendor's list and models.dev say; 0 takes the user's away, which DropModelOutput does. The id is spelled "provider/model", or "provider/*" for every model of that provider; setting one has to name a model the provider serves, as one no lookup would ever match reads as set and is not. A removal may name a model that has since gone, or a provider that has: that is the entry left to be cleared.

The agents are told of it (catalog.Touched), as for any change of the catalog: a reply limit is a number they keep in files of their own — Pi's maxTokens, OpenCode's limit — and read at start-up, so one only the gateway knew would leave every agent a reply limit behind.

func SetModelOutputs added in v0.1.876

func SetModelOutputs(providerID string, outs map[string]int) error

SetModelOutputs makes a provider's reply limits outs, by model id, "*" for all of them, as its editor's Max output says (ARNO on Discord: a model's maxTokens was wrong, and only the context window could be set in the editor): those it leaves out are taken away, and every one set or changed has to be a model the provider serves, as for SetModelOutput. One the user set for a model the provider has since stopped listing, sent back as it is, is kept and not refused: the editor is given it (OutputsOf) and sends it again on every Save, so refusing it stopped each Save of that provider, whatever else changed, and the model may be listed again at the next refresh (#3305, LoKi). Taking it out of Max output clears it. Nothing is saved, nor the agents told, when nothing changed.

func SetModelPrefs added in v0.1.648

func SetModelPrefs(pid string, prefs map[string]ModelPref) error

SetModelPrefs makes the changes to a provider's models, by model id, as SetModelName, SetModelEfforts, SetModelImage, SetModelAPI and setModelSame do, and tells the agents once, after them all, rather than once a change. It stops at the first that fails, telling the agents of those made before it.

func SetModelPrice added in v0.1.504

func SetModelPrice(id string, p *catalog.Price) error

SetModelPrice is what a provider's model costs the user, in USD per million tokens, kept in settings' ModelPrices the way a name is. A nil price takes the user's away, leaving the model at what its provider lists and only then at its maker's on models.dev; a price of zero is not that, but a model served at no cost. A price no vendor could charge is refused, naming the part that is wrong.

Unlike the other model preferences this does not tell the agents. What a call costs is not what an agent picks a model by, and the model lists magpie keeps in the agents' own files are not its to rewrite over a number in a cost report.

func SetModelReasonless added in v0.1.1231

func SetModelReasonless(ref string, on bool) error

SetModelReasonless says whether a provider's model, spelt "provider/model", takes no reasoning ask, whatever its list says: on, it offers no levels (Efforts, the agents' lists, a group's) and the gateway sends it no reasoning field on any API — Chat's reasoning_effort, Responses' reasoning, Anthropic's thinking and output_config effort — as it does a model known not to think (yuexian7 on Discord: models.dev lists a model with reasoning, and the vendor answers reasoning_effort with 422 while the request without it works). Off gives it the levels it had again.

func SetModelSpec added in v0.1.1360

func SetModelSpec(ref string, c SpecChange) error

SetModelSpec makes the changes c says to a provider's model, spelt "provider/model", or "provider/*" for every model of that provider (the window and the reply limit only, as `magpie model context` and `output` take it). Every part is checked before anything is written, so a bad one writes nothing; the agents are told once, after them all.

func SetModels added in v0.1.1134

func SetModels(id string, models []string) error

SetModels gives the provider id the models the user picked for its agents; none gives them the vendor's list again.

func SetNativeCompaction added in v0.1.1243

func SetNativeCompaction(id string, on bool) error

SetNativeCompaction turns a provider's native compaction on or off (Provider.NativeCompaction). One whose wire can't carry it is refused turning it on.

func SetOff added in v0.1.346

func SetOff(id string, off bool) error

SetOff switches a provider off, or on again (see Provider.Off). Saving it brings the model lists written into agents' files up to date.

func SetOnlyPicked added in v0.1.1130

func SetOnlyPicked(agent string, on bool) error

SetOnlyPicked switches agent between being shown every model not taken out of its lists, a new one among them, and being shown only the ones picked for it (#1337). Either way the models it is shown now stay as they are: switched on, they are its picks; switched off, the ones listed for it and not picked are taken out, and a model that comes later is shown again.

func SetOrder added in v0.1.627

func SetOrder(ids []string) error

SetOrder saves the order the providers are listed and tried in, by id. Every id must be a provider's, once; the ones left out follow those named, as they are now, so a provider added later goes after them all.

func SetOwnModelsHidden added in v0.1.1198

func SetOwnModelsHidden(agent string, on bool) error

SetOwnModelsHidden switches agent's pickers between offering its own models beside magpie's and offering magpie's alone.

func SetPickedModels added in v0.1.1130

func SetPickedModels(agent string, ids []string) error

SetPickedModels makes these entries the only ones agent's lists show, for an agent shown only the models picked for it. A pick of an entry not listed for it now (its provider switched off for a while, a model its vendor dropped from the list) is kept, so it is shown again when it is back, as it was picked.

func SetPlainNames added in v0.1.516

func SetPlainNames(on bool) error

SetPlainNames has the agents' model lists name models by their names alone (see Labels), or with their providers' again, and the agents told.

func SetPluginOff added in v0.1.538

func SetPluginOff(_ context.Context, name string, off bool) error

SetPluginOff turns the plugin named off, or back on. A built-in moved onto it stays moved, off with it: nothing moves it back, as the built-in is going.

func SetQueue added in v0.1.1009

func SetQueue(id string, limit, wait int) error

SetQueue sets how many requests may wait for each of the provider's keys or accounts, and how long one waits, in seconds; 0 is no bound.

func SetQuotaResetAt added in v0.1.1230

func SetQuotaResetAt(id, at string) error

SetQuotaResetAt sets the time of day the provider's keys out of quota are back, when the vendor doesn't say: "" for none. Setting one lets go of QuotaRest, which it would stand over.

func SetQuotaRest added in v0.1.1214

func SetQuotaRest(id string, minutes int) error

SetQuotaRest sets how many minutes the provider's keys sit out of quota when the vendor doesn't say when they are back, 0 for the gateway's own.

func SetRPM added in v0.1.1119

func SetRPM(id string, n int) error

SetRPM sets how many requests a minute each of the provider's keys or accounts may send, 0 for no limit.

func SetRefreshEvery added in v0.1.1234

func SetRefreshEvery(id, every string) error

SetRefreshEvery sets how often the gateway fetches the provider's list by itself, as ParseRefreshEvery reads it; "off" for only when asked.

func SetRestCap added in v0.1.1230

func SetRestCap(id string, minutes int) error

SetRestCap sets the most, in minutes, the provider's keys and accounts sit out while they keep failing or being rate limited, 0 for the gateway's own, RestCapOff for no rest after an unknown failure.

func SetRouting added in v0.1.25

func SetRouting(id, routing string) error

SetRouting changes how a provider's requests spread over its keys or accounts.

func SetSearchAPI added in v0.1.587

func SetSearchAPI(a SearchAPI) error

SetSearchAPI adds a search API, last, or changes the one of its vendor where it is; a change with no key keeps the key it has, and one with no Pick the pick it has ("turns" puts the default back). One switched off stays off.

func SetSink added in v0.1.777

func SetSink(id string, sink bool) error

SetSink sends a provider's keys or accounts rate limited with quota left to the back of its order, or lets them keep their place (Provider.Sink).

func SetSuffixMode added in v0.1.595

func SetSuffixMode(mode string) error

SetSuffixMode has the agents' model lists name models as mode says (see Labels), and the agents told when it changes.

func SetSwitchOnly added in v0.1.1224

func SetSwitchOnly(id string, on bool) error

SetSwitchOnly has magpie only move Codex's own sign-in between its accounts (Provider.SwitchOnly), its requests never sent through the gateway for account failover, or lets failover go through it again.

func SetUpstreamName added in v0.1.560

func SetUpstreamName(ref, name string) error

SetUpstreamName is the name to send a provider for one of its models; an empty name takes the user's away and sends the one magpie knows. A name is only given for a model the provider really serves: a relay lists the model under the id magpie knows it by and asks for it under the vendor's own, and one it does not list is a request magpie would never send, so naming it is refused here, as a price and a limit are for the same id. A "*" stands for every model of the provider rather than for one, and a removal is exempt, so an entry left for a model that has since gone can still be taken away.

A provider magpie asks through an agent's own backend has no model field to put a name in — the request goes out carrying the id the agent knows — so a name given for one of its models would never be sent (asksOwnBackend).

The ref is taken as the provider it names, by its id now, and the name is kept under that id: a ref is as likely to be spelled with an id the provider had before a rename (Was) or with the name it is shown by, and every lookup of a wire name goes by the id the provider has (UpstreamName). A name under any other spelling of the provider is one no lookup will ever match — a name the provider is never asked for, and a removal that takes away nothing.

The key is checked here, where it is given, and not as the whole settings are written: a hand-edited key no lookup will ever match is a no-op of the user's own making, and must not keep every other setting from being saved.

Kept in settings, and saved without telling the agents, like a price: which model an agent picks, and what it is called, have not changed — only the name the request goes out under.

A removal goes to DropUpstreamName, which works off the key rather than off this provider, so that taking a name away is the same operation whether or not the provider it was given for is still there.

A blank name is a removal, and whether there was a name there to take away is DropUpstreamName's to say, not this one's: a caller with something of its own to say about a name that was not there — `magpie model wire -- reset`, which tells a mistyped id from a model already asked for by the name magpie knows it by — asks DropUpstreamName for the removal itself, the way `magpie model price --reset` asks DropModelPrice. A caller that only wants the model left as it is has nothing to tell the user either way, which is why a blank name is an error and not a second answer.

func SetUsageAlias added in v0.1.1358

func SetUsageAlias(from, to string) (changed bool, err error)

SetUsageAlias counts usage of the model from under the name to, or, with to "", under its own id again. Both are model ids as any vendor spells them, matched as the groups magpie finds match them (sameModel: a vendor's prefix, case, "_" or a snapshot date make no difference). It refuses an alias of a model to itself and one that would loop back to from through the others. changed is false when there was nothing to change.

func SetWindowCap added in v0.1.1134

func SetWindowCap(id, ref, window string, cap int) error

SetWindowCap sets the share of the window named window of the account ref of the subscription id: 1–99, 100 for no cap on that window whatever the account's cap, or 0 to have it follow the account's cap again.

func ShareGroup added in v0.1.1181

func ShareGroup(id string) (string, error)

ShareGroup is group id as text to paste into another magpie: its members as it names them, its patterns, routing, rules, classifier, effort, context, levels, fast and off members. A group holds no key or account of its own, only provider/model ids, so nothing secret goes with it; what is derived (the models its patterns match now, found, hidden, switched off) stays behind, and so do the rules that hold by a folder, in it or outside it: a folder is a path on the sharer's own machine, which names their projects and means nothing on another.

func ShowAccount added in v0.1.31

func ShowAccount(id string) error

ShowAccount brings back the signed-in account of an agent the user had removed from magpie.

func ShowGroup added in v0.1.38

func ShowGroup(id string) error

ShowGroup brings back a group magpie found that the user had removed.

func Shows added in v0.1.111

func Shows(names []string, e Entry) bool

Shows reports whether a visibility shows e.

func SignInExpired added in v0.1.1335

func SignInExpired(status int, body []byte) bool

SignInExpired says a reply is the vendor's word that the access token it was sent with has expired, for a refresh to mend.

func SignInMarked added in v0.1.1213

func SignInMarked(a *Account) bool

SignInMarked says account a is marked revoked: a request is asked of another account first where the gateway picks one alone (compaction).

func SignInRevoked added in v0.1.1213

func SignInRevoked(status int, body []byte) bool

SignInRevoked says a reply is the vendor's word that the sign-in it was sent with is revoked.

func SignOutStepFun added in v0.1.389

func SignOutStepFun(id string) error

SignOutStepFun forgets the provider's sign-in, and no other's.

func Slug

func Slug(name string) string

Slug derives an id from a name: "My Relay" → "my-relay".

func SpendExpiringCodexResets added in v0.1.701

func SpendExpiringCodexResets(ctx context.Context)

SpendExpiringCodexResets goes over the Codex accounts the user lets spend their resets and spends one about to run out unused (see check).

func SpentShareOf added in v0.1.641

func SpentShareOf(routing string) float64

SpentShareOf is the share past which routing counts an account spent: SpentShare, but In order sends requests to the first until a window of it is used up or the vendor refuses it, so there an account at 98% is still tried in its turn (#530).

func SplitKeys added in v0.1.930

func SplitKeys(text string) []string

SplitKeys is the keys in text pasted at once: one a line, or separated by commas, semicolons or spaces, trimmed of quotes, each once.

func SplitWords added in v0.1.1272

func SplitWords(split []BalancePart) string

SplitWords is a balance's split on one line, in English, for the TUI and the CLI: "granted ¥10.00 · topped up ¥100.00".

func StaleAllowance added in v0.1.38

func StaleAllowance(agent, user string)

StaleAllowance makes the next Allowances ask the vendor again for user's allowance rather than trust what it last said, or what a reading out now, asked before, comes back with: the account just answered that it has run out.

func StaleKeyAllowance added in v0.1.1086

func StaleKeyAllowance(p Provider)

StaleKeyAllowance has the next KeyAllowance ask the vendor again for p's key's windows rather than trust what it last said: the key just answered that it is out of them.

func StepFunBookmarklet added in v0.1.389

func StepFunBookmarklet() string

StepFunBookmarklet is the bookmarklet the user runs on a StepFun platform page they are signed in on: it renews the session as the page does, on either site, and copies it to be pasted into magpie.

func StepFunOrigin added in v0.1.389

func StepFunOrigin(site string) string

StepFunOrigin is the site's platform.

func StepFunSignInURL added in v0.1.389

func StepFunSignInURL(site string) string

StepFunSignInURL is the page the user signs in on, for the site.

func StepFunSignedIn added in v0.1.389

func StepFunSignedIn(id string) bool

StepFunSignedIn reports whether magpie has a sign-in for the provider.

func StepFunSite added in v0.1.389

func StepFunSite(p Provider) string

StepFunSite is which of StepFun's platforms the provider's key is for, "ai" or "com", or "" for another vendor.

func StoreIcon added in v0.1.10

func StoreIcon(data []byte) (string, error)

StoreIcon keeps a picture (PNG, JPEG, GIF, WebP, ICO or SVG) and returns the Icon value that points at it. The same picture is stored once.

func StoreIconFile added in v0.1.10

func StoreIconFile(path string) (string, error)

StoreIconFile is StoreIcon for a picture on disk.

func StoredGroupOrder added in v0.1.843

func StoredGroupOrder() ([]string, error)

StoredGroupOrder is the order the user put the groups in, as saved; as with Stored, a file that can't be read is an error.

func StoredOrder added in v0.1.638

func StoredOrder() ([]string, error)

StoredOrder is the order the user put the providers in, as saved; as with Stored, a file that can't be read is an error.

func SubmitSignInCallback added in v0.1.415

func SubmitSignInCallback(id, raw string) error

SubmitSignInCallback finishes a browser sign-in whose callback could not reach this machine — the address the browser ended on, pasted — or a plugin's with the code its page showed.

func SubscriptionUsageReading added in v0.1.1076

func SubscriptionUsageReading() bool

SubscriptionUsageReading says a read of the accounts' usage is under way: what SubscriptionUsage just gave may be the stale copy it replaces, for a page to ask again once it lands (#959: the panel, opened, kept the old copy until refreshed by hand, while the window's next read had the new).

func SuffixMode added in v0.1.595

func SuffixMode() string

SuffixMode is how the agents' lists name models: SuffixOn, SuffixOwn or SuffixOff.

func SwitchGroup added in v0.1.989

func SwitchGroup(id string, on bool) error

SwitchGroup switches a group of the user's on or off (Group.Disabled). A group magpie found is the catalog's, so it is removed rather than switched off; and one that classifies for another stays on, or that group's rules would have no one to ask.

func SwitchLogin added in v0.1.11

func SwitchLogin(agent, user string) error

SwitchLogin signs an agent in to a remembered account. Sessions of the agent that are already running keep the account they started with until they restart; so does Codex's background app-server, which new Codex sessions attach to (CodexDaemonStale says when it is).

func SwitchOnly added in v0.1.1224

func SwitchOnly(agent string) bool

SwitchOnly reports whether magpie only moves agent's own sign-in between its accounts, sending none of its requests through the gateway for account failover (Provider.SwitchOnly). While providers.json can't be read the user's choice is unknown, and failover, magpie's own idea, is not taken up on it.

func SwitchSearchAPI added in v0.1.1258

func SwitchSearchAPI(vendor string, on bool) error

SwitchSearchAPI switches the vendor's search API on or off (#2286), keeping its key, address and place.

func SwitchWhenSpent added in v0.1.402

func SwitchWhenSpent(ctx context.Context, agent string) (string, error)

SwitchWhenSpent signs agent in to the next of its accounts when the one it is on is spent, or back to the one it moved off once that has room (NextLogin), and answers the account it signed it in to, "" when it stayed.

func SyncClaudeProxyEnv added in v0.1.1212

func SyncClaudeProxyEnv(user string) (string, error)

SyncClaudeProxyEnv has the env of Claude Code's settings.json name the proxy of the account user, the one it is signed in to (see the top of this file), and answers the proxy written, "" when none of magpie's is there now.

func TakesBalanceToken added in v0.1.90

func TakesBalanceToken(p Provider) bool

TakesBalanceToken says the provider's vendor tells the account's balance to a token of its own (BalanceToken), which the editor then asks for.

func TakesTencentAccessKey added in v0.1.1182

func TakesTencentAccessKey(p Provider) bool

TakesTencentAccessKey says p is on Tencent Cloud's Token Plan 企业版 (at /plan on TokenHub's hosts), whose editor then asks for the account's SecretId and SecretKey.

func TakesVolcAccessKey added in v0.1.1142

func TakesVolcAccessKey(p Provider) bool

TakesVolcAccessKey says p is on Volcengine Ark (ark.<region>.volces.com), whose editor then asks for the account's AccessKey ID and Secret.

func TakesZhipuTeam added in v0.1.431

func TakesZhipuTeam(p Provider) bool

TakesZhipuTeam says p is a key of Zhipu's or Z.ai's, whose editor then offers the team's organization and project (#236).

func TestAs added in v0.1.1158

func TestAs(ctx context.Context, client string) context.Context

TestAs is ctx with Test and TestModels asking as client asks ("" as magpie does).

func ThenUses added in v0.1.196

func ThenUses(rules []Rule, q RuleRequest, n int, use string) []string

ThenUses are the members the rules after the n-th (from 1) that also match q send to, each once and in the rules' order, leaving out use: who a request a rule sent to use fails over to before the group's others (#112).

func TookOpenedURL added in v0.1.574

func TookOpenedURL(args []string) bool

TookOpenedURL is magpie run as the browser of a `claude auth login` it started: the page is written down for magpie's window to open, and nothing else runs.

func TuckAccount added in v0.1.773

func TuckAccount(id string, on bool) error

TuckAccount hides a removed account from the Add sheet's "Removed from magpie" too (on), or lists it there again (off). Tucked, it is quiet as well: no reminder line either (#116).

func UltraModels added in v0.1.1270

func UltraModels() map[string]bool

UltraModels are the models one of Codex's accounts offers Ultrafast on.

func UltraOn added in v0.1.1270

func UltraOn(p Provider, model string, ultra map[string]bool) bool

UltraOn is CanUltra with UltraModels read once, for a list of them all.

func UltraPicks added in v0.1.1270

func UltraPicks(agent string) []string

UltraPicks are the fast picks agent's requests for are sent as Ultrafast.

func Unflat added in v0.1.1137

func Unflat(id string) (string, bool)

Unflat is the served id (a provider's model or a routing group) whose flat spelling is id, when exactly one has it. An id with a slash, or with no tilde, is never a flat one.

func Unretire added in v0.1.1148

func Unretire(pid, model string)

Unretire takes back a retirement of provider pid's model, when it has one: the vendor answered a request for it.

func UpstreamName added in v0.1.560

func UpstreamName(p Provider, model string) string

UpstreamName is the name to send a provider for one of its models: the one the user gave, for the model or for every model of that provider, else the name magpie knows the model by. Every "*" in the name the user gave is that model, wherever it stands: "vendor-c/*" for a provider's every model sends vendor-c/model-3 for model-3, so one name covers a relay that namespaces its models and still asks for each of them by its own, and "vendor/*/pro" sends vendor/model-3/pro. A name with no "*" in it is that one name for every model of the key, which is the right answer only for a relay that does serve them all alike.

The two are deliberately different things. Everything a user or an agent sees — the catalog, the routing groups' membership, what a call is recorded and priced as — is in magpie's name for the model, so a rename upstream never renames a model here. Only the request that goes out carries the vendor's name, and what a reply says answered is compared with it, so a model asked for by the name the vendor serves it under is not read as another one.

func UpstreamNameAs added in v0.1.560

func UpstreamNameAs(p Provider, model, sent string) string

UpstreamNameAs is UpstreamName for a request that goes out asking for sent, which is not always the model magpie knows: an Antigravity account is asked for the variant of it the effort picks, and that is the id the body carries. The two levels of the lookup are kept apart, since they are about different things. A name given for the model itself is the model's, whichever variant answers for it, so a "*" in it is that model and not the variant: the vendor is asked for the model by the name its owner gave, as it is everywhere else in magpie, and not for a "*" it never heard of. A "*" in the provider's own name is whatever the request is going out under, so one name for a provider asks for gemini-3.7-flash-high and gemini-3.7-flash-low each by its own, rather than for the one id whatever level the effort picked.

func UpstreamNameAsIn added in v0.1.560

func UpstreamNameAsIn(wires map[string]string, pid, model, sent string) string

UpstreamNameAsIn is UpstreamNameAs over a settings' ModelWires already read. A name that is only whitespace is no name, as it is in UpstreamNameIn: the lookup falls through to the level below it, and a request with no name at all goes out under the id it was built with.

func UpstreamNameIn added in v0.1.560

func UpstreamNameIn(wires map[string]string, pid, model string) string

UpstreamNameIn is UpstreamName over a settings' ModelWires already read, for a caller that walks a whole ledger of models in a row. A name that is only whitespace — one an older magpie stored, or one hand-edited into the file — is no name, as it is where one is given.

func UsageAlias added in v0.1.1358

func UsageAlias() func(string) string

UsageAlias is the name a model's usage is counted under: the alias the user set for it, followed through any alias of that, else the model's own id. It is nil when there are no aliases, so a caller does nothing for each row. Read once for a whole summary, not for each row; it reads settings.json, so it is taken before any lock a reader of the usage waits on.

func UsageAliasFor added in v0.1.1358

func UsageAliasFor(id string) (from, to, counted string, ok bool, err error)

UsageAliasFor is the alias the user set for the model id, as settings.json has it (from as written there), and where usage of it is counted in the end, through any alias of that. ok is false when it has none. err is settings.json not read: unknown, not "none".

func UsageAliasIn added in v0.1.1358

func UsageAliasIn(m map[string]string) func(string) string

UsageAliasIn is UsageAlias for the aliases m.

func UsageAliases added in v0.1.1358

func UsageAliases() map[string]string

UsageAliases are the aliases the user set, as settings.json has them.

func UsageClaudeVia added in v0.1.558

func UsageClaudeVia(f func(ctx context.Context, configDir string) (string, error))

UsageClaudeVia sets how Claude Code's /usage runs. It returns once no run is still going through the one it replaces.

func UseKey added in v0.1.14

func UseKey(id, keyRef string) error

UseKey makes one of a provider's keys the first, and turns it on; the one it replaces stays on, next in line.

func UsedUp added in v0.1.791

func UsedUp(q SubscriptionQuota, now time.Time) bool

UsedUp is usedUp for the CLI's magpie quota wait, so what it waits out is what stops an account here.

func Verification added in v0.1.304

func Verification(b []byte) (link string, ok bool)

Verification says whether an error body is Google's refusal of an account it wants verified first — Cloud Code Assist's 403 whose details say VALIDATION_REQUIRED with a validation_url in their metadata (#152) — and the https link to verify it at, when the body has one.

func VerifyMessage added in v0.1.304

func VerifyMessage(said, link string) string

VerifyMessage is a verification refusal as the agent and the app show it: the vendor's words, then what to do.

func VertexForTest added in v0.1.1162

func VertexForTest(root, token, iam string) func()

VertexForTest points Vertex AI at root, Google's token endpoint at token and IAM Credentials at iam until the returned function runs, and forgets the tokens minted. Tests outside this package use it.

func VertexPath added in v0.1.1162

func VertexPath(model string) string

VertexPath is where, after a Vertex AI provider's base, a request for model goes: streamed, as the gateway asks every one there but a Gemini client's own asked whole (VertexWholePath).

func VertexWholePath added in v0.1.1162

func VertexWholePath(model string) string

VertexWholePath is where a request for model answered as one JSON body goes.

func Via added in v0.1.418

func Via(ctx context.Context, id string) context.Context

Via is ctx for requests made on behalf of the provider or signed-in account with id (see Provider.Via).

func ViaLogin added in v0.1.427

func ViaLogin(ctx context.Context, id, user string) context.Context

ViaLogin is ctx for requests made on behalf of the account user of the subscription id (ProxyOfLogin).

func ViaSignedIn added in v0.1.427

func ViaSignedIn(ctx context.Context, id string) context.Context

ViaSignedIn is ctx for requests made with the sign-in an agent has now (Codex's own, relayed as it came): through the proxy of the account it is signed in to.

func VisibleTo added in v0.1.111

func VisibleTo(agent string) ([]string, bool)

VisibleTo is what agent's lists are narrowed to, and whether they are.

func WBRestricted added in v0.1.1217

func WBRestricted(status int, body []byte) bool

WBRestricted says body is WorkBuddy's refusal of a restricted account: its code 11140 (top level, or under data or error, as a number or a string), or its displayMsg's words. Only for a WorkBuddy answer: another vendor's 11140 is its own.

func WatchQuotas added in v0.1.540

func WatchQuotas(ctx context.Context, wake <-chan struct{}, send func(QuotaAlert))

WatchQuotas reads every allowance and balance while an alert is set, and hands send each one due, until ctx ends. wake, when it gets a value, has it look at once (an alert just turned on).

func WindowCapID added in v0.1.1134

func WindowCapID(name string) string

WindowCapID is how a window is known to its cap: its name, trimmed, in lower case.

func WindowTyped added in v0.1.1214

func WindowTyped(id string) bool

WindowTyped says the window agents are told for a model, by its catalog id (as CompactSet takes it), is one the user typed: the group's own size, a group's smallest member's that the user typed (smallestWindow, #2224), its largest member's when it names no size and the user typed that one (largestWindow), or one set on the provider for the model or all of its models. Claude Code then isn't handed magpie's default compaction window for it (CompactFor's rule, as Entry.WindowSet).

func WithAutoPicks added in v0.1.921

func WithAutoPicks(ctx context.Context, onPick func(model string)) (context.Context, func() []AutoPick)

WithAutoPicks has the Auto picks a request is sent with noted: the func returns them. onPick, when set, is told each model the request goes as, for the reply to name the one it went as last.

func WithAutoPrompt added in v0.1.914

func WithAutoPrompt(ctx context.Context, prompt string) context.Context

WithAutoPrompt carries the prompt of the request Copilot's Auto picks a model for: POST /auto picks for a prompt.

func WithCapped added in v0.1.809

func WithCapped(m map[string]SubscriptionQuota) map[string]SubscriptionQuota

WithCapped is m with Capped set on each window an account's usage cap counts, for the GUI to mark the cap and say an account is held at it as routing does — a window one model's own counts for that model, so it is marked as the rest are; the windows are copied, the cache's left as they are.

func WithMemberEffort added in v0.1.379

func WithMemberEffort(model, effort string) string

WithMemberEffort is the member id of model at effort: the model itself for "".

func ZedBody added in v0.1.632

func ZedBody(body []byte) []byte

Zed's cloud reads an OpenAI model's request into its own Responses types (zed-industries/zed, crates/open_ai/src/responses.rs) before it goes on to OpenAI, and turns the whole request away over anything they don't name: "failed to parse OpenAI Responses API request: unknown variant `developer`, expected one of `user`, `assistant`, `system`, `tool`" on Codex's developer messages. What they take:

  • input items tagged by type: message, function_call, function_call_output, custom_tool_call, custom_tool_call_output, reasoning, compaction, compaction_trigger;
  • a message's role: user, assistant, system, tool; its content a list;
  • a reasoning item's content a list, if there (serde's default is for a missing field, not a null one);
  • tools of type function or custom;
  • include: reasoning.encrypted_content alone;
  • reasoning.summary: auto, concise, detailed.

ZedBody is a Responses request fitted to those, Codex's above all; a request in another API (one with no input list) goes as it came.

func ZhipuCodingBase added in v0.1.1224

func ZhipuCodingBase(base string) (string, bool)

ZhipuCodingBase is the GLM Coding Plan's OpenAI base for base, Zhipu's or Z.ai's pay-as-you-go one (https://open.bigmodel.cn/api/paas/v4 → https://open.bigmodel.cn/api/coding/paas/v4), and whether base is one.

func ZhipuEnveloped added in v0.1.1252

func ZhipuEnveloped(req *http.Request, res *http.Response) *http.Response

ZhipuEnveloped is res, or — when it is a 2xx from Zhipu or Z.ai holding the platform's refusal envelope — the refusal at its status, with the body as their OpenAI API words one. A stream, a compressed body and every other host's reply pass as they came.

func ZhipuKeyRefused added in v0.1.1252

func ZhipuKeyRefused(code int) bool

ZhipuKeyRefused says whether an envelope's code is Zhipu refusing the key itself (1000–1005: not taken, missing, expired, needs a second factor), not the request.

func ZhipuNoBalanceHint added in v0.1.1224

func ZhipuNoBalanceHint(from, coding, said string) string

ZhipuNoBalanceHint says what a 1113 at the pay-as-you-go endpoint from means when the Coding Plan's endpoint coding didn't serve the key either (said is what it answered), and what to change.

Types

type Account

type Account struct {
	Agent string `json:"agent"`          // the agent's id: codex, copilot
	User  string `json:"user"`           // who is signed in: an email, a GitHub login
	Plan  string `json:"plan,omitempty"` // the subscription, when the agent says

	// Stream is set when the backend only streams; magpie then translates
	// a non-streaming request instead of relaying it.
	Stream bool `json:"-"`

	// Home is where a Grok, Kiro or Devin account keeps its sign-in: the
	// agent's own (the CLI's home for Grok, "" for Kiro and Devin), or one
	// of magpie's for a further account (grok_accounts.go, kiro_accounts.go,
	// devin_accounts.go).
	Home string `json:"-"`
	// contains filtered or unexported fields
}

Account is the signed-in agent behind a provider.

func (*Account) AgentsOwn added in v0.1.648

func (a *Account) AgentsOwn() bool

AgentsOwn says the account is the one the agent itself is signed in to, run in the agent's own home with what it keeps there, not with a sign-in magpie hands it. Which account that is moves with a switch (SwitchLogin): a Claude Code started on it before goes on as whatever Claude Code is signed in to by then, as it reads its keychain again every half minute.

func (*Account) Levels added in v0.1.635

func (a *Account) Levels(model string) (levels []string, ok bool)

Levels are the reasoning levels the account's own list gives the model — a Free ChatGPT plan's may be fewer than a Plus one's — and ok is false when that list wasn't fetched, doesn't have the model or gives it none.

func (*Account) Lists added in v0.1.35

func (a *Account) Lists(model string) bool

Lists reports whether the account's plan has the model, as far as magpie knows: one whose list was never fetched is taken to have them all.

func (*Account) StandIn added in v0.1.623

func (a *Account) StandIn() bool

StandIn says the account is a saved one served in the place of the agent's own sign-in, which is signed out.

func (*Account) Tiers added in v0.1.1122

func (a *Account) Tiers(model string) (tiers []string, ok bool)

Tiers are the service tiers the account's own model list offers on model, when its list says: a list that gives no model a tier doesn't say, as one fetched before ChatGPT listed them.

func (*Account) Token added in v0.1.14

func (a *Account) Token(ctx context.Context) (tok string, ok bool, err error)

Token is the access token of a saved account in use beside the agent's own — for a Claude account, the config directory Claude Code runs on it in; ok is false for the agent's own, which the agent signs itself. A Claude account that can't be used, Anthropic having refused its sign-in, is an error, whichever it is (claude_auth.go).

func (*Account) UsageAgent added in v0.1.514

func (a *Account) UsageAgent() string

UsageAgent is the agent an account's allowance is asked for by (LoginUsage, Allowances): a plugin's accounts by their provider's.

type AccountRef added in v0.1.1076

type AccountRef struct {
	ID   string
	User string
	Plan string
	Key  bool // one of the provider's keys, not a signed-in account
}

AccountRef is one of a provider's accounts or keys as a gateway key's account list knows it (#905): ID what the list keeps — an account's stable id, kept through renames, a key's fingerprint — User and Plan what it is shown as.

func (AccountRef) Shown added in v0.1.1326

func (a AccountRef) Shown(p Provider) string

Shown is how the account or key a is shown on p: an account by the name the user gave it, a key by its own name.

type Allowance added in v0.1.29

type Allowance []Limit

Allowance is an account's allowance windows as last known.

func FactoryAllowanceForTest added in v0.1.1227

func FactoryAllowanceForTest(limits []byte, now time.Time) Allowance

FactoryAllowanceForTest is the allowance an account's /api/billing/limits answer gives routing, for the gateway's tests.

func KeyAllowance added in v0.1.1086

func KeyAllowance(p Provider) (Allowance, bool)

KeyAllowance is the provider's key in use's own usage windows as last read, asked for again in the background when that was over a minute ago; ok is false for a key without any, or one not read yet. It never waits: a key not read yet goes by the last reading on its card, else counts as not known.

func PluginAllowanceForTest added in v0.1.1227

func PluginAllowanceForTest(usage []byte, now time.Time) Allowance

PluginAllowanceForTest is the allowance a plugin's usage answer gives routing, for the gateway's tests.

func (Allowance) CapHeld added in v0.1.809

func (a Allowance) CapHeld(model string, caps WindowCaps, now time.Time) *CapHold

CapHeld says how an allowance, as last known, holds the account for model at now: some window counting model at or past its own share of caps (WindowCaps.Of), not renewed since; nil when none is. A window whose reset has passed is empty again; no caps hold nothing.

func (Allowance) Count added in v0.1.738

func (a Allowance) Count(model string, now time.Time) (amount, of float64, unit string)

Count is the count of the window For's share is of — the fullest that counts model — when the vendor counts it (WorkBuddy's credits): how much of of is used, in unit; of is zero when it isn't counted so. A window whose reset has passed is empty again.

func (Allowance) For added in v0.1.38

func (a Allowance) For(model string, now time.Time) (used float64, renews []time.Time)

For is what an allowance leaves a request for model at now: the share used of the fullest window that counts it, and when those windows renew, the biggest first — the longest, the week before the five hours in it. A window whose reset has passed is empty again, its next reset not known.

func (Allowance) Full added in v0.1.38

func (a Allowance) Full(model string, share float64, now time.Time) time.Time

Full is when an account used up for model can take it again: the last reset of its windows that are full, zero when none is or it isn't known.

func (Allowance) Fullest added in v0.1.1210

func (a Allowance) Fullest(model string, now time.Time) time.Time

Fullest is when the window For's share is of renews: the fullest that counts model, the later of those as full. A display pairs the two, so it names one window: a Factory account 32% into its week and 16% into its month is 32% used, renewing with the week, not the month (#1778). Zero when that window's reset isn't known, or has passed (it is empty again then, its next reset not known).

func (Allowance) OnCredits added in v0.1.1339

func (a Allowance) OnCredits() bool

OnCredits says whether the account goes on past its allowance on its credits, as its last reading says (a ChatGPT account holding them, QuotaWindow.Credits): a window used up doesn't stop it. Whether it is let spend them is the user's (CodexCredits).

func (Allowance) Pace added in v0.1.644

func (a Allowance) Pace(model string, now time.Time) (pace float64, due time.Time)

Pace is the share of its week an account has left for model, per hour until that week renews: the rate it would have to be used at to spend the week just in time, so the account with the highest has the most to lose at its reset. Of several budget windows that count the model (Opus's own beside the general), the tightest; due is when that one renews, zero when it isn't known. A window not started, or whose reset isn't known, is taken to run its whole span from now; one that doesn't say how long it runs (a plugin may not) is a budget, for as long as its reset says, else a week. The hours until a reset are never taken as fewer than one, or a window a minute from renewing would outweigh all the rest. An account whose vendor tells no budget window, only a short one (Claude Enterprise's five hours), has nothing longer to keep for: what its five hours have left is lost at their reset, so it goes by that, per hour until then — the whole span when not started (#576): ahead of nearly every week, behind only one with more of it to lose sooner. Where the reading may leave a week out (a Claude account only heard of as Claude Code answered, partial) it is instead taken to have a week not started with the share its fullest window has used: those go by what they have used, among the rest as the fresh are. An account whose windows an auto-used reset starts again sooner than they renew (Restarts) goes by that instead, and due is then that time: what it has left is lost there.

func (Allowance) Pooled added in v0.1.1046

func (a Allowance) Pooled(model string, share float64, now time.Time) bool

Pooled says whether a refusal of model for its allowance leaves the account's other models alone: the windows that count model and are full at share are each of some models only (Opus's own week, Cursor's Other Models pool) — or, none known full, no window of the whole account counts it, only pools. Then it is that model which is out, not the account: Cursor's Other Models used up leaves Auto and Composer in theirs (Xiaopodev on X).

func (Allowance) Renewal added in v0.1.670

func (a Allowance) Renewal(model string, now time.Time) []time.Time

Renewal is For's renews as routing ranks them: a window not started, or whose reset has passed, that says how long it runs is taken to renew that long from now — a five hours not started renews within five hours, the soonest of an account that has nothing longer (#576). One whose credits left run out before it renews (Limit.RunsOut) renews then, as what is left is lost then all the same: WorkBuddy's accounts, whose credits have no reset, go by the package that ends first (cdredfox on X).

func (Allowance) Restarts added in v0.1.792

func (a Allowance) Restarts(now time.Time) time.Time

Restarts is when an auto-used reset starts the account's windows again, as the Codex reset about to run out is spent (expiringResetSpent): resetExpiryLead before it runs out, or now when the account is held up past then. What they have left then is lost, as at their own reset, so Weekly pace and Smart take it for their renewal when it comes sooner (#717, #718). Zero when none will be.

type AppImport added in v0.1.25

type AppImport struct {
	Ref      string   `json:"ref"`            // stable within its source
	From     string   `json:"from,omitempty"` // where in the app: Claude Code, Codex…
	Provider Provider `json:"provider"`
	// Status is "new", "same" (magpie has it already: same endpoint and
	// key) or "taken" (its id is another provider's here).
	Status   string `json:"status"`
	Existing string `json:"existing,omitempty"` // the magpie provider it matches or collides with
	// KeyOf is a magpie provider at the same address with another key:
	// this one can join it as one more key instead of being a provider
	// of its own.
	KeyOf string `json:"keyOf,omitempty"`
	// Reserved: its id is a subscription's (claude, workbuddy…), whose
	// name it happens to have. It can't replace that subscription, only
	// come in as a provider of its own beside it.
	Reserved bool   `json:"reserved,omitempty"`
	Off      string `json:"off,omitempty"`  // why it isn't picked by default
	Skip     string `json:"skip,omitempty"` // why it can't be imported at all
}

AppImport is one provider an app holds, as magpie would add it.

type AppPick added in v0.1.25

type AppPick struct {
	Source string `json:"source"`
	Ref    string `json:"ref"`
	Mode   string `json:"mode,omitempty"`
	Name   string `json:"name,omitempty"`
}

AppPick is one entry the user chose, and how it comes in: as a provider ("add", beside any with its id), in place of the one with its id ("replace"), or as one more key of the provider KeyOf names ("key"). Name is the name the user gave it in the picker, when its own collides with one magpie has (#1487); a renamed entry is added, never replaces.

type AppSource added in v0.1.25

type AppSource struct {
	ID    string      `json:"id"`   // cc-switch, alma
	Name  string      `json:"name"` // as the app calls itself
	Path  string      `json:"path"` // the file read
	Found bool        `json:"found"`
	Error string      `json:"error,omitempty"`
	Items []AppImport `json:"items"`
}

AppSource is one app magpie can import from, with what it holds.

func DiscoverSources added in v0.1.1256

func DiscoverSources() []AppSource

DiscoverSources reads the apps the Providers page looks in by itself: those not read only when asked.

func ImportSources added in v0.1.25

func ImportSources() []AppSource

ImportSources reads every app magpie can import from, as the user asked.

type AutoPick added in v0.1.921

type AutoPick struct {
	Model   string `json:"model"`
	Via     string `json:"via"`
	Skipped string `json:"skipped,omitempty"`
	Refused string `json:"refused,omitempty"`
	API     string `json:"api,omitempty"`
	Session bool   `json:"session,omitempty"`
}

AutoPick is a model Copilot's Auto picked for a try of a request: where the pick came from, why not from /auto when it didn't, and Copilot's refusal of it, which the route shows (#256: a Student plan's picks were refused, the tries logged as "auto"). API is the path it was sent to (/responses, /chat/completions), Session whether Auto's session token went with it.

type BalancePart added in v0.1.587

type BalancePart struct {
	Label   string   `json:"label,omitempty"`
	Text    string   `json:"text"`
	Percent *float64 `json:"percent,omitempty"`
	// Error is why the amount couldn't be read, its Text then "—".
	Error string `json:"error,omitempty"`
}

BalancePart is one amount of a balance field, for a card to show each of several on a line of its own, its label apart from its figure, rather than all of them run together: Percent is its share, 0 to 100, when it was asked as one ("%" after it), for a meter.

type BalancePoint added in v0.1.1050

type BalancePoint struct {
	At     time.Time `json:"at"`
	Amount float64   `json:"amount"`
}

BalancePoint is one reading of a balance: Amount was left at At.

type BalanceTrend added in v0.1.1050

type BalanceTrend struct {
	Points   []BalancePoint `json:"points"`
	FitFrom  *time.Time     `json:"fitFrom,omitempty"`
	FitStart float64        `json:"fitStart,omitempty"`
	FitNow   float64        `json:"fitNow,omitempty"`
	PerDay   float64        `json:"perDay,omitempty"`
	RunsOut  *time.Time     `json:"runsOut,omitempty"`
	// Currency is the sign the points are in ("$"), set when the balance
	// is told in several currencies and the points are only the first's
	Currency string `json:"currency,omitempty"`
}

BalanceTrend is a balance's points over balanceShowSpan, oldest first, and the line fitted through the latest of them: spent PerDay a day, from FitFrom (the amount FitStart then) to now (FitNow), running out at RunsOut. With no fit (too few points, or a top-up just now) only Points.

type Bare added in v0.1.1226

type Bare struct {
	ID string
	Of int
}

Bare is a row a list adds for a bare id: ID, and Of, the index in the list of the entry a request for it reaches.

func BareEntries added in v0.1.1226

func BareEntries(shown []Entry) []Bare

BareEntries are the rows a list of shown adds for the bare ids, in the order the models first appear in shown, each once.

type CapHold added in v0.1.1134

type CapHold struct {
	Used    float64
	Cap     int
	Back    time.Time
	Credits bool
}

CapHold is how an account is held by its caps for a model: the share used of the fullest window holding it, that window's cap, when the last of those windows renews (zero when one doesn't say), and Credits when only the credits hold it, at 100%.

type CheckinAccount added in v0.1.1224

type CheckinAccount struct {
	Key  string `json:"key"`
	By   string `json:"by"`
	User string `json:"user"`
	On   bool   `json:"on"`
}

CheckinAccount is an account a daily check-in reaches, for Settings: its entry in its vendor's file (Key, which settings.CheckinOff names), the vendor (By, as WorkBuddyCheckin's), and whether it is checked in while its vendor's check-in is on (#1902, magicLaLa: 根据每个账号设置是否开启 自动签到).

func CheckinAccounts added in v0.1.1224

func CheckinAccounts() []CheckinAccount

CheckinAccounts are the accounts in use that each vendor's check-in reaches, WorkBuddy's, Trae CN's, MiniMax Code's, Qoder's and the plugins' that check in themselves, each once; asks nothing.

type ClaudeLimit added in v0.1.199

type ClaudeLimit struct {
	Kind     string
	Used     float64
	ResetsAt int64
}

ClaudeLimit is one allowance window as Claude Code tells it: its kind (five_hour, seven_day, seven_day_opus, seven_day_sonnet, seven_day_overage_included), the share used, 0–1, and when it renews, in Unix seconds (0 when not said).

func KeptClaudeLimits added in v0.1.1113

func KeptClaudeLimits(user string) []ClaudeLimit

KeptClaudeLimits is what is kept of user's allowance as of now, in the windows Claude Code names (ClaudeLimit's kinds), each that says when it renews: what Claude Code last said as it answered, or its /usage read. Nil when nothing is kept.

type CodexDaemonCheck added in v0.1.1151

type CodexDaemonCheck struct {
	// Behind: a daemon runs that started before what it reads changed
	Behind bool
	// Since is when that daemon started
	Since time.Time
	// Attached is how many codex sessions may be on it, which magpie
	// doesn't restart it under
	Attached int
	// Restarted: magpie restarted it, and new sessions get the new list
	Restarted bool
	Err       error
}

A CodexDaemonCheck is what KeepCodexDaemonCurrent found and did.

func KeepCodexDaemonCurrent added in v0.1.1151

func KeepCodexDaemonCurrent(ctx context.Context, home string, changed time.Time) CodexDaemonCheck

KeepCodexDaemonCurrent restarts the managed app-server of the Codex home home when it started before changed (when magpie last changed what Codex reads at start) and no codex session is attached to it. One that can't be found or timed, or a restart already under way, is left as it is.

type CodexLimit added in v0.1.1118

type CodexLimit struct {
	Used   float64
	Span   time.Duration
	Resets time.Time
}

CodexLimit is one of an account's windows as a reply tells it: the share used (0–100), how long the window runs, and when it renews (zero when not said).

type CodexWarm added in v0.1.182

type CodexWarm struct {
	User    string   `json:"user"`
	Windows []string `json:"windows"`
	Err     string   `json:"error,omitempty"`
}

CodexWarm is what came of looking at one account: the windows it was sent a request for, and why that failed.

type DailyCredits added in v0.1.664

type DailyCredits struct {
	// Since is the day magpie first read the account's credits: the days
	// before it aren't known, not unused.
	Since string `json:"since"`
	// Days are the days of the last creditsShown with credits used, oldest
	// first.
	Days []DayCredits `json:"days"`
}

DailyCredits is what an account's credits went to day by day.

type DayCredits added in v0.1.664

type DayCredits struct {
	Day  string  `json:"day"`
	Used float64 `json:"used"`
}

DayCredits is one day's credits used ("2006-01-02", the local day).

type Detection added in v0.1.663

type Detection struct {
	Result
	// Base is the URL the provider keeps for it, as the editor's fields
	// take it: …/v1 for OpenAI's two, the root for Anthropic's, …/v1beta
	// for Gemini's.
	Base string `json:"base"`
}

Detection is what one API answered at the URL it was asked at.

type DevinFamily added in v0.1.45

type DevinFamily struct {
	UID     string
	Label   string
	Aliases []string
	Models  []catalog.Model
}

DevinFamily is one entry of `devin models list`: a name that follows the family's newest model, and the pinned variants under it.

func DevinFamilies added in v0.1.45

func DevinFamilies(ctx context.Context) ([]DevinFamily, error)

DevinFamilies is the CLI's model list, kept a few minutes: the picker and the provider ask for it often and `devin models list` spawns a process that takes seconds (switching Claude Code's model took 5–10s while every state asked it anew). A list past its time is served as it is while it is read again in the background; only a caller with nothing known yet waits, and not one marked DevinNoWait.

type Entry

type Entry struct {
	ID      string `json:"id"`                // what the agent sends magpie
	Model   string `json:"model"`             // what magpie sends the vendor
	Name    string `json:"name"`              // the user's name for it, when they gave one (SetModelName)
	Default string `json:"default,omitempty"` // the model's own name, when the user gave it another
	// Plain is a remote magpie's model's name there alone, when Name is
	// its label there with that magpie's provider after it (catalog.Model's)
	Plain      string   `json:"-"`
	Efforts    []string `json:"efforts,omitempty"`
	Provider   Provider `json:"-"`                // a group's: its first member's
	Group      string   `json:"group,omitempty"`  // set on a routing group (group.go)
	Named      bool     `json:"-"`                // a routing group the user made or changed: its name is theirs (Labels)
	Icons      []string `json:"-"`                // a group's: its providers' icons, one per provider
	Images     bool     `json:"images,omitempty"` // takes images as input (a group's: a member does)
	ImageInput *bool    `json:"-"`                // explicit answer, nil when unknown
	// Inputs and Outputs are what the model's source listed it takes and
	// gives (catalog.Model's InputModalities, OutputModalities); see
	// Modalities
	Inputs, Outputs []string `json:"-"`
	// Context is the tokens a prompt may hold, when known (a group's: the
	// least of its members')
	Context int `json:"context,omitempty"`
	// WindowSet is set when Context is a window the user typed: on the
	// provider for the model or for all of its models (ContextOf), or on
	// the group (Group.Context, a size). Codex and Claude Code are then
	// told it whole rather than magpie's default working window
	// (CompactFor, #1809).
	WindowSet bool `json:"-"`
	// Output is the most tokens a reply may hold, when known (a group's:
	// the least of its members')
	Output int `json:"output,omitempty"`
	// OutputSet is set when Output is a Max output the user typed on the
	// provider, for the model or for all of its models (outputOf). An
	// agent's own cap on a vendor's figure gives way to it (#2064).
	OutputSet bool `json:"-"`
	// Family is the provider's or group's tag (see Visible).
	Family string `json:"family,omitempty"`
	// Free is set on a model its subscription serves at no cost to it.
	Free bool `json:"free,omitempty"`
	// Rate and RateWas are the credits a request costs its subscription,
	// as a multiple, and before a discount running now (catalog.Model's).
	Rate    float64 `json:"rate,omitempty"`
	RateWas float64 `json:"rateWas,omitempty"`
	// Shared are a group's levels its members have in common: its Efforts,
	// unless the group names its own (Group.Levels).
	Shared []string `json:"-"`
	// Reasoning is set on a model that thinks, levels or not: one with a
	// thinking switch alone has it and no Efforts (a group's: a member
	// thinks).
	Reasoning bool `json:"reasoning,omitempty"`
	// Reasonless is set on a model the user said takes no reasoning ask
	// (SetModelReasonless): it is sent none, and as a group's member it
	// leaves the group the levels the others have
	Reasonless bool `json:"-"`
	// AgentsV2 is set on a model offering Codex's Ultra that no ChatGPT
	// account answers for (a group's: none of its members): Codex is told
	// multi-agent V2 for it, so Ultra hands work to its agents, whose
	// tasks a magpie-served lead writes as text.
	AgentsV2 bool `json:"-"`
	// Tiers are the service tiers its list offers Codex on the model:
	// another magpie's, those it offers its own Codex (#1234); a provider
	// plugin's, those it says its vendor serves the model at (#2514)
	Tiers []string `json:"-"`
	// Released is the model's release day (YYYY-MM-DD) as its list or
	// models.dev says it, "" when neither does: what a group's template
	// weighs a newer model by (grouptemplate.go)
	Released string `json:"-"`
}

Entry is one model as the agents see it.

func BareEntry added in v0.1.1226

func BareEntry(shown []Entry, id string) (Entry, bool)

BareEntry is the entry of shown a client asking for a model by its bare id is told of (GET /v1/models/{id}), its ID the bare id.

func Catalog

func Catalog() []Entry

Catalog lists the routing groups, then every exposed model of every ready provider not kept unlisted. A provider switched off has none in it.

func CatalogFor added in v0.1.111

func CatalogFor(agent string) (shown, hidden []Entry)

CatalogFor is the catalog as agent is shown it, and what is kept from it (none when its lists aren't narrowed): its visibility's, less the models taken out of its lists one by one (HiddenModels), or, when it is shown only the models picked for it, those alone (PickedModels).

func CodexSubagentModels added in v0.1.1142

func CodexSubagentModels() []Entry

CodexSubagentModels are the models and routing groups Codex's subagents may be put on, the ones Codex's own lists show (a model taken out of them, or not picked, isn't offered here either): the ChatGPT accounts' first, as they open a task sealed for them too, then the rest in the catalog's order.

func Deciders added in v0.1.142

func Deciders() []Entry

Deciders are the models of the decision providers ready now, as a group's classifier names them: every one the gateway answers.

func EntryOf added in v0.1.532

func EntryOf(id string) (Entry, bool)

EntryOf is the model as the agents see it, by the id they ask for. It is the catalog's own entry, so the window and reply limit it carries are the ones a request is routed and metered against, with whatever the user set already applied.

func InOrder added in v0.1.952

func InOrder(agent string, es []Entry) []Entry

InOrder is es in agent's order: the entries ModelOrder names first, as it names them, then the rest as they come — a model added since goes after. Codex's own, a ChatGPT account's models, lead the rest, as Codex's list has them before magpie's.

func ListedFor added in v0.1.460

func ListedFor(agent string) (listed, kept []Entry)

ListedFor is the catalog agent's visibility gives it, the models it may pick to show or not among, and what the visibility keeps from it.

func OfferedDeciders added in v0.1.1242

func OfferedDeciders(keep func(id string) bool) []Entry

OfferedDeciders are the Deciders a routing group's pickers and templates offer: of a provider whose decision models are listed beside its chat models (OpenRouter's, a Bailian plan's, a plugin's, a remote magpie's), with picks saved, those among the picks alone, as its editor shows the rest unpicked (coeo91 on Discord: two OpenRouter models picked, and a new group's picker listed OpenRouter's twenty-odd decision models after them). With none picked every one is offered, as before. keep, when given, says a decision model a group names already, offered whatever the picks, so a group made of one before reads as it did.

func Served added in v0.1.77

func Served() []Entry

Served is the catalog with the unlisted providers' models as well: every model a routing group can be made of, or a request can name.

func ServedEntryOf added in v0.1.532

func ServedEntryOf(id string) (Entry, bool)

ServedEntryOf is the model a limit may be set on, by the id the user typed: any model its provider serves, not only the catalog's own entry. The setters ask serves — the provider's own models deciding, switched off or not — so a provider kept unlisted, still served through a routing group, takes a window and a reply limit all the same, and a provider switched off is served again as soon as it is on, keeping what it was given. Both keep it in the entry they answer with, so a query that said "is not a model this provider serves" about such an id would contradict the command run right after it, which stores one.

func Unlisted added in v0.1.572

func Unlisted() []Entry

Unlisted are the models Served has and Catalog doesn't: those of the providers kept for routing groups (Provider.Unlisted), and those a group keeps out of the lists (Group.Unlists), which agents aren't offered.

func (Entry) Label added in v0.1.137

func (e Entry) Label() string

Label is how an agent's list names the entry: its name (the user's own, when they gave one, else the vendor's) with its provider's after it, or "routing group" for a group's — dropped only when a name of the user's own already carries the provider's, so it isn't said twice.

func (Entry) Modalities added in v0.1.1189

func (e Entry) Modalities() (in, out []string)

Modalities are what the model takes and gives, as an agent's model list says them: every kind its source listed (a plugin's audio, video and pdf too, #1595), with image as Images has it, the user's say included. With no list, the input is text and image or text alone when whether it takes images is known, and nil when it isn't; output is nil unless said.

func (Entry) Names added in v0.1.111

func (e Entry) Names() []string

Names are what an entry answers to in a visibility: its family, and its provider's id or its group's id (as group/<id> too, and a found group's auto/<model>).

func (Entry) PlainName added in v0.1.1158

func (e Entry) PlainName() string

PlainName is the entry's name alone: a remote magpie's model's without the provider its list put after it by that magpie's own setting, which this one's Provider in model names Off leaves out as well (ARNO on Discord: "· Relay A" and "· routing group" stayed under Off).

func (Entry) PublishedOutput added in v0.1.1144

func (e Entry) PublishedOutput() int

PublishedOutput is e's reply limit as it is handed out beside its window (OutputWithin).

func (Entry) Quiet added in v0.1.1112

func (e Entry) Quiet() bool

Quiet reports whether the model is known not to think: magpie has a word on it — its vendor's or its maker's list, or its provider's own account list — and that word says no reasoning. A model nothing speaks for isn't quiet: the gateway sends it the effort the agent asked for, as #597 leaves it. Nor is one that takes levels — a model that thinks, or one the user gave levels of their own, which the gateway fits an effort to. A group's member that is quiet is sent no reasoning ask, which some vendors turn away with a 400 on a model that can't think, but for one the user fixed at an effort (Group's member syntax, #189): the gateway leaves that alone, the user's word over magpie's.

func (Entry) Thinks added in v0.1.1258

func (e Entry) Thinks() bool

Thinks is whether the model thinks, as /v1/models says it and every agent's list is told it: a model with levels, or one marked Reasoning with a thinking switch alone. An export that read the levels alone marked Trae CN's kimi-k3-max, which always thinks and has no levels magpie knows, not reasoning for Pi, and `magpie pi effort high` was clamped to off (#2380).

type Exclusion

type Exclusion struct {
	Agent    string `json:"agent"`
	Provider string `json:"provider,omitempty"` // set when the user removed it; saving it brings it back
	// Name is the removed provider's, for a sign-in no agent names: a
	// plugin's, whose Agent is "plugin" (#694)
	Name string `json:"name,omitempty"`
	Why  string `json:"why"`
	// SignedOut: the agent has accounts saved in magpie but isn't signed
	// in where magpie looks, and so none of them is offered.
	SignedOut bool `json:"signedOut,omitempty"`
	// Users names those saved accounts (no secrets), so they can be
	// removed from magpie while none of them is offered.
	Users []string `json:"users,omitempty"`
	// Quiet: the user asked not to be reminded of it; only the Add sheet
	// offers it back.
	Quiet bool `json:"quiet,omitempty"`
	// Tucked: hidden from the Add sheet too, but for its "Show N hidden"
	// and a search by name (#116).
	Tucked bool `json:"tucked,omitempty"`
	// Retry: the keychain didn't give Codex's sign-in (refused, no
	// answer, or its prompt still up); Try again asks it once more
	// (RetryCodexKeychain, #2367).
	Retry bool `json:"retry,omitempty"`
}

Exclusion is a sign-in magpie found but will not offer as a provider.

func Excluded

func Excluded() []Exclusion

Excluded lists sign-ins magpie detects but leaves out: the accounts the user removed from magpie, and the saved accounts of an agent that isn't signed in here (a magpie serve under another HOME, say).

type ExtraBody added in v0.1.1191

type ExtraBody map[string]json.RawMessage

ExtraBody is a provider's extra body fields, each value as the user wrote it, a name that begins with "!" forced.

func (*ExtraBody) UnmarshalJSON added in v0.1.1191

func (e *ExtraBody) UnmarshalJSON(b []byte) error

UnmarshalJSON reads an object; anything else written by hand (a string, a list) is read as none, rather than failing the whole providers file.

type GatewayKeyLimit added in v0.1.1179

type GatewayKeyLimit struct {
	// Limited is false for a key the remote holds to no limit.
	Limited bool `json:"limited"`
	// Period is "day", "week", "month", "days" (a cycle of Days days) or
	// "hours" (of Hours hours).
	Period string    `json:"period,omitempty"`
	Days   int       `json:"days,omitempty"`
	Hours  int       `json:"hours,omitempty"`
	Start  time.Time `json:"start,omitzero"`
	Reset  time.Time `json:"reset,omitzero"`
	Calls  int       `json:"calls,omitempty"`
	// TokensLeft and CostLeft are what is left of each cap there is.
	TokensLeft *int64   `json:"tokensLeft,omitempty"`
	CostLeft   *float64 `json:"costLeft,omitempty"`
	// Spent: the remote refuses the key until Reset.
	Spent bool `json:"spent,omitempty"`
	// Unpriced calls add nothing to the cost, so it reads low.
	Unpriced int `json:"unpriced,omitempty"`
}

GatewayKeyLimit is a remote gateway key's limit as its card carries it. Windows on the card show each cap; this says what they don't.

type Group added in v0.1.38

type Group struct {
	ID      string   `json:"id"`
	Name    string   `json:"name"`
	Members []string `json:"members"` // "provider/model[:effort]" or "group/<id>", in order (see MemberEffort)
	// Match are patterns its models are found by as well (#766): a glob
	// over the "provider/model" id with * in it ("openrouter/*:free"), or
	// a regular expression after "re:". Kept apart from Members, so the
	// group follows the catalog: read, it has the models they match now
	// after those it names (see withMatches).
	Match []string `json:"match,omitempty"`
	// Matched are the members the patterns match now, as Members has them
	// after its own. Derived each time the group is read, never stored.
	Matched  []string `json:"matched,omitempty"`
	Routing  string   `json:"routing,omitempty"`  // as Provider.Routing, over all the members' keys and accounts; or Manual
	Affinity string   `json:"affinity,omitempty"` // as Provider.Affinity
	// Sink is Provider.Sink over the group's members' accounts and keys
	// together: one rate limited with quota left goes behind every other
	// member's. Not for "rotate" or Manual.
	Sink bool `json:"sink,omitempty"`
	// FirstToken is how many seconds a member's streamed reply may take to
	// its first content — text, reasoning or a tool call — before the next
	// member is asked instead, nothing of it having reached the agent; 0
	// waits as long as it takes. The last one left is always waited for,
	// and the slow one doesn't rest.
	FirstToken int `json:"firstToken,omitempty"`
	// Patience is how many seconds more a request may be kept, once every
	// member has failed and nothing of a reply has been sent, for the
	// members that failed in a way that passes —
	// busy, overloaded, rate limited for a moment — to be asked again
	// after a pause, in turn, until one answers (#1418). 0 is
	// PatienceDefault; PatienceOff gives the agent the last one's error
	// once each has been asked.
	Patience int `json:"patience,omitempty"`
	// Off are the members switched off: kept where they are in the
	// order, with their rules, but sent nothing until switched on again,
	// so trying a group without one doesn't mean taking it out.
	Off []string `json:"off,omitempty"`
	// Pick is the member a Manual group sends every request to, as the
	// user picked it on the group's card; "" is its first. It is kept
	// while the group routes otherwise, for when it is manual again.
	Pick string `json:"pick,omitempty"`
	// Rules send the requests they match to one member first, in order:
	// the first that matches decides (see Rule).
	Rules []Rule `json:"rules,omitempty"`
	// Classifier is the model ("provider/model") asked which of the rules'
	// intents a user's message is, or a group ("group/<id>", never this
	// one) whose models are asked in turn, failing over as for any request.
	// Rules with an intent need one; a small, fast model without reasoning
	// does.
	Classifier string `json:"classifier,omitempty"`
	// Effort "auto" has the classifier — Jev, from TypeSafe's decision API,
	// or any model, asked in words — judge how hard each turn is to think
	// about as it begins, and the turn asks its model for that much
	// reasoning, where the agent asked for some (see EffortAuto).
	Effort string `json:"effort,omitempty"`
	// Context is how long a request the user says the group takes, in
	// tokens: agents are told it rather than its largest member's.
	// ContextSmallest tells them its smallest member's, whichever that is
	// as the members change (Mikan on Discord), so the agent compacts
	// before any member would turn the conversation away.
	Context int `json:"context,omitempty"`
	// Levels are the reasoning levels agents are offered for the group,
	// lowest first, when the user names them (#295): rather than those
	// every member has, so that a member with few doesn't take the rest
	// from the others. A member without the level a request asks for is
	// sent the one it has nearest, as ever. Empty offers the members'
	// shared levels.
	Levels []string `json:"levels,omitempty"`
	// Fast are the members (as Members spells them) sent in their
	// vendor's fast mode, where the model has one (see CanFast). Kept
	// beside Members, not in their ids, so a version before it still
	// routes to them, only not fast.
	Fast []string `json:"fast,omitempty"`
	// Weights are the members' shares (as Members spells them) when the
	// group routes by weight (Weighted, #1910): one weighing 3 takes three
	// requests for every one a member weighing 1 takes. One not in it
	// weighs 1. Kept while the group routes otherwise, for when it is by
	// weight again.
	Weights map[string]int `json:"weights,omitempty"`
	// Family is a tag the group goes by in which agents are shown it
	// (settings' Visible), with its id.
	Family string `json:"family,omitempty"`
	// Unlists keeps the models the group names, or its patterns match,
	// out of the lists agents and the gateway's model list show (#1783):
	// they are offered through the group alone, as a provider kept for
	// routing groups offers its own (Provider.Unlisted), and a request
	// naming one is still served. A group in it keeps its own, as it
	// says. Not while the group is switched off.
	Unlists bool `json:"unlists,omitempty"`
	// Auto is set on a group magpie found: one model served by several
	// providers. It is derived, never stored.
	Auto bool `json:"auto,omitempty"`
	// Spelled is how a vendor spells the model of a group magpie found
	// (auto-…), which agents are given it by: auto/<Spelled> (Ref). It is
	// derived from the members each time the groups are read, never stored.
	Spelled string `json:"-"`
	// Hidden is stored for a found group the user removed.
	Hidden bool `json:"hidden,omitempty"`
	// Disabled is a group of the user's switched off (PAMI on Discord):
	// kept on the Routing page as it is, but not offered to agents, a
	// request to it turned away with a word of why, and skipped where
	// another group has it in it, until switched on again (SwitchGroup).
	// Only SwitchGroup changes it: a save keeps it as it was.
	Disabled bool `json:"disabled,omitempty"`
}

Group is a routing group.

func AddTemplate added in v0.1.1163

func AddTemplate(kind, name string) (Group, error)

AddTemplate saves the template kind as the user's models make it now, as a group of the user's named name (the template's own name when empty), numbered past a name or id in use, so it never replaces a group there is. It is listed last, as a group made in the editor is.

func CopyGroup added in v0.1.1158

func CopyGroup(id, name string) (Group, error)

CopyGroup makes a group of the user's that is the group id as it is now (lc on Discord): its models and patterns, routing, rules, classifier, effort, context, levels, fast and off members, under name — "<name> copy" when empty, numbered past a name or id in use — listed right after the one it copies. A found group's copy is the user's, with the members it has now. The copy is on, whether the group was or not, and the original is left as it is.

func DisabledGroup added in v0.1.989

func DisabledGroup(id string) (Group, bool)

DisabledGroup is the group of the user's a model id names ("group/<id>", or a model's as GroupFor takes it) when it is switched off.

func GroupDisabledOut added in v0.1.1219

func GroupDisabledOut(id string) (Group, []string, bool)

GroupDisabledOut is the group id names when it has no model left only because the user disabled every one it would have (#1867), and those models: the gateway says so, not that the group is empty.

func Groups added in v0.1.38

func Groups() []Group

Groups lists the user's groups, then those magpie found, hidden ones too (marked so), in the order the user put them in (SetGroupOrder) where they did: the Routing page, the gateway's model list, the CLI and the TUI all list them so.

func GroupsWith added in v0.1.102

func GroupsWith(id string) []Group

GroupsWith are the groups that have the group id in them as a member.

func StoredGroups added in v0.1.76

func StoredGroups() ([]Group, error)

StoredGroups is the groups as saved: the user's own, and the found ones the user removed. As with Stored, a file that can't be read is an error.

func (Group) Decides added in v0.1.1170

func (g Group) Decides() bool

Decides reports whether g is a decision group: every model it names is a decision model.

func (Group) IsFast added in v0.1.577

func (g Group) IsFast(id string) bool

IsFast reports whether the group sends its member id fast.

func (Group) IsOff added in v0.1.688

func (g Group) IsOff(id string) bool

IsOff is whether the group's member id is switched off.

func (Group) Live added in v0.1.498

func (g Group) Live() Group

Live is the group as the gateway routes it: a manual group's rules wait (the member picked is all it sends to), though they are kept.

func (Group) MemberWeight added in v0.1.1224

func (g Group) MemberWeight(id string) int

MemberWeight is the share of the group's requests its member id takes when the group routes by weight (Group.Weights): 1 when none is set.

func (Group) Picked added in v0.1.498

func (g Group) Picked() string

Picked is the member a manual group sends to: the one the user picked while it is in the group, else its first.

func (Group) Ref added in v0.1.1294

func (g Group) Ref() string

Ref is the id agents pick the group by: auto/<model> for a group magpie found (one with an auto-… id whose members are that model), its model spelt as a vendor spells it; group/<id> for any other, and for every group while a provider of the user's is called auto.

func (*Group) RenameMember added in v0.1.577

func (g *Group) RenameMember(from, to string)

RenameMember has the group's member from go by to (its effort changed): its rules, its pick, its fast mode, its being off and its weight follow it.

func (Group) Ruled added in v0.1.142

func (g Group) Ruled() bool

Ruled reports whether the group decides anything as a user's turn begins: a rule to put a member first, or the turn's effort. A pause rule decides nothing then (PausedOut is looked at on every request).

func (*Group) SetMemberFast added in v0.1.577

func (g *Group) SetMemberFast(id string, fast bool)

SetMemberFast sends the group's member id fast, or not, where it is in the group.

func (*Group) SetMemberWeight added in v0.1.1224

func (g *Group) SetMemberWeight(id string, weight int)

SetMemberWeight sets the share the group's member id takes when the group routes by weight; 1 or less is the default, left out.

func (Group) Waits added in v0.1.1159

func (g Group) Waits() time.Duration

Waits is how long a request to the group may be kept for its members to come back (Patience), 0 for not at all.

type Imported added in v0.1.1181

type Imported struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	// Missing are the models and groups the text names that this magpie
	// has none of, left out of the group: members, and the classifier.
	Missing []string `json:"missing,omitempty"`
	// Instead are the members this magpie has under another provider: the
	// same model (AutoGroupOf), "shared → here".
	Instead []string `json:"instead,omitempty"`
	// Rules is how many of the group's rules were left out with the
	// member they send to, or the classifier their intent needs, or for
	// holding by a folder of the sharer's.
	Rules int `json:"rules,omitempty"`
}

Imported is what ImportGroup made of a shared group.

func ImportGroup added in v0.1.1181

func ImportGroup(text string) (Imported, error)

ImportGroup adds the group a shared text holds as a group of the user's, named as it was shared and numbered past a name or id in use, so it never replaces a group there is. It is listed last. A member this magpie has no provider of is the same model under one it has, where it serves it (Instead), else left out (Missing), and with it the rules that send to it and its place among the fast and off members. Nothing is added when none of its members is left.

type ImportedAccount added in v0.1.326

type ImportedAccount struct {
	// User is the account's email, or "#n" (its place in the file) when
	// the file doesn't say and Google wasn't asked or didn't answer.
	User string `json:"user"`
	// Status: "added", "updated" (in magpie already, now with this
	// sign-in), "exists" (in magpie already with this very sign-in),
	// "failed".
	Status string `json:"status"`
	Plan   string `json:"plan,omitempty"`
	Error  string `json:"error,omitempty"`
	// File is the place (from 1) of a file, among several imported at
	// once, that held no account to read: User is empty then, and Error
	// says why. A file that can't be read is said so, never passed over.
	File int `json:"file,omitempty"`
}

ImportedAccount is what became of one account in an import.

func ImportFactoryKeys added in v0.1.638

func ImportFactoryKeys(ctx context.Context, texts []string) ([]ImportedAccount, error)

ImportFactoryKeys adds Factory accounts by their API keys, found in the pasted texts, each checked with whoami first, and says what became of each.

func ImportGoogleAccounts added in v0.1.326

func ImportGoogleAccounts(ctx context.Context, agent string, files []string) ([]ImportedAccount, error)

ImportGoogleAccounts brings in the accounts in exports from other tools (see above), each file's text one element of files, and says what became of each.

func ImportLogins added in v0.1.401

func ImportLogins(ctx context.Context, agent string, files []string) ([]ImportedAccount, error)

ImportLogins brings in ChatGPT (agent "codex") or Claude ("claude") accounts from other tools' files (see above), each file's text one element of files, and says what became of each.

type KeyAccount added in v0.1.14

type KeyAccount struct {
	Name string `json:"name,omitempty"`
	Key  string `json:"key"`
	Off  bool   `json:"off,omitempty"`
	// Protocol, when set, is the only one the key works with: some relays
	// give out one key for Anthropic and another for OpenAI. Empty is any.
	Protocol Protocol `json:"protocol,omitempty"`
	// Weight is the key's share of the requests when the provider's
	// routing is Weighted (#841): one with 3 takes three for every one a
	// key with 1 takes. None, or 0, counts as 1.
	Weight int `json:"weight,omitempty"`
}

KeyAccount is a saved key after the first. Off keeps it without using it.

func (KeyAccount) WeightOf added in v0.1.933

func (k KeyAccount) WeightOf() int

WeightOf is the key's weight as Weighted routing counts it: 1 when none.

type KeyInfo added in v0.1.14

type KeyInfo struct {
	ID     string `json:"id"` // a fingerprint, to name it in a switch
	Name   string `json:"name,omitempty"`
	Masked string `json:"masked"`
	Active bool   `json:"active"` // the first, where requests go
	On     bool   `json:"on"`     // in use: the first, or next in line

	Protocol Protocol `json:"protocol,omitempty"` // the only one it works with
	Weight   int      `json:"weight,omitempty"`   // its share when routing is Weighted

	// Rest is why the gateway passes it over now, after a failure, and
	// until when; nil while it takes requests.
	Rest *KeyRest `json:"rest,omitempty"`
}

KeyInfo describes one of a provider's keys without giving it away.

type KeyRest added in v0.1.930

type KeyRest struct {
	Why    string    `json:"why"`
	Status int       `json:"status"`
	Until  time.Time `json:"until"`
	Key    string    `json:"key"`
}

KeyRest is a key's rest as the gateway keeps it: failQuota, failRate…, the status it answered, until when, and the key to lift it by.

type Kind

type Kind string

Kind groups presets in the picker.

const (
	KindVendor Kind = "vendor" // the model's own maker
	KindRelay  Kind = "relay"  // an aggregator / API relay reselling many vendors
	KindLocal  Kind = "local"  // something running on this machine
	// KindRemote is another computer's magpie: not a relay, so the add
	// lists give it a heading of its own, after this machine's
	KindRemote Kind = "remote"
)
const KindPartner Kind = "partner"

KindPartner is a partner's Kind: the add sheet lists them apart.

type KiroAuth added in v0.1.141

type KiroAuth struct {
	Token     string
	TokenType string // the tokentype header: API_KEY, EXTERNAL_IDP, or none
	Profile   string // the profile ARN
	Region    string // where the account's API is
}

KiroAuth is what a call to Kiro's API is made with.

func KiroAuthOf added in v0.1.141

func KiroAuthOf(ctx context.Context, key, home string, stale bool) (KiroAuth, error)

KiroAuthOf is a Kiro account's credentials: those of the key saved on the provider, of the account magpie signed in in home, or of Kiro's own sign-in when both are "". A token about to expire is refreshed first; stale, after Kiro turned one down, refreshes it now.

func (KiroAuth) Header added in v0.1.141

func (a KiroAuth) Header(h http.Header)

Header sets the headers that say who is calling.

type LeftRecord added in v0.1.1232

type LeftRecord struct {
	Package  string   `json:"package"`
	Provider Provider `json:"provider"`
}

LeftRecord is a record set aside when the plugin it was one of was removed: Package is the plugin's package name, as plugin.PackageName gives it.

type Limit added in v0.1.38

type Limit struct {
	Used   float64       // share used, 0–100
	Resets time.Time     // zero when not known
	Span   time.Duration // how long the window runs; zero when not known
	Model  string        // the only models it counts, by a word in their ids
	// Amount of Of in Unit: the window's own count, used, when the vendor
	// counts it so (QuotaWindow.Amount)
	Amount, Of float64
	Unit       string

	Name string // QuotaWindow.Name: which window it is, one reading to the next (WindowCapID)
	// ResetRunsOut is when the reset the account spends by itself before
	// it runs out does (resetRunsOut): spent then, it starts this window
	// again — at Restarts, which routing takes for the window's renewal
	// when it is the sooner. Zero when none will be spent so.
	ResetRunsOut time.Time
	// RunsOut is when the soonest of what the window has left is lost,
	// apart from its reset (QuotaWindow.RunsOutAt): zero when not known.
	RunsOut time.Time
	// Credits: the account goes on past this window on its credits
	// (QuotaWindow.Credits)
	Credits bool
	// contains filtered or unexported fields
}

Limit is one window of an allowance.

type Login added in v0.1.11

type Login struct {
	Agent  string    `json:"agent"`
	User   string    `json:"user"`
	Plan   string    `json:"plan,omitempty"`
	Seen   time.Time `json:"seen"`
	Active bool      `json:"active"` // the agent is signed in to this one now
	On     bool      `json:"on"`     // in use: the active one, or next in line
	// Lapsed says the vendor refused to refresh a saved account's sign-in:
	// it has to be signed in again before it can be used.
	Lapsed string `json:"lapsed,omitempty"`
	// Own is the agent's own sign-in, which magpie only reads: removed, it
	// is hidden rather than deleted (side_logins.go).
	Own bool `json:"own,omitempty"`
	// Paused is the account the agent is signed in to, passed over by the
	// gateway while another is on (savedLogin.Paused).
	Paused bool `json:"paused,omitempty"`
	// Returns is the account magpie signed the agent out of when it was
	// spent, and signs it back in to once it has room again (#408).
	Returns bool `json:"returns,omitempty"`
	// contains filtered or unexported fields
}

Login is a remembered subscription account, without its secrets.

func Logins added in v0.1.11

func Logins(agent string) []Login

Logins lists the remembered accounts of an agent ("" for every one), the active one flagged.

type Member added in v0.1.38

type Member struct {
	ID string // the group's member it is: the model, or the group in the group it is of
	// Path is the members from the group's own down to the model: [ID] for
	// a model the group names itself, ["group/fast", "a/m"] for one of
	// its group fast, and so on down.
	Path []string
	// Via are the groups in the group it is of, the outermost first: the
	// group each of Path's members but the last names.
	Via      []Group
	Provider Provider
	Model    string // what the vendor is asked for
	// Effort is the reasoning the member is fixed at ("provider/model:low"),
	// asked of the model whatever the agent or the group's classifier
	// asked; "" follows the group.
	Effort string
	// Fast is set on a member the group sends in its vendor's fast mode
	// (Group.Fast), where its model has one.
	Fast bool
	// At is where the walk down the group met it, counting every model of
	// every group in it, the same model's later places too: a group's own
	// models are met in its own order.
	At int
	// Also are the other places further down the walk that have the same
	// model at the same effort, which the group asks once, where it was
	// met first: a rule naming a later group in the group still has it,
	// in that group's own order (#2361).
	Also []Member
}

Member is one of a group's models as it resolves now.

func (Member) Below added in v0.1.102

func (m Member) Below(depth int) Member

Below is the member as the group at depth (0 the group itself, 1 the group in it Path[0] names, …) has it.

func (Member) Groups added in v0.1.102

func (m Member) Groups() []string

Groups are the ids of the groups in the group the model is of, the outermost first.

func (Member) Homed added in v0.1.1258

func (m Member) Homed(path []string) (Member, bool)

Homed is the member as the place under the members path names (the group's member ids from the top) has it, its others in Also; ok is false when none of its places is there.

func (Member) In added in v0.1.1258

func (m Member) In(id string) (Member, bool)

In is the member as the group's member id has it: itself, where it was met further down the walk (Also), or, for a model, where a group in the group ahead of it has it too (#625). ok is false when id isn't one of its places.

type Migration added in v0.1.506

type Migration struct {
	State   string    `json:"state"`
	Package string    `json:"package,omitempty"`
	At      time.Time `json:"at"`
	Err     string    `json:"error,omitempty"`
	// Accounts are the plugin's accounts the move made or took over.
	Accounts []movedAccount `json:"accounts,omitempty"`
	// Backup is the built-in's accounts as logins.json kept them.
	Backup []savedLogin `json:"backup,omitempty"`
	// Kept is what else of the built-in's the move set aside (Kiro's key).
	Kept json.RawMessage `json:"kept,omitempty"`
	// Installed is whether the move installed the plugin: a failed move
	// takes it away again.
	Installed bool `json:"installed,omitempty"`
	// Host is the built-in's API host, which the plugin's provider shows.
	Host string `json:"host,omitempty"`
	// Why is a failed move's reason, for the page to say in the user's
	// language.
	Why *MoveWhy `json:"why,omitempty"`
}

Migration is where one built-in's move stands.

func MigrationOf added in v0.1.506

func MigrationOf(id string) (Migration, bool)

MigrationOf is where the built-in id's move stands.

type ModelDetection added in v0.1.671

type ModelDetection struct {
	Model   string      `json:"model"`
	Results []Detection `json:"results"`
}

ModelDetection is what each API answered for one model (01huadalang on Discord: 应该能看出来选择的模型支持情况…有的仅支持 response 有的双协议).

type ModelList added in v0.1.1133

type ModelList struct {
	// Visible is what its lists are narrowed to; nil when they aren't.
	Visible *[]string `json:"visible,omitempty"`
	Hidden  []string  `json:"hidden,omitempty"`
	// Only: it is shown only Picked, none when Picked is empty.
	Only   bool     `json:"only,omitempty"`
	Picked []string `json:"picked,omitempty"`
	Order  []string `json:"order,omitempty"`
}

ModelList is everything that decides which of magpie's models an agent's lists show, and in what order, as a profile keeps it (#1368): its visibility (Visible), the models taken out one by one (HiddenModels) or, for an agent shown only its picks, the ones picked (PickedModels), and the order it was put in (OrderedModels). The fast picks are not here: they say how a model is sent, not whether it is listed.

func ModelListOf added in v0.1.1133

func ModelListOf(agent string) ModelList

ModelListOf is agent's model list as it is now.

func (ModelList) Default added in v0.1.1133

func (l ModelList) Default() bool

Default reports whether l is what an agent never picked for is shown: every model, in magpie's own order.

type ModelPref added in v0.1.648

type ModelPref struct {
	Name    *string   `json:"name,omitempty"`
	Efforts *[]string `json:"efforts,omitempty"`
	// Reasonless, set, is SetModelReasonless's word: true for no
	// reasoning ask, false to take that back
	Reasonless *bool          `json:"reasonless,omitempty"`
	Images     *bool          `json:"images,omitempty"`
	OwnImages  bool           `json:"ownImages,omitempty"`
	API        *string        `json:"api,omitempty"`
	Same       *string        `json:"same,omitempty"`
	Price      *catalog.Price `json:"price,omitempty"`
	OwnPrice   bool           `json:"ownPrice,omitempty"`
	// Kind is what the model makes, as SetModelKind takes it: "image",
	// "video", or "" for what its vendor's list and name say (#1399)
	Kind *string `json:"kind,omitempty"`
}

ModelPref is what the provider editor's Names & levels changed of one model, sent with its Save: each part left nil is as it was. Name "" gives the model its own name back, Efforts [] all its levels, OwnImages the vendor's answer for whether it sees images, API "" every API the provider has for it, Same "" its own id to merge it with other vendors' by (see setModelSame), OwnPrice its list price again in place of Price, what the user said it costs (SetModelPrice, #819), and Kind "" what its vendor's list says it makes (SetModelKind, #1399).

type MoveCandidate added in v0.1.552

type MoveCandidate struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Package  string `json:"package"`
	Accounts int    `json:"accounts"`
	// Error and Why are the last try's failure, when one failed
	Error string   `json:"error,omitempty"`
	Why   *MoveWhy `json:"why,omitempty"`
}

MoveCandidate is a built-in with accounts its plugin could run instead.

func MoveCandidates added in v0.1.552

func MoveCandidates() []MoveCandidate

MoveCandidates are the built-ins not on their plugins that have accounts to move, by name.

type MoveWhy added in v0.1.552

type MoveWhy struct {
	Code string            `json:"code"`
	Args map[string]string `json:"args,omitempty"`
}

MoveWhy is why a move didn't go through: Code names the case, Args fill in its sentence.

offline   magpie couldn't reach npm (or Bun's download) to install the plugin
install   npm couldn't install it: line

An older magpie also failed a move for an account (lapsed, unserved, account), which the page still reads from migrations.json; since the built-ins are retired every account goes along.

func WhyOf added in v0.1.552

func WhyOf(err error) *MoveWhy

WhyOf is the reason a move failed, nil for one it has no words for.

type Moving added in v0.1.506

type Moving struct {
	User      string
	First, On bool
	// Lapsed is an account the vendor already refused: it goes along, but
	// isn't tried.
	Lapsed bool
	// Plan is the plan the account showed, kept beside it until the
	// plugin tells it anew.
	Plan string
	// Own is the agent's own sign-in (its CLI's, its app's), which the
	// plugin reads where the agent keeps it, as the built-in did.
	Own  bool
	Auth map[string]any
}

Moving is one of a built-in's accounts on its way to the plugin.

type Partner added in v0.1.1122

type Partner struct {
	PresetDef
	// IconURL is the partner's logo, kept beside the user's own pictures
	// and shown as Icon.
	IconURL string `json:"iconUrl,omitempty"`
	// Notes is the tagline by language ("en", "zh", "zh-TW", "ja", ...);
	// "en" stands in for a language without one.
	Notes map[string]string `json:"notes,omitempty"`
	// Langs, when set, are the only languages the partner is listed in.
	Langs []string `json:"langs,omitempty"`
	// From and Until bound when it is listed; zero is unbounded.
	From  time.Time `json:"from,omitzero"`
	Until time.Time `json:"until,omitzero"`
}

Partner is one entry of the list: a preset, its tagline in each language, the languages it is shown in, and when it is shown.

func Partners added in v0.1.1122

func Partners() []Partner

Partners are the partners listed now, in the list's order: what was fetched last, never waited for. A list this process hasn't fetched, or fetched an hour ago, is fetched again behind the call, and the page asked again shows it.

func PartnersNow added in v0.1.1122

func PartnersNow(wait time.Duration) []Partner

PartnersNow is Partners for a command that ends at once, before a fetch behind it could: a list due is fetched first, waited for at most wait.

func (Partner) Live added in v0.1.1122

func (p Partner) Live(now time.Time) bool

Live reports whether the partner is listed at now.

type PartnerCount added in v0.1.1126

type PartnerCount struct {
	Day   string `json:"day"` // 2006-01-02, UTC
	ID    string `json:"id"`
	What  string `json:"what"`
	Count int    `json:"count"`
}

PartnerCount is one day's count of one kind for one partner.

func PartnerCounts added in v0.1.1126

func PartnerCounts(now time.Time) []PartnerCount

PartnerCounts are the counts of the days before today, to be sent.

type PatternHit added in v0.1.826

type PatternHit struct {
	Pattern string `json:"pattern"`
	Models  int    `json:"models"`
}

PatternHit is one of a group's patterns and how many of the models served now it matches.

func PatternHits added in v0.1.826

func PatternHits(g Group) []PatternHit

PatternHits are the group's patterns, each with the number of models it matches now — those the group names itself as well — so that one that matches nothing is said, not left an empty group.

type Paused added in v0.1.1155

type Paused struct {
	Member string   `json:"member"`          // "provider/model[:effort]"
	Group  string   `json:"group,omitempty"` // the group in the group whose rule it is; "" the group's own
	Rule   int      `json:"rule"`            // the rule, from 1
	Use    string   `json:"use"`             // the member the rule names: the model, or a group in the group
	When   []string `json:"when"`
	// Folder: the folder the agent said it works in, when the rule holds
	// by folder (ByFolder); "" when it said none, which is outside every
	// folder of a rule's ExceptFolders.
	Folder   string `json:"folder,omitempty"`
	ByFolder bool   `json:"byFolder,omitempty"`
}

Paused is a model a pause rule left out of a request's group.

type PluginCheckin added in v0.1.1085

type PluginCheckin struct {
	ID       string             `json:"id"`
	Name     string             `json:"name"`
	On       bool               `json:"on"`
	Checkins []WorkBuddyCheckin `json:"checkins,omitempty"`
}

PluginCheckin is a plugin's provider that checks in, for Settings: its switch and how each account's last check-in went.

func PluginCheckins added in v0.1.1085

func PluginCheckins() []PluginCheckin

PluginCheckins are the plugins' providers that check in, each with its accounts' last check-ins as kept; asks nothing.

type PresetDef

type PresetDef struct {
	ID        string   `json:"id"`
	Name      string   `json:"name"`
	Icon      string   `json:"icon"`
	Kind      Kind     `json:"kind"`
	Chat      string   `json:"chat,omitempty"`
	Responses string   `json:"responses,omitempty"`
	Anthropic string   `json:"anthropic,omitempty"`
	Decide    string   `json:"decide,omitempty"` // a decision API: the provider only routes (see decide.go)
	Catalog   string   `json:"catalog,omitempty"`
	Website   string   `json:"website,omitempty"`
	SiteHost  string   `json:"siteHost,omitempty"` // a partner's: the host its usemagpie.ai/go Website sends the browser to, which the editor's link reads
	KeysURL   string   `json:"keysUrl,omitempty"`
	NoKey     bool     `json:"noKey,omitempty"`     // local servers: a key is optional
	KeyHint   string   `json:"keyHint,omitempty"`   // the key field's placeholder, when it says more than NoKey's
	Sponsored bool     `json:"sponsored,omitempty"` // shown first, with a tag
	Note      string   `json:"note,omitempty"`      // one line under the name
	Short     string   `json:"short,omitempty"`     // the add sheet's name for it, when Name is long
	Regions   []Region `json:"regions,omitempty"`   // base-URL choices (a relay's regional endpoints, a vendor's plans)
	// RegionLabel names what the Regions choose between, "Region" if unset.
	RegionLabel string `json:"regionLabel,omitempty"`
	// HeaderHints name optional request headers the vendor documents, which
	// the editor offers to add; their values are the user's to fill in.
	HeaderHints []string `json:"headerHints,omitempty"`
	// Only, for a plan behind a key that also buys much else, is what its
	// models' ids start with: the rest of the vendor's list is left out.
	// Models are the plan's, for when the list has none of them.
	Only   string   `json:"only,omitempty"`
	Models []string `json:"models,omitempty"`
	// NoList: the vendor has no list of models to ask for (Bedrock's
	// runtime serves no /models), so Models are its list
	NoList bool `json:"noList,omitempty"`
	// Endpoint, for a vendor reached at the user's own resource (Azure
	// OpenAI), is an example of its address: the preset gives no URL, and
	// the editor asks for the one the user's resource is at, with
	// EndpointHint under it.
	Endpoint     string `json:"endpoint,omitempty"`
	EndpointHint string `json:"endpointHint,omitempty"`
	// EndpointNeeded is what the editor says when no endpoint was given.
	EndpointNeeded string `json:"endpointNeeded,omitempty"`
	// Hosts: a vendor serving other makers' models as well as its own
	// (Groq, Ollama Cloud, Azure), whose list is no maker's word on theirs
	Hosts bool `json:"-"`
}

PresetDef describes one preset.

func AtAddress added in v0.1.1224

func AtAddress(pr PresetDef, addr string) (PresetDef, error)

AtAddress is pr reached at addr: the scheme, host and port of each of its URLs replaced by addr's, its decision API's (oMLX's System One, #1641) among them, which the same server serves. An empty addr leaves pr as it is.

func Preset

func Preset(id string) *PresetDef

Preset finds a preset by id, or by an id it carried before (presetAliases), or a partner listed now or before (partners.go).

func Presets

func Presets() []PresetDef

Presets lists every preset, sponsored ones first within their kind.

type Protocol

type Protocol string

Protocol is a wire API magpie can speak to an upstream.

const (
	Chat      Protocol = "chat"      // OpenAI Chat Completions
	Responses Protocol = "responses" // OpenAI Responses
	Anthropic Protocol = "anthropic" // Anthropic Messages
	Gemini    Protocol = "gemini"    // Google Gemini's generateContent: served to clients; spoken upstream at a custom provider's Gemini URL, Vertex AI and Factory's generate route
)
const CodeAssist Protocol = "codeassist"

CodeAssist is Google's Code Assist API, which magpie only speaks upstream, to a Gemini CLI or Antigravity account. Not in Protocols: no other provider serves it.

type Provider

type Provider struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	// Was are ids the provider had before it was renamed (see Rename):
	// a model still picked by one of them reaches it.
	Was    []string `json:"was,omitempty"`
	Icon   string   `json:"icon,omitempty"`
	Preset string   `json:"preset,omitempty"` // preset this was created from, if any
	Key    string   `json:"key"`              // API key, as typed by the user

	// AccessKeyID and SecretAccessKey are a Volcengine account's access
	// key (TakesVolcAccessKey), what Ark tells its Coding or Agent Plan's
	// windows to (volcengine_usage.go), or a Tencent Cloud account's API
	// key, its SecretId and SecretKey (TakesTencentAccessKey), what TokenHub
	// tells Token Plan 企业版's usage to (tencent_usage.go); not the plan's
	// inference key in Key. They are kept, backed up and synced as the keys are: the Secret
	// is never sent to the GUI, and a backup without keys has neither.
	AccessKeyID     string `json:"accessKeyID,omitempty"`
	SecretAccessKey string `json:"secretAccessKey,omitempty"`

	// KeyName names the key in use, and Keys are the provider's other
	// accounts: keys saved to switch to (see keys.go).
	KeyName string       `json:"keyName,omitempty"`
	Keys    []KeyAccount `json:"keys,omitempty"`
	// KeyProtocol, when set, is the one protocol the first key is good
	// for: a relay that hands out one key for Anthropic and another for
	// OpenAI (see KeyAccount.Protocol).
	KeyProtocol Protocol `json:"keyProtocol,omitempty"`
	// KeyWeight is the first key's weight (see KeyAccount.Weight).
	KeyWeight int `json:"keyWeight,omitempty"`

	// Base URLs, one per protocol the vendor serves natively. magpie appends
	// the usual paths: chat/responses bases end in /v1 (OpenAI style),
	// the Anthropic base is the root (what ANTHROPIC_BASE_URL takes).
	Chat      string `json:"chat,omitempty"`
	Responses string `json:"responses,omitempty"`
	Anthropic string `json:"anthropic,omitempty"`
	// Gemini is the base of Google's Gemini API, or of one that answers as
	// it does (…/v1beta): models/{model}:streamGenerateContent is asked
	// under it, with the key in x-goog-api-key, and models under it lists
	// them (#1346).
	Gemini string `json:"gemini,omitempty"`
	// Decide is the base of a decision API (TypeSafe's System One, which
	// Jev answers), for routing groups' choices of model and effort. The
	// provider may also serve conversations on the other endpoints.
	Decide string `json:"decide,omitempty"`
	// BaseAPI is the API the user gave a custom provider's Base URL as,
	// in its editor: "chat", "responses", "anthropic", "gemini" or "decide". The
	// editor shows that pick again, where it would otherwise show the
	// first API with a URL (01huadalang: Responses picked and saved came
	// back as OpenAI compatible). Requests go by which URLs are set.
	BaseAPI string `json:"baseAPI,omitempty"`

	// Fallback is where a request goes when this provider can't take it —
	// out of quota, rate limited, overloaded or down — before any of the
	// reply has been sent: models as agents pick them (provider/model),
	// tried in order.
	Fallback []string `json:"fallback,omitempty"`

	// Routing is how requests spread over the keys or accounts it has on:
	// "" smart, the first while it has quota to spare, then whichever has
	// the most; "order" in order, the next one only when the one before
	// can't take it; "rotate" each in turn; "usage" the least used first;
	// "pace" the one with the most remaining allowance per hour until
	// its window resets first, so less allowance is lost at reset.
	// The window can be shorter than a week. "weight" by each key's
	// weight, a key with 3 taking three requests to one with 1's.
	// Whichever it is, one out of credit, out of quota, rate limited or
	// failing is passed over for as long as that lasts.
	Routing string `json:"routing,omitempty"`

	// Sink sends a key or account that a 429 rate limited while it still
	// had quota to the back of the order Routing gives (01huadalang): it
	// is tried again only after every one not rate limited since — so the
	// load goes round, rather than back to the first each time its rest
	// ends. Off, the default, it keeps its place. Not for "rotate", which
	// goes round already. See gateway.sink.
	Sink bool `json:"sink,omitempty"`

	// Affinity is how long a conversation stays with the key or account
	// that answered it, so the vendor's prompt cache it filled is read
	// again rather than lost (see Affinities): "" auto, "session",
	// "turn", "off", "strict".
	Affinity string `json:"affinity,omitempty"`

	// KeepLogin, on Codex's or Claude Code's subscription, keeps the agent
	// signed in to the account the user made first: magpie doesn't sign it
	// in to another when that one runs low or out (#524). The gateway still
	// spreads its requests over the accounts that are on, as Routing says.
	KeepLogin bool `json:"keepLogin,omitempty"`
	// KeepLoginAs, with KeepLogin, is the account the agent is kept signed
	// in to whichever is first in the order the gateway tries them: the one
	// the user uses the agent as, while the first is only the one whose
	// allowance is spent first (#524). Empty, it is the first.
	KeepLoginAs string `json:"keepLoginAs,omitempty"`
	// SwitchOnly, on Codex's subscription, has magpie only move Codex's
	// own sign-in (auth.json) to the next account with room and back:
	// Codex's requests then go straight to OpenAI, never through the
	// gateway for account failover, however many of its accounts are on
	// (#1907).
	SwitchOnly bool `json:"switchOnly,omitempty"`

	// MaxConcurrency is how many requests may be out at the vendor at once
	// on each of its keys or accounts (Discord, Lemon: a Codex account is
	// risk-controlled past five or six at once); the rest wait their turn,
	// in the order they came (see Concurrency). nil follows what a
	// plugin's provider says it takes, else none; 0 is no limit.
	MaxConcurrency *int `json:"maxConcurrency,omitempty"`
	// AccountConcurrency is, for one account or key, its own limit over
	// MaxConcurrency (#892): an account by its name in lower case, a key
	// by its KeyID; 0 there is no limit for it. One not in it takes the
	// provider's (see LaneLimit).
	AccountConcurrency map[string]int `json:"accountConcurrency,omitempty"`
	// QueueLimit is how many requests may wait for a slot of each key or
	// account at once (#892); one more is turned away as the queue being
	// full. 0 is no bound.
	QueueLimit int `json:"queueLimit,omitempty"`
	// QueueWait is how long, in seconds, a request waits for a slot before
	// it is turned away as having waited too long (#892). 0 waits as long
	// as it takes.
	QueueWait int `json:"queueWait,omitempty"`
	// MaxRPM is how many requests a minute each of its keys or accounts
	// sends the vendor, over a rolling 60 seconds (coeo91 on Discord:
	// OpenRouter's free models take 20 a minute, which a limit at once
	// can't keep to); one more waits for room (see RPMLimit). 0 is no
	// limit.
	MaxRPM int `json:"maxRPM,omitempty"`
	// QuotaRest is how many minutes one of its keys sits out once the
	// vendor says it is out of its allowance without saying when it is
	// back (#1772: Ollama Cloud's weekly limit); 0 is the gateway's own
	// quarter of an hour. A time the vendor names stands over it.
	QuotaRest int `json:"quotaRest,omitempty"`
	// QuotaResetAt is the time of day a key of it out of its allowance is
	// back, when its vendor refuses for a day's allowance without saying
	// when (#2008: a free tier's "today's free-model token quota"): "08:00"
	// on this computer's clock, or "00:00+08:00" on the vendor's. Set, it
	// stands over QuotaRest; a time the vendor names stands over both.
	QuotaResetAt string `json:"quotaResetAt,omitempty"`
	// RestCap is the most, in minutes, one of its keys or accounts sits
	// out while it keeps failing or keeps being rate limited as soon as
	// its rest is over (#2008); 0 is the gateway's own, 10 minutes for a
	// failure and 30 for a rate limit. The vendor's own "try again in"
	// still stands over it. RestCapOff (-1): no rest at all after a
	// failure that says nothing of why, a rate limit's as the gateway's own.
	RestCap int `json:"restCap,omitempty"`

	// PriceRate is what the provider charges against the official price
	// (ITea312, #819): a relay that bills 0.8× or 1.5× of it. It scales the
	// provider's list price, else its maker's, wherever a cost is counted;
	// a price the user set for one of its models stands as set. 0 is the
	// price as listed; at most three decimals (PriceRateOK).
	PriceRate float64 `json:"priceRate,omitempty"`

	// Headers are extra HTTP request headers sent to the vendor, exactly as
	// the user typed them. They ride on every request magpie makes to a plain
	// key+URL provider — forwarded calls, connectivity tests, and model-list
	// fetches — applied after the auth headers, so the user can override those
	// when a gateway insists on a private scheme. Signed-in agent accounts
	// ignore them: their auth is the agent's own.
	Headers map[string]string `json:"headers,omitempty"`

	// ExtraBody are JSON fields added to the body of every request to the
	// vendor (#1604), filling in what the body lacks, or replacing it for a
	// name written "!name"; ${sessionId} in a value is the conversation's
	// id (extrabody.go). Signed-in agent accounts ignore it, as Headers.
	ExtraBody ExtraBody `json:"extraBody,omitempty"`

	// Searches says the vendor answers a web search tool offered on its
	// Anthropic or Responses API by itself (web_search_20250305,
	// web_search): a relay in front of Anthropic's or OpenAI's API, which
	// magpie can't tell from its host. A request offering one then goes to
	// it as the client sent it, rather than given magpie's search (#359).
	Searches bool `json:"searches,omitempty"`

	// CodexAsSent has a request Codex sends on the Responses API go to it
	// as Codex sent it, its model name alone swapped: a relay that checks
	// it is Codex's own (#1758: "Codex 客户端请求特征无效", 10014), which
	// the shape magpie fits it to for another backend (Responses Lite's
	// additional_tools lifted into tools, the tool search as a function,
	// OpenAI-only fields left out) fails. Off, the default, keeps that
	// fitting, which a backend that isn't OpenAI's needs (#350).
	CodexAsSent bool `json:"codexAsSent,omitempty"`

	// AdditionalTools says the provider's Responses API takes an
	// additional_tools input item, as OpenAI's does: a deferred tool an
	// Anthropic client's tool search loaded goes to it in such an item
	// where the search loaded it, not in the top-level tools, which keeps
	// the prompt's cached prefix (#2660). OpenAI's own API is sent one
	// without it; another vendor isn't unless this is set, since xAI's
	// turns the item away (#350).
	AdditionalTools bool `json:"additionalTools,omitempty"`

	// NativeCompaction has Codex's compaction_trigger go to the provider
	// as Codex sent it, and the compaction the provider writes back go to
	// Codex as it came (#1099), where magpie otherwise asks the model for
	// a summary and hands Codex that (its "magpie1:" compaction). Only a
	// provider whose wire carries it takes it (CarriesCompaction): a
	// Responses API (Sub2API, a remote magpie), a ChatGPT account, GitHub
	// Copilot's GPT models. Such a compaction is sealed by the key or
	// account that wrote it, so its conversation stays there, or is
	// refused, never sent elsewhere to be dropped. Off, the default,
	// keeps magpie's summary.
	NativeCompaction bool `json:"nativeCompaction,omitempty"`

	// PassUserAgent has a request go to the vendor with the User-Agent the
	// agent that sent it gave (pi, opencode, Claude Code…), in place of
	// magpie's own (#1851): a coding plan that serves only agents it names
	// knows them by it. One the agent didn't give, or magpie's own
	// requests, go as magpie. Off, the default, every request goes as
	// magpie. Only a key+URL provider takes it: a signed-in account, a
	// plugin's and one that goes as a client of its vendor's own keep the
	// identity their signing gives (see PassesUserAgent).
	PassUserAgent bool `json:"passUserAgent,omitempty"`

	// PinUpstream, on the Cline API, has its DeepSeek models answered only
	// by DeepSeek's own API (White Immortal on Discord) and its GLM models
	// only by Z.ai's (sdytman on Discord): Cline routes a model through an
	// AI gateway that may serve it from any host, and the maker's own
	// keeps its prompt cache. See ClinePin.
	PinUpstream bool `json:"pinUpstream,omitempty"`

	// AuthHeader is which header the key goes in on a third-party
	// Anthropic API, which is sent both x-api-key and Authorization:
	// Bearer by default (AuthBoth). A vendor that refuses the two together
	// (Aloha on Discord: "x-api-key 和 Authorization 不可以同时存在") is
	// sent one, AuthXAPIKey or AuthBearer: picked in the editor, or
	// learned from that refusal (RetryOneAuth). Anthropic's, Bedrock's and
	// Azure's own APIs, which take x-api-key alone, ignore it.
	AuthHeader string `json:"authHeader,omitempty"`

	// Unredacted has requests to a provider on this machine or the local
	// network (Ollama, LM Studio, a vLLM box) go as the agent wrote them,
	// unmasked by Settings' redaction, which keeps secrets from vendors
	// (lc on Discord). It is the user's word, not the address's: a relay
	// run locally, or Ollama's cloud models, pass a request on to a vendor.
	// See SkipsRedaction.
	Unredacted bool `json:"unredacted,omitempty"`

	// InsecureTLS has magpie take the certificate of the provider's own
	// HTTPS host as it is, unchecked (#2383, fangzhengjin: a vLLM on the
	// LAN, Ollama behind a self-signed cert). Only a provider the user
	// added takes it (TakesInsecureTLS), and only for the hosts of its own
	// base URLs (UncheckedHosts); see Via.
	InsecureTLS bool `json:"insecureTLS,omitempty"`

	// Proxy is the proxy magpie's requests to this provider go through
	// (#237: Codex through one, a vendor at home without): "" follows
	// the global one (Settings' Proxy, the environment's, the system's),
	// "direct" none, anything else the proxy's address (http://, https://,
	// socks5://; host:port means http). Signed-in accounts keep it too.
	Proxy string `json:"proxy,omitempty"`
	// AccountProxies is, for a provider holding several accounts or keys
	// (Codex's accounts, a relay's keys…), the proxy of each one that has
	// one of its own, as Proxy takes one: an account by its name in lower
	// case, a key by its KeyID. One not in it follows Proxy (see
	// ProxyChoice).
	AccountProxies map[string]string `json:"accountProxies,omitempty"`
	// AccountModels is, for a provider holding several accounts or keys,
	// the models each one the user narrowed serves, and no others (#474):
	// an account by its name in lower case, a key by its KeyID. One not in
	// it serves every model the provider does (see account_models.go).
	AccountModels map[string][]string `json:"accountModels,omitempty"`
	// AccountCaps is, for a subscription, the share (1–99) of its usage
	// windows each account the user capped is used to at most, by its name
	// in lower case: past it, routing takes the account for used up until
	// the window renews (see account_caps.go). One not in it has no cap.
	AccountCaps map[string]int `json:"accountCaps,omitempty"`
	// AccountWindowCaps is, for a subscription, the share of each usage
	// window an account is used to at most where the user set one for that
	// window apart (willz on Discord), by the account's name in lower case
	// and then the window's WindowCapID: 1–99, or 100 for none on it. A
	// window not in it takes the account's AccountCaps.
	AccountWindowCaps map[string]map[string]int `json:"accountWindowCaps,omitempty"`
	// AccountNames is, for a subscription, the name the user gave each
	// account they named (#1515: a team's seats told apart by who holds
	// them, not by a masked email), by the account's name in lower case.
	// It is magpie's own: the vendor's or plugin's sign-in never sees it
	// (see account_names.go).
	AccountNames map[string]string `json:"accountNames,omitempty"`

	// BalanceURL, when set, is where the vendor tells what is left on a
	// key, asked with the key the way a chat request carries it; BalancePath
	// picks the amount out of the JSON reply (see balance.go). The vendors
	// magpie knows need neither.
	BalanceURL  string `json:"balanceURL,omitempty"`
	BalancePath string `json:"balancePath,omitempty"`
	// BalanceMethod is how BalanceURL is asked: "" (or GET), or POST with
	// no body, for an endpoint that answers only a POST (#2368). Any other
	// is refused when the balance is read (balanceMethodOf).
	BalanceMethod string `json:"balanceMethod,omitempty"`
	// BalanceToken is what a vendor tells the whole account's balance to,
	// where a key is told only what is left on itself: AiHubMix's system
	// access token, or a new-api relay's for its /api/user/self named in
	// BalanceURL (see TakesBalanceToken). It is asked with nothing else but
	// the provider's headers, when the endpoint is one named.
	BalanceToken string `json:"balanceToken,omitempty"`
	// ZhipuTeam, for a Zhipu or Z.ai key on a team's GLM Coding Plan, is
	// the team's organization and project, from the BigModel console: the
	// team's windows are told to the key only with them (see
	// zhipuKeyTeamWindows). nil for a key of the user's own plan.
	ZhipuTeam *ZhipuTeam `json:"zhipuTeam,omitempty"`
	// Vertex, for a Google Vertex AI provider, is the project and location
	// its requests go to and the Google credentials that sign them, in
	// place of a key (see vertex.go).
	Vertex *Vertex `json:"vertex,omitempty"`

	// ModelsURL, when set, is where the vendor lists its models, for one
	// that lists them away from the base URL requests go to (Xiaomi MiMo's
	// plans are served at their own hosts, the list at api.xiaomimimo.com).
	ModelsURL string `json:"modelsURL,omitempty"`

	// Models the user chose to expose. Empty means "the preset's picks, or
	// everything the vendor lists when that list is short" — unless NoModels.
	Models []string `json:"models,omitempty"`
	// NoModels is the user's Select none (#1818): with no Models picked,
	// none of its models are served — not to agents, not to any routing
	// group, not by a "provider/model" id — while its balance and usage
	// are still read and shown. Without it, no picks is the vendor's list
	// as ever, so a file saved before it reads as it did. A pick clears it.
	NoModels bool `json:"noModels,omitempty"`
	// PickedFrom are the models the vendor listed when Models were saved: one
	// listed since is served beside picks that held every one listed then
	// (withNewlyListed), and one listed then and left unpicked stays out.
	PickedFrom []string `json:"pickedFrom,omitempty"`
	// Delisted are picks the provider's list stopped listing (dropGonePicks):
	// out of Models, so not served, until a list has them again, when they
	// go back among the picks (relistPicks). A plugin's list shrinks for a
	// while and comes back (多喝热水 on Discord: Our Free Model lists its
	// account channels' models only once its service has read them after a
	// restart, and a free pool it finds down leaves its list until it is
	// up), and the user's picks came back with it no more. Every save keeps
	// it but for what it picks again; Select none clears it.
	Delisted []string `json:"delisted,omitempty"`
	// RefreshEvery, for a provider of the user's own, is how often the
	// gateway fetches its model list by itself ("6h", "1d"; none, only when
	// asked), as Fetch models does (#2135). See autolist.go.
	RefreshEvery string `json:"refreshEvery,omitempty"`
	// AutoInclude are patterns over a model's id (a glob with *, or a
	// regular expression after "re:"): a model a fetch newly lists that one
	// matches joins Models, beside the picks already there (#2135).
	AutoInclude []string `json:"autoInclude,omitempty"`
	// Unlisted keeps the provider's own models out of the list agents see:
	// it serves only through the routing groups it is in, and by its
	// "provider/model" ids.
	Unlisted bool `json:"unlisted,omitempty"`
	// Off switches the provider off without removing it: its keys and
	// settings stay, but agents aren't given its models, no request,
	// routing group or fallback goes to it, and its balance isn't asked,
	// until it is switched on again (#163) — for a key out of quota.
	Off bool `json:"off,omitempty"`
	// Contexts is how long a request the user says a model takes, in
	// tokens, over what the vendor or models.dev says: by model id, "*"
	// for all the provider's models. Agents are told it.
	Contexts map[string]int `json:"contexts,omitempty"`
	// Family is a tag the provider's models go by in which agents are
	// shown them (settings' Visible), with the provider's id.
	Family string `json:"family,omitempty"`

	Catalog string `json:"catalog,omitempty"` // models.dev id, for names and reasoning levels
	Website string `json:"website,omitempty"`
	KeysURL string `json:"keysUrl,omitempty"`

	// IconURL is a picture the vendor named in an import link, to be fetched
	// once the user confirms. It is only a carrier between parsing and that
	// fetch: Save drops it, so it never reaches providers.json.
	IconURL string `json:"iconUrl,omitempty"`

	// Hidden is set on an account the user removed from magpie; the
	// agent stays signed in, magpie just leaves it alone.
	Hidden bool `json:"hidden,omitempty"`
	// Quiet is set on a removed account whose "Add it back" line the user
	// dismissed: it is offered again only from the Add sheet (#116).
	Quiet bool `json:"quiet,omitempty"`
	// Tucked is set on a quiet one the user hid from the Add sheet too:
	// it is listed there only behind "Show N hidden", or when searched
	// for by name (#116).
	Tucked bool `json:"tucked,omitempty"`

	// Account is set when the provider is an agent the user signed in to
	// (see account.go); it is derived, never stored.
	Account *Account `json:"-"`
}

Provider is one configured vendor.

func Accounts

func Accounts() []Provider

Accounts lists the signed-in agents as providers.

func All

func All() []Provider

All lists the configured providers in the order they were added, then the signed-in agents. An entry in the file with no URL is only the model picks for one of those accounts. A request that holds the catalog (Hold) builds it once: each build reads every agent's sign-in, a keychain item or a CLI's among them, and Codex's /models asked for it seven times over, past the 5 s Codex waits for the list (#746).

func Find

func Find(id string) (*Provider, error)

Find looks a provider up by id (or name, case-insensitively).

func FromPreset

func FromPreset(id string) (Provider, error)

FromPreset builds a provider from a preset; the caller adds the key. An id the preset carried before builds it at the region that id was.

func Hidden added in v0.1.9

func Hidden() []Provider

Hidden lists the signed-in accounts the user removed from magpie.

func KeepSecrets added in v0.1.1214

func KeepSecrets(in, here Provider, keyless bool) Provider

KeepSecrets is in, as sync or a restore brings it over here, with the secrets that didn't come along kept from here (#1821). keyless is that in came from a copy without keys: its keys and its secret headers are here's then. An AccessKey ID and Secret, or a balance token, that in hasn't at all are kept when it came without keys or with the key here has, the same account: a magpie from before access keys were synced (v0.1.1142), or one the key was never given on, sends a provider with its key and nothing else, and taking that whole wiped the Volcengine and Tencent plan cards' access keys on this computer. A key of its own is another account's, whose access key this one's isn't.

func ParseImport added in v0.1.8

func ParseImport(link string) (Provider, error)

ParseImport reads an import link into the provider it describes.

func Resolve

func Resolve(id string) (Provider, string, bool)

Resolve maps an id an agent sent to a provider and the vendor's model id. It accepts catalog ids, "provider/model" for any model (exposed or not), and a bare model id: the first provider in the Providers order (All) that exposes it, else the one provider that lists it unexposed. The gateway asks GroupFor first, so with found groups on a bare id several providers serve is that group, its members in the same order (MOMO on Discord: glm-5.3 under opencode-go and a6api). magpie writes only provider/model ids into agents' configs, so a bare one is the user's. A group's id resolves to its first member.

func RouteDecider added in v0.1.411

func RouteDecider(model string) (Provider, string, error)

RouteDecider is the decision provider a System One model names, and the model that provider is asked with. The name's prefix is the provider (gptload-jev/jev-latest, vercel-jev/typesafe-ai/jev). A bare Jev id goes to the only provider that can answer it, as that provider names Jev.

func Stored added in v0.1.28

func Stored() ([]Provider, error)

Stored is the providers as providers.json keeps them: keys included, signed-in accounts only as the model picks the user made for them. A file that can't be read is an error, never none: a backup or a sync carrying none would take every provider away where it is put back.

func SwitchedOff added in v0.1.346

func SwitchedOff(id string) (Provider, bool)

SwitchedOff is the provider switched off in magpie that a model id names: as "provider/model", or a model only switched-off providers list. A request for it is refused as that, not as a model magpie doesn't know.

func (Provider) APIs added in v0.1.40

func (p Provider) APIs(model string) []Protocol

APIs lists the APIs model is served on, as the provider's last model list said: Copilot serves its GPT models on Responses alone and its Claude models on Chat and Anthropic's. nil is not known, and every API the provider speaks may be tried. One the user set for the model (SetModelAPI) is the only one.

func (Provider) AccountCap added in v0.1.809

func (p Provider) AccountCap(user string) int

AccountCap is the share (1–99) of its windows the account user of p is used to at most, 0 when it has no cap. An account not had from All or AlsoOn (made afresh by its sign-in) carries none of the provider's settings: they are read from providers.json then.

func (Provider) AccountConcurrencyOf added in v0.1.1009

func (p Provider) AccountConcurrencyOf(ref string) (int, bool)

AccountConcurrencyOf is the account's or key's own limit, and whether it has one (else it takes the provider's).

func (Provider) AccountID added in v0.1.1076

func (p Provider) AccountID() string

AccountID is the stable id of p's account or key as a gateway key's account list knows it (#905): the account's, kept through renames, or a key's fingerprint.

func (Provider) AccountIDs added in v0.1.1076

func (p Provider) AccountIDs() []AccountRef

AccountIDs are the provider's accounts and keys as a gateway key's account list knows them (#905): an account by its stable id, a key by its fingerprint, with the name and plan each is shown by.

func (Provider) AccountName added in v0.1.1172

func (p Provider) AccountName(user string) string

AccountName is the name the user gave the account user of p, "" when none. As with AccountCap, an account made afresh beside the agent's own reads it from providers.json.

func (Provider) AccountRefOf added in v0.1.1009

func (p Provider) AccountRefOf(ref string) (string, bool)

AccountRefOf is the account or key of p that ref names, as its limit is kept: an account's name, a key's KeyID (by its id or name).

func (Provider) AccountRefs added in v0.1.610

func (p Provider) AccountRefs() []string

AccountRefs are the provider's accounts, or keys, as AccountModels knows them: a signed-in account's name, a key's KeyID.

func (Provider) AccountServes added in v0.1.610

func (p Provider) AccountServes(ref, model string) bool

AccountServes says whether the account or key ref (a signed-in account's name, a key's KeyID) is let serve model: true when it has no list of its own, and for a model Codex calls by itself that no list can hold (codexOwnHidden).

func (Provider) AccountShown added in v0.1.1326

func (p Provider) AccountShown(user string) string

AccountShown is how the account user of p is shown: by the name the user gave it, else as its vendor names it. Records and lists keep the vendor's name, the key the user's name is kept by, and look this up as they are shown, so a rename reaches what came before it too (magpie-community/plugins#310: a renamed Kiro account read by its old name on the requests after).

func (Provider) AddedByAddress added in v0.1.1191

func (p Provider) AddedByAddress() bool

AddedByAddress reports whether the user added the provider by its address: no preset, no account, no plugin. The tier an agent asks for goes to it as it was asked (the gateway's OwnTier).

func (Provider) AlsoOn added in v0.1.14

func (p Provider) AlsoOn() []Provider

AlsoOn is a signed-in agent's other accounts that are on, each as a provider of its own, in the order they were saved. Each keeps what the user set on the provider, as p has it from All: its queue, limits, routing and models (withPicks). A Claude or Codex account is p with another sign-in, and had them always; one a sign-in of its own makes afresh had none, and a second WorkBuddy AI account queued 62s with the wait set to 1s (#1899).

func (Provider) AnonymousKey added in v0.1.1214

func (p Provider) AnonymousKey() string

AnonymousKey is the key the provider is asked with when the user has none of their own, "" when it has no such key: OpenCode Zen's public, which its free models answer (normalize gives it to a Zen provider saved with no key).

func (Provider) AskSystemOne added in v0.1.723

func (p Provider) AskSystemOne(ctx context.Context, model string) error

AskSystemOne sends model the smallest System One question at p's decision API, and says why it wasn't answered.

func (Provider) AsksDecideModels added in v0.1.838

func (p Provider) AsksDecideModels() bool

AsksDecideModels reports whether each of p's decision models can be sent a System One question of its own (TestModels): where the API is System One's, TypeSafe's or a gateway's that serves it as it is (Vercel's TypeSafe API, OpenRouter's), or Workers AI's, which DecideAsk wraps it for (ARNO on Discord: cloudflare-jev's models couldn't be tested from their right-click); not Vercel's evaluation models, which name the model in headers of their own.

func (*Provider) AtAddress added in v0.1.1224

func (p *Provider) AtAddress(addr string) error

AtAddress moves the provider's URLs to addr as the package's AtAddress does; a refused address leaves them as they were.

func (Provider) AutoNext added in v0.1.914

func (p Provider) AutoNext(ctx context.Context) string

AutoNext is the model Copilot's Auto picks now for a request ctx resolved for it (ResolveAuto), "" for any other: once Retry has said a refused pick is worth sending again, the one it goes as.

func (Provider) Available

func (p Provider) Available() []catalog.Model

Available lists every model the vendor is known to serve: the list fetched from the vendor itself when there is one, over the models.dev catalog (or, for an account, whatever the agent's own sign-in can see).

func (Provider) Base

func (p Provider) Base(proto Protocol) string

Base returns the base URL for a protocol, or "" when the vendor lacks it.

func (Provider) BothAuth added in v0.1.1211

func (p Provider) BothAuth() bool

BothAuth says p's Anthropic requests carry its key in both x-api-key and Authorization, as they do by default to a third-party Anthropic API: the ones AuthHeader can narrow to one. Anthropic's, Bedrock's, Azure's and Vertex AI's never do, nor a signed-in account's.

func (Provider) CapsOf added in v0.1.1134

func (p Provider) CapsOf(user string) WindowCaps

CapsOf is the caps of the account user of p: its usage cap and its windows' own. As with AccountCap, an account made afresh beside the agent's own reads them from providers.json.

func (Provider) CarriesCompaction added in v0.1.1243

func (p Provider) CarriesCompaction() bool

CarriesCompaction says whether p's wire can carry Codex's own compaction (NativeCompaction, #1099): a compaction_trigger asked and a sealed compaction item given back, on the Responses API, as Codex sent them. A provider of no sign-in with a Responses API does (Sub2API and other relays of OpenAI's, OpenAI's own, a remote magpie), as do a ChatGPT account and GitHub Copilot, whose GPT models answer on Responses. Another signed-in agent's, or a plugin's, is asked in its own client's format, which has no such item.

func (Provider) Catalogs added in v0.1.13

func (p Provider) Catalogs() []string

Catalogs are the models.dev ids the provider's models are looked up in, first match wins: a gateway that resells several vendors names them all ("openai, deepseek").

func (Provider) Chosen

func (p Provider) Chosen(id string) bool

Chosen reports whether a model is exposed.

func (Provider) ClinePassAsked added in v0.1.1389

func (p Provider) ClinePassAsked(model string) string

ClinePassAsked is the upstream a request for model asks the Cline API to serve it from on p, "" when it asks for none: ClinePin's, sent with the Upstream tick, or, on the Cline plugin's provider, DeepSeek for a ClinePass DeepSeek model, which opencode-cline-auth 0.1.11 pins by itself unless its pinUpstream option is set off. The Routing page says it beside a reply that names no provider, so a route ClinePass picked reads as asked for DeepSeek or not (zRain on Discord, 10-24).

func (Provider) ClinePassHas added in v0.1.1347

func (p Provider) ClinePassHas(model string, images bool) []string

ClinePassHas is the capability filter (providerOptions.gateway.has) a pinned request for model carries beside only, or nil. On ClinePass the server's own routing for a DeepSeek model wins over only alone, and a fake upstream in only was served all the same; with has beside it the request went to DeepSeek and a fake upstream was refused "no matching upstream" (hy125245 on X, 10-23). The upstream must cache a repeated prefix by itself, and, for a model that takes images (images: the fetched list says so, or the request carries one), take them: a text-only model asked "vision" (deepseek-v4-pro) would have no upstream left. The Cline plugin's provider has none here: the plugin writes it.

func (Provider) ClinePin added in v0.1.934

func (p Provider) ClinePin(model string) (upstream string, openRouter bool)

ClinePin is the upstream a request for model is pinned to on p (PinUpstream), and whether Cline sends the model through OpenRouter (pinned by provider.only) rather than Vercel's AI Gateway (pinned by providerOptions.gateway.only): "deepseek" for a DeepSeek model of the Cline API, "zai" for a GLM one, "z-ai" through OpenRouter for glm-5.3-flash, "" for anything else. Cline's free models are served where Cline puts them, so they never are.

func (Provider) ClinePinnable added in v0.1.959

func (p Provider) ClinePinnable() bool

ClinePinnable reports whether p's requests reach Cline's API and can be pinned to an upstream (PinUpstream): the ClinePass provider, one on cline.bot, or the Cline plugin's (@magpie-community/opencode-cline-auth), whose requests magpie writes before the plugin sends them on.

func (Provider) CompactsOn added in v0.1.1243

func (p Provider) CompactsOn(model string) bool

CompactsOn says whether a Codex compaction for model at p goes to it as Codex sent it: the user turned NativeCompaction on, its wire carries it, and model is asked on Responses there (Copilot's Claude models are not). The gateway also asks whether the model fits Responses as it has seen it answer (Server.compactsNatively).

func (Provider) Concurrency added in v0.1.633

func (p Provider) Concurrency() int

Concurrency is how many requests the gateway lets be out at the vendor at once on each of the provider's keys or accounts, 0 for no limit: the user's MaxConcurrency when they set one, else what the plugin giving the provider says it takes (its auth hook's maxConcurrency, or its package.json's magpie.maxConcurrency), else none.

func (Provider) ContextOf added in v0.1.107

func (p Provider) ContextOf(model string) int

ContextOf is the context the user set for the provider's model: its own, else the provider's "*"; 0 when none is set.

func (Provider) DecideModelURL added in v0.1.859

func (p Provider) DecideModelURL(ctx context.Context, model string) (string, error)

DecideModelURL is where a question for model is posted: DecideURL, or, for a Clef on Workers AI, its own run under it.

func (Provider) DecideOnly added in v0.1.686

func (p Provider) DecideOnly() bool

DecideOnly reports whether the provider has no conversation endpoint.

func (Provider) DecideURL added in v0.1.218

func (p Provider) DecideURL(ctx context.Context) (string, error)

DecideURL is where a question for p's decision API is posted. Workers AI's is under an account: the one its base names, else the one the token belongs to, looked up once.

func (Provider) DecideVia added in v0.1.218

func (p Provider) DecideVia() string

DecideVia is the way p's decision API is asked, known by its host or by the gateway's own path (Vercel's /typesafe or /v4/ai, Cloudflare's /client/v4).

func (Provider) Decides added in v0.1.142

func (p Provider) Decides() bool

Decides reports whether the provider is a decision API.

func (Provider) DecidesModel added in v0.1.686

func (p Provider) DecidesModel(model string) bool

DecidesModel distinguishes Jev from the conversation models a gateway also serves. A dedicated decision API may use any model name, and a plugin's are the ones it marks besides Jev's (#1514).

func (Provider) DecisionModels added in v0.1.928

func (p Provider) DecisionModels() []catalog.Model

DecisionModels are the decision models listed separately from a provider's conversations: OpenRouter's own list, a Bailian Token Plan's decision model, or a remote magpie's or a plugin's marked models.

func (Provider) Detect added in v0.1.663

func (p Provider) Detect(ctx context.Context, base, model string, picked ...string) ([]Detection, error)

Detect asks each of Chat, Responses, Anthropic and Gemini at the URL p has for it, else at base as it takes it (DetectBase), the smallest request, and says what each answered, in that order. model is asked on all three; with none, one is picked for each — a Claude model on Anthropic's, an OpenAI one on Responses — from picked, the models the editor's form has and hasn't saved yet (#1545: a relay with no model list is asked for the models typed in the form, not only after a Save), else from p's list, and with no list the vendor is asked for one first (a GET of its models, which costs nothing). Only those URLs are asked, and only a key's provider: a sign-in's API is its agent's.

func (Provider) DetectDecide added in v0.1.723

func (p Provider) DetectDecide(ctx context.Context, model string) Detection

DetectDecide asks the System One API at p's decision URL (…/systemone pasted whole is cut to its root) the smallest question for model, or the one p is asked with when none is given, and says how it answered.

func (Provider) DetectModels added in v0.1.671

func (p Provider) DetectModels(ctx context.Context, base string, models []string) ([]ModelDetection, []Detection, error)

DetectModels asks each of models (the first DetectMax, an image model left out: it is asked on the images API) on each of Chat, Responses, Anthropic and Gemini at the URL p has for it, else at base as it takes it, and says what each answered, model by model; and, by API, the first answer from a model it served, else the first model's — what Detect says for one. A probe not started before ctx ends says so, unasked.

func (Provider) Do added in v0.1.479

func (p Provider) Do(client *http.Client, req *http.Request) (*http.Response, error)

Do sends req, through the account's own transport when it has one (a plugin's), the client the account asks for this request when it asks for one (ZCode's Start Plan: zcodeStartClient), and client otherwise.

func (Provider) Efforts added in v0.1.59

func (p Provider) Efforts(model string) []string

Efforts are the reasoning levels the model takes, when known: its own, or those the user gave it when it has none known (magpie model spec --reasoning on a custom provider's model). The gateway fits a request to these. Levels the user kept of a model's own only narrow what is offered (#92): the vendor is still asked at any level it has.

func (Provider) EndpointCatalog added in v0.1.1231

func (p Provider) EndpointCatalog() string

EndpointCatalog is the models.dev catalog a provider the user added by its endpoint alone is priced from: the one models.dev says serves its models at that address, when exactly one does (#2052, mengyianx: a provider at AMD's own https://developer.amd.com.cn/radeon/api/v1 had no price for Qwen3.8-27B, which models.dev's amd lists at $0 there, while its maker sells no such model). Only a key's provider with no catalog named counts: a catalog the user or a preset gave stands, and a subscription's account is priced as its own code says. A plan's catalog is never one: it lists what its membership charges per token, $0, not what the model costs (membershipCatalogs).

func (Provider) Explain added in v0.1.447

func (p Provider) Explain(msg string, status int, body []byte) string

Explain is the error a refusal is passed on as: msg, with what the user can do about it when the account knows.

func (Provider) Exposed

func (p Provider) Exposed() []catalog.Model

Exposed lists the models magpie offers to agents for this provider: the user's picks; else the preset's; else everything, when that is few; none after Select none (ServesNone).

func (Provider) FactoryGemini added in v0.1.1125

func (p Provider) FactoryGemini() bool

FactoryGemini is Factory's sign-in, whose Gemini models are asked on its own generate route (…/generate, the model in the body), not at models/{model}:streamGenerateContent as Google's Gemini API asks them.

func (Provider) Fetch

func (p Provider) Fetch(ctx context.Context) ([]catalog.Model, error)

Fetch asks the vendor which models it serves and remembers the answer.

func (Provider) Fetched

func (p Provider) Fetched() (time.Time, bool)

Fetched reports when the vendor's own list was last fetched.

func (Provider) FreeModel added in v0.1.1297

func (p Provider) FreeModel(model string) bool

FreeModel says model costs nothing on p: its vendor serves it at no cost to the subscription's allowance or credits (catalog.Model's Free: WorkBuddy's "x0.00", Qoder's is_free, Cline's free models, an OpenCode Zen free one), or, with no such word from the vendor, it is listed at $0 on every count — a vendor's free model a catalog prices at 0, as mimo-v2.6-flash-free is, and a key's free model, which has no allowance to draw on and so is judged by its price alone.

A model neither listed free nor priced is not free: nothing says it costs nothing, and the routes that go by this put it with the paid ones, so a pool without free models behaves as In order.

func (Provider) HasKey added in v0.1.1214

func (p Provider) HasKey(key string) bool

HasKey reports whether key is one of the provider's, on or off.

func (Provider) Host

func (p Provider) Host() string

Host is the vendor's API host, for display.

func (Provider) IsAzure added in v0.1.419

func (p Provider) IsAzure() bool

IsAzure reports whether the provider is Azure OpenAI: made from its preset, or at a resource's host.

func (Provider) IsBedrock added in v0.1.364

func (p Provider) IsBedrock() bool

IsBedrock reports whether the provider is Amazon Bedrock: its runtime (bedrock-runtime.{region}.amazonaws.com) or its Mantle endpoint (bedrock-mantle.{region}.api.aws), made from either's preset or at either's host. The two take the same Bedrock API key and share what Bedrock asks of a request: x-api-key alone on Messages, its own names for Anthropic's betas, no metadata.user_id, max_completion_tokens on chat completions, Claude on Messages and OpenAI's GPT models on Responses first. What only the runtime does (no list of models) is the preset's; what only Mantle does is IsBedrockMantle's.

func (Provider) IsBedrockMantle added in v0.1.1270

func (p Provider) IsBedrockMantle() bool

IsBedrockMantle reports whether the provider is Amazon Bedrock's Mantle endpoint (@marktoown on X): made from its preset, or added by its address at bedrock-mantle.{region}.api.aws.

func (Provider) IsCline added in v0.1.630

func (p Provider) IsCline() bool

IsCline reports whether the provider is the Cline API: made from the ClinePass preset, or at Cline's host.

func (Provider) IsKilo added in v0.1.635

func (p Provider) IsKilo() bool

IsKilo reports whether the provider is the Kilo Gateway: made from its preset, or at Kilo's API host.

func (Provider) IsOpenCode added in v0.1.7

func (p Provider) IsOpenCode() bool

IsOpenCode reports whether the provider is OpenCode's gateway (Zen or Go), which routes and caches by conversation and turns away requests that do not name one in x-opencode-session.

func (Provider) IsPlugin added in v0.1.479

func (p Provider) IsPlugin() bool

IsPlugin is whether the provider is a plugin's.

func (Provider) IsRemoteMagpie added in v0.1.527

func (p Provider) IsRemoteMagpie() bool

IsRemoteMagpie reports whether the provider is another magpie.

func (Provider) IsVertex added in v0.1.1162

func (p Provider) IsVertex() bool

IsVertex reports whether the provider is Google Vertex AI.

func (Provider) Jev added in v0.1.218

func (p Provider) Jev() string

Jev is the model a decision provider is asked with when the user picked none: TypeSafe's latest stable one, or the one Jev a gateway serves.

func (Provider) KeyList added in v0.1.14

func (p Provider) KeyList() []KeyInfo

KeyList is a provider's keys, in the order requests try them.

func (Provider) KeysOn added in v0.1.14

func (p Provider) KeysOn() []KeyAccount

KeysOn is the keys in use, first to last: the first key, then every saved one that's on. A key listed twice — providers.json's "keys" naming the first key again, as #1772's did — is one key, asked once.

func (Provider) KindModels added in v0.1.1225

func (p Provider) KindModels(kind string) []string

KindModels are the ids of p's models the user said make kind, those it still serves, sorted (a provider's id has no "/", so a model's may: OpenRouter's).

func (Provider) Known added in v0.1.161

func (p Provider) Known(model string) []string

Known are the model's own reasoning levels, when known.

func (Provider) LaneLimit added in v0.1.1009

func (p Provider) LaneLimit() int

LaneLimit is how many requests may be out at once on p's key or account, 0 for no limit: its own (AccountConcurrency), else the provider's (Concurrency). An account not had from All or AlsoOn (made afresh by its sign-in) carries none of the provider's settings: they are read from providers.json then.

func (Provider) Levelless added in v0.1.404

func (p Provider) Levelless(model string) bool

Levelless reports whether the model is known to have no reasoning levels to pick from, as against not known to have any: its vendor or its maker lists it with a thinking switch alone, or nothing (Xiaomi's mimo-v2.6-flash), and the user gave it none.

func (Provider) List added in v0.1.673

func (p Provider) List(ctx context.Context) ([]catalog.Model, error)

List asks the vendor which models it serves, as Fetch does, and keeps nothing: a provider still being added (#578, the add form's Fetch models) is shown its vendor's list to pick from before it is saved.

func (Provider) ListError added in v0.1.1001

func (p Provider) ListError() string

ListError is why a plugin's account lists only the plugin's defaults, "" for any other provider.

func (Provider) ListPrice added in v0.1.411

func (p Provider) ListPrice(model string) (catalog.Price, bool)

ListPrice is a model's list price as its vendor's models.dev entry gives it, else as its maker's does (#224): a subscription (Codex's ChatGPT account, Copilot) or a relay with no models.dev id of its own is priced at gpt-6-astra's or gemini-3.8-flash's maker's price, as a Claude account is at Anthropic's. A remote magpie's is what that magpie counts the model at, as its list says (remotePrice). A model no catalog prices is at the price its plugin lists it at (pluginListPrice), else, when the plugin says the plan serves it free, costs nothing (pluginFree).

func (Provider) Listed added in v0.1.552

func (p Provider) Listed() (time.Time, bool)

Listed is when the models listed now were had from the vendor: fetched for a built-in, listed by its plugin for a plugin's.

func (Provider) ListedAPIs added in v0.1.731

func (p Provider) ListedAPIs(model string) []Protocol

ListedAPIs are the APIs model is served on as its vendor says, whatever the user set: what APIs gives with nothing set (the editor's Auto).

func (Provider) LoginRanks added in v0.1.672

func (p Provider) LoginRanks() map[string]int

LoginRanks is, for the account Codex or Claude Code is signed in to while it is kept signed in to one of the user's choosing (KeepLoginAs), each of the agent's accounts' place in the order the gateway tries them, the one signed in to at its own place among them; nil otherwise, when the one signed in to is the first.

func (Provider) MarksKinds added in v0.1.1225

func (p Provider) MarksKinds() bool

MarksKinds is whether p's models can be said to make images or videos: a provider set up with a base URL, which magpie asks at the OpenAI-shaped images and videos APIs under it. A subscription's account, another magpie (whose own list says) and a decision API's can't.

func (Provider) MessagesFirst added in v0.1.1081

func (p Provider) MessagesFirst(model string) bool

MessagesFirst: a Claude model where the provider has Anthropic's Messages API, which is best asked there though its Chat or Responses API serves it too — a relay that serves both drops cache_control on Chat, so every turn was billed uncached (#997; ReturnTrue on Discord: 0% cache hits until the relay's OpenAI URL was left empty), and thinking with it.

func (Provider) ModelAPI added in v0.1.663

func (p Provider) ModelAPI(model string) (Protocol, bool)

ModelAPI is the API the user said p's model is asked on, when p has a URL for it still.

func (Provider) ModelEfforts added in v0.1.137

func (p Provider) ModelEfforts() map[string][]string

ModelEfforts are the reasoning levels the user kept of the provider's models, by model id.

func (Provider) ModelKind added in v0.1.1225

func (p Provider) ModelKind(model string) string

ModelKind is what the user said p's model makes: KindImage, KindVideo, or "" when they said nothing, or p can't be told (MarksKinds).

func (Provider) ModelNames added in v0.1.137

func (p Provider) ModelNames() map[string]string

ModelNames are the names the user gave the provider's models, by model id.

func (Provider) ModelTest added in v0.1.636

func (p Provider) ModelTest() string

ModelTest says why p's models can't each be sent a test request ("" when they can): "decide" for a decision API whose models can't each be sent a System One question (AsksDecideModels), whose endpoint Test asks it for them; "own-api" for a sign-in reached through its agent's own API (Cursor, Devin, Kiro, Zed, Qoder, a Google sign-in), which the gateway translates every request for, so a probe has no endpoint to go to. A Google sign-in's are asked through the gateway's translator (testsTranslated). Vertex AI's generateContent is asked as it is.

func (Provider) NamedOnlyOn added in v0.1.1237

func (p Provider) NamedOnlyOn(proto Protocol) bool

NamedOnlyOn is whether p serves on proto only the models its list names that API for, so that one it names none for isn't asked there: OpenCode's Gemini API, which serves the Gemini models alone (each of OpenCode's models is served on one API family, its inference docs say). The rest are asked on chat, Responses or Messages, as before it had a Gemini URL (#2168).

func (Provider) Native added in v0.1.300

func (p Provider) Native(model string) Protocol

Native is the API model is best asked on at this provider: one it serves the model on itself, so a request on it is relayed as it is rather than translated — Responses for a ChatGPT sign-in, or an OpenAI model on OpenAI's API or Copilot's; Anthropic's Messages for a Claude model where that is served; Chat where that is served. "" when every request is translated anyway: a sign-in served through its agent's own API (Claude Code's binary, Devin, Code Assist).

func (Provider) NoAPIFor added in v0.1.1234

func (p Provider) NoAPIFor(model string) bool

NoAPIFor says the provider has a URL for none of the APIs the vendor's list serves model on (or the one the user set for it): a relay's Claude listed on /messages alone, at a provider given only a chat URL. Agents aren't offered it, as no request for it could be answered (#2094). Only a provider of keys, whose URLs the user typed: a sign-in's APIs are magpie's own. A model whose list says no API, and a provider with no URL at all, are never left out here.

func (Provider) NoFailRest added in v0.1.1236

func (p Provider) NoFailRest() bool

NoFailRest says p's keys and accounts don't rest after an unknown failure (RestCapOff).

func (Provider) On added in v0.1.346

func (p Provider) On() bool

On is whether the provider takes requests: ready, and not switched off.

func (Provider) OnMessages added in v0.1.1083

func (p Provider) OnMessages(model string) bool

OnMessages: a Claude model MessagesFirst asks on Messages whatever API the client spoke, not only when the client's isn't served — unless the user set the API it is asked on, or the vendor's list names the APIs it serves it on (Copilot's Claude on Chat and Messages), where a request is relayed on the client's own API as before.

func (Provider) OpenCodeFree added in v0.1.616

func (p Provider) OpenCodeFree(model string) bool

OpenCodeFree says whether model is one of OpenCode Zen's free ones on p, which Zen serves only to what looks like OpenCode: besides the headers OpenCodeClient sets, a streamed request offering tools named bash and read (lowercase, each taking a parameter: OpenCodeToolSchemas) at the inference API (OpenCodeFreeURL), as checked against Zen in October 2026. The gateway asks them so whoever the client is (gateway/zenfree.go), and the Test button's probe so (zenFreeProbe). A free model is one whose id ends in -free, or one models.dev's opencode prices at nothing, as big-pickle, whose id doesn't say so (361 on Discord: it answered 403 "OpenCode's free tier can only be used from within OpenCode"); openCodeFreeIDs are such ones known without the catalog.

func (Provider) Origin added in v0.1.755

func (p Provider) Origin(ctx context.Context) string

Origin is the scheme and host p's requests go to, for a URL of the vendor's own outside its API (WorkBuddy's /v3/config beside its /v2): a plugin's where its loader sends them, which p.Do then takes there through the plugin; any other's its API's. "" when it has none.

func (Provider) OwnClient added in v0.1.1217

func (p Provider) OwnClient() bool

OwnClient says magpie's requests to p go as a client the vendor serves, whatever agent sent them: OpenCode's gateway is sent OpenCode's User-Agent, Cline's Cline's, Kilo's the Kilo CLI's, and another magpie magpie's.

func (Provider) OwnPaused added in v0.1.455

func (p Provider) OwnPaused() bool

OwnPaused says the provider is the account a Claude Code or Codex agent is signed in to, paused while another of its accounts is on (#263): the gateway passes over it, the agent staying signed in to it.

func (Provider) OwnQuotaRest added in v0.1.1230

func (p Provider) OwnQuotaRest(now time.Time) time.Duration

OwnQuotaRest is how long, from now, one of p's keys sits out of quota when the vendor doesn't say when it is back: until the next QuotaResetAt when one is set, else QuotaRest; 0 for the gateway's own.

func (Provider) PaidBesideFree added in v0.1.1214

func (p Provider) PaidBesideFree(model string) bool

PaidBesideFree says model costs its subscription's credits while the subscription serves other models at no cost to them (catalog.Model's Free: WorkBuddy's "x0.00", Qoder's is_free, Cline's free models). Its credits running out then says nothing of those: they draw on none (Creat.wu on Discord). False for a model not on the list, or where no model is free.

func (Provider) ParseLevels added in v0.1.1360

func (p Provider) ParseLevels(model, v string) (levels []string, off bool, err error)

ParseLevels is a typed reasoning answer for p's model: the levels to keep in their order, and off for no reasoning ask. "auto" is no levels and not off. Levels are the model's own when its list gives them, else any of Levels; a range runs from one to the other in that order, both included.

func (Provider) PassesUserAgent added in v0.1.1217

func (p Provider) PassesUserAgent() bool

PassesUserAgent says a request to p goes with the User-Agent of the agent that sent it (#1851): the user set PassUserAgent, and p is a key+URL provider whose requests go as magpie's. A signed-in account and a plugin's provider sign as their own client; OpenCode's, Cline's and Kilo's gateways are sent the client they serve (OwnClient), and another magpie is told magpie by it: none of them takes the agent's in its place.

func (Provider) Picks added in v0.1.1162

func (p Provider) Picks() []string

Picks are the models the user picked, with those the vendor has listed since beside them (withNewlyListed): what agents are served of the picks, and what an editor starts its picks from. None when nothing is picked.

func (Provider) PlanDrawers added in v0.1.1117

func (p Provider) PlanDrawers() []catalog.Model

PlanDrawers are the image-generation models explicitly included in the preset region's plan. They are separate from its chat models.

func (Provider) PlanEmbeddings added in v0.1.1117

func (p Provider) PlanEmbeddings() []catalog.Model

PlanEmbeddings are the embedding models explicitly included in the preset region's plan. They are resolved by the embeddings API but kept out of agents' chat-model lists.

func (Provider) PlanVideos added in v0.1.1117

func (p Provider) PlanVideos() []catalog.Model

PlanVideos are the video-generation models explicitly included in the preset region's plan.

func (Provider) PluginConcurrency added in v0.1.633

func (p Provider) PluginConcurrency() int

PluginConcurrency is what the plugin giving the provider says it takes at once, as it lists it now; 0 for none, or for a provider no plugin gives.

func (Provider) PluginProvider added in v0.1.584

func (p Provider) PluginProvider() string

PluginProvider is the id OpenCode knows the plugin's provider p is by (grok, kiro), whatever magpie names it; "" for one no plugin gives.

func (Provider) Prepare

func (p Provider) Prepare(body []byte) []byte

Prepare adjusts a request body the way the backend wants it.

func (Provider) ProxyChoice added in v0.1.427

func (p Provider) ProxyChoice() string

ProxyChoice is the proxy requests made on the provider's behalf go through, as netproxy.With takes it: for one account of a subscription that holds several, or one key of a provider that holds several (Beyfish_Wang on X: 不同 key 走不同的代理), its own (AccountProxies), else the provider's (Proxy); "" follows the global one. An account in use beside the agent's own is made afresh by some agents (AlsoOn), without the provider's settings: those are read from providers.json.

func (Provider) QuotaRestFor added in v0.1.1214

func (p Provider) QuotaRestFor() time.Duration

QuotaRestFor is how long one of p's keys sits out of quota when the vendor doesn't say when it is back, 0 for the gateway's own.

func (Provider) RPMLimit added in v0.1.1119

func (p Provider) RPMLimit() int

RPMLimit is how many requests a minute each of p's keys or accounts may send the vendor, 0 for no limit: the provider's MaxRPM. An account not had from All or AlsoOn (made afresh by its sign-in) carries none of the provider's settings: it is read from providers.json then.

func (Provider) Ready

func (p Provider) Ready() bool

Ready reports whether the provider can be used: it has a key, needs none, is a signed-in agent, or is Vertex AI at a project (whose credentials are read when a request is signed).

func (Provider) Refetch added in v0.1.769

func (p Provider) Refetch(ctx context.Context) ([]catalog.Model, []string, error)

Refetch is Fetch, and says which of the user's picks it dropped: those the list fetched before had and the one fetched now doesn't. The new list replaces the old one, and a pick made from the old list goes with it — kept, it stayed among the models agents see, as if typed in by hand, though the vendor serves it no more (akic404 on Discord: a remote magpie offering far fewer models, and one of its providers renamed, still listed every old "ws-ba5my…/qwen3.6-max" here after a Refresh). A pick the old list didn't have was typed in by hand, and stays; a fetch that fails, or that answers no model at all, changes nothing.

func (Provider) RefetchTaking added in v0.1.1234

func (p Provider) RefetchTaking(ctx context.Context) (ms []catalog.Model, dropped, taken []string, err error)

RefetchTaking is Refetch, and says which models the provider's AutoInclude rules took into its picks: those the list fetched now has, the one before didn't, and a rule matches (takeMatching, #2135).

func (Provider) RefreshInterval added in v0.1.1234

func (p Provider) RefreshInterval() time.Duration

RefreshInterval is how often the gateway fetches the provider's list by itself: 0 for only when asked, and for one RefreshEvery can't be read.

func (Provider) RejectsTemperature

func (p Provider) RejectsTemperature(model string) bool

RejectsTemperature reports whether the model is known to refuse temperature and top_p. The answer comes from the catalog — models.dev plus the vendor's own list — so a model released after this binary was built is handled without a code change.

func (Provider) RemotePriced added in v0.1.1131

func (p Provider) RemotePriced(model string) bool

RemotePriced reports whether the model's list price is the one a remote magpie's list gave, for the editor to say whose it is.

func (Provider) ReplyLimit added in v0.1.916

func (p Provider) ReplyLimit(m catalog.Model) int

outputOf is the most a reply of a model may hold, as the user said it: the model's own, else the one given for every model of its provider, else 0 for the vendor's own list and models.dev to answer. It mirrors ContextOf, which the user sets on the provider itself. ReplyLimit is the most a reply of the provider's model may hold, in tokens, as agents are told it and the Gateway's model list shows it: the user's Max output, else the vendor's list's, else models.dev's.

func (Provider) ReplyLimitIn added in v0.1.1093

func (p Provider) ReplyLimitIn(m catalog.Model, s settings.Settings) int

ReplyLimitIn is ReplyLimit from settings s already read.

func (Provider) ResolveAuto added in v0.1.444

func (p Provider) ResolveAuto(ctx context.Context, model string) (context.Context, string, error)

ResolveAuto turns a request for a model the account picks itself (Copilot's Auto) into one for the model it picked: ctx then carries what the request is signed with. Any other model comes back as it was.

func (Provider) ResponsesFirst added in v0.1.300

func (p Provider) ResponsesFirst(model string) bool

ResponsesFirst: an OpenAI model on OpenAI's API, Copilot's, PipeLLM's or Bedrock's, which is best asked on the Responses API though Chat serves it too; and every model where only the Responses API tells what the vendor's cache answered (ResponsesTellsCache).

func (Provider) ResponsesTellsCache added in v0.1.1183

func (p Provider) ResponsesTellsCache() bool

ResponsesTellsCache is a provider whose Responses API says how much of the prompt its cache answered (input_tokens_details.cached_tokens) and what the model reasoned, while its Chat API, served by the same cache, says neither: ModelScope's API-Inference, by its preset or its host (#1578, sparrowbits: Claude Desktop, translated to Chat, read 0 of 34.9M tokens from cache; Codex on Responses, 94%). A translated request goes there on Responses, and an agent that asks each model on one API is wired to it. Other vendors with both URLs keep Chat: their Chat reports its cache (Groq, Volcengine Ark), their Claude-format requests go to their Anthropic URL as they are, or nothing is known of their Responses API (a relay the user added).

func (Provider) RestCapOr added in v0.1.1230

func (p Provider) RestCapOr(def time.Duration) time.Duration

RestCapOr is the most one of p's keys or accounts sits out while it keeps failing: the user's RestCap, else the gateway's own def (RestCapOff included: it says nothing of a rate limit's rest).

func (Provider) RestKey added in v0.1.930

func (p Provider) RestKey(k KeyInfo) string

RestKey is what the gateway rests the key k of a provider by: the provider's id while it has one key on, else the id and the key's.

func (Provider) RestKeys added in v0.1.1265

func (p Provider) RestKeys() func(KeyInfo) string

RestKeys is RestKey for each of a provider's keys in turn, whether it has more than one on found once: found again for every key, a list of a thousand keys was read a thousand times over, and the Providers page took seconds to draw it, minutes for five thousand (@NetRozee on X).

func (Provider) Retries added in v0.1.438

func (p Provider) Retries() bool

Retries is whether the account can mend a refusal (Retry), so the refusal's body is worth reading before it is passed on.

func (Provider) Retry added in v0.1.438

func (p Provider) Retry(ctx context.Context, sent []byte, status int, body []byte) bool

Retry is whether a request (sent) the backend refused with status and body is worth sending once more, the account having mended what it named.

func (Provider) Serves added in v0.1.38

func (p Provider) Serves(k KeyAccount, model string) bool

Serves reports whether key k can be asked for model: false only when the vendor's lists say another of the provider's keys sees it and k doesn't. A key no list marks — its own wasn't answered, or it was added since — is unknown, and serves: a failed list is not an empty one (#1598, the first of five keys left out of every request). The lists are read whole, the models that draw or make videos among them: a text key never says it serves an image model only another key lists (#1657).

func (Provider) ServesNone added in v0.1.1214

func (p Provider) ServesNone() bool

ServesNone is the user's Select none (NoModels) with nothing picked: none of its models are served, its balance and usage still read.

func (Provider) Serving added in v0.1.1265

func (p Provider) Serving(model string) func(KeyAccount) bool

Serving is Serves for model, for each of the provider's keys in turn: the lists are read once, not once a key. Read for every key of every request, a provider of a thousand keys had its list's file looked at a thousand times, and each model's thousand keys looked along, before a request went out: a tenth of a second a request, seconds for five thousand keys (@NetRozee on X).

func (Provider) Sign

func (p Provider) Sign(ctx context.Context, req *http.Request, proto Protocol, body []byte) error

Sign authenticates a request to the provider, refreshing what needs it. Plain providers get their key; accounts get the agent's tokens.

func (Provider) SignedOut added in v0.1.1310

func (p Provider) SignedOut() bool

SignedOut says that p is a signed-in account whose every account in use (on, or the one the agent is signed in to) has had its sign-in refused: listed, so it can be signed in again, but not "signed in". It is what the app's Providers row says as "{user} is signed out", for magpie providers and the TUI to say the same (LeeHom on Discord: Claude Code listed on two lapsed accounts).

func (Provider) SkipsRedaction added in v0.1.1091

func (p Provider) SkipsRedaction() bool

SkipsRedaction says requests to p go unmasked: the user set Unredacted, and every address p has is on this machine or the local network. One edited to a vendor's afterwards is masked again. A signed-in account, a plugin's provider and another magpie are always masked: each reaches a vendor.

func (Provider) Speaks

func (p Provider) Speaks() []Protocol

Speaks lists the protocols the vendor serves natively, preferred first.

func (Provider) TakesInsecureTLS added in v0.1.1258

func (p Provider) TakesInsecureTLS() bool

TakesInsecureTLS is whether the provider may have its certificate left unchecked (InsecureTLS, #2383): only one the user added with a base URL of their own. A subscription's or a plugin's account, a preset's (whose vendor serves a certificate that checks) and a built-in's never do, whatever providers.json says.

func (Provider) Test

func (p Provider) Test(ctx context.Context) []Result

Test sends the smallest possible request to each endpoint the vendor serves, signed with a key made for it and asking for a model that key sees, and reports what came back.

func (Provider) TestClients added in v0.1.1158

func (p Provider) TestClients() map[string]string

TestClients is the clients p's models can be tested as, each with why it can't be yet ("" when it can): those whose API p has, of a provider reached with a key; Claude Code only of a relay.

func (Provider) TestModels added in v0.1.163

func (p Provider) TestModels(ctx context.Context, models []string) []Result

TestModels sends each of models the smallest request, a few at a time, on the endpoint it's served on and with a key that sees it: whether each answers, not only whether the vendor does. Results are in models' order.

func (Provider) TestsAs added in v0.1.1158

func (p Provider) TestsAs(client string) string

TestsAs says why p can't be tested as client asks ("" when it can).

func (Provider) Thinks added in v0.1.1084

func (p Provider) Thinks(model string) bool

Thinks reports whether the model reasons: it has levels, its list says it thinks, or models.dev says most of those serving it do (Entry's Reasoning).

func (Provider) UncheckedHosts added in v0.1.1258

func (p Provider) UncheckedHosts() []string

UncheckedHosts are the base URLs whose host's certificate is taken as it is when the provider has InsecureTLS: its own endpoints, never a models, balance or image URL elsewhere.

func (Provider) UpstreamNames added in v0.1.560

func (p Provider) UpstreamNames() map[string]string

UpstreamNames are the names the user gave the provider's models, by model id, with the one given for all of them under "*" — each as it will be sent, trimmed, "*" and all, which is what a list of them shows. A name that is only whitespace is none, and is not listed.

func (Provider) Via added in v0.1.418

func (p Provider) Via(ctx context.Context) context.Context

Via is ctx for requests made on the provider's behalf: they go through its own proxy (ProxyChoice), or the global one when it has none. A provider the user added and asked not to have its certificate checked (InsecureTLS) has its own hosts' taken as they are, no other host's.

func (Provider) Where added in v0.1.122

func (p Provider) Where() string

Where is what the provider's calls go to, as usage keeps it: the API's host, and for a subscription who is signed in there too. The id alone can't tell: it can be given to another vendor or account later.

func (Provider) WindowOf added in v0.1.816

func (p Provider) WindowOf(m catalog.Model) int

WindowOf is the window one of the provider's models takes, as agents are told it and requests are routed on it: the one the user set for the model over ListedWindow. The one set for all of the provider's models ("*") is no larger than a model's own, where the provider says it (the window its list or its models.dev catalog gives, or the most it may be asked for, MaxContext): set to 512K to spend less, it told opencode-go's cat-jam-free, which takes 262K, 512K (#2112). The window models.dev gives the id under other vendors (catalog.ContextOf) is not the provider's word but magpie's guess, and never caps what the user set: a custom OpenAI-compatible relay set to 1M told its claude-sonnet-4-5 200K (MisakaNatsuxun on Discord, 10-23). One set for the model itself is the user's word on it, larger or not. The catalog's entries and the Providers page's model lists both read it, so the page shows the window agents are told.

func (Provider) WithExtraBody added in v0.1.1191

func (p Provider) WithExtraBody(body []byte, session string) []byte

WithExtraBody is body with the provider's extra fields merged in, as the package's comment says; session is the conversation's id for ${sessionId}. A body that isn't a JSON object goes as it came.

func (Provider) WithKey added in v0.1.15

func (p Provider) WithKey(k KeyAccount) Provider

WithKey is p using key k: its endpoints narrowed to k's protocol when k has one. It has none left when p doesn't serve that protocol.

type Quota added in v0.1.114

type Quota struct {
	Provider string      `json:"provider"`
	Name     string      `json:"name"`
	Kind     string      `json:"kind"` // subscription, plan (bought with a key) or balance (a key's money)
	Plan     string      `json:"plan,omitempty"`
	User     string      `json:"user,omitempty"`
	Windows  []QuotaSpan `json:"windows"`
	Balance  string      `json:"balance,omitempty"`
	// BalanceSplit is what the Balance is made of, when the vendor tells
	// it (SubscriptionQuota's)
	BalanceSplit []BalancePart `json:"balanceSplit,omitempty"`
	Error        string        `json:"error,omitempty"`
	AsOf         *time.Time    `json:"asOf,omitempty"` // the cached reading's time, nil for a new one
	// ReadDeferred says no request was made this time, rather than one failed.
	ReadDeferred bool `json:"readDeferred,omitempty"`
	// ReadAt is when the windows or balance shown were read, nil when not
	// known; a Claude account's can be well before now (claudeReadAt).
	ReadAt *time.Time `json:"readAt,omitempty"`
	// Until is when the plan's paid time ends, renewed then when Renew is
	// "auto", over when "off", either when "".
	Until *time.Time `json:"until,omitempty"`
	Renew string     `json:"renew,omitempty"`
	// Resets are a Codex account's rate-limit resets, when it holds any.
	Resets *ResetCredits `json:"resets,omitempty"`
	// ResetsUsed are the Codex account's resets magpie spent, newest
	// first, by itself or by hand (codex_resets_used.go)
	ResetsUsed []ResetUse `json:"resetsUsed,omitempty"`
	// LastServedAt is when the account, plan or key last answered a
	// request through the gateway, nil when it hasn't in the last 30 days
	// (served.go); Last is on the latest of them (#570).
	LastServedAt *time.Time `json:"lastServedAt,omitempty"`
	Last         bool       `json:"last,omitempty"`
	// From is the remote magpie whose account this is, by its name here
	// (remote_quotas.go); "" for this computer's own.
	From string `json:"from,omitempty"`
	// Alias is the account's name of the user's own, else Seat: the name
	// of the key plan whose card this account's stands in for (#1515).
	Alias string `json:"alias,omitempty"`
	Seat  string `json:"seat,omitempty"`
}

Quota is one account's or key's allowance as magpie quota --json and the gateway's GET /v1/magpie/quotas tell it, for an agent choosing where to send its work: Provider is the first part of the models' ids (provider/model) for a key's plan or balance, the agent for a subscription.

func KeptQuotaReport added in v0.1.1231

func KeptQuotaReport(now time.Time) []Quota

KeptQuotaReport is QuotaReport from what was last read (CachedCards), asking no vendor: for a status line, which Claude Code runs again on every message (#1997), so it must neither wait for a read nor start one.

func QuotaReport added in v0.1.114

func QuotaReport(ctx context.Context, now time.Time) []Quota

QuotaReport is Quotas as Quota, the reset times made absolute from now.

func RefreshReport added in v0.1.1233

func RefreshReport(ctx context.Context, provider, user string, now time.Time) []Quota

RefreshReport is RefreshUsage answering the cards it read, as QuotaReport tells them: magpie quota refresh (#2104), which reads the card the Usage page's refresh button does and shows only it. A process that has read no other card yet (the CLI) has nothing to merge it into, so the cards come from the read itself, not from the caches.

type QuotaAlert added in v0.1.540

type QuotaAlert struct {
	Provider string
	Name     string // the card's name, as the Usage page shows it
	User     string // the account or key, when the provider has several
	Window   string // the window's name
	Used     float64
	ResetsAt *time.Time
	Balance  string // the balance as the vendor tells it
	// Kind is "" for the alerts above; "renews" for a long window renewing
	// within the reminder's hours with much of it left, "expires" for
	// reset credits running out by then, Credits of them (#720)
	Kind    string
	Credits int
}

QuotaAlert is one thing to tell the user: a window used past the share (Window set) or a balance at or under the amount (Balance set).

type QuotaHistory added in v0.1.722

type QuotaHistory struct {
	Provider string      `json:"provider"`
	User     string      `json:"user"`
	Lines    []QuotaLine `json:"lines"`
}

QuotaHistory is one account's windows over time. User is lowercased.

func QuotaHistories added in v0.1.722

func QuotaHistories(since time.Time, provider, user string) []QuotaHistory

QuotaHistories is every account's windows' points since since, the accounts and windows in name order; provider and user, when given, pick one provider's, or one account's.

func RemoteQuotaHistories added in v0.1.1078

func RemoteQuotaHistories(ctx context.Context, days string) []QuotaHistory

RemoteQuotaHistories is every remote magpie's quota history since days ago, as its own GET /v1/magpie/quotas/history has it (read from its disk, no vendor asked), the providers named as RemoteCards names them.

type QuotaLine added in v0.1.722

type QuotaLine struct {
	Name   string       `json:"name"`
	Points []QuotaPoint `json:"points"`
}

QuotaLine is one window's points, oldest first.

type QuotaPoint added in v0.1.722

type QuotaPoint struct {
	At       time.Time  `json:"at"`
	Left     float64    `json:"left"`
	Start    *time.Time `json:"start,omitempty"`
	ResetsAt *time.Time `json:"resetsAt,omitempty"`
}

QuotaPoint is one reading of a window: at At, Left percent was left; the window began at Start and starts again at ResetsAt, when told.

func (QuotaPoint) StartsCycleAfter added in v0.1.1258

func (p QuotaPoint) StartsCycleAfter(previous QuotaPoint) bool

StartsCycleAfter uses the same observed reset boundaries that history sampling preserves, including refills with an unchanged deadline.

type QuotaSpan added in v0.1.114

type QuotaSpan struct {
	Unlimited bool       `json:"unlimited,omitempty"`
	Name      string     `json:"name"`
	Used      float64    `json:"used"`
	Remaining float64    `json:"remaining"`
	ResetsAt  *time.Time `json:"resetsAt,omitempty"`
	Display   string     `json:"display,omitempty"` // the vendor's own count, "1.2k / 3k"
	// Amount of Limit in Unit: the window's count, used, when the vendor
	// counts it so ("credits")
	Amount float64 `json:"amount,omitempty"`
	Limit  float64 `json:"limit,omitempty"`
	Unit   string  `json:"unit,omitempty"`
	Pool   string  `json:"pool,omitempty"` // the shared pool the window draws on ("Gemini")
	// Holds and HoldsWhy are the window's whole as the Usage page's card
	// tells it (QuotaWindow.Holds, #2333): reckoned when ReckonHolds is
	// set, else left out.
	Holds    *WindowHolds `json:"holds,omitempty"`
	HoldsWhy string       `json:"holdsWhy,omitempty"`
}

QuotaSpan is one window of an allowance: how much of it is used and left, in percent, and when it starts again.

type QuotaWindow

type QuotaWindow struct {
	Unlimited bool       `json:"unlimited,omitempty"`
	Name      string     `json:"name"`
	Used      float64    `json:"used"`
	ResetsAt  *time.Time `json:"resetsAt,omitempty"`
	ResetSecs int64      `json:"resetSecs,omitempty"`
	Display   string     `json:"display,omitempty"`
	// Amount of Limit is the window's own count in Unit, when the vendor
	// counts it so (WorkBuddy's credits): Used is Amount as a share of
	// Limit. The GUI says it as used or left, as it says the share (#659).
	Amount float64 `json:"amount,omitempty"`
	Limit  float64 `json:"limit,omitempty"`
	Unit   string  `json:"unit,omitempty"`
	// RunsOutAt is when the soonest of what is left is lost, and RunsOut
	// how much (in Unit), when it runs out apart from the window's reset:
	// WorkBuddy's credits come in packages that each end on their own
	// day. Smart routing takes it for the window's renewal (cdredfox on X).
	RunsOutAt *time.Time `json:"runsOutAt,omitempty"`
	RunsOut   float64    `json:"runsOut,omitempty"`
	// Family is the model family a per-model window belongs to (Antigravity's
	// "Gemini 3.1 Pro (High)" is Gemini's), for the GUI to show one figure a
	// family, the tightest; each window is still here, and routing reads
	// them one by one.
	Family string `json:"family,omitempty"`
	// Pool is the group of models that share one allowance (Antigravity's
	// "Gemini", "Claude & GPT"): on the group's own windows, a 5-hour and
	// a weekly, which name no Model, and on each per-model window drawing
	// on it, for the GUI to show the group's windows in place of its
	// models'.
	Pool string `json:"pool,omitempty"`

	// For routing (see Allowances): how long the window runs, zero when
	// not known; the only models it counts, by a word in their ids
	// ("opus"), when it doesn't count them all; and Aside when using it up
	// doesn't stop the account — on-demand spending past the allowance,
	// or Copilot's code completions, which no request here makes.
	Span  time.Duration `json:"-"`
	Model string        `json:"-"`
	Aside bool          `json:"-"`
	// Credits is set on each window of a ChatGPT account that holds
	// credits (has_credits with a balance left, or unlimited): using the
	// window up doesn't stop it, the vendor spends the credits instead
	// (codexGoesOnCredits). Routing reads it (Allowance.OnCredits); kept
	// with the reading, so one shown from before still says it.
	Credits bool `json:"credits,omitempty"`
	// Capped is set, for the GUI only (WithCapped), on a window an
	// account's usage cap counts: neither Aside nor unlimited. One model's
	// own counts for that model (CapHeld), so it is marked like the rest.
	Capped bool `json:"capped,omitempty"`
	// CapsSome is set beside Capped on a window that counts some models
	// only — one model's own, or a pool's — so the cap holds the account
	// for those alone, and the GUI says which.
	CapsSome bool `json:"capsSome,omitempty"`
	// CapID is, beside Capped, how the window is known to a cap of its
	// own (WindowCapID), for the GUI to set and show one.
	CapID string `json:"capId,omitempty"`
	// Holds is what the whole window holds, reckoned from magpie's own
	// calls through the account (usage.WithWindowHolds), for the GUI and,
	// through ReckonHolds, magpie quota --json and /v1/magpie/quotas
	// (#2333); nil where that can't be told honestly.
	Holds *WindowHolds `json:"holds,omitempty"`
	// HoldsWhy is, where Holds is nil on a window of an account's own card
	// that runs out and starts again, why its whole isn't told (#2045):
	// HoldsLow, HoldsNoClock, HoldsBeforeLog, HoldsNoneRouted or
	// HoldsCredits. Empty where no whole is ever told (a pool, a family,
	// money aside, another magpie's card).
	HoldsWhy string `json:"holdsWhy,omitempty"`
	// StartsAt is when the window began (Bounds), for the GUI only
	// (WithWindowStarts): with ResetsAt it places an even pace through the
	// window, which the card's Pace number is measured from (fflake33).
	StartsAt *time.Time `json:"startsAt,omitempty"`
	// contains filtered or unexported fields
}

QuotaWindow is one rolling allowance reported by a subscription provider.

func PooledWindows added in v0.1.613

func PooledWindows(ws []QuotaWindow) []QuotaWindow

PooledWindows are ws as a page of text shows them: a pool's own windows, named with their pool ("Gemini · 7 days"), in place of the per-model windows drawing on it; ws as it is when it has no pool. A model's window goes only for a pool window of its span: one whose pool has only its 7 days stays, the 5 hours it reads being the only ones to be had (#745).

func (QuotaWindow) Bounds added in v0.1.1120

func (w QuotaWindow) Bounds(readAt time.Time) (start, end time.Time, ok bool)

Bounds is when w, read at readAt, began and ends: its reset, and that less how long it runs; a month's window began on the same day a month before. ok is false when either isn't known.

func (QuotaWindow) Count added in v0.1.738

func (w QuotaWindow) Count(left bool) string

Count is the window's own count as the GUI says it, beside its share: "355 / 500 credits" used, or what is left of it when left (#659); the vendor's Display when it doesn't count in amounts.

func (QuotaWindow) Counts added in v0.1.1120

func (w QuotaWindow) Counts(model string) bool

Counts is whether a call to model counts against w: every model, or only the ones its scope names ("opus", a plugin's list).

func (QuotaWindow) Pace added in v0.1.1232

func (w QuotaWindow) Pace(readAt, now time.Time) (pace float64, ok bool)

Pace is how far w's use, read at readAt, is from an even pace through the window at now, in points of the window (fflake33 on Discord): what is used less the share of the window gone by. +12 is twelve points more used than an even pace would have used by now, so at this rate the window runs out before it resets; -8 is eight points to spare. ok is false for a window with no limit, or whose start or reset isn't known, or when now is outside it.

type Region

type Region struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Chat      string `json:"chat,omitempty"`
	Responses string `json:"responses,omitempty"`
	Anthropic string `json:"anthropic,omitempty"`
	// Lists is set on a region that serves a model list although the
	// preset as a whole has none to ask for (NoList): a provider at its
	// endpoints is asked for it. KeysURL, when the region's keys are made
	// on another page than the preset's, is where its Get-a-key link goes.
	Lists   bool   `json:"lists,omitempty"`
	KeysURL string `json:"keysUrl,omitempty"`
	// Website, when the region's docs are another page than the preset's,
	// is where the editor's link goes.
	Website  string `json:"website,omitempty"`
	SiteHost string `json:"siteHost,omitempty"` // as PresetDef's
	// Catalog, for a region whose models another models.dev entry names
	// than the preset's (Tencent Cloud's pay as you go, beside its plan's
	// none), is that entry's id.
	Catalog string `json:"catalog,omitempty"`
	// Models are a plan's text models, for a region that is one beside
	// another plan or pay as you go (PresetDef.Models, for the region alone).
	// Embeddings, Drawers and Videos are its non-chat models, kept apart from
	// agents' model pickers.
	Models     []string `json:"models,omitempty"`
	Embeddings []string `json:"embeddings,omitempty"`
	Drawers    []string `json:"drawers,omitempty"`
	Videos     []string `json:"videos,omitempty"`
	// Decide is the region's decision API, for a preset that routes groups
	Decide string `json:"decide,omitempty"`
}

Region is one base-URL option of a preset that offers several. The first is the default; picking another in the editor swaps the endpoints.

type Renewal added in v0.1.75

type Renewal struct {
	Agent string `json:"agent"`
	User  string `json:"user"`
	// Renewed is false when it wasn't due; Err is why it failed, and Lapsed
	// whether the sign-in is gone (the vendor refused it) or may yet renew.
	Renewed bool   `json:"renewed"`
	Err     string `json:"error,omitempty"`
	Lapsed  bool   `json:"lapsed,omitempty"`
}

Renewal is what came of renewing one saved account.

func RenewLogins added in v0.1.75

func RenewLogins(ctx context.Context, every time.Duration) []Renewal

RenewLogins renews the saved ChatGPT sign-ins not in the agent's hands that have gone every or longer without it; every 0 renews all of them.

type ResetAt added in v0.1.1230

type ResetAt struct {
	Hour, Minute int
	Loc          *time.Location
}

ResetAt is a time of day an allowance comes back: an hour and minute, on this computer's clock (Loc nil) or at a fixed offset from UTC.

func ParseResetAt added in v0.1.1230

func ParseResetAt(s string) (*ResetAt, error)

ParseResetAt reads a time of day as QuotaResetAt keeps it: "08:00", "8:30", "00:00+08:00", "16:00Z". "" is none, with no error.

type ResetCard added in v0.1.1076

type ResetCard struct {
	Until  *time.Time `json:"until,omitempty"`
	Window string     `json:"window,omitempty"`
}

ResetCard is one reset: when it runs out (nil: it never does) and, of resets counted by window, which one's ("fiveHour", "weekly").

type ResetCredits added in v0.1.282

type ResetCredits struct {
	Count int        `json:"count"`
	Until *time.Time `json:"until,omitempty"`
	// ByWindow: each reset is for one window, FiveHour of the five hours'
	// and Weekly of the week's, and is spent on the vendor's own page (a
	// GLM Coding team plan's, zcode_team.go), not from magpie
	ByWindow bool `json:"byWindow,omitempty"`
	FiveHour int  `json:"fiveHour,omitempty"`
	Weekly   int  `json:"weekly,omitempty"`
	// Team: the resets are a GLM Coding team plan's, not the person's own
	Team bool `json:"team,omitempty"`
	// Each is every reset still to be used and when it runs out, the
	// soonest first, one that never does last (#960: the card's tooltip
	// lists them, where it only said the first). Empty when the vendor
	// didn't say.
	Each []ResetCard `json:"each,omitempty"`
}

ResetCredits is how many rate-limit resets an account holds and the soonest one of them runs out; Until is nil when none does, or when that couldn't be read.

func (ResetCredits) Words added in v0.1.425

func (r ResetCredits) Words() string

Words are the resets counted: "2 resets", or by window, "2 five-hour resets · 1 weekly reset".

type ResetOutcome added in v0.1.282

type ResetOutcome struct {
	Code    string `json:"code"`
	Windows int    `json:"windows"`
}

ResetOutcome is what spending a reset did: Code is the vendor's word for it (reset, nothing_to_reset, no_credit, already_redeemed) and Windows how many windows started again. Claude's resets are gone (9bf6d4352, #1972); "already_used" below was their word and no longer comes.

func AutoUseCodexReset added in v0.1.507

func AutoUseCodexReset(ctx context.Context, user string) (ResetOutcome, error)

AutoUseCodexReset spends one of the Codex account user's resets (the one Codex is signed in to when "") if the user turned that on for it, its weekly window is used up, it holds one, and none was spent by itself in this week yet. Code is "" when none was tried; the caller asks again only on "reset".

func UseCodexReset added in v0.1.282

func UseCodexReset(ctx context.Context, user string) (ResetOutcome, error)

UseCodexReset spends one of the rate-limit resets of the Codex account user (the one Codex is signed in to when ""), starting its current usage windows again: the one that runs out first, so none that would last longer goes before it. It can't be undone: callers ask first. The account's usage is read afresh after, and the use is kept as one made by hand (ResetsUsed).

func (ResetOutcome) Text added in v0.1.282

func (o ResetOutcome) Text() string

Text says an outcome in words.

type ResetUse added in v0.1.1227

type ResetUse struct {
	User    string    `json:"user"`
	At      time.Time `json:"at"`
	Why     string    `json:"why"`
	Windows int       `json:"windows,omitempty"` // how many windows started again
}

ResetUse is one reset magpie spent on an account.

func ResetsUsed added in v0.1.1227

func ResetsUsed(user string) []ResetUse

ResetsUsed is what magpie spent of the Codex account user's resets, newest first, resetsUsedShown at most; nil when none, or when the file can't be read.

type Result

type Result struct {
	Account  string   `json:"account,omitempty"`
	Protocol Protocol `json:"protocol"`
	OK       bool     `json:"ok"`
	Status   int      `json:"status,omitempty"`
	Millis   int64    `json:"ms"`
	Model    string   `json:"model,omitempty"`
	Error    string   `json:"error,omitempty"`
}

Result is what a probe of one endpoint came back with.

type Rule added in v0.1.94

type Rule struct {
	Use string `json:"use"` // the member, as the group names it: "provider/model"
	// UseEffort: the reasoning the member is asked for on the requests the
	// rule sends it (one of Efforts), in place of what the agent asked —
	// an intent picks the model and its effort as a pair (#2633). Like a
	// member fixed at an effort, it is fitted to the model's own levels,
	// and a model whose levels aren't known is asked as the agent asked.
	// It is an output, as Use is; Effort below is a condition.
	UseEffort string `json:"useEffort,omitempty"`
	// Tokens: the request is at least this long, in tokens — the larger of
	// an estimate from its size and what the vendor counted for the
	// conversation's last request.
	Tokens int `json:"tokens,omitempty"`
	// Images: the request carries an image, in this turn or before.
	Images bool `json:"images,omitempty"`
	// Effort: the agent asked for reasoning at least this level (one of
	// Efforts), or "on" for any reasoning at all.
	Effort string `json:"effort,omitempty"`
	// Agents: the request is from one of these agents (usage.AgentOf ids).
	Agents []string `json:"agents,omitempty"`
	// Intent: the user's message at the turn's start is of this kind, as
	// the group's Classifier judges it — "writing or fixing tests",
	// "a quick question". When the classifier can't say, it doesn't match.
	Intent string `json:"intent,omitempty"`
	// Compact: the agent is compacting its conversation — asking a model to
	// summarize it so it can go on in less room (Claude Code's /compact,
	// Codex's, OpenCode's, Pi's…) — which a cheaper, faster model can do
	// in place of the one the conversation is on.
	Compact bool `json:"compact,omitempty"`
	// Time: the turn begins within these hours of the day, local time — a
	// vendor's peak-price hours sent to another, say.
	Time *TimeWindow `json:"time,omitempty"`
	// Folders: the request's working folder, as the agent states it in
	// the request, is one of these or inside one — a project, or every
	// project under a folder (Cario0x on X). "~/work", "/Users/me/x",
	// "C:\work"; WSL's /mnt/c/work is C:\work. When the agent doesn't
	// say its folder, it doesn't match.
	Folders []string `json:"folders,omitempty"`
	// ExceptFolders: the request's working folder is none of these nor
	// inside one, as Folders reads them. A request whose agent doesn't say
	// its folder is not known to be in one, so it holds for it: a pause
	// "except in ~/big-task" keeps the model for requests known to come
	// from there (#1606), never for one that may come from elsewhere.
	ExceptFolders []string `json:"exceptFolders,omitempty"`
	// Pause: rather than sending to Use first, the rule leaves Use out of
	// the group while it holds (John on Discord: a model paused in a
	// vendor's peak hours). Only Time, Agents, Folders and ExceptFolders
	// can be its conditions: the request's clock, its agent and the folder
	// it says, never what it asks for — a pause keeps the model out of the
	// request whatever it is.
	Pause bool `json:"pause,omitempty"`
}

Rule sends the requests it matches to one of its group's members first. Every condition set must hold; a rule sets at least one.

func ParseRule added in v0.1.136

func ParseRule(g Group, words []string) (r Rule, at int, classifier string, err error)

ParseRule makes a rule of k=v words; the model is resolved among the group's members. classifier is the group's classifier when one was given, at the place asked for (from 1) when one was.

func (Rule) ByFolder added in v0.1.1191

func (r Rule) ByFolder() bool

ByFolder reports whether the rule holds by the folder the agent works in, in some or outside them: the request's folder is then read for it.

func (Rule) Conditions added in v0.1.94

func (r Rule) Conditions() []string

Conditions says what a rule matches, for a list or a trace.

func (Rule) Line added in v0.1.136

func (r Rule) Line() string

Line is the rule as ParseRule reads it back.

func (Rule) Matches added in v0.1.94

func (r Rule) Matches(q RuleRequest) bool

Matches reports whether the request is one the rule sends to its member first; a pause rule sends none (see Pauses).

func (Rule) MatchesBesidesIntent added in v0.1.95

func (r Rule) MatchesBesidesIntent(q RuleRequest) bool

MatchesBesidesIntent is Matches but for the rule's intent: whether the classifier's answer is all it waits on.

func (Rule) Pauses added in v0.1.1155

func (r Rule) Pauses(agent, folder string, at time.Time) bool

Pauses reports whether a pause rule holds for a request from agent at the time given, working in folder ("" when it didn't say).

type RuleRequest added in v0.1.94

type RuleRequest struct {
	Tokens   int
	Images   bool
	Thinking bool   // the agent asked for reasoning
	Effort   string // at what level, when it said
	Agent    string
	// Intent is the one of the rules' intents the classifier said the
	// user's message is; "" when none, or it wasn't asked.
	Intent string
	// Compact: the request is the agent compacting its conversation.
	Compact bool
	// At is when the request came, for a rule's hours; a zero time is in
	// none.
	At time.Time
	// Folder is the working folder the agent says the request is from;
	// "" when it doesn't say, which is in no rule's folders.
	Folder string
}

RuleRequest is what a rule looks at in a request.

type SearchAPI added in v0.1.587

type SearchAPI struct {
	Vendor string `json:"vendor"` // one of SearchVendors
	// Key is its key, or several separated by commas (Keys), each tried
	// when the one before is refused (#1477).
	Key string `json:"key,omitempty"`
	// Pick is how a search picks among several keys: "" takes them in
	// turn (SearchPickTurns), each search the next one; SearchPickOrder
	// asks the first until it is refused, then the next (SlouchyQuill on
	// Discord). Either way a key refused lately is asked last.
	Pick string `json:"pick,omitempty"`
	// URL is where it is: a SearXNG's own, or another address for one of
	// the others (a Firecrawl run by the user); empty is the vendor's.
	URL string `json:"url,omitempty"`
	// Off keeps it, key and all, out of every search until it is switched
	// on again (#2286): to try one API alone, or rest one whose credit is
	// nearly spent, without taking its key away.
	Off bool `json:"off,omitempty"`
}

SearchAPI is a web search API the user gave magpie a key to.

func SearchAPIs added in v0.1.587

func SearchAPIs() []SearchAPI

SearchAPIs are the search APIs that can be asked, in the order they are tried: ready, and not switched off.

func StoredSearchAPIs added in v0.1.587

func StoredSearchAPIs() []SearchAPI

StoredSearchAPIs are the search APIs as saved, keys and all.

func (SearchAPI) Base added in v0.1.587

func (a SearchAPI) Base() string

Base is the address it is asked at, without a slash at its end.

func (SearchAPI) Keys added in v0.1.1160

func (a SearchAPI) Keys() []string

Keys are the keys in Key: one, or several the user gave separated by commas, spaces or lines, each once, in the order given.

func (SearchAPI) MaskedKey added in v0.1.1160

func (a SearchAPI) MaskedKey() string

MaskedKey is Key as shown: each of its keys masked (MaskSearchKey), so a list of them shows no more of any one than a single key does.

func (SearchAPI) Name added in v0.1.587

func (a SearchAPI) Name() string

Name is the vendor's name.

func (SearchAPI) Ready added in v0.1.587

func (a SearchAPI) Ready() bool

Ready is whether it can be asked: a vendor magpie knows, at an address, with a key where it needs one (a SearXNG, You.com, may not).

type SearchVendor added in v0.1.587

type SearchVendor struct {
	ID, Name string
	Base     string // its address, "" for one the user runs
	KeysURL  string // where its keys are made
	// KeyOptional: it answers with no key too (a SearXNG; You.com's free
	// search, YouFreeSearch)
	KeyOptional bool
}

SearchVendor is a search API magpie can ask.

func SearchVendorOf added in v0.1.587

func SearchVendorOf(id string) (SearchVendor, bool)

SearchVendorOf is the vendor by its id.

type SessionIdentity added in v0.1.579

type SessionIdentity struct {
	Agent, AccountID, UserID, OrganizationID, User string
	// OfficialLogin describes this account's recorded login method, not the
	// route or credentials used for any particular historical request.
	OfficialLogin bool
}

SessionIdentity is an account's public identity, without its credentials.

func SessionIdentities added in v0.1.579

func SessionIdentities(codexDir string) []SessionIdentity

SessionIdentities reads the agent's current identity and remembered identities. Callers must match the IDs recorded in a session; presence alone is not evidence that the account served that session's requests.

type ShareError added in v0.1.1181

type ShareError struct {
	Why    string
	Format int
	Models []string
	Err    error
}

ShareError is why a text can't be imported as a group, by Why, for the GUI to say in the reader's language: "not_shared" (no group shared from magpie), "newer" (a format past ShareVersion, in Format), "no_format", "unreadable" (Err), "none_here" (none of its models here, in Models).

func (*ShareError) Error added in v0.1.1181

func (e *ShareError) Error() string

func (*ShareError) Unwrap added in v0.1.1181

func (e *ShareError) Unwrap() error

type SharedGroup added in v0.1.1181

type SharedGroup struct {
	Magpie  string `json:"magpie"`
	Version int    `json:"version"`
	Group   Group  `json:"group"`
}

SharedGroup is the text a group is shared as.

func ReadShared added in v0.1.1181

func ReadShared(text string) (SharedGroup, error)

ReadShared reads a shared group's text, as copied or pasted from a chat: the object may have words or a code fence around it.

type SignInOptions added in v0.1.1200

type SignInOptions struct {
	Site string // where to sign in, for one with more than one (StartSignInAt)
	// Proxy is the one to sign in through, as netproxy.With takes it ("" the
	// global one, "direct" none, or its address); nil for the one the
	// account's requests would go through. Picked, it is kept as the
	// account's own once the sign-in is done.
	Proxy *string
	// User is the account signed in to again, for the proxy it goes through
	User string
}

SignInOptions are a sign-in's choices beyond its subscription.

type SignInState added in v0.1.14

type SignInState struct {
	ID            string `json:"id"`
	Agent         string `json:"agent"`
	URL           string `json:"url"`                     // the vendor's page, to open or copy
	Code          string `json:"code,omitempty"`          // what to type there, for a device code
	State         string `json:"state"`                   // installing, waiting, done, failed or canceled
	PasteCallback bool   `json:"pasteCallback,omitempty"` // a callback URL can also finish this sign-in
	// PasteCode is a plugin's sign-in finished by the code its page shows
	PasteCode bool `json:"pasteCode,omitempty"`
	// PasteKey is a sign-in an API key made on KeysURL also finishes
	// (Command Code's, whose page posts its key where a pasted address
	// can't carry it)
	PasteKey     bool   `json:"pasteKey,omitempty"`
	KeysURL      string `json:"keysURL,omitempty"`
	Instructions string `json:"instructions,omitempty"` // a plugin's words for its page
	// Opened is a page the plugin's own CLI opened already (Grok Build's
	// `grok login`), shown but not opened a second time
	Opened bool `json:"opened,omitempty"`
	// Installing is the CLI being installed before the sign-in can start
	Installing string `json:"installing,omitempty"`
	User       string `json:"user,omitempty"`  // the account, once done
	Plan       string `json:"plan,omitempty"`  //
	Using      bool   `json:"using,omitempty"` // the agent was signed in to it too
	// Again is an account listed already: its sign-in was renewed rather
	// than a new account added (#413)
	Again bool   `json:"again,omitempty"`
	Error string `json:"error,omitempty"`
	// CallbackBlocked says why the port the browser is sent back to
	// couldn't be opened: "reserved" (Windows keeps it for Hyper-V, WSL or
	// Docker) or "busy" (another program has it). The sign-in goes on
	// without it, finished by the address its page ends on, pasted (#1782).
	CallbackBlocked string `json:"callbackBlocked,omitempty"`
	CallbackPort    int    `json:"callbackPort,omitempty"`
	// Proxy is the one the sign-in goes through ("" the global one,
	// "direct" none): the one the account's requests will (#1663)
	Proxy string `json:"proxy,omitempty"`
}

SignInState is where a sign-in stands, for the window to show.

func SignInStatus added in v0.1.14

func SignInStatus(id string) (SignInState, bool)

SignInStatus reports on a sign-in StartSignIn began.

func StartPluginSignIn added in v0.1.479

func StartPluginSignIn(id string, method int, inputs map[string]string) (SignInState, error)

StartPluginSignIn begins signing in to a plugin's provider (OpenCode's id) with its OAuth method, the method's questions answered: the page to open, then either the plugin notices on its own or the code the page shows is pasted back (SubmitSignInCallback). SignInStatus follows it, as it does a built-in sign-in; its Agent is the provider's magpie id. The account goes beside those signed in already, or replaces the one it is. A built-in moved onto its plugin installs the CLI it runs through first, as the built-in's sign-in did.

func StartPluginSignInWith added in v0.1.1200

func StartPluginSignInWith(id string, method int, inputs map[string]string, o SignInOptions) (SignInState, error)

StartPluginSignInWith is StartPluginSignIn through the proxy o picks, else the one the provider's requests go through (#1663).

func StartSignIn added in v0.1.14

func StartSignIn(agent string) (SignInState, error)

StartSignIn begins adding an account to an agent: open the returned URL in a browser and the rest happens on its own; SignInStatus follows it.

An agent signed in with a CLI that isn't installed has it installed first: the sign-in is then "installing", and gets its URL when that is done.

func StartSignInAt added in v0.1.425

func StartSignInAt(agent, site string) (SignInState, error)

StartSignInAt is StartSignIn on one of the sites an agent signs in on: ZCode's "zai" (the default) or "bigmodel".

func StartSignInWith added in v0.1.1200

func StartSignInWith(agent string, o SignInOptions) (SignInState, error)

StartSignInWith is StartSignIn with the sign-in's choices: its site and the proxy it goes through.

func WaitSignIn added in v0.1.14

func WaitSignIn(ctx context.Context, id string) (SignInState, error)

WaitSignIn blocks until a sign-in is over, for the command line.

type SignedInError added in v0.1.1025

type SignedInError struct{ Agent, User string }

SignedInError is ForgetLogin's refusal of the account an agent is signed in to now while it has another: that one is signed in to first (its Use), and this one removed then. The GUI says it in the reader's language (code signed_in).

func (*SignedInError) Error added in v0.1.1025

func (e *SignedInError) Error() string

type Spec added in v0.1.1360

type Spec struct {
	Context, Output, Vision, Reasoning SpecPart
	Entry                              Entry
}

Spec is a model's spec as magpie goes by it: the entry the gateway routes and the GUI and agents are shown, with where each part came from.

func SpecOf added in v0.1.1360

func SpecOf(ref string) (Spec, bool)

SpecOf is the spec of a model a provider serves, by "provider/model".

type SpecChange added in v0.1.1360

type SpecChange struct {
	// Context and Output are numbers of tokens; 0 takes the user's away.
	Context, Output *int
	// Vision is "on", "off", or "auto" for the vendor's list's answer.
	Vision *string
	// Reasoning is the levels the model offers: a range ("low-high"), a
	// list ("low,medium,high"), "off" for no reasoning ask at all, or
	// "auto" for the levels its list gives.
	Reasoning *string
}

SpecChange is what `magpie model spec` changes of one model. Each part left nil stays as it is.

func (SpecChange) Empty added in v0.1.1360

func (c SpecChange) Empty() bool

Empty is whether c changes nothing.

type SpecPart added in v0.1.1360

type SpecPart struct {
	Value string
	From  string
}

SpecPart is one part of a model's spec as it is in force: its value and where it came from — "model" for what the user set on it, "provider" for what they set on every model of its provider, "" for the vendor's list and models.dev.

type SpecRow added in v0.1.1360

type SpecRow struct {
	Key                                string
	Context, Output, Vision, Reasoning string
	// Gone: no provider of that id is there any more
	Gone bool
}

SpecRow is one model the user gave a spec, as `magpie model specs` lists it: each part as they set it, "" where they set none.

func ModelSpecs added in v0.1.1360

func ModelSpecs() []SpecRow

ModelSpecs are the models the user gave any part of a spec, by key.

type Stamp added in v0.1.1298

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

Stamp marks what the catalog is built from, read without building it. Two equal stamps mean nothing magpie wrote or was told of came between them: no Changed (a provider, an account, a setting saved), no plugin's change, no catalog.Reset or Touched, no filememo.Forget, the same environment, and the providers', the settings' and the catalog's own files with the same time and size, as another process leaves them. What it can't see — another app rewriting an account's file, a model retired by its date — a caller that keeps what it built across stamps builds again now and then all the same.

func StampNow added in v0.1.1298

func StampNow() Stamp

StampNow is the Stamp as things are now.

type SubscriptionQuota

type SubscriptionQuota struct {
	Provider  string        `json:"provider"`
	Name      string        `json:"name"`
	Icon      string        `json:"icon"`
	Plan      string        `json:"plan,omitempty"`
	AccessSKU string        `json:"accessSku,omitempty"`
	User      string        `json:"user,omitempty"` // the account, so two of one vendor tell apart
	Windows   []QuotaWindow `json:"windows"`
	Balance   string        `json:"balance,omitempty"` // what is left on an API key, instead of windows
	// BalanceParts are the Balance's amounts each apart, when the balance
	// field the user wrote has several or a percent (cardParts)
	BalanceParts []BalancePart `json:"balanceParts,omitempty"`
	// BalanceSplit is what the Balance is made of, when the vendor tells
	// it: DeepSeek's granted credit and the money topped up, each a part
	// labelled SplitGranted or SplitTopUp
	BalanceSplit []BalancePart `json:"balanceSplit,omitempty"`
	// BalanceTrend is the Balance over time, as magpie read it, and when
	// it runs out at that pace (balance_history.go)
	BalanceTrend *BalanceTrend `json:"balanceTrend,omitempty"`
	// Until is when the plan's paid time ends: it renews then when Renew
	// is "auto", is over when "off", and either when "" (the vendor
	// doesn't say which).
	Until *time.Time `json:"until,omitempty"`
	Renew string     `json:"renew,omitempty"`
	Error string     `json:"error,omitempty"`
	// PluginError is an Error a plugin's own usage read gave, in its own
	// words: magpie has no reading of it to say better, so the GUI shows
	// it on the card rather than only in a tooltip (aqiu817/magpie-sensenova#1).
	PluginError bool `json:"pluginError,omitempty"`
	// NeedsAccessKey is a plan read with the account's access key, which
	// its provider hasn't (accessKeyCard, #1821): the Usage page offers
	// the provider's settings to give it in.
	NeedsAccessKey bool `json:"needsAccessKey,omitempty"`
	// SeeAt is the vendor's page that shows what its API tells no key:
	// OpenCode Zen's credits, on its console (errOpenCodeNoBalance). The
	// Usage page offers to open it.
	SeeAt string `json:"seeAt,omitempty"`
	// AsOf is when an allowance shown in place of one that couldn't be
	// read was read (see keepLast); nil for a reading just made.
	AsOf *time.Time `json:"asOf,omitempty"`
	// ReadDeferred distinguishes a reading deliberately not requested from
	// a request that failed. AsOf and ReadAt still date the cached values.
	ReadDeferred bool `json:"readDeferred,omitempty"`
	// ReadAt is when what is shown was read: a key's balance, kept a
	// minute (KeyBalances), or an account's allowance, which a cache (a
	// minute's, or a Claude account's until Claude Code tells it again)
	// can hand back long after; nil when not known.
	ReadAt *time.Time `json:"readAt,omitempty"`
	// Resets are the rate-limit resets a Codex account holds, nil when it
	// holds none (codex_resets.go).
	Resets *ResetCredits `json:"resets,omitempty"`
	// ResetsUsed are the Codex account's resets magpie spent, newest
	// first, by itself or by hand (codex_resets_used.go): what the card
	// says when one is gone and the user asks where
	ResetsUsed []ResetUse `json:"resetsUsed,omitempty"`
	// Held is set on a ChatGPT account the Codex app sends nothing for
	// now (codexHeld): not on a window at 100% alone, which credits get
	// past.
	Held bool `json:"held,omitempty"`
	// Daily is a WorkBuddy account's credits used day by day, as magpie
	// counted them from its readings (credits_daily.go).
	Daily *DailyCredits `json:"daily,omitempty"`
	// Checkins is set on a WorkBuddy (China) or Trae CN account whose
	// daily check-in is pressed for, CheckinBy whose ("" WorkBuddy's,
	// "trae" Trae CN's), and Checkin is how its last one went, nil before
	// the first; never cached, added as the page asks (WithCheckins).
	Checkins  bool              `json:"checkins,omitempty"`
	CheckinBy string            `json:"checkinBy,omitempty"`
	Checkin   *WorkBuddyCheckin `json:"checkin,omitempty"`
	// CheckinOff is set on such an account the user left out of its
	// vendor's check-in (settings.CheckinOff, #1902): it isn't checked in.
	CheckinOff bool `json:"checkinOff,omitempty"`
	// Kind is the card's kind as another magpie is told it (CachedCards):
	// subscription, plan or balance; "" here.
	Kind string `json:"kind,omitempty"`
	// From is the remote magpie a card is that one's (remote_quotas.go),
	// by its name here; "" for this computer's own.
	From string `json:"from,omitempty"`
	// LastServedAt is when the account, plan or key last answered a
	// request through this computer's gateway, nil when it hasn't in the
	// last 30 days (served.go); set by Quotas, never cached.
	LastServedAt *time.Time `json:"lastServedAt,omitempty"`
	// Alias is the account's name of the user's own (AccountNames), else
	// Seat; Seat is the name of the key plan this account's card stands
	// in for (seatCards, #1515): the same GLM seat added both as a key
	// and as a signed-in account. Both "" when none; set as cards are
	// handed out, never cached.
	Alias string `json:"alias,omitempty"`
	Seat  string `json:"seat,omitempty"`
	// GatewayKey is set on the card of a gateway key a remote magpie gave
	// this computer (#1547, remote_key_limits.go): the limit that magpie
	// holds the key to, beside the windows that show it.
	GatewayKey *GatewayKeyLimit `json:"gatewayKey,omitempty"`
	// contains filtered or unexported fields
}

SubscriptionQuota is provider-reported allowance usage. This is separate from Dial's local token log: vendors expose percentages, not token totals.

func Allotted added in v0.1.791

func Allotted(ctx context.Context) []SubscriptionQuota

Allotted is Quotas without the keys' balances: the accounts and plans whose allowance runs out and starts again, which is what magpie quota wait waits on; no key's balance is asked for.

func CachedCards added in v0.1.1078

func CachedCards(now time.Time) []SubscriptionQuota

CachedCards is the Usage page's cards as this magpie last read them, each with its kind, for another magpie to show: no vendor is asked, whatever their age, and another magpie's cards shown here aren't passed on.

The cards are the page's with what was read of the same accounts and keys behind it since (cards_kept.go): a magpie serving only other magpies has nobody on its page (#1313).

func InProviderOrder added in v0.1.1307

func InProviderOrder(qs []SubscriptionQuota) []SubscriptionQuota

InProviderOrder is qs in the order the user put the providers in on the Providers page (SetOrder), each provider's cards as they came; a card of no provider here (a remote magpie's) after them all. The window's Usage page and the tray panel's Allowances tab draw them so, where the user hasn't arranged the cards themselves (Zhenbao TONG on Discord: the providers moved in the window, the tray kept its own order).

func KeyBalances added in v0.1.37

func KeyBalances(ctx context.Context) []SubscriptionQuota

KeyBalances is the balance of every provider magpie can ask one of, the key in use and each other key it has on — or its account's, once, when it has a token for that — as cards beside the subscriptions' allowances. What was asked less than a minute ago is not asked again, unless the providers were saved since (ForgetBalances).

func PlanQuotas added in v0.1.86

func PlanQuotas(ctx context.Context) []SubscriptionQuota

PlanQuotas is the windows of every plan magpie has a key for, each key on a card of its own when a provider has several. What was asked less than a minute ago is not asked again.

func Quotas added in v0.1.114

func Quotas(ctx context.Context) []SubscriptionQuota

Quotas is what is left everywhere magpie can ask: the signed-in subscriptions' windows, the plans bought with a key, and the keys' balances, as the Usage page shows them. The vendors are asked at once; what doesn't answer before ctx ends comes back with an error.

func RemoteCards added in v0.1.1078

func RemoteCards(ctx context.Context) []SubscriptionQuota

RemoteCards is every remote magpie's cards, named for this computer.

func SubscriptionUsage

func SubscriptionUsage(ctx context.Context) []SubscriptionQuota

SubscriptionUsage returns rolling quotas for signed-in first-party agents. Results are cached because these private account endpoints are aggressively rate limited when several CLI sessions are active. Once there is something cached it comes back at once, and a stale copy is refreshed in the background; only the very first call waits, for as long as ctx allows.

func WithCheckins added in v0.1.773

func WithCheckins(qs []SubscriptionQuota) []SubscriptionQuota

WithCheckins is qs with each WorkBuddy (China) account's card told it is checked in each day and how its last check-in went, for the Usage page to say on the card (#694: having to look in Settings to know whether it checked in is wrong). It holds for a moved account too: magpie checks those in through the plugin's fetch. qs, which may be the usage cache, is left as it is; nothing is asked.

func WithWindowStarts added in v0.1.1232

func WithWindowStarts(qs []SubscriptionQuota, now time.Time) []SubscriptionQuota

WithWindowStarts is qs with each window's StartsAt set where its bounds are known, for the GUI's Pace number; qs and its windows, which the caches share, are left as they were.

type Template added in v0.1.1163

type Template struct {
	Kind string `json:"kind"`
	// Group is the group it makes, not saved: no Members when it can't be
	// made of the models there are, Why saying what is missing
	Group Group  `json:"group"`
	Why   string `json:"why,omitempty"`
	// Need is what is missing, for the GUI to say in the user's language:
	// NeedProvider, NeedProviders (Of the only one) or NeedCheap (Of the
	// strong model)
	Need string `json:"need,omitempty"`
	Of   string `json:"of,omitempty"`
}

Template is one template as the user's models make it now.

func MakeTemplate added in v0.1.1163

func MakeTemplate(kind string) (Template, error)

MakeTemplate is the template kind as the user's models make it now, or why it can't be made.

func Templates added in v0.1.1163

func Templates() []Template

Templates are every template as the user's models make it now.

type TimeWindow added in v0.1.570

type TimeWindow struct {
	From string   `json:"from"`
	To   string   `json:"to"`
	Days []string `json:"days,omitempty"`
}

TimeWindow is hours of the day, local time: From until To, "HH:MM" each, past midnight when To comes before From (22:00–08:00), the whole day when they are the same. Days, when set, are the days it holds on ("mon" … "sun"); a window past midnight is of the day it begins on, so Friday's 22:00–08:00 takes Saturday's early hours too.

func ParseTimeWindow added in v0.1.570

func ParseTimeWindow(v string) (*TimeWindow, error)

ParseTimeWindow reads hours of the day: 09:00-18:00, 22:00-08:00.

func (TimeWindow) DaysText added in v0.1.570

func (w TimeWindow) DaysText() string

DaysText is the window's days for a list: "Mon–Fri", "Sat,Sun", "Mon,Wed–Fri"; "" for every day.

func (TimeWindow) Holds added in v0.1.570

func (w TimeWindow) Holds(at time.Time) bool

Holds reports whether at is within the window, on the machine's clock.

func (TimeWindow) Text added in v0.1.570

func (w TimeWindow) Text() string

Text is the window as a rule's conditions show it: "09:00–18:00 Mon–Fri".

type Vertex added in v0.1.1162

type Vertex struct {
	// Project is the Google Cloud project's id: requests are made, and
	// billed, there.
	Project string `json:"project,omitempty"`
	// Location is global, us, eu or a region (us-central1); each serves
	// models of its own (vertexModels).
	Location string `json:"location,omitempty"`
	// Credentials is a credentials file; "" finds them as Google's
	// libraries do (vertexCredentialsFile).
	Credentials string `json:"credentials,omitempty"`
	// Impersonate is the email of a service account the credentials are
	// traded for, "" to ask as their own account.
	Impersonate string `json:"impersonate,omitempty"`
}

Vertex is where a Vertex AI provider's requests go, and whose credentials sign them.

func (*Vertex) Normal added in v0.1.1162

func (v *Vertex) Normal() *Vertex

Normal is v as it is kept: trimmed, at global when no location is given, nil when nothing is. The app's Refresh and Test ask with the values typed spelled so.

type WindowCaps added in v0.1.1134

type WindowCaps struct {
	All     int
	Windows map[string]int
	Credits bool
}

WindowCaps is what holds an account at a share of its windows: its usage cap for every window (All), the share of each window the user set one on (Windows, by WindowCapID; 100 is none on that window), and Credits for a Codex account set not to spend its credits, which holds any window with no cap at the vendor's own 100%.

func AccountCapsOf added in v0.1.1134

func AccountCapsOf(id, user string) WindowCaps

AccountCapsOf is CapsOf of the provider id.

func HoldCaps added in v0.1.1134

func HoldCaps(p Provider, agent, user string) WindowCaps

HoldCaps is the shares of its windows at which routing holds the account user of p, of agent, as used up: its usage cap and its windows' own (account_caps.go), and for a Codex account set not to spend its credits 100% of any window with no cap. Holds() is false when nothing holds it before the vendor does.

func (WindowCaps) Holds added in v0.1.1134

func (c WindowCaps) Holds() bool

Holds says whether any window can hold the account before the vendor does.

func (WindowCaps) Of added in v0.1.1134

func (c WindowCaps) Of(name string) (share int, credits bool)

Of is the share at which the window named name holds the account, 0 for none, and whether it is the credits that hold it there.

type WindowHolds added in v0.1.1120

type WindowHolds struct {
	Tokens int64   `json:"tokens"`
	Cost   float64 `json:"cost,omitempty"`
	Priced bool    `json:"priced"`
	Used   float64 `json:"used"`
	Routed struct {
		Calls      int     `json:"calls"`
		Tokens     int64   `json:"tokens"`
		CacheRead  int64   `json:"cacheRead,omitempty"`
		CacheWrite int64   `json:"cacheWrite,omitempty"`
		Cost       float64 `json:"cost,omitempty"`
	} `json:"routed"`
	Since time.Time `json:"since"`
}

WindowHolds is a window's whole allowance reckoned from magpie's own calls: Tokens of input and output (cache traffic aside, as the Usage page counts tokens) and, when every call's model has an API list price, Cost at those prices (cache reads and writes at the vendor's own rates). Routed is what magpie routed through the account in the window so far, up to when the share was read, and Used that share. A call made with the account outside magpie is in Used but not in Routed, so the estimate is then lower than the window really holds.

type WorkBuddyCheckin added in v0.1.356

type WorkBuddyCheckin struct {
	User    string    `json:"user,omitempty"` // as listed now; never kept
	Day     string    `json:"day"`
	At      time.Time `json:"at"`
	Outcome string    `json:"outcome"`
	Credit  float64   `json:"credit,omitempty"`
	Streak  int       `json:"streak,omitempty"`
	Msg     string    `json:"msg,omitempty"`
	// ValidUntil is a campaign's end, when a successful answer must be
	// checked again, even if the Beijing day hasn't changed.
	ValidUntil time.Time `json:"until,omitzero"`
	// Offline is a failure that never reached WorkBuddy, and Tries how
	// many before it the same day did the same.
	Offline bool `json:"offline,omitempty"`
	Tries   int  `json:"tries,omitempty"`
	// By is the vendor whose check-in it is: "" WorkBuddy's, "trae"
	// Trae CN's; never kept.
	By string `json:"by,omitempty"`
	// Vendor is a plugin's provider by name, for a check-in By
	// "plugin:<id>"; never kept.
	Vendor string `json:"vendor,omitempty"`
	// Asked is true of one checked in on this run, not one read back;
	// sent so a press can tell a claim now from one earlier today.
	// Never kept: the file is written before it is set.
	Asked bool `json:"asked,omitempty"`
	// Claimed is when magpie last saw the account's credits claimed,
	// carried over while later answers that day say done: a done after
	// magpie's own claim is the day's, one before it may be yesterday's
	// (#3326).
	Claimed time.Time `json:"claimed,omitzero"`
	// Again says the answer is provisional (provisional): magpie asks
	// the vendor again later that day. Worked out when shown, never
	// kept.
	Again bool `json:"again,omitempty"`
}

WorkBuddyCheckin is what came of a WorkBuddy account's check-in on Day (Beijing): the credits it gave and the streak it made, or why none.

func CheckInMiniMax added in v0.1.910

func CheckInMiniMax(ctx context.Context) []WorkBuddyCheckin

CheckInMiniMax checks each MiniMax Code account in use in for today now, those not in yet, and says how each stands.

func CheckInPlugins added in v0.1.1085

func CheckInPlugins(ctx context.Context, ids ...string) []WorkBuddyCheckin

CheckInPlugins checks the accounts of each plugin that checks in in for today now, those not in yet; with ids, only those providers'. It says how each stands.

func CheckInQoder added in v0.1.1077

func CheckInQoder(ctx context.Context) []WorkBuddyCheckin

CheckInQoder checks each Qoder account in use in for today now, those not in yet, and says how each stands.

func CheckInTrae added in v0.1.784

func CheckInTrae(ctx context.Context) []WorkBuddyCheckin

CheckInTrae checks each Trae CN account in use in for today now, those not in yet, and says how each stands.

func CheckInWorkBuddy added in v0.1.356

func CheckInWorkBuddy(ctx context.Context) []WorkBuddyCheckin

CheckInWorkBuddy checks each WorkBuddy (China) account in use in for today now, those not in yet, and says how each stands.

func MiniMaxCheckins added in v0.1.910

func MiniMaxCheckins() []WorkBuddyCheckin

MiniMaxCheckins is each MiniMax Code account's last check-in, as kept, by its name now; asks nothing.

func QoderCheckins added in v0.1.1077

func QoderCheckins() []WorkBuddyCheckin

QoderCheckins is each Qoder account's last check-in, as kept, by its name now; asks nothing.

func TraeCheckins added in v0.1.784

func TraeCheckins() []WorkBuddyCheckin

TraeCheckins is each Trae CN account's last check-in, as kept, by its name now; asks nothing.

func WorkBuddyCheckins added in v0.1.356

func WorkBuddyCheckins() []WorkBuddyCheckin

WorkBuddyCheckins is each WorkBuddy (China) account's last check-in, as kept, by its name now; asks nothing.

func (WorkBuddyCheckin) Checked added in v0.1.356

func (r WorkBuddyCheckin) Checked() bool

Checked says whether the day's credits are in, claimed now or before.

type ZhipuTeam added in v0.1.431

type ZhipuTeam struct {
	Org     string `json:"org,omitempty"`
	Project string `json:"project,omitempty"`
}

ZhipuTeam is the team a Zhipu or Z.ai key's GLM Coding Plan belongs to: its organization and project IDs, as the BigModel console shows them.

Source Files

Jump to

Keyboard shortcuts

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