Repository navigation
feat(status-bar): track Z.ai GLM Coding Plan usage - #18507
ArtemBozhenko wants to merge 2 commits into
Conversation
Adds Z.ai as a usage provider so the status bar shows GLM Coding Plan quota next to Claude, Codex, Gemini, OpenCode Go, Kimi, MiniMax and Grok. The key is a settings-level protected secret (same path as the OpenCode Go cookie), and the fetcher reads z.ai's monitor endpoint, which takes the raw key — a `Bearer` prefix is rejected. The 5-hour and weekly windows map onto the contracted 300 / 10080-minute buckets so the bar labels them like every other provider; window units the API has not documented are dropped rather than guessed into the wrong bucket. The MiniMax status-bar search entry moves to its own module so the shared catalog stays under the max-lines ratchet, matching the Grok/Antigravity entries that already live in their own files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FNBmqKA9PvYQ7A8pYiW5GY
There was a problem hiding this comment.
ℹ️ One minor cleanup — otherwise this is solid.
Reviewed changes
- Z.ai fetcher — new
fetchZaiRateLimits(...)againstapi.z.ai/api/monitor/usage/quota/limit, raw-keyAuthorizationheader, unit-code mapping to the 5-hour/weekly contract buckets. - Credential plumbing —
zaiApiKeyinGlobalSettings, encrypted viaPROTECTED_SECRET_SLOT, decrypted on load, retained blob dropped on clear. - Service wiring — seventh slot in the full fetch cycle, config-hash change tracking, failure streak, stale-policy application, poll state aggregation.
- Renderer — status bar segment (
Zletter), visibility menu checkbox, tooltip icon,ZaiIconSVG, settings pane API key input, search entries,_zaiStatusBarDefaultAddedone-shot migration. - Housekeeping — MiniMax status-bar search entry extracted to its own module (
appearance-status-bar-minimax-toggle-search.ts), matching the Grok/Antigravity split.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
📝 WalkthroughWalkthroughThe change adds Z.ai GLM Coding Plan quota tracking. It stores the Z.ai API key as an encrypted setting, fetches 5-hour and weekly quota windows, and integrates Z.ai into rate-limit state and polling. The renderer adds Z.ai account configuration, search entries, status-bar visibility controls, icons, labels, default-item hydration, and localized strings. Tests cover quota parsing, request authentication, credential errors, HTTP errors, API failures, and updated provider state fixtures. Documentation describes setup and usage tracking. Merge Risk: 🔵 Low · up to Z.ai quota tracking adds API-backed status-bar usage data. Cancellation behavior for an in-flight quota request is not yet demonstrated, so a cancelled refresh could wait for the request timeout if abort propagation fails. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The implementation satisfies issue Full details: Docstring CoverageExplanation Docstring coverage is 13.89% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 36 functions across 45 files. (3 skipped: 3 unsupported.) Full details: Description checkExplanation The description follows the required template and covers the change, rationale, linked issue, implementation details, testing, security, compatibility, and checklist items. It includes an after screenshot and explains the before state, although a separate before attachment is not provided.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Team
Run ID: 86c50112-62c5-4d00-8e39-04e25eae95bc
📒 Files selected for processing (49)
docs/site/content/docs/agents/usage-tracking.mdxdocs/site/content/docs/settings.mdxsrc/main/codex-accounts/runtime-home-settings-test-fixtures.tssrc/main/codex-accounts/service-reset-credit-test-fixtures.tssrc/main/codex-accounts/service-test-harness.tssrc/main/persistence/applying-settings/settings-update.tssrc/main/persistence/loading-store/loaded-state-parsing.tssrc/main/persistence/loading-store/state-serialization-secret-handling.tssrc/main/protected-secret-persistence.tssrc/main/rate-limits/service/service-configuration.tssrc/main/rate-limits/service/service-full-cycle-application.tssrc/main/rate-limits/service/service-full-cycle-preparation.tssrc/main/rate-limits/service/service-polling.tssrc/main/rate-limits/service/service-result-policy.tssrc/main/rate-limits/service/service-state.tssrc/main/rate-limits/service/service-types.tssrc/main/rate-limits/zai-fetcher.test.tssrc/main/rate-limits/zai-fetcher.tssrc/main/runtime/rpc/methods/client-ui-schemas.tssrc/main/startup/main-process-account-services.tssrc/renderer/src/components/settings/AccountsPane.tsxsrc/renderer/src/components/settings/accounts-pane-zai-section.tsxsrc/renderer/src/components/settings/accounts-search.tssrc/renderer/src/components/settings/appearance-status-bar-minimax-toggle-search.tssrc/renderer/src/components/settings/appearance-status-bar-search.tssrc/renderer/src/components/settings/appearance-status-bar-zai-toggle-search.tssrc/renderer/src/components/stats/GrokUsagePane.test.tsxsrc/renderer/src/components/status-bar/StatusBarProviderSegment.tsxsrc/renderer/src/components/status-bar/StatusBarVisibilityMenu.tsxsrc/renderer/src/components/status-bar/icons.tsxsrc/renderer/src/components/status-bar/status-bar-provider-visibility.test.tssrc/renderer/src/components/status-bar/status-bar-provider-visibility.tssrc/renderer/src/components/status-bar/tooltip.tsxsrc/renderer/src/components/status-bar/usage-error-copy.tssrc/renderer/src/components/status-bar/usage-provider-settings-target.tssrc/renderer/src/components/status-bar/use-status-bar-controller.tssrc/renderer/src/hooks/settings-navigation-capability-sections.tssrc/renderer/src/i18n/en-runtime-required.jsonsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/store/slices/rate-limits.tssrc/renderer/src/store/slices/ui/ui-slice-hydration-actions.tssrc/renderer/src/web/preload-api/web-rate-limits-api.tssrc/shared/default-global-settings.tssrc/shared/global-settings-types.tssrc/shared/persisted-ui-state-types.tssrc/shared/rate-limit-types.test.tssrc/shared/rate-limit-types.tssrc/shared/status-bar-defaults.tssrc/shared/ui-chrome-types.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.
…oint, docs - pass the fetch-cycle AbortSignal into fetchZaiRateLimits and combine it with the 15s timeout, so a cancelled poll cycle no longer lingers in allSettled - drop the unused CN endpoint constant and the endpoint override it fed - correct the usage-tracking doc: Z.ai is API-backed, unlike the local-state providers, and reads "Usage unavailable" without a key - add Z.ai to the stale English accounts-section catalog string - docstrings on the new exported helpers Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FNBmqKA9PvYQ7A8pYiW5GY
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Fetch-cycle abort signal —
fetchZaiRateLimitsnow accepts a callersignaland combines it with the 15s timeout viaAbortSignal.any; the full fetch cycle passes itssignalthrough, so a cancelled poll no longer lingers inPromise.allSettled. This mirrors the existinggrok-fetcheridiom exactly. - Dead-code removal — dropped
ZAI_CN_USAGE_ENDPOINTand theendpointoverride; the fetcher now always targetsZAI_USAGE_ENDPOINT. - Tests — added a case asserting the caller signal propagates through to
net.fetchand aborts with the controller. - Docs —
usage-tracking.mdxnow documents Z.ai's key requirement and theUsage unavailablestate instead of the prior "no API calls" claim. - i18n — added the Z.ai accounts-section catalog string and the new Z.ai settings/status-bar strings to
en.jsonanden-runtime-required.json.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/rate-limits/zai-fetcher.test.ts (1)
103-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winMake the cancellation test exercise an in-flight request.
netFetchMock.mockResolvedValue(...)completes the request beforecontroller.abort()runs, so the test checks only signal state. Keep the mock pending, reject it on signal abort, and assert thatfetchZaiRateLimitssettles promptly instead of waiting for the 15-second timeout.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Team
Run ID: 8f05351a-8b47-4e94-9609-764f4abef747
📒 Files selected for processing (9)
docs/site/content/docs/agents/usage-tracking.mdxsrc/main/rate-limits/service/service-full-cycle-preparation.tssrc/main/rate-limits/zai-fetcher.test.tssrc/main/rate-limits/zai-fetcher.tssrc/renderer/src/components/settings/accounts-pane-zai-section.tsxsrc/renderer/src/components/settings/appearance-status-bar-minimax-toggle-search.tssrc/renderer/src/components/settings/appearance-status-bar-zai-toggle-search.tssrc/renderer/src/i18n/en-runtime-required.jsonsrc/renderer/src/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (6)
- src/renderer/src/components/settings/appearance-status-bar-zai-toggle-search.ts
- src/renderer/src/components/settings/appearance-status-bar-minimax-toggle-search.ts
- src/renderer/src/i18n/en-runtime-required.json
- src/renderer/src/components/settings/accounts-pane-zai-section.tsx
- src/renderer/src/i18n/locales/en.json
- docs/site/content/docs/agents/usage-tracking.mdx
Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.
|
Reviewed against current main. The feature request and @ArtemBozhenko's work on quota visibility are valid, but this branch now duplicates the GLM Coding Plan integration already delivered by #23520 and #24618. Current main has a separately stored quota key, Z.AI/BigModel selection, Accounts controls, status-bar visibility, cancellation, and five-hour/weekly/monthly quota parsing through the existing Merging this PR would add a parallel The linked quota-only issue #18506 is already closed. The broader model/OAuth request #8476 remains open. |

ELI5
Orca already shows how much of your Claude/Codex/Gemini/Kimi/MiniMax plan you have burned. This adds the same readout for Z.ai's GLM Coding Plan: paste your Z.ai API key in Settings → AI Provider Accounts, and the status bar gains a
Zsegment with the 5-hour and weekly windows.What Changed
zaiend to end:ProviderRateLimits['provider'],RateLimitState.zai, thezaistatus-bar item (default-on, with the one-shot_zaiStatusBarDefaultAddedmigration used by the other late-added items), visibility menu entry, appearance/accounts search entries, tooltip icon, and provider letter.src/main/rate-limits/zai-fetcher.ts—net.fetchagainsthttps://api.z.ai/api/monitor/usage/quota/limit. The endpoint takes the raw key inAuthorization(aBearerprefix 401s). Windows are mapped by their{unit, number}pair onto the contracted 300 / 10080-minute buckets so the bar labels them like every other provider; an undocumented unit code is dropped rather than guessed into the wrong bucket.data.levelbecomesplanType.zaiApiKeyinGlobalSettings, persisted through the existingPROTECTED_SECRET_SLOTmachinery (encrypt on serialize, decrypt on load, retained blob dropped when cleared), i.e. the same path as the OpenCode Go cookie. It is never written to the runtime client settings.Record<ActiveRateLimitProvider, …>, so the compiler forced each one).appearance-status-bar-minimax-toggle-search.ts), matching Grok/Antigravity, so the shared catalog stays under themax-linesratchet.Why
The provider roster is compiled in, so a GLM Coding Plan user has no way to see quota inside Orca even though they are already running GLM through Claude Code (
ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic), OpenCode or Cline. The plan enforces a rolling 5-hour window and a weekly window — exactly the two buckets the status bar is built around — so it drops into the existing shape without new UI concepts.Linked Issue
Fixes #18506
Visual Proof
Before: no Z.ai segment — the bar ends after Grok.
After (dev build, real
proplan, key pasted into Settings → AI Provider Accounts → Z.ai):The
Zsegment is the new one: 5-hour window at 7%, weekly at 74%, each with its own reset countdown; the tooltip/roster row readsZ.ai · pro. The "before" is the same bar with that segment absent (nothing else changes), so only the after shot is attached.Review follow-ups (56712d6)
AbortSignalnow reachesfetchZaiRateLimits(combined with the 15s timeout viaAbortSignal.any), so a cancelled poll cycle no longer lingers — new test covers it.endpointoverride.Usage unavailablestate.en-runtime-required.json+locales/en.json).Testing
src/main/rate-limits/zai-fetcher.test.ts(new, 6 cases): window mapping from a real captured payload, raw-key header contract, unconfigured key →unavailable(not an error), 401 →stale-token, payload-level failure, unknown unit code ignored.Updated the fixtures/tests that enumerate providers exhaustively.
pnpm lint✅,pnpm typecheck✅ (node/cli/web),pnpm test src/main/rate-limits src/renderer/src/components/status-bar src/shared/rate-limit-types.test.ts✅ — the 4 failures incodex-fetcher-pty-settle.test.tsreproduce on a clean checkout ofmainon this machine and are unrelated.Manual: macOS dev build, real Z.ai
prokey — pasted the key in Settings, watched the bar populate, confirmed the fetched snapshot (status: 'ok', both windows,planType: 'pro'), and confirmed an empty key hides the segment again. Not tested on Linux/Windows/SSH: the code is a plainnet.fetchplus settings plumbing with no platform- or host-specific paths.I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Written with Claude Code (Opus 5), reviewed by me before pushing.
Review
Agent skill upstream boundary
Notes
api.z.ai.zaiApiKeyis deliberately not part ofRuntimeClientSettings, so a remote client shows no Z.ai bar rather than shipping the secret over the wire — same treatment as the OpenCode Go cookie.zaiis a new optional slot; the one-shot default-add flag keeps existing status-bar layouts intact.StatusBarItemgains a value in the client-UI RPC schema, so an older host rejects'zai'from a newer client the same way it did whengrokwas added.Checklist
Zsegment)pnpm lint,pnpm typecheck,pnpm testpass locally (pnpm buildnot run: this machine's Xcode install is broken, CI covers it)🤖 Generated with Claude Code
https://claude.ai/code/session_01FNBmqKA9PvYQ7A8pYiW5GY