跳过主要内容
D

dws-quota

deepwerkspace/dws-quota

Tokens remaining widget

安装

dsh plugin --profile web add github:deepwerkspace/dws-quota

README

dws-quota

A tiny DSH plugin that shows the Deepwerkspace estimated-remaining-token count in the web client's composer dock, right next to the context meter (the ring that shows % of context used).

The Deepwerkspace quota endpoint reports the remaining output token limit. Because uncached input tokens are charged against output tokens at 1/10th, a ~50/50 input/output split means one output token "buys" about 5.5 total tokens (1 output + 10 input). So the estimated remaining total token budget is 5.5 × remaining_tokens. If real traffic skews more input-heavy than 50/50, the estimate is conservative (low) — the safe direction.

The pill reads e.g. ≈ 11M est. for a 1,995,521-token output quota (5.5 × 1,995,521 = 10,975,366 ≈ 11M). Hover for the raw output-token count.

The pill also holds an always-visible Topup link (visible even before the first successful poll, or if the quota is unreadable) that opens the Deepwerkspace top-up page in a new tab. It points at a stable, generic redirect (https://deepwerkspace.com/products/get-more-tokens) so the real product URL can change without a plugin update.

Files

FileRole
package.jsonPackage manifest + dsh.bundle (manager-installable) + dsh.client declaration (browser half opt-in).
cordis.patch.ymlThe bundle's own patch layer — what the plugin manager loads when the bundle is selected.
index.jsHost half. Reads the key from the credentials store, queries the quota API, serves GET /dws-quota.
client.jsBrowser half. Lazy-CJS bundle; renders a single pill (budget text + always-visible "Topup" link) in conversation.composer.dock.
.test-harness.jsMock test for the Host half (run node .test-harness.js).
.test-client.jsMock test for the client bundle (run node .test-client.js).

Design / safety

  • The key never reaches the browser. The Host reads it from the credentials store and does the API call; only the computed JSON (remaining_tokens, estimated) crosses the wire to the client.
  • No hard dependencies. The Host half reads every service through ctx.get() (not inject), so a missing webServer / connection / credentials degrades the plugin to a no-op instead of failing fiber activation. This is the key reason it cannot break boot the way a malformed inject list can.
  • Reversible mounting. It mounts as a bundle: the plugin manager adds the package to the profile's dsh.profile.bundles and loads the package's own cordis.patch.yml layer. Removing the bundle (and the package) fully reverts it — the bundle cordis.yml is never edited.
  • Auth fence. When a connection service is mounted, the route applies connection.requestRejection() (Host/Origin + browser-session check) before serving. On a loopback-only dsh web this is belt-and-suspenders.
  • Caching. The Host caches the quota for 30s so a burst of client polls does not hammer the quota API. The client re-polls every 60s.

Installing (in any DSH instance)

Prerequisite — the key in the credentials store

Append the Deepwerkspace key to the refs: block of ~/.dsh/.credentials.yaml (the local credentials provider reads that file):

version: 1
refs:
  # ...your existing refs...
  DEEPWERKSPACE_API_KEY: dws-tRVAvvmTtQVlbw1OkKeayyMmAbml5dTT

The ref name must be exactly DEEPWERKSPACE_API_KEY (that is what the plugin resolves). The value is the bearer token. If you add the key through the Models settings page instead, name the custom provider's route id deepwerkspace (lowercase, no separators) — the UI then stores the key under DEEPWERKSPACE_API_KEY automatically.

The one-command install

The package declares dsh.bundle, so the DSH plugin manager installs it end-to-end — it runs pnpm add in the profile directory, selects the bundle (appends it to dsh.profile.bundles), loads this package's cordis.patch.yml layer, and HMR applies it live on a patchReload: live profile:

dsh plugin --profile web add dws-quota

(Adjust web to whichever profile you actually run. The plugin works in any profile that mounts a webServer, credentials, and the web client — i.e. the web profile.)

The same operation is available in the GUI sidebar's Plugins page and the plugin_manager agent tool (Creator mode). For a package that is not on the default npm registry, pass a tarball URL or an absolute path instead of a registry name.

Manual fallback (no plugin manager)

If you must mount it by hand: place this dws-quota/ directory in the profile's node_modules (cp -r or ln -s), then append to the profile's cordis.patch.yml:

- insert:
  - name: 'dws-quota'

That is the entire registration — no inject (the plugin has no hard deps) and no config. Then restart dsh web (or let HMR pick it up).

Open the GUI, start a session, and look at the composer dock (bottom of the input card, next to the context ring) for the ≈ 11M est. pill.

Verify

# The Host route (loopback; needs the browser session cookie in a real browser,
# but on a bare loopback dsh web the connection fence is the only gate):
curl -s http://127.0.0.1:<port>/dws-quota
# -> {"remaining_tokens":1995521,"estimated":10975366}

Error shapes (all 5xx/4xx, never a crash):

  • {"error":"missing-credential","ref":"DEEPWERKSPACE_API_KEY"} — step 1 not done.
  • {"error":"no-credentials-provider"} — no credentials service in this profile.
  • {"error":"quota-http","status":403} — the API rejected the key.
  • {"error":"quota-failed","detail":"..."} — network/parse failure.

Remove

Plugin manager: dsh plugin --profile web remove dws-quota (or the Plugins page / plugin_manager tool) — it deselects the bundle, unloads its contributions, and runs pnpm remove. Manual mount: delete the insert block from cordis.patch.yml and remove the node_modules/dws-quota entry. Optionally remove the DEEPWERKSPACE_API_KEY ref. Restart. No trace remains — the plugin registers nothing in the bundle cordis.yml.

Troubleshooting

  • Pill never appears. Check curl /dws-quota first. If it returns missing-credential, the ref name/value in step 1 is wrong. If the route 404s, the plugin did not load — confirm step 2 (node_modules) and step 3 (patch entry) and that the profile was restarted.
  • GUI fails to boot after adding it (the failure mode from a prior attempt): the most common cause is a malformed client bundle (not the lazy-CJS window.__ModuleLoader__.load({ id, factory }) shape) or a dsh.client declaration that references a package that is not in the client graph. This bundle was verified against the shipped ui-theme bundle shape, and the dsh.client.inject edge (@deepseek-ai/dsh-client-ui-conversation) is a core web-client package. If boot breaks, remove the insert entry and restart to recover, then diff client.js against this file.
  • /dws-quota is 401. The connection fence rejected the request (Host/Origin or browser-session mismatch). In a real browser this is handled by the session cookie; a bare curl without the cookie will 401, which is expected.

相关插件