Skip to content

fix(quota): ignore GLM MCP call counts and announce a cleared quota - #210

Merged
fylorn merged 1 commit into
mainfrom
fix/glm-quota-drop-mcp-window
Sep 26, 2026
Merged

fylorn merged 1 commit into
mainfrom
fix/glm-quota-drop-mcp-window

Conversation

@fylorn

@fylorn fylorn commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

What this changes

The GLM Coding Plan quota added in 0.50.0 (#204, #208) no longer reports the MCP call count of the older plans, and core now tells the UI when it takes an upstream's quota down.

  • The TIME_LIMIT item is ignored. In the older plans' answer from the quota endpoint it counts calls to Z.ai's own MCP tools (search-prime, web-reader, zread). It is no longer read, so there is no monthly window: it is not reported, not shown, does not count towards the tightest window and cannot raise a used-up notice.
  • 1310 marks weekly only. On a model request 1310 means the weekly quota is used up, whatever its message says ("Weekly/Monthly", "Monthly", "5 hour" all give weekly). 1308 is unchanged. 1316-1321 keep the existing mapping without monthly: 5h or weekly when the message says which, otherwise the fuller of the known 5h and weekly windows, and weekly when neither is known. guess_window no longer takes the code, since only 1316-1321 reach it now.
  • credits come only from CREDIT_LIMIT items. With monthly gone, the doc comments of QuotaCredits and QuotaWindow::credits describe the credit plan only. The parser now enforces it as well: a TOKENS_LIMIT item that carries usage / currentValue / remaining counts tokens, and the app would show those numbers as credits.
  • A cleared quota emits an event. When a key is judged to have no plan, core clears the quota it stored for that upstream and emits QuotaSeen with empty windows. Nothing is emitted when nothing was stored.

Why

The MCP calls never pass through the gateway, so their count says nothing about whether requests through it will be served. It showed up as a quota window, and a used-up monthly count could colour the upstream as used up or notify.

A key found to have no plan had its quota cleared silently, so the app kept showing the old quota until it next read /quota. The app already replaces an upstream's quota with the windows of each QuotaSeen it receives (useUpstreamStats in Lite), so an empty QuotaSeen collapses the quota cell at once. Reusing that event is the smallest change that does this: no new variant, and the bus and recorder already treat QuotaSeen as upstream state, not request history.

Protocol changes

CONTROL_API_VERSION 23 -> 24.

  • The quota window vocabulary (QuotaWindow.window, QuotaExhausted.window) no longer has monthly.
  • QuotaSeen is documented as carrying the upstream's full set of windows, to replace what the client had. Empty windows means the upstream's quota was taken down: the earlier windows no longer count and the upstream is gone from /quota. It is emitted when a GLM key is found to have no plan and core had a quota stored for it.
  • QuotaWindow.credits / QuotaCredits: only credit-plan windows (CREDIT_LIMIT) have them.

No endpoints, types or message codes change. The config manual does not change.

How it was verified

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-targets -- -D warnings: clean
  • cargo test --workspace (proxy variables unset): 1696 passed, 0 failed
  • cargo clippy -p tw-api --all-targets --features ts -- -D warnings, cargo test -p tw-api --features ts, export_ts and tsc --noEmit --strict on the export: clean, CONTROL_API_VERSION = 24 in the bindings

New or changed tests:

  • glm::tests::an_old_v2_plan_adds_a_weekly_window_and_ignores_the_mcp_calls: a V2 answer whose TIME_LIMIT is used up (100%, remaining 0) gives exactly weekly and 5h, and nothing is marked rejected because of it. an_old_v1_plan_has_only_the_five_hour_window does the same for V1.
  • glm::tests::a_1310_is_the_weekly_window_whatever_the_message_says and state::glm::tests::a_1310_marks_only_the_weekly_window: a 1310 whose message says "Monthly" marks only weekly, even when the known 5h window is fuller, and emits a single QuotaExhausted for weekly.
  • glm::tests::team_limits_count_too: 1316-1321 read 5h and weekly from the message, and a message that says monthly names no window.
  • glm::tests::only_a_credit_window_has_credits: a TOKENS_LIMIT item with the three numbers has no credits.
  • state::glm::tests::forgetting_a_quota_tells_the_ui_with_an_empty_quota_seen: clearing a stored quota emits one empty QuotaSeen, clearing again emits nothing, and a later used-up window is reported again.
  • tests/glm_quota.rs::a_key_found_to_have_no_plan_takes_its_quota_down_at_once: end to end against the fake GLM. A key with a credit plan is read, the key is replaced by one without a plan, and the next /quota refresh clears the quota and emits an empty QuotaSeen.

Notes for review

  • The app needs a release built on this tag: it only connects to a core with the same protocol version, and its window labels still have monthly (harmless once core stops sending it).
  • Lite's notice rules clear used-up notices per window from the windows a QuotaSeen carries, so an empty one clears none. Lite can treat an empty QuotaSeen as clearing that upstream's quota notices. That is a change on the Lite side, not here.

🤖 Generated with Claude Code

The older GLM Coding Plans report a monthly TIME_LIMIT item that counts
calls to Z.ai's own MCP tools (search-prime, web-reader, zread). Those
calls never pass through the gateway, so the count says nothing about
whether requests through it will be served. It was still reported as the
`monthly` quota window, shown, counted towards the tightest window and
able to raise a used-up notice.

- The TIME_LIMIT item is ignored and `monthly` is no longer a quota
  window.
- A 1310 on a model request means the weekly quota is used up, so it
  marks `weekly` only, whatever its message says. 1316-1321 still take
  5h or weekly from the message, and otherwise the fuller of the known
  5h and weekly windows.
- `credits` are read only from credit-plan items (CREDIT_LIMIT). A
  TOKENS_LIMIT item carrying usage/currentValue/remaining counts tokens,
  and showing those as credits would be wrong.
- When a key is found to have no plan and core clears the quota it had
  stored for that upstream, it now emits a QuotaSeen with empty
  `windows`. The UI already replaces an upstream's quota with the
  windows of the event, so the quota cell collapses at once instead of
  on the next read of /quota. Nothing is emitted when nothing was stored.

CONTROL_API_VERSION is now 24: the window vocabulary no longer has
`monthly`, and an empty QuotaSeen means the upstream's quota was taken
down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn
fylorn merged commit 9791cca into main Sep 26, 2026
4 checks passed
@fylorn
fylorn deleted the fix/glm-quota-drop-mcp-window branch September 26, 2026 05:10
@fylorn fylorn mentioned this pull request Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant