zhangsaizz/dsh-widgets-plugin--packages-dsh-balance ↗★ 0
@dsh-plugins/balance
The balance plugin in one package: ctx.balance capability seam (balance/query + balance/list Remotes), shipped vendor providers, provider-bindings settings + Web route, and the floating Web balance dashboard
安装
此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗
说明文档
阅读完整 README ↗@dsh-plugins/balance
The balance plugin, one package: the ctx.balance capability seam (Service
Definition, provider role, domain types, generated Remotes), the shipped
vendor providers plus user-managed bindings, and the floating Web balance
dashboard. Formerly three packages (balance seam, balance-vendors,
client-ui-balance); merged into one plugin row so a single install mounts
the whole balance line.
Preview

What's inside
-
Capability seam —
ctx.balance(BalanceRuntime) binds LLM provider routes to vendor balance providers, resolves the vendor API key through the optional credential seam (ctx.credentials) once per query, and answers balance queries over the generatedbalance/queryRemote. Business states return asBalanceQueryResultbranches (bound: false, oraccount.statusofunconfigured/unsupported/error/ok) rather than throwing; the runtime folds the previous observation intotrend(up/down/flat/unknown) anddeltaper route. Thebalance/listRemote returns every bound route in registration order (serial vendor calls) for the dashboard's multi-account view. -
Shipped vendors — concrete providers for the mainstream vendors that expose a public balance endpoint through their API key, plus explicit
supported: falsebindings for OpenAI / Anthropic / Google / xAI / Mistral so the dashboard shows a clear "no public balance endpoint" state instead of "unbound".Provider Endpoint Default route Credential ref Currency DeepSeek GET /user/balancedeepseek-officialDEEPSEEK_API_KEYCNY Moonshot GET /v1/users/me/balancemoonshotMOONSHOT_API_KEYCNY OpenRouter GET /api/v1/creditsopenrouterOPENROUTER_API_KEYUSD SiliconFlow GET /v1/user/infosiliconflowSILICONFLOW_API_KEYCNY New API GET /api/user/self(quota ÷ 500000 = USD)new-apiNEW_API_KEYUSD -
User-managed bindings — the
balancesettings section (bindings[]:provider+vendor+credentialReforcredential+ optionalbaseURL) is registered on thesettingsseam and reconciled live on change; a same-origin Web route (/_dsh/balance/settings) serves a redacted GET snapshot and POST save (blank credential keeps the stored value; acredentialClearflag removes it explicitly). The config panel in the widget manager's "Configure" dialog supports add, inline edit (provider route, vendor, credential source, base URL) and two-step delete. This is how self-hosted or custom routes get balance queries without code changes. -
Web dashboard — the browser half (
exports["./client"], discovered throughdsh.client) mounts the balance Remote intoctx.remote, then registers the floatingBalanceWidgetintoshell.overlay(idbalance, order 100) with its view-settings store (zoom/dock/collapse, persisted underdsh.balance.view), and the providers config panel into the widget manager's "Configure" dialog (widgets.configslot). A singleBalanceControllerfollows the current session + model and refreshes on a fixed 30 s interval.
Installation
Recommended: install the bundle, which mounts this plugin together with the
token-crit widget, the session monitor dashboard and the widgets manager page.
Once published to npm, install it into the target profile with the official
dsh plugin command (it installs dependencies and appends the bundle to
dsh.profile.bundles):
dsh plugin --profile add @dsh-plugins/dsh-widgets-plugin
For local development you can also link: the bundle directory from this repo
(see "安装" in the root README).
Or add the plugin row directly to the profile's cordis.patch.yml:
- insert:
- id: balance
name: '@dsh-plugins/balance'
config:
requestTimeoutMs: 10000
# New API is self-hosted; point the /api/user/self balance query at the instance.
newApiBaseURL: http://localhost:3000
bindings: []
# bindings:
# - provider: new-api
# vendor: new-api
# credential: sk-xxxxxxxx
# baseURL: http://localhost:3000
# - provider: deepseek-official
# vendor: deepseek
# credentialRef: DEEPSEEK_API_KEY
The dashboard appears as a floating overlay once a session is open. The
default bindings need no configuration — just store the matching API key in
the credential reference (DeepSeek → DEEPSEEK_API_KEY, Moonshot →
MOONSHOT_API_KEY, OpenRouter → OPENROUTER_API_KEY, SiliconFlow →
SILICONFLOW_API_KEY, New API → NEW_API_KEY). To query additional or
self-hosted routes, add a binding in Web settings → Widgets manager →
Balance → Configure (dialog) and store the token (the provider route
dropdown mirrors the model list — only providers that expose models — or the
route can be typed freely); the next dashboard refresh picks it up without a
restart. Bindings can be edited in place and removed with a two-step confirm;
to drop a stored key, edit the binding and click Clear stored key before
saving (leaving the key blank keeps it).
Model Experience
None. The balance service and dashboard are consumed only by the Web widget; no balance value, credential or trend enters session logs, model context or telemetry.
KV Cache effect
None; the runtime keeps an in-process trend seed per route and the widget
persists only its own view-settings key in localStorage.
Known Limitations and Deferred Work
- Trend history is in-process — after a restart the first observation
returns to
unknown; there is no persisted balance history. - One provider per route — a route binds at most one vendor; OpenAI compatible gateways reselling several vendors cannot dispatch per account.
- Deployment-wide timeout —
requestTimeoutMs(default 10000) applies to all vendor queries; per-vendor timeouts are not supported yet. - Fixed refresh interval — the 30 s dashboard refresh is a constant, not a settings or composition field.
- Response-structure sensitive — vendors changing their response shape
fail normalization with
provider-error; no versioned fallback.
Invariant companion
@dsh-plugins/balance/invariant ships the package-owned invariant companion
registered with the invariants seam. It is optional and not mounted by the
bundle.