Summary
On v2.14.5 the DeepSeek dashboard tab (/?provider=deepseek) renders no balance cards and no statistics at all, even though the backend collects and serves the data correctly. The tab falls through to the Synthetic default renderer, so the card grid stays empty and the usage chart shows the Synthetic dataset labels with 0 points.
Moonshot (the other balance-based provider) looks affected by exactly the same gap.
Environment
- onWatch v2.14.5 (linux/amd64), self-hosted, dashboard on
:9211
- Reproduced in a fresh browser session (no cached JS) and directly against the API
DEEPSEEK_API_KEY set in .env; provider_visibility.deepseek = {"dashboard":true,"polling":true}
- DeepSeek polling works: balance snapshots are written every 2 min
Steps to reproduce
- Configure
DEEPSEEK_API_KEY so the DeepSeek provider is enabled.
- Open
http://localhost:9211/?provider=deepseek.
Expected
Total / Granted / Topped-Up balance cards populated from /api/current?provider=deepseek, as documented for DeepSeek in the README.
Actual
- The quota grid exists but is empty:
document.getElementById('quota-grid-deepseek').children.length === 0 (no innerHTML).
- "Usage Insights" → "Unable to load insights."
- The usage chart shows the Synthetic datasets (
Subscription, Search, Tool Calls) with 0 points each.
- Session History / Logging History / Cycle Overview show empty states.
Contrast: the Codex/Anthropic tabs render fine.
Backend is fine (curl evidence)
GET /api/current?provider=deepseek
→ 200 {"balance":{"available":true,"total":4.02,"toppedUp":4.02,"granted":0,"currency":"USD",
"description":"DeepSeek API balance","avgPerCycle":0.03,"completedCycles":1,"rate":0.04,"status":"healthy",...}}
GET /api/history?provider=deepseek&range=24h → 200 (46 KB; total_balance / granted_balance / topped_up_balance)
GET /api/logging-history?provider=deepseek&range=24h → 200 (121 KB)
GET /api/sessions?provider=deepseek → 200 (8 KB)
GET /api/insights?provider=deepseek → 200 {"stats":[],"insights":[]}
So the data is present; only the client rendering is missing.
Root cause
In internal/web/static/app.js (v2.14.5), the card render dispatch that runs after GET /api/current only branches for these providers:
copilot, anthropic, codex, antigravity, minimax, gemini, cursor,
openrouter, grok, kimi, opencode, ollama, muse, commandcode, zai
There is no else if (provider === 'deepseek') (and none for moonshot). Therefore provider === 'deepseek' falls through to the final default branch — the Synthetic renderer:
} else if (provider === 'zai') {
updateCard('tokensLimit', data.tokensLimit);
updateCard('timeLimit', data.timeLimit);
updateCard('toolCalls', data.toolCalls);
} else {
updateCard('subscription', data.subscription);
updateCard('search', data.search);
updateCard('toolCalls', data.toolCalls);
}
/api/current?provider=deepseek returns { capturedAt, balance } — no subscription/search/toolCalls — so updateCard(...) finds no matching elements and nothing is rendered. That matches the empty #quota-grid-deepseek and the Synthetic chart labels.
Confirming grep on the shipped asset (/static/app.js, 556 976 bytes):
$ grep -n -i deepseek app.js
6952: } else if (provider === 'minimax' || provider === 'gemini' || provider === 'openrouter' || provider === 'moonshot' || provider === 'deepseek') {
7372: if (provider === 'deepseek') { ... chart datasets ...
7380: return buildDynamicDatasetsForRows(rows, range, dsDisplayNames, dsColors, dsFallback, 'deepseek');
7718: } else if (slot.provider === 'deepseek') { ... chart datasets ...
7722: datasets = createDynamicDatasets(slot.rows, dsDN, dsCM, dsFB, 'deepseek');
8062: const usePercent = ... || provider === 'deepseek' || ...
8063: const deltaUsesPercent = usePercent && provider !== 'minimax' && provider !== 'moonshot' && provider !== 'deepseek';
12557: <option value="deepseek" ...>DeepSeek</option>
All 8 hits are in chart/settings code — there is no card renderer for deepseek (nor moonshot), even though the chart dataset builders already know the balance fields (total_balance, granted_balance, topped_up_balance).
Also note: internal/web/static/app.js on main is byte-identical to v2.14.5 (both 556 976 bytes, identical deepseek lines), so this is not fixed yet on main.
Suggested fix
Add a deepseek (and moonshot) branch to the dispatch that renders the balance cards from data.balance — e.g. Total / Granted / Topped-Up — reusing the existing card markup/classes for balance providers.
Happy to open a PR if you can point me at the preferred card markup/CSS classes for balance-based providers.
Summary
On v2.14.5 the DeepSeek dashboard tab (
/?provider=deepseek) renders no balance cards and no statistics at all, even though the backend collects and serves the data correctly. The tab falls through to the Synthetic default renderer, so the card grid stays empty and the usage chart shows the Synthetic dataset labels with 0 points.Moonshot (the other balance-based provider) looks affected by exactly the same gap.
Environment
:9211DEEPSEEK_API_KEYset in.env;provider_visibility.deepseek = {"dashboard":true,"polling":true}Steps to reproduce
DEEPSEEK_API_KEYso the DeepSeek provider is enabled.http://localhost:9211/?provider=deepseek.Expected
Total / Granted / Topped-Up balance cards populated from
/api/current?provider=deepseek, as documented for DeepSeek in the README.Actual
document.getElementById('quota-grid-deepseek').children.length === 0(noinnerHTML).Subscription,Search,Tool Calls) with 0 points each.Contrast: the Codex/Anthropic tabs render fine.
Backend is fine (curl evidence)
So the data is present; only the client rendering is missing.
Root cause
In
internal/web/static/app.js(v2.14.5), the card render dispatch that runs afterGET /api/currentonly branches for these providers:There is no
else if (provider === 'deepseek')(and none formoonshot). Thereforeprovider === 'deepseek'falls through to the final default branch — the Synthetic renderer:/api/current?provider=deepseekreturns{ capturedAt, balance }— nosubscription/search/toolCalls— soupdateCard(...)finds no matching elements and nothing is rendered. That matches the empty#quota-grid-deepseekand the Synthetic chart labels.Confirming grep on the shipped asset (
/static/app.js, 556 976 bytes):All 8 hits are in chart/settings code — there is no card renderer for
deepseek(normoonshot), even though the chart dataset builders already know the balance fields (total_balance,granted_balance,topped_up_balance).Also note:
internal/web/static/app.jsonmainis byte-identical tov2.14.5(both 556 976 bytes, identicaldeepseeklines), so this is not fixed yet onmain.Suggested fix
Add a
deepseek(andmoonshot) branch to the dispatch that renders the balance cards fromdata.balance— e.g. Total / Granted / Topped-Up — reusing the existing card markup/classes for balance providers.Happy to open a PR if you can point me at the preferred card markup/CSS classes for balance-based providers.