Files
magpie/internal
yetone d1d4b7ed2a usage: a heatmap of the last 53 weeks on the Requests tab, by tokens, requests or cost (#1369, nianlee-official)
What changed: the Requests tab of the Usage page shows a heatmap card like
CC Switch's: a cell per day for the last 53 weeks, Monday on top, month
names over the weeks and weekday names at the edge, a Tokens / Requests /
Cost switch (kept in localStorage), a five-shade Less…More legend, and a
tip on each day with its date, tokens, requests and cost.

How: GET /api/usage/heatmap (usage.HeatmapOf) reads QueryPage's cached
request index over a hidden period, "heatmap", which starts on the Monday 52
weeks before this week's. Its rows are summed by local calendar day in both
the compact and the ledger path. So no raw log is scanned per render, and the
days count what the chart counts:
- the page's agent/provider/model/key filters, but not the period or day
  picked;
- the gateway's own rejections left out;
- cost of priced calls only, with an unpriced count.
The days are in the local time zone and the shades use theme tokens
(.l0–.l4, as in the sessions calendar). There are no left-border accents and
no native <select>. A click never scrolls the page. A narrow window scrolls
the card sideways inside itself, with the newest week in sight (kept there
as it's laid out or resized, until the reader scrolls back), and the weekday
names stay at the card's edge. The card is hidden when no day has calls. New
strings are in zh, zh-TW, ja and de.

Run:
- go test -tags nogui ./internal/usage ./internal/gui (new TestHeatmapDays,
  TestHeatmapOf, TestUsageHeatmapRoute); gofmt -l clean; go vet darwin,
  GOOS=linux and GOOS=windows go vet -tags nogui on both packages; go build
  for darwin, linux and windows.
- New internal/gui/tests/usage-heatmap.test.cjs in Chromium and WebKit, at
  420 and 1100, in en, zh, zh-TW, ja and de, plus dark and the empty case.
  It checks:
  - the cells, labels, legend and the busiest and quiet days;
  - the newest week in sight and only the card scrolling sideways;
  - the tip's text and that it stays inside the card;
  - that a metric click moves nothing and is kept;
  - that the filters, but no period or day, are sent.
- Breaking checks: with the keep-at-end guard reverted, 5 of its 11 subtests
  fail in WebKit; with the server's heatmap dropped, TestUsageHeatmapRoute
  fails.
- i18n-keys, click-scroll, gui-de, gui-ja, gui-zh-tw, sessions-usage-open
  and all usage-*.test.cjs GUI tests pass in both engines (161 each).
- A sandboxed `magpie web` (temp HOME, 2605 fake calls over 400 days, ports
  3671/3672): the card fills 369 days at 1280 and 420 wide, and the tip
  reads "2026年10月1日周四 / 2.6M token · 23 个请求 · ≈$1.05+".
2026-10-09 11:33:47 +08:00
..
settings: keep awake can keep the display on too (#975, Hu9956: magpie's keep-awake held the system up, but the screen still went black and locked, and their agents record the screen to check their work, which a locked screen stops) — Settings › General's "Keep awake while agents work" row now has three segments, Off / On / Screen on too, saved as keepAwake and the new keepAwakeDisplay (default off, so On and every existing settings.json behave as before). awake.Keep takes a Level (Off, System, Display) in place of a bool; a level changed while held releases and takes the hold anew. On a Mac the display level runs caffeinate -i -d -w <pid> (pmset -g assertions on a caffeinate of the same flags shows PreventUserIdleDisplaySleep beside PreventUserIdleSystemSleep); on Windows SetThreadExecutionState gets ES_DISPLAY_REQUIRED too; on Linux logind's idle inhibitor (systemd-inhibit --what=idle:sleep, unchanged) is all there is, and whether the screen stays on is up to the desktop. keepAwakeDisplay is this computer's own (KeepOwn) and goes in prefsKeep, so another setting's save keeps it. The row's line says the display stays on when it's chosen; it keeps its English in data-en, so a language change re-translates it. zh/ja/de strings added. No TUI or CLI has keep-awake, so none changed. TestKeepDisplay (taken once, taken anew with the display, not again at the same level, back to System, released at Off), TestCaffeinateArgs, TestExecutionState (GOOS=windows test build) and TestKeepAwakeKeptAndOwn cover it; go test ./internal/awake ./internal/settings ./internal/gui ./internal/gateway pass, -race -count=5 on awake. keep-awake.test.cjs now runs en/zh/ja/de at 900px and 440px in Chromium and WebKit (display posts keepAwake+keepAwakeDisplay true, the line changes, another setting's save keeps it, segments fit the row, On and Off clear it, no click moves the page): 32/32 twice; gui-ja, gui-de, i18n-keys and click-scroll pass. go vet (darwin, windows, linux), darwin, linux (nogui) and windows builds pass. Not tried with an agent recording the screen; the reporter is asked to confirm.
2026-10-06 15:33:28 +08:00
…
netproxy: a host on the user's own network goes around the proxy (#982, jiz4oh: a Remote magpie's model list failed with "no model list: http://server…:3425/v1/models: 502 Bad Gateway", and Test with "no model to try", while curl with the key got the list) — the 502 had no body, which magpie's own errors always carry, and the other magpie logged nothing for the refresh: the request went to the proxy magpie takes from its settings, the environment or the system (Clash and the like), which couldn't reach the LAN name and answered 502. netproxy.Func now sends a request directly when the global proxy would take it and the host is on the user's network: a private, link-local, loopback or 100.64/10 (Tailscale) address, a .local name, or a name whose every address is one of those (looked up for at most 400ms, kept a minute; a name that doesn't resolve still goes through the proxy). A provider's own proxy is still taken as it is. Models, chat, count_tokens and the shared quota cards to a Remote magpie all go through Func (http.DefaultClient and the gateway's transport), so all are covered; so is any other provider on the LAN (an Ollama on a NAS). TestLANModelListNotThroughProxy (a proxy that answers 502 to everything, set in magpie, and a fake remote magpie on this computer's LAN address) fails without the change with the reporter's bare "502 Bad Gateway" and passes; TestLANGoesAroundTheProxy (IPs, LAN/Tailscale names, a vendor, a provider's own proxy) fails without it. Not tried on the reporter's network; they're asked to confirm. go test ./internal/netproxy/ ./internal/catalog/ ./internal/provider/ ./internal/gateway/ ./internal/update/ ./internal/usage/ pass; -race -count=5 on the new tests; go vet, darwin/linux(nogui)/windows builds pass.
2026-10-06 13:35:32 +08:00
upstream: the vendors' own status pages say when their API is down (#971, emo172: an Anthropic or OpenAI outage looked like a sign-in or quota problem) — a provider that calls Anthropic's, OpenAI's or Moonshot's API (by its base URL's host: api.anthropic.com, which the Claude subscription calls too; api.openai.com and chatgpt.com, Codex's; api.moonshot.cn/.ai) carries "API outage" (red), "API degraded" or "API maintenance" beside its name on its Providers row and its Usage card while the vendor's page says so; its title names the parts and the open incidents, and a click opens the incident (or the page), not the row. internal/upstream reads each page's Statuspage-style summary.json (status.claude.com; status.openai.com, incident.io's; status.moonshot.cn), checked by hand on 2026-10-06, and only the API's own parts (Claude API and Claude Code, not claude.ai; Chat Completions, Responses, Codex, Codex CLI, not "Codex in ChatGPT Desktop", which was degraded that day); an incident naming no parts (OpenAI's) counts only while those parts are affected. Pages are read only when the Providers or Usage page asks (GET /api/upstream), at most once in five minutes, never on a request's way; a page that fails, isn't JSON or no longer lists the API's parts is unknown and marks nothing. A relay serving the same models is never marked. DeepSeek's page (Flashduty) has nothing readable and is only known for its link; OpenRouter, xAI, Mistral and z.ai have no page read. The gateway's failure messages, TUI, CLI and tray aren't changed. zh/ja/de added. upstream_test (fake pages from the real summaries: API down, claude.ai down isn't the API, Claude Code degraded, OpenAI's app isn't the API, 503/HTML/changed page unknown, read once in Fresh and Of never waits, hosts; -race -count=5) and gui's TestUpstreamRoute pass; upstream-status (Anthropic down: its provider and the Claude subscription marked, relay/OpenAI/unread Moonshot not, click opens the incident not the row, all well marks nothing; 900 and 440px, the badge whole, the name giving way) passes in Chromium and WebKit, en and zh, and fails 8/8 without the app.js change. i18n-keys, gui-ja, gui-de, click-scroll, account-return, account-models, usage-keys-fold, deprecated-subscriptions and add-sheet pass; go vet, go test ./internal/gui/, linux/windows/nogui builds pass.
2026-10-06 12:36:05 +08:00
…