You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: add DeepSeek status bar usage provider - #12873
Show DeepSeek prepaid balance in the status bar when DEEPSEEK_API_KEY is set.
Fetches GET https://api.deepseek.com/user/balance (Bearer key), prefers the USD balance row, and maps remaining credit into the existing rate-limit / usage pipeline (provider: 'deepseek', monthly window + balance text).
Screenshots
No visual change beyond a new optional status-bar usage chip when a DeepSeek API key is configured (same roster/tooltip chrome as other providers). A dedicated monogram “DS” icon is used; no new layout surfaces.
Focused fix
In scope (this PR / v1 slice):
'deepseek' on ProviderRateLimits + RateLimitState
deepseek-fetcher + unit tests (env DEEPSEEK_API_KEY only)
Issue #12869 lists three contribution slices. This PR lands types + fetcher + status-bar wiring with env-only auth so usage is useful without shipping a full Accounts surface in the same review. Accounts UI will be a separate focused PR after this lands (tracked on #12869).
Preserves
Existing provider poll cadence, activation retry, and stale-data policy for other providers
No new secret store or IPC auth surface in v1 (reads process env only; key never written by Orca)
Reviewed with an AI coding agent (Grok Build) against the Orca merge playbook (focused fix / preserves intent / regression coverage).
Main risks checked:
Cross-platform (macOS / Linux / Windows): fetcher uses Electron net.fetch + process.env.DEEPSEEK_API_KEY only — no path separators, no shell quoting, no keyboard accelerators. Status-bar UI reuses existing roster chrome (no new shortcuts/labels that differ by platform).
SSH / remote: usage fetch runs in the desktop main process against the public DeepSeek API; no remote PATH or host-specific credential files in v1.
Secrets: key is read from env for outbound Authorization header only; not logged; not persisted by this PR.
Scope: no Reasonix agent registration; no drive-by provider refactors.
Flagged / resolved during authoring:
Balance is prepaid remaining credit, not a rolling % quota → document tradeoff; map to monthly window with 0%/100% used + amount in resetDescription so hasUsageData works without inventing fake session/weekly limits.
Accounts UI deferred deliberately for reviewability (issue suggested slices).
Security Audit
Input handling: no new user-controlled command strings; balance JSON parsed with type guards.
Command execution: none.
Path handling: none for credentials (env only).
Auth / secrets: Bearer token from env; 401/403 → stale-token failure kind without echoing the key.
Dependencies / IPC: no new deps; rate-limit state only extends existing snapshot shape (mobile/web schemas updated in lockstep).
Follow-up: Accounts UI must use the same desktop-safe secret patterns as other providers (not plain settings JSON) when implemented.
Docstring coverage warning: project style (AGENTS.md) prefers concise why comments only when non-obvious — not JSDoc on every function. The new fetcher has a short module/export doc for the balance mapping; bulk docstrings would fight repo conventions.
Prepaid balance UX: meter shows 0% used with credit left and 100% when depleted/unavailable; currency amount is in the window description / provenance.
It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.
The change adds DeepSeek prepaid-balance fetching and integrates its results into rate-limit state and refresh handling. It adds DeepSeek visibility, fetching-state behavior, and provider presentation to the status bar. It also adds status-bar controls, search metadata, localization, default-item migration, and shared type updates. Tests cover fetcher responses, service refresh behavior, provider visibility, and persisted UI migration.
Merge Risk: High · previous review 92f3a
As written, the change breaks the rate-limit service module and fails typechecking, so the app cannot build or run correctly. Once those errors are fixed, the DeepSeek status-bar item shows a 0% or 100% monthly meter rather than the prepaid balance it is meant to display. Fix the syntax error and the provider map, and render the balance, before merging.
Security architecture risk: Moderate · up to 64bd3
A configured DeepSeek key now triggers an external balance request and makes balance information available in the usage interface. The request’s redirect protection is not established, and a balance result is not tied to the key that initiated it. No credential disclosure has been verified.
Retained concerns
Medium · security · observed: The new Bearer-authenticated request leaves redirect handling implicit. Cross-origin credential forwarding is not established, so this is a transport-control uncertainty, not a verified disclosure.
Low · security · inferred: If the process key is changed or removed during an in-flight request, the old balance can be applied without checking that it belongs to the current credential. Runtime key rotation is not established for this env-only release.
Security review details
Security Blast Radius
inferred — Credential exposure is bounded in the reviewed path to a desktop process with DEEPSEEK_API_KEY configured and its outbound provider request. Balance and error results enter shared UI state; the mobile schema accepts the identifier, but automatic mobile transmission of this balance was not established.
Security Findings and Attack Paths
observed — No verified Security finding is retained for this PR. The credential-disclosure candidate remains deferred because the available evidence does not determine cross-origin redirect handling; it must not be read as a demonstrated leak.
Trust Boundaries and Controls
observed — The main process reads the environment key and sends it to a fixed HTTPS provider URL with a timeout and optional cancellation signal. The code supplies no explicit redirect-destination control.
Resilience and Maintainability Implications
inferred — Cycle serialization and abort checks limit competing writes, but they do not bind a completed DeepSeek result to the credential currently in the environment. A subsequent completed no-key cycle returns unavailable and clears the prior balance.
Hardening Proposals
proposed — Establish the pinned Electron version’s cross-origin redirect behavior and explicitly constrain redirect destinations if Bearer headers can survive such a redirect. If live key changes are supported, associate results with a credential generation before applying them; avoid forwarding raw transport error text until its contents are characterized.
Pre-merge checks: 5
Check name
Status
Explanation
Title check
The title clearly and concisely identifies the main change: adding DeepSeek status-bar usage support.
Description check
The description provides detailed scope, rationale, linked issue, implementation details, testing evidence, security considerations, and deferred work. It uses headings that differ from the repository…
Docstring Coverage
Docstring coverage is inconclusive: files from earlier reviews still need to be rechecked within the check's analysis limits. Not blocking.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Description check
Explanation
The description provides detailed scope, rationale, linked issue, implementation details, testing evidence, security considerations, and deferred work. It uses headings that differ from the repository template and does not include actual before/after visual proof, but it is sufficiently complete and relevant.
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
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.
GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.
Description check — PR body rewritten to the full template (Summary, Screenshots, Testing, AI Review Report, Security Audit, Notes), plus merge-playbook Focused fix / Preserves / Evidence.
Linked Issues / Accounts UI — intentional v1 deferral, not an accidental miss. Issue [Feature]: DeepSeek usage in the status bar (rate-limit / usage provider) #12869 suggested multi-slice PRs; this PR lands types + fetcher + status-bar wiring with env-only DEEPSEEK_API_KEY. Desktop-safe credential storage + Accounts UI will be a separate focused follow-up on the same issue after this lands (keeping the review surface small).
Docstring coverage — non-actionable against Orca AGENTS.md (concise why comments only when non-obvious). The fetcher documents the balance→monthly mapping; bulk JSDoc would fight repo conventions.
Also rebased onto latest upstream/main after the review; focused vitest still green (deepseek-fetcher + service + provider-visibility).
GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.
…es after deepseek merge
Merging stablyai#12873 pushed appearance-status-bar-search.ts and client-ui-schemas.ts
past the 300-line cap. Extract the Gemini toggle entry to its own file (matching
the antigravity/grok/deepseek pattern) and derive the StatusBarItem zod enum from
a new shared STATUS_BAR_ITEMS const, removing a drift-prone hand-copied union.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…es after deepseek merge
Merging stablyai#12873 pushed appearance-status-bar-search.ts and client-ui-schemas.ts
past the 300-line cap. Extract the Gemini toggle entry to its own file (matching
the antigravity/grok/deepseek pattern) and derive the StatusBarItem zod enum from
a new shared STATUS_BAR_ITEMS const, removing a drift-prone hand-copied union.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…es after deepseek merge
Merging stablyai#12873 pushed appearance-status-bar-search.ts and client-ui-schemas.ts
past the 300-line cap. Extract the Gemini toggle entry to its own file (matching
the antigravity/grok/deepseek pattern) and derive the StatusBarItem zod enum from
a new shared STATUS_BAR_ITEMS const, removing a drift-prone hand-copied union.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Heads-up: first-class DeepSeek Harness support is up for review in #22468, with an installable test build at v1.4.210-adhoc (macOS signed/notarized, Windows unsigned — SmartScreen warns once).
You can test it now and give any feedback. Once we get feedback that it works, we'll release to stable.
It covers detect/launch, status, question state, resume, orchestration and headless Source Control AI, routed through DeepSeek's own @deepseek-ai/dsh-hooks-claude-code bridge. Full instructions and the two known gaps are on the tracking issue: #14323 (comment)
Since you worked on this area, your read on whether it matches what you needed would be especially useful — including if it conflicts with or supersedes what you have here.
Thanks for the heads-up. #22468 does not supersede this PR.
#22468 is the DeepSeek Harness agent: detect, launch, hooks, resume, orchestration, and headless Source Control AI. This PR is only the status-bar usage provider. It fetches DeepSeek rate-limit usage and shows it in the status bar (src/main/rate-limits/deepseek-fetcher.ts and the status-bar provider wiring). Those files are not in #22468, so the two changes do not overlap.
I have since run the v1.4.210-adhoc build beside the installed app, with a temporary DSH home and stock dsh-tui 0.11.0 so the session used DEEPSEEK_API_KEY rather than an OpenRouter profile.
worktree create --agent dsh launched DeepSeek Harness. The tab title showed the whale mark, and the TUI reported deepseek-flash.
ask_user_question marked the pane waiting, and answering it produced a normal reply.
Closing the tab and running dsh-tui --resume <id> restored that session.
Not covered: SSH, Windows, headless Source Control AI, and this usage-provider PR itself. terminal wait --for tui-idle still timed out while the composer was ready, and the send receipt reported delivery as unsupported for this provider.
I am leaving this usage PR open unless you would rather fold quota display into the harness work.
Rebased onto current main. The rate-limit service is split now, so DeepSeek is wired through that provider cycle (service-full-cycle-preparation.ts / service-full-cycle-application.ts) instead of the old monolithic service.ts.
This is still only the status-bar usage provider: DEEPSEEK_API_KEY balance from GET /user/balance, mapped into the monthly slot. Accounts UI and desktop credential storage stay out of this PR. None of these files are in #22468, so that harness change does not supersede this one.
Preserves: the existing poll and stale-snapshot policy. A thrown balance refresh keeps the last balance and reports the error, and a missing key stays unavailable.
Store write-only API-key entries in protected execution-host storage and poll the documented balance endpoint through the existing account usage service.
Display each currency's exact monetary strings in Accounts and the status bar, with explicit unsupported hosts and stale errors.
Builds on the DeepSeek balance and mobile account work in #12873 and #23294.
Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
The PR adds environment-authenticated DeepSeek balance polling and wires the resulting provider state through desktop/mobile contracts, polling, persistence, settings, and status-bar UI.
Adds a DeepSeek balance fetcher using DEEPSEEK_API_KEY.
Extends rate-limit service state and stale-result handling for DeepSeek.
Adds status-bar visibility controls, defaults, iconography, search metadata, and tests.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
E[DEEPSEEK_API_KEY] --> F[DeepSeek balance fetcher]
F --> M[Synthetic monthly window]
M --> S[Rate-limit service state]
S --> R[Renderer status-bar controller]
R --> C[Usage chip]
R --> T[Provider tooltip]
The reason will be displayed to describe this comment to others. Learn more.
Balance amount is never rendered
When DeepSeek returns a valid positive balance, this mapping stores the amount only in resetDescription and emits a synthetic 0% monthly window, but the status-bar chip and tooltip never render resetDescription, causing values such as USD 110.00 to appear only as “Monthly 0% used.”
Files skipped from review as they are similar to previous changes: 1
src/renderer/src/i18n/locales/en.json
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.
The reason will be displayed to describe this comment to others. Learn more.
Critical · Functional Correctness · Quick win
Remove the comma after the import.
The comma after '../../../shared/zcode-plan-sites' is invalid import syntax. It prevents this service module from parsing, so the affected build and tests cannot run. (raw.githubusercontent.com)
Proposed fix
--- "a/src/main/rate-limits/service/service-full-cycle-preparation.ts"+++ "b/src/main/rate-limits/service/service-full-cycle-preparation.ts"@@ -8,7 +8,7 @@
import { fetchZcodeRateLimits } from '../zcode-usage-fetcher'
import { fetchAntigravityRateLimits } from '../antigravity-usage-fetcher'
import { antigravityUsageDisabledSnapshot } from '../antigravity-usage-snapshot'
-import { ZCODE_PLAN_SITE_BASE_URLS } from '../../../shared/zcode-plan-sites',+import { ZCODE_PLAN_SITE_BASE_URLS } from '../../../shared/zcode-plan-sites'
import { fetchDeepSeekRateLimits, isDeepSeekAuthConfigured } from '../deepseek-fetcher'
import { fetchMiniMaxRateLimits } from '../minimax/minimax-fetcher'
import { createHash } from 'node:crypto'
Committable suggestion
IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
# Check whether authProvenance (which carries the balance text) is read by any renderer or shared code.
rg -n -F 'authProvenance' src/renderer src/shared ||test"$?" -eq 1
# Check for any non-test status-bar source that mentions balance text.
rg -n -i -F 'balance' src/renderer/src/components/status-bar --glob '!*.test.*'||test"$?" -eq 1
# Check how the monthly window is rendered in non-test status-bar sources.
rg -n -F 'monthly' src/renderer/src/components/status-bar --glob '!*.test.*'||test"$?" -eq 1
Repository: stablyai/orca
Length of output: 9731
Script executed:
# Find every non-test renderer or shared source that reads resetDescription. The status-bar grep earlier did not cover formatter modules outside that directory.
rg -n -F 'resetDescription' src/renderer src/shared --glob '!*.test.*'||test"$?" -eq 1
# Locate the definition of the chip-label formatter used by the monthly chip and inline usage.
rg -n -F 'formatRateLimitWindowChipLabel' src/renderer src/shared --glob '!*.test.*'||test"$?" -eq 1
Repository: stablyai/orca
Length of output: 3982
Show the DeepSeek balance amount in the status bar.
A successful balance response reaches the status bar only as a monthly usage window. mapBalanceWindow sets usedPercent to 0 when is_available is true and total_balance is positive. Otherwise it sets usedPercent to 100. It stores the balance label, for example USD 110.00, in resetDescription. The status-bar renderers do not read resetDescription, and they do not read authProvenance for DeepSeek. The chip, roster, and tooltip therefore show only the usage percentage and window label. A balance of USD 110.00 appears as a 0% monthly chip, not as prepaid credit.
Add a field that carries the balance amount to the renderers. The status bar already renders extraUsage balances in provider-extra-usage-section.tsx and StatusBarProviderSegment.tsx. Setting that field from the fetcher may reuse the existing display. Confirm its activation rules before relying on it. Otherwise, add a dedicated field to ProviderRateLimits in src/shared/rate-limit-types.ts, and render it in the DeepSeek chip, roster, and tooltip. This change spans the fetcher, the shared type, and several status-bar components, so it is not a localized edit.
Add the DeepSeek entry to the remote-owner provider map.
UsageProviderKey includes every RateLimitState field whose type is ProviderRateLimits | null. The new deepseek field matches that rule, so USAGE_PROVIDER_IDS must include it. Without the entry, the Record fails typechecking. mapProviders also iterates only the keys in that map. DeepSeek therefore never gets remote-owner placeholder handling or unverifiable-owner stamping.
Suggested fix
In src/renderer/src/components/status-bar/owner-usage-rate-limits.ts:
Older hosts omit deepseekAuthConfigured. The other *Configured flags in adoptRemoteRateLimits normalize missing values with === true. Add the DeepSeek flag to that list:
Rebased onto current main. DeepSeek prepaid balance still comes from DEEPSEEK_API_KEY through GET /user/balance and now sits beside Muse in the rate-limit service, status-bar visibility, and default-on hydration. The mobile snapshot keeps the open string provider schema, and the DeepSeek display name lives in the shared provider map. Deleted test suites stay deleted; the DeepSeek assertions sit next to the current modules.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Show DeepSeek prepaid balance in the status bar when
DEEPSEEK_API_KEYis set.Fetches
GET https://api.deepseek.com/user/balance(Bearer key), prefers the USD balance row, and maps remaining credit into the existing rate-limit / usage pipeline (provider: 'deepseek', monthly window + balance text).Screenshots
No visual change beyond a new optional status-bar usage chip when a DeepSeek API key is configured (same roster/tooltip chrome as other providers). A dedicated monogram “DS” icon is used; no new layout surfaces.
Focused fix
'deepseek'onProviderRateLimits+RateLimitStatedeepseek-fetcher+ unit tests (envDEEPSEEK_API_KEYonly)Issue #12869 lists three contribution slices. This PR lands types + fetcher + status-bar wiring with env-only auth so usage is useful without shipping a full Accounts surface in the same review. Accounts UI will be a separate focused PR after this lands (tracked on #12869).
Preserves
Testing
deepseek-fetcher,service,status-bar-provider-visibility, appearance search, ui migration, usage-error-copy, settings-target, agent-gating (292 passed on pre-push set; rebased onto latestupstream/main)pnpm lint— not re-run full-tree this pass (no product code change in this follow-up; body-only + rebase)pnpm typecheck— samepnpm build— CI package jobEvidence
pnpm exec vitest run --config config/vitest.config.ts \ src/main/rate-limits/deepseek-fetcher.test.ts \ src/main/rate-limits/service.test.ts \ src/renderer/src/components/status-bar/status-bar-provider-visibility.test.tsDEEPSEEK_API_KEYunavailable,deepseekAuthConfigured: false)USD 110.00)AI Review Report
Reviewed with an AI coding agent (Grok Build) against the Orca merge playbook (focused fix / preserves intent / regression coverage).
Main risks checked:
net.fetch+process.env.DEEPSEEK_API_KEYonly — no path separators, no shell quoting, no keyboard accelerators. Status-bar UI reuses existing roster chrome (no new shortcuts/labels that differ by platform).Flagged / resolved during authoring:
resetDescriptionsohasUsageDataworks without inventing fake session/weekly limits.Security Audit
stale-tokenfailure kind without echoing the key.Notes
AGENTS.md) prefers concise why comments only when non-obvious — not JSDoc on every function. The new fetcher has a short module/export doc for the balance mapping; bulk docstrings would fight repo conventions.Fixes #12869
Refs #12200