Skip to content

feat(status-bar): track Z.ai GLM Coding Plan usage - #18507

Closed
ArtemBozhenko wants to merge 2 commits into
stablyai:mainfrom
ArtemBozhenko:feat/zai-usage-status-bar
Closed

ArtemBozhenko wants to merge 2 commits into
stablyai:mainfrom
ArtemBozhenko:feat/zai-usage-status-bar

Conversation

@ArtemBozhenko

@ArtemBozhenko ArtemBozhenko commented Sep 3, 2026 •

Copy link
Copy Markdown

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 Z segment with the 5-hour and weekly windows.

What Changed

  • New provider zai end to end: ProviderRateLimits['provider'], RateLimitState.zai, the zai status-bar item (default-on, with the one-shot _zaiStatusBarDefaultAdded migration 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.fetch against https://api.z.ai/api/monitor/usage/quota/limit. The endpoint takes the raw key in Authorization (a Bearer prefix 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.level becomes planType.
  • Credential — zaiApiKey in GlobalSettings, persisted through the existing PROTECTED_SECRET_SLOT machinery (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.
  • Service wiring — resolver + config-hash generation so a changed key discards stale data, a seventh slot in the full fetch cycle, and entries in the per-provider failure-streak/retry records (which are Record<ActiveRateLimitProvider, …>, so the compiler forced each one).
  • Housekeeping — the MiniMax status-bar search entry moves into its own module (appearance-status-bar-minimax-toggle-search.ts), matching Grok/Antigravity, so the shared catalog stays under the max-lines ratchet.
  • Docs: usage-tracking and settings pages mention Z.ai.

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 pro plan, key pasted into Settings → AI Provider Accounts → Z.ai):

✳ 13% used 3h 39m · 60% used 4d 7h · 29% used Fable   ◎ 98% used 3d 13h   ✂ Run Grok to refresh   Z 7% used 1h 51m · 74% used 15h 53m

Status bar with the new Z.ai segment

The Z segment is the new one: 5-hour window at 7%, weekly at 74%, each with its own reset countdown; the tooltip/roster row reads Z.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)

  • fetch-cycle AbortSignal now reaches fetchZaiRateLimits (combined with the 15s timeout via AbortSignal.any), so a cancelled poll cycle no longer lingers — new test covers it.
  • dropped the unused CN endpoint constant and its endpoint override.
  • usage-tracking doc no longer claims "no API calls" for Z.ai; it documents the key requirement and the Usage unavailable state.
  • Z.ai added to the stale English accounts-section catalog string (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 in codex-fetcher-pty-settle.test.ts reproduce on a clean checkout of main on this machine and are unrelated.

  • Manual: macOS dev build, real Z.ai pro key — 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 plain net.fetch plus 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

  • Not applicable.

Notes

  • Security: the key is a protected secret, is not synced to runtime clients, and is only ever sent to api.z.ai.
  • Cross-platform: no platform branches; no filesystem access.
  • Remote/SSH: zaiApiKey is deliberately not part of RuntimeClientSettings, so a remote client shows no Z.ai bar rather than shipping the secret over the wire — same treatment as the OpenCode Go cookie.
  • Backwards compatibility: zai is a new optional slot; the one-shot default-add flag keeps existing status-bar layouts intact. StatusBarItem gains a value in the client-UI RPC schema, so an older host rejects 'zai' from a newer client the same way it did when grok was added.

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after attached (PNG of the after state; before = same bar without the Z segment)
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered
  • pnpm lint, pnpm typecheck, pnpm test pass locally (pnpm build not run: this machine's Xcode install is broken, CI covers it)

🤖 Generated with Claude Code

https://claude.ai/code/session_01FNBmqKA9PvYQ7A8pYiW5GY

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

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ One minor cleanup — otherwise this is solid.

Reviewed changes

  • Z.ai fetcher — new fetchZaiRateLimits(...) against api.z.ai/api/monitor/usage/quota/limit, raw-key Authorization header, unit-code mapping to the 5-hour/weekly contract buckets.
  • Credential plumbing — zaiApiKey in GlobalSettings, encrypted via PROTECTED_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 (Z letter), visibility menu checkbox, tooltip icon, ZaiIcon SVG, settings pane API key input, search entries, _zaiStatusBarDefaultAdded one-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.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/rate-limits/zai-fetcher.ts Resolved
@coderabbitai

coderabbitai Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The 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 56712

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)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning 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:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation satisfies issue #18506. It adds protected Z.ai API-key settings, the required quota fetcher and raw-key authorization, 5-hour and weekly window mapping, plan-tier reporting, and def…
Out of Scope Changes check ✅ Passed The changes remain focused on Z.ai usage tracking. The MiniMax search-entry extraction is a small supporting refactor required to add the new Z.ai search entry without exceeding the catalog limits.
Title check ✅ Passed The title is concise, specific, and accurately summarizes the main change: adding Z.ai GLM Coding Plan usage tracking to the status bar.
Description check ✅ Passed 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 screen…
Full details: Linked Issues check

Explanation

The implementation satisfies issue #18506. It adds protected Z.ai API-key settings, the required quota fetcher and raw-key authorization, 5-hour and weekly window mapping, plan-tier reporting, and default-on status-bar and search controls.

Full details: Docstring Coverage

Explanation

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 check

Explanation

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.

  • Fix all pre-merge checks with AI

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 86c50112-62c5-4d00-8e39-04e25eae95bc

📥 Commits

Reviewing files that changed from the base of the PR and between 3cd817c and 03bfc4f.

📒 Files selected for processing (49)
  • docs/site/content/docs/agents/usage-tracking.mdx
  • docs/site/content/docs/settings.mdx
  • src/main/codex-accounts/runtime-home-settings-test-fixtures.ts
  • src/main/codex-accounts/service-reset-credit-test-fixtures.ts
  • src/main/codex-accounts/service-test-harness.ts
  • src/main/persistence/applying-settings/settings-update.ts
  • src/main/persistence/loading-store/loaded-state-parsing.ts
  • src/main/persistence/loading-store/state-serialization-secret-handling.ts
  • src/main/protected-secret-persistence.ts
  • src/main/rate-limits/service/service-configuration.ts
  • src/main/rate-limits/service/service-full-cycle-application.ts
  • src/main/rate-limits/service/service-full-cycle-preparation.ts
  • src/main/rate-limits/service/service-polling.ts
  • src/main/rate-limits/service/service-result-policy.ts
  • src/main/rate-limits/service/service-state.ts
  • src/main/rate-limits/service/service-types.ts
  • src/main/rate-limits/zai-fetcher.test.ts
  • src/main/rate-limits/zai-fetcher.ts
  • src/main/runtime/rpc/methods/client-ui-schemas.ts
  • src/main/startup/main-process-account-services.ts
  • src/renderer/src/components/settings/AccountsPane.tsx
  • src/renderer/src/components/settings/accounts-pane-zai-section.tsx
  • src/renderer/src/components/settings/accounts-search.ts
  • src/renderer/src/components/settings/appearance-status-bar-minimax-toggle-search.ts
  • src/renderer/src/components/settings/appearance-status-bar-search.ts
  • src/renderer/src/components/settings/appearance-status-bar-zai-toggle-search.ts
  • src/renderer/src/components/stats/GrokUsagePane.test.tsx
  • src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx
  • src/renderer/src/components/status-bar/StatusBarVisibilityMenu.tsx
  • src/renderer/src/components/status-bar/icons.tsx
  • src/renderer/src/components/status-bar/status-bar-provider-visibility.test.ts
  • src/renderer/src/components/status-bar/status-bar-provider-visibility.ts
  • src/renderer/src/components/status-bar/tooltip.tsx
  • src/renderer/src/components/status-bar/usage-error-copy.ts
  • src/renderer/src/components/status-bar/usage-provider-settings-target.ts
  • src/renderer/src/components/status-bar/use-status-bar-controller.ts
  • src/renderer/src/hooks/settings-navigation-capability-sections.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/store/slices/rate-limits.ts
  • src/renderer/src/store/slices/ui/ui-slice-hydration-actions.ts
  • src/renderer/src/web/preload-api/web-rate-limits-api.ts
  • src/shared/default-global-settings.ts
  • src/shared/global-settings-types.ts
  • src/shared/persisted-ui-state-types.ts
  • src/shared/rate-limit-types.test.ts
  • src/shared/rate-limit-types.ts
  • src/shared/status-bar-defaults.ts
  • src/shared/ui-chrome-types.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread src/main/rate-limits/zai-fetcher.ts Resolved
…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

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Fetch-cycle abort signal — fetchZaiRateLimits now accepts a caller signal and combines it with the 15s timeout via AbortSignal.any; the full fetch cycle passes its signal through, so a cancelled poll no longer lingers in Promise.allSettled. This mirrors the existing grok-fetcher idiom exactly.
  • Dead-code removal — dropped ZAI_CN_USAGE_ENDPOINT and the endpoint override; the fetcher now always targets ZAI_USAGE_ENDPOINT.
  • Tests — added a case asserting the caller signal propagates through to net.fetch and aborts with the controller.
  • Docs — usage-tracking.mdx now documents Z.ai's key requirement and the Usage unavailable state 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.json and en-runtime-required.json.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/main/rate-limits/zai-fetcher.test.ts (1)

103-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Make the cancellation test exercise an in-flight request.

netFetchMock.mockResolvedValue(...) completes the request before controller.abort() runs, so the test checks only signal state. Keep the mock pending, reject it on signal abort, and assert that fetchZaiRateLimits settles 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

📥 Commits

Reviewing files that changed from the base of the PR and between 03bfc4f and 56712d6.

📒 Files selected for processing (9)
  • docs/site/content/docs/agents/usage-tracking.mdx
  • src/main/rate-limits/service/service-full-cycle-preparation.ts
  • src/main/rate-limits/zai-fetcher.test.ts
  • src/main/rate-limits/zai-fetcher.ts
  • src/renderer/src/components/settings/accounts-pane-zai-section.tsx
  • src/renderer/src/components/settings/appearance-status-bar-minimax-toggle-search.ts
  • src/renderer/src/components/settings/appearance-status-bar-zai-toggle-search.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/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.

@nwparker

Copy link
Copy Markdown
Contributor

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 zcode provider. Those controls work without requiring ZCode installation. #24674 extends that implementation for current CLI credentials and account-change races; it does not introduce another provider/store.

Merging this PR would add a parallel zai provider, credential setting/store, and status-bar item for the same plan. I am closing it as superseded instead of maintaining two quota paths. Credit to @ArtemBozhenko for the original implementation and tests; no claim is made that their authored code was merged through this review.

The linked quota-only issue #18506 is already closed. The broader model/OAuth request #8476 remains open.

@nwparker nwparker closed this Oct 10, 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.

[Feature]: Show Z.ai GLM Coding Plan quota in the status bar

2 participants