@mars-sea/dsh-commandcode-provider 0.11.17 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -1
- package/README.md +16 -10
- package/README.zh-CN.md +13 -7
- package/lib/client.js +197 -123
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +166 -66
- package/lib/index.js +1249 -608
- package/lib/index.js.map +1 -1
- package/package.json +37 -37
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,43 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [0.12.0] - 2026-09-29
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **The model list now shows how far each model stretches your plan: its monthly allowance.** The pricing page publishes a **per-model allowance** (its own term) alongside every model's rates — "$47 of monthly usage on GOAT, $57 on Pro", to quote its MiniMax M3 example, which is the exact pair the new snapshot carries. The settings page's model dropdowns (Visible models, and the per-account routing pickers, which share one component) now render it beside the model name as `$20/mo`, with a tooltip spelling out what it is. **It is not extra credit**: every allowance draws on the same monthly pool, so `$20/mo` means "this model may consume $20 of that pool", not "$20 added to it". Two facts shape the implementation, both from the page rather than from guesswork: the figure exists for **GOAT and Pro only** ("the boost is a per-model allowance, so it lives on the plans that have them"), and deals are **already baked in** — MiniMax M3's `$47 / $57` IS its 2× promotion, folded in upstream. So `allowanceTierForWeight()` maps a subscription tier weight onto those two brackets and answers `undefined` for Go / Provider / Max / Ultra, and the Host resolves the bracket from the POOL's highest plan (`adapter.allowanceTier()`), matching the question `modelVisibleForAnyAccount` already answers for a pool. A Go or Max account therefore sees no allowance at all rather than a GOAT number — the honest outcome, and the reason the badge is absent rather than zero. The data rides the price rows (`allowance: { goat, pro }`, same page record, same slug resolution as the rates) and reaches the browser through the existing `commandcode/models` Remote as a single Host-resolved number; the wire stays a plain `allowance?: number` so the browser never re-derives the bracket. `tests/model-prices.test.ts` checks the snapshot against the page's own prose (MiniMax M3 at `$47 / $57`), asserts every priced catalog model carries both brackets, and pins that only weights 1 and 2 map; `tests/adapter.test.ts` covers the pool's highest-plan rule and its fail-open shape when billing is unreadable.
|
|
12
|
+
|
|
13
|
+
- **One accessibility fix on the way past: badges are no longer below the 12 px floor.** The shared `.cc-badge` / `.cc-badgeMuted` rule rendered at `font-size: 11px`. It is now 12px, the minimum the repository's visual rules allow for labels and auxiliary text. Only that one rule changed — the remaining sub-12px declarations in `panel-styles.ts` and the usage-plan pill are untouched and still need a decision.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **A header timeout now names its real cause, and stops being retried forever (#67).** The single message "通常是网络或代理问题,请检查后重试" was wrong for both transports and sent the reporter of #67 to their proxy while their gateway was simply not answering. Measured 2026-09-28, keeping **headers** separate from **totals** (a total includes the model producing every token and says nothing about the header wait). Headers, with `max_tokens: 16` to collapse the generation, 26 250-token prompt: `/alpha/generate` 2.12 / 2.56 / 2.75 s, `/provider/v1/chat/completions` 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap, with the Provider API route swinging 2.5 s where the CLI route moved 0.6 s. Totals at `max_tokens: 1024` were 11.1 s / 17.9 s for the CLI route and 116.7 s / 30.5 s for the Provider API route at 200 k and 1.2 M chars — the 200 k prompt finishing 10× slower than the 1.2 M one is why a size-based rule was wrong, and it is also why the 116.7 s figure is not header evidence. So the message branches on the transport: the CLI route names provider queueing, Go-plan capacity or a network/proxy path and says a longer budget will not help; the Provider API route names the upstream first token and suggests a concrete `requestTimeoutMs` (doubled, floored at 5 minutes, capped at the retry backoff's own 15). Both say outright that prompt size is not the cause. Separately, three consecutive header timeouts on one unchanged payload now leave the retryable whitelist as `PROVIDER_HTTP_ERROR` with an explanation, because dsh-llm exposes a single scalar `maxRetries` and no per-code limit, and `maxRetries: 1000` with a 500 ms → 15 min backoff meant the identical multi-megabyte body was re-sent for hours instead of producing a diagnosis. `RATE_LIMIT` / `SERVER` / `TRANSPORT` keep retrying — each carries a real "come back later" signal — and any answer from the gateway ends the streak. The "Request timeout" hint in the Advanced card now says when the Provider API route needs a bigger budget, and **the default moved from 60 s to 300 s to match the official CLI**. That number is the CLI's, not a round choice: decompiling `command-code@1.66.0` shows its `createNodeTransport` fetch passes only the caller's `signal` and sets no timeout at all, so a model request inherits Node/undici's own default — measured at 301.0 s against a local server that accepts the connection and never sends headers. Being stricter than the CLI only ever costs legitimate requests, since the Provider API route charges its upstream's time-to-first-token to the header wait. The trade is that a genuinely dead gateway now takes longer to name itself, which is what the streak is for.
|
|
18
|
+
|
|
19
|
+
- **The output budget was raised from 64 000 to 131 072.** It was never a provider requirement: probing `/alpha/generate` directly, 64 000 → 200, 131 072 → 200, 196 608 → 200, **200 000 → 200, 200 704 → 400**, 1 000 000 → 400. The server caps `max_tokens` at 200 000, and identically so for a 262 144-window model and a 1 000 000-window one — the cap is global, not per model — so 64 000 was using 32 % of what the provider allows, and the 384 000 figure quoted elsewhere would be refused. 131 072 keeps a 35 % margin under the measured ceiling while covering the real output limits of the models that declare one (Claude 64 K, Gemini 64 K, several at 128 K). It cost nothing in latency to leave at 64 000 (a 64 000 request answered headers in 1.28 s against 1.57 s for 131 072) but it did cap what a model could say in one turn. `DEFAULT_MAX_OUTPUT_TOKENS` moved with it: `/provider/v1/models` publishes only `context_length` and no output ceiling, so the catalog derives a stand-in from the window, and leaving that fallback lower would have re-capped every request before the ceiling was ever consulted. Per request, `requestContextBudget` still lowers the budget from the prompt actually being sent, so raising the ceiling cannot push a large session over its window.
|
|
20
|
+
|
|
21
|
+
- **Both timeout fields are edited in seconds, not milliseconds.** The settings page asked users to do arithmetic to answer "how long is a reasonable wait" — the defaults were `300000` and the ceiling `2147483647`. The stored unit is unchanged (milliseconds, the Host schema, and switching it would break every existing profile); this is presentation only, formatted and parsed through a new `secondsField` spec. Inputs are whole seconds from 1 to 3600 — past an hour a header wait is a hung process, not a budget, and the input is the place to refuse it. Fractions are refused rather than rounded, so the box and the saved profile cannot disagree, and a profile hand-edited beyond the range still displays its true number instead of being silently clamped. The hints now state the default in seconds, and a test reads `DEFAULT_REQUEST_TIMEOUT_MS` to keep the copy from drifting away from the constant.
|
|
22
|
+
|
|
23
|
+
- **CLI image requests now match the official final wire shape (#64).** `/alpha/generate` sends image data URLs with `mimeType`, and both chat transports label each request image with the media type returned by `readImageRequest()` after any JPEG/WebP transcode. Tests cover tool-result images, stored-PNG/request-JPEG variants and stable historical image messages when another image is appended. Live calls showed that this correction alone does not prevent the provider's cache retreat when another image arrives.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Updated the exact DeepSeek Harness pairing from `0.1.7-rc.2` to `0.2.0-rc.1`.** Every Harness peer and development range, `dsh.compatibility.dsh`, `engines.dsh`, and the single `dshReleases` record now name 0.2.0-rc.1 together, and no business code changed: the release audit over the full public source delta (1111 changed paths, 322 package manifests) found 13 of the 16 Harness packages with **zero source changes** — `dsh-llm`, `dsh-settings`, `dsh-typert-protocol`, `dsh-credentials`, `dsh-commands`, `dsh-web`, `dsh-timeout`, `dsh-agent`, `dsh-attachment`, `dsh-launch-environment`, `dsh-invariants`, `cordis` and the two client-only rows — so `GenerateOptions`/`RequestMessage`/`ContentBlock`/`LlmError` and the settings `volatile` contract are byte-identical. The three that moved are additive: `dsh-api-remotes/client` adds one `productAnalyticsRemote` contribution to its assembly list, and `dsh-client-ui-primitives` adds one `pointerModality` export. All five slot ids this plugin registers (`settings.section`, `settings.models.provider-card`, `settings.models.footer`, `sidebar.footer.action`, `conversation.composer.dock`) survive in the new slot catalog with an unchanged `slot-contract.ts`, `apps/web` has no source change so the platform seed table is untouched, and the nine `staticModules` seeds were re-read out of the 0.2.0-rc.1 frontend and are identical to 0.1.7-rc.2's — the argument for keeping `react`, `dsh-client-ui-primitives` and `dsh-client-ui-slots` optional still holds. The `data-composer-stats` outlet the cost readout attaches to is still present at its original site. `npm run test:engine` passes against a real `@deepseek-ai/dsh@0.2.0-rc.1` (ESM link, every static named import, the client `require()` seed audit, image pricing, the volatile Config, tool history on both transports, and the durable offload contract). Deliberately not adopted: the optional `dsh-experimental-schedule-bundle` that automation tasks moved into, the desktop-only product-analytics telemetry, and `resolveAccountToken` in the official `web-search-deepseek` — this plugin ships its own `web_search` provider over the same credential chain and gains nothing from it.
|
|
28
|
+
|
|
29
|
+
- **Opt-in cache-aware image history for the CLI transport (#64).** `offloadSeenImagesForCache` asks dsh's durable image-offload surface to replace older images only after the same model has answered with them. A four-request live A/B showed that the next image then retained the growing text prefix instead of reverting to the first image boundary. It is off by default because old pixels are unavailable until reread or reattached; this is a mitigation, not a provider-side cache fix.
|
|
30
|
+
|
|
31
|
+
- **Internal cleanup with no behavior change: dead-code removal, comment trimming, and small refactors.** Removed the unreferenced `isPeakHour()` helper (the readout prices through `cost-facts.ts` and `capabilities.ts`; its test is replaced by one that pins billing-vs-picker peak agreement across every weekday boundary), inlined the single-use `StatTile` wrapper, dropped the never-used `AccountReport summaryOnly` mode, narrowed the mirror's internal status union to the states it actually writes, and registered the login endpoints through `LOGIN_HOST_CONTRIBUTION` instead of spreading the raw descriptors. Trimmed duplicated design narratives in `transport-retry.ts`, `accounts.ts`, and the slot-declaration files (one canonical copy each). Small performance refactors: `costGroupKey()` now resolves prices through a per-table index instead of scanning the table per call, and the cost projection builds its group lookup in one pass. Typecheck clean, full suite green (679 tests).
|
|
32
|
+
|
|
33
|
+
- **Synced with the official command-code@1.67.0 and 1.68.0 CLIs.** `COMMAND_CODE_CLI_VERSION` and the `x-command-code-version` header now report `1.68.0`. Both releases landed within hours of each other (npm `1.67.0` at 2026-09-28T21:39Z, `1.68.0` at 2026-09-28T23:13Z) and **the official changelog page still documents neither** — its newest entry is 1.66.0 (2026-09-26) — so the integrity-verified tarballs are the evidence, and the two releases were separated by diffing the pinned 1.66.0 artifact, the 1.67.0 artifact and `latest` side by side. 1.67.0 adds **`deepseek/deepseek-v4.1-flash-fast`** (DeepSeek V4.1 Flash Fast): `/chat/completions` + `/responses`, 1M context, text+image, `low`/`high`/`max` efforts, **Go**-tier, hourly peak/off-peak pricing at its own $0.16/$0.58/$0.016 off-peak and $0.32/$1.16/$0.032 peak — deliberately **not** 2× its `deepseek-v4.1-flash` sibling's rates, so only that row's own `timeOfDay` block is the evidence — and it is **not** ZDR-covered. 1.68.0 adds **`claude-sonnet-5-5`** (Claude Sonnet 5.5): `/messages`, 1M context, text+image, the five-level effort set, **GOAT and above**, at $2.00/$10.00/$0.20/$2.50 — one tier *above* its `claude-sonnet-5` predecessor, which keeps its Pro slot. 1.68.0 also adds one non-model feature, the TUI setting **"Show Taste learning in feed"** (`showTasteLearningInFeed`, boolean, user scope, default on), which hides Taste notices from the feed without disabling learning; it lives in the CLI's own config and has no counterpart in this plugin. Everything else is unchanged and was re-verified rather than assumed: the subscription plan maps, the ZDR anchor sets beyond the new row, the API route table, the `x-command-code-version` / `x-cmd-zdr` header table, the account-rejection vocabulary and the stream event names are byte-identical across 1.66.0 → 1.68.0. The remaining artifact diff is minified identifier rotation (e.g. `kR` → `CR`), which carries no behavior.
|
|
34
|
+
|
|
35
|
+
- **The capability snapshot grew by two models, and the vendored price table with it.** `KNOWN_EFFORTS` 53 → 55, `KNOWN_IMAGE_MODELS` 62 → 64, `KNOWN_PLANS` 82 → 84 (Go 52 → 53, GOAT 8 → 9 more; the cumulative chain is now **53/62/76/84** against a catalog that serves 84 models at 66 × chat/completions + responses, 10 Claude ids × messages, 8 × chat/completions), `KNOWN_PEAK_PRICING` 4 → 5, and `KNOWN_NON_ZDR_MODELS` 22 → 23. `scripts/sync-model-prices.mjs` rewrote `MODEL_PRICE_ROWS` with exactly two new rows and no other change, which is also what keeps `tests/model-prices.test.ts`'s "every catalog model is either priced or explicitly free" invariant green. `tests/zdr.test.ts` pins the new membership deliberately, `tests/adapter.test.ts` gained the two models' effort/plan/Vision/peak assertions and its version constant moved with the header.
|
|
36
|
+
|
|
37
|
+
- **One provenance note was corrected, not carried forward.** The `stealth/pixel-canary` comment claimed it entered the ZDR exclusion set "through `modelSupportsZdr` alone", and the `KNOWN_NON_ZDR_MODELS` docstring repeated that both stealth previews were missing from the sibling route table. Re-reading all three artifacts (1.66.0 / 1.67.0 / 1.68.0) on 2026-09-29 shows the row is listed in **both** anchor sets in every one of them; `meituan/LongCat-2.0` is the only genuine divergence. Membership never depended on this — the snapshot is the union — but the explanation was wrong and is now the evidence it claims to be.
|
|
38
|
+
|
|
39
|
+
- **A lapsed discount no longer prices a session at the promotional rate.** The picker has always hidden an expired deal, but the vendored price table kept charging its discount: Grok 4.7's 40%-off launch promotion ended `2026-09-27T23:59:59.999Z`, yet the composer still quoted **$1.20 / $3.60 / $0.30** against a row the page reverts to **$2.00 / $6.00 / $0.50** — a 40% under-report on every session, with the >200K band off by the same factor. The page publishes both sets (the promotional figures as the row's own rates, the pre-discount `listRates` alongside), so `scripts/sync-model-prices.mjs` now copies both and `modelPriceTable(now)` picks between them on **`dealLabel()`'s own clock**. Badge and dollars therefore flip on the same instant, and both context bands flip together so a >200K request is never priced off a mixed pair. The table is rebuilt per request, so the switch needs no redeploy; a deal with no `expiresAt` (the two MiMo rows, MiniMax M3) never lapses and keeps its promotional rates. `tests/model-prices.test.ts` pins the revert, the shared boundary (inclusive on the expiry side) and the no-expiry case.
|
|
40
|
+
|
|
41
|
+
- **The page's `discountPercent` is not the revert factor, and the script no longer pretends it is.** Dividing the promotional rates by `1 - pct/100` looks obvious and is wrong: MiMo V2.5 is advertised at "98% off" while its published list is `0.8 / 4 / 0.16` against charged `0.14 / 0.28 / 0.0028` — ratios of 5.7×, 14.3× and 57×, not one percentage. The generator therefore copies the page's literal `listRates` verbatim, scales a context tier only by that row's own per-bucket ratios, and prints a warning instead of guessing when those disagree. A deal with **no** literal `listRates` is left alone deliberately: the page is saying the unit price does not change (Qwen 3.7 Max's `2x-usage` doubles the allowance, it does not discount a token). Rows whose list equals their charged rates (typesafe/jev) get no fallback data, so nothing dormant ships.
|
|
42
|
+
|
|
43
|
+
- **Fixed, same day: the price script's HTML cross-check had been blind since the page redesign.** `renderedRates()` split on `<tr>`/`<td>`, but the model table is now a `<div>` grid — a live run extracted **6 rows out of 88 models**, and those six were the plan cards (Go/GOAT/Pro/Max 10×/Max 20×/Team Pro). Every model row had therefore been rewritten from the embedded JSON alone with no second opinion, which is the exact safety net that once caught `deepseek-v4-flash-vision-exp` shipping ~47% high. The parser now anchors on the row's name cell (`flex min-w-0 items-center gap-2 px-4 py-3`, whose display name is marked `text-[13px] font-medium` — a deal badge next to it uses `text-[10px]`, so they never collide) and harvests **88 of 88** rows. Re-running the generator on the fixed parser produced a **byte-identical table**, which is what makes the previous write trustworthy in hindsight rather than merely unchecked. Two guards came out of it: `main()` now **exits 2 instead of rewriting** when the harvest falls below half the record count, so the next layout change fails loudly rather than comparing nothing; and a discounted row's struck-through `<s>` figures are compared against the table JSON's `listRates`, giving the pre-discount copy an independent rendering to agree with. The `STRUCK_RATE` regex is deliberately `<s(?:\s[^>]*)?>`: the obvious `<s[^>]*>` also matches `<span …>`, which read the DeepSeek rows' tooltip spans as struck-through prices during development. Rows showing a word (`Free`) or an em-dash publish no figure and are skipped — an unparseable row is never counted as agreement.
|
|
8
44
|
|
|
9
45
|
## [0.11.17] - 2026-09-27
|
|
10
46
|
|
package/README.md
CHANGED
|
@@ -35,21 +35,22 @@ See [Screenshots](#screenshots) below for what the UI looks like.
|
|
|
35
35
|
|
|
36
36
|
## Install
|
|
37
37
|
|
|
38
|
-
This release supports **dsh 0.
|
|
38
|
+
This release supports **dsh 0.2.0-rc.1 and nothing else** — the plugin's peer
|
|
39
39
|
range is that one version, and its compatibility record names it alone:
|
|
40
40
|
|
|
41
41
|
```sh
|
|
42
42
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
- **Older dsh releases.** The 0.1.2–0.1.
|
|
45
|
+
- **Older dsh releases.** The 0.1.2–0.1.7 line is no longer supported: those
|
|
46
46
|
engines predate the 0.1.7 settings rewrite, the `RequestMessage` envelope, and
|
|
47
47
|
the durable image-offload contract, and the compatibility code that bridged
|
|
48
|
-
the two was removed. The last plugin release covering
|
|
49
|
-
0.
|
|
50
|
-
version and
|
|
48
|
+
the two was removed. The last plugin release covering 0.1.7 is 0.11.17; the
|
|
49
|
+
0.1.2–0.1.6 line's last release is 0.11.11; the 0.5.0-era Harness line's last
|
|
50
|
+
release is 0.9.1. All are installed by exact version and none is maintained:
|
|
51
51
|
|
|
52
52
|
```sh
|
|
53
|
+
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.11.17 # dsh 0.1.7
|
|
53
54
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.11.11 # dsh 0.1.2–0.1.6
|
|
54
55
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.9.1 # dsh 0.5.0 line
|
|
55
56
|
```
|
|
@@ -69,7 +70,7 @@ Fresh pnpm 10 marketplace generations are supported directly. Do not add a separ
|
|
|
69
70
|
Update with the same tag you installed with:
|
|
70
71
|
|
|
71
72
|
```sh
|
|
72
|
-
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # dsh 0.
|
|
73
|
+
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # dsh 0.2.0-rc.1
|
|
73
74
|
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@0.9.1 # older dsh (0.5.0 line, unmaintained)
|
|
74
75
|
```
|
|
75
76
|
|
|
@@ -143,7 +144,7 @@ cmd login # writes ~/.commandcode/auth.json
|
|
|
143
144
|
cwd: !!js process.cwd()
|
|
144
145
|
```
|
|
145
146
|
|
|
146
|
-
**Engine version.** The plugin is maintained against exactly one engine: **dsh 0.
|
|
147
|
+
**Engine version.** The plugin is maintained against exactly one engine: **dsh 0.2.0-rc.1**. Its `@deepseek-ai/dsh-*` peer range is `^0.2.0-rc.1` (semver resolves that to 0.2.0-rc.1 alone), and `dsh.compatibility.dshReleases` records that single release. On an older engine the settings page, the message envelope, or the request-image budget will not line up — install the last release that supported your engine (see [Install](#install)) instead of forcing this one.
|
|
147
148
|
|
|
148
149
|
## Usage dashboard
|
|
149
150
|
|
|
@@ -191,7 +192,7 @@ llm-commandcode:
|
|
|
191
192
|
|
|
192
193
|
## Configure
|
|
193
194
|
|
|
194
|
-
**Settings → Command Code** is organized as **Accounts** (keys, sign-in, live quota, pinning, dedicated models), **Models** (hide out-of-plan models, visible models), **Privacy & security** (zero data retention, off by default, see below), **Integrations & display** (serve web search with Command Code, show the quota card in the sidebar, off by default), and a collapsed **Advanced** section (API base URL, request/stream timeouts, transport retries). The working directory is no longer on the page; `workingDir` in config still works.
|
|
195
|
+
**Settings → Command Code** is organized as **Accounts** (keys, sign-in, live quota, pinning, dedicated models), **Models** (hide out-of-plan models, visible models), **Privacy & security** (zero data retention, off by default, see below), **Integrations & display** (serve web search with Command Code, show the quota card in the sidebar, off by default), and a collapsed **Advanced** section (API base URL, request/stream timeouts, transport retries, cache-aware image offload). The working directory is no longer on the page; `workingDir` in config still works.
|
|
195
196
|
|
|
196
197
|
The same options live in `$DSH_HOME/settings.yaml` (changes apply immediately, no restart):
|
|
197
198
|
|
|
@@ -201,12 +202,17 @@ llm-commandcode:
|
|
|
201
202
|
apiBase: https://api.commandcode.ai
|
|
202
203
|
workingDir: /path/to/project # optional
|
|
203
204
|
modelsCachePath: ~/.commandcode/models-cache.json
|
|
204
|
-
requestTimeoutMs:
|
|
205
|
+
requestTimeoutMs: 300000 # default 300s (the official CLI's own budget)
|
|
205
206
|
streamIdleTimeoutMs: 300000 # default 300s
|
|
207
|
+
# offloadSeenImagesForCache: true # opt in to CLI cache mitigation; later requests omit old pixels
|
|
206
208
|
showSidebarQuota: true # optional: show the plans & quota card in the sidebar (default off)
|
|
207
209
|
zdr: true # optional: route requests only through zero-data-retention upstreams (default off)
|
|
208
210
|
```
|
|
209
211
|
|
|
212
|
+
### Repeated image cache misses
|
|
213
|
+
|
|
214
|
+
On the CLI transport (`/alpha/generate`), a new image can make Command Code's reported prompt cache retreat to the first historical image even when every previous request message is byte-identical. The opt-in **Stop replaying images already seen** setting (`offloadSeenImagesForCache`) asks dsh's durable `image/offload` surface to replace an older image with a stable text placeholder after this same model has answered with it. The next request keeps its new image; later text can be cached without replaying old pixels. The default is off because the model cannot inspect an offloaded image again unless it rereads the source file or the user reattaches it. This mitigates the observed cost spike; it does not repair Command Code's underlying multimodal cache behavior. [Live evidence and limits](docs/issue-64-cache-review.md).
|
|
215
|
+
|
|
210
216
|
## Web search
|
|
211
217
|
|
|
212
218
|
When your deployment's dsh shell mounts the web capability (`@deepseek-ai/dsh-web` + `@deepseek-ai/dsh-tool-web`), the model's `web_search` tool is served by this plugin's `commandcode` search provider — it calls the Command Code Provider API's `/alpha/web-search` endpoint with the **same API key and base URL** as chat. You do not configure a separate search key, endpoint, or model.
|
|
@@ -225,7 +231,7 @@ Command Code can serve a request only through upstreams that retain no prompts o
|
|
|
225
231
|
|
|
226
232
|
**Off by default.** Turn it on with the *"Zero data retention (ZDR)"* toggle (`zdr`) in the Privacy & security card, or in your profile config. How this plugin implements it:
|
|
227
233
|
|
|
228
|
-
- The header is sent on **every chat request** while ZDR is on. The plugin maintains an informational exception list (`KNOWN_NON_ZDR_MODELS`, synced from the official CLI —
|
|
234
|
+
- The header is sent on **every chat request** while ZDR is on. The plugin maintains an informational exception list (`KNOWN_NON_ZDR_MODELS`, synced from the official CLI — 23 models as of 2026-09-29, e.g. `xai/grok-4.5`, `stepfun/Step-3.7-Flash`, `meta/muse-spark-1.3`). A model without an available ZDR upstream fails with `422 cmd_zdr_no_providers`; the request is never retried without the header.
|
|
229
235
|
- If a refusal still happens (coverage churn, or no ZDR upstream with spare capacity at that moment), the error names the cause and how to turn ZDR off, instead of surfacing as a bare HTTP 422.
|
|
230
236
|
- **ZDR usually costs more**: capacity is limited and billed at each upstream's pass-through rates, and which upstream serves a request can change per request. The session-cost readout keeps quoting the ordinary catalog rates; the real per-request price shows in Command Code's Studio usage page.
|
|
231
237
|
- Works on every plan; plan credits meter ZDR requests at the plan's default allowance.
|
package/README.zh-CN.md
CHANGED
|
@@ -33,15 +33,16 @@
|
|
|
33
33
|
|
|
34
34
|
## 安装
|
|
35
35
|
|
|
36
|
-
本版本**只支持 dsh 0.
|
|
36
|
+
本版本**只支持 dsh 0.2.0-rc.1**:插件的 peer 范围就是这一个版本,兼容性记录里也只列它。
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
39
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
- **更早的 dsh 版本。** 0.1.2–0.1.
|
|
42
|
+
- **更早的 dsh 版本。** 0.1.2–0.1.7 线已不再支持:那些引擎早于 0.1.7 的设置重写、`RequestMessage` 消息封装和持久化图片卸载契约,用来桥接两代引擎的兼容代码已经删除。覆盖 0.1.7 的最后一个插件版本是 0.11.17;0.1.2–0.1.6 线的最后一个版本是 0.11.11;0.5.0 时代 Harness 线的最后一个版本是 0.9.1。三者都按精确版本安装,且都不再维护:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
+
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.11.17 # dsh 0.1.7
|
|
45
46
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.11.11 # dsh 0.1.2–0.1.6
|
|
46
47
|
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.9.1 # dsh 0.5.0 线
|
|
47
48
|
```
|
|
@@ -61,7 +62,7 @@ dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@0.11.15
|
|
|
61
62
|
用与安装时相同的 tag 更新:
|
|
62
63
|
|
|
63
64
|
```sh
|
|
64
|
-
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # dsh 0.
|
|
65
|
+
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # dsh 0.2.0-rc.1
|
|
65
66
|
dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@0.9.1 # 更早的 dsh(0.5.0 线,不再维护)
|
|
66
67
|
```
|
|
67
68
|
|
|
@@ -135,7 +136,7 @@ cmd login # 写入 ~/.commandcode/auth.json
|
|
|
135
136
|
cwd: !!js process.cwd()
|
|
136
137
|
```
|
|
137
138
|
|
|
138
|
-
**引擎版本要求。** 插件只针对一个引擎维护:**dsh 0.
|
|
139
|
+
**引擎版本要求。** 插件只针对一个引擎维护:**dsh 0.2.0-rc.1**。它的 `@deepseek-ai/dsh-*` peer 范围是 `^0.2.0-rc.1`(按 semver,这只会解析到 0.2.0-rc.1),`dsh.compatibility.dshReleases` 也只记录这一个版本。在更早的引擎上,设置页、消息封装或请求图片预算总有一处对不上——请改装支持你所用引擎的最后一个版本,而不是硬装这一个。
|
|
139
140
|
|
|
140
141
|
## 用量面板
|
|
141
142
|
|
|
@@ -183,7 +184,7 @@ llm-commandcode:
|
|
|
183
184
|
|
|
184
185
|
## 配置
|
|
185
186
|
|
|
186
|
-
**设置 → Command Code** 分为:**账户**(密钥、网页登录、实时额度、固定账户、专用模型)、**模型**(隐藏套餐外模型、可见模型)、**隐私与安全**(零数据保留 ZDR,默认关闭,见下)、**集成与显示**(用 Command Code 承载联网搜索、在侧边栏显示额度卡片,默认关闭),以及默认折叠的**高级设置**(API
|
|
187
|
+
**设置 → Command Code** 分为:**账户**(密钥、网页登录、实时额度、固定账户、专用模型)、**模型**(隐藏套餐外模型、可见模型)、**隐私与安全**(零数据保留 ZDR,默认关闭,见下)、**集成与显示**(用 Command Code 承载联网搜索、在侧边栏显示额度卡片,默认关闭),以及默认折叠的**高级设置**(API 地址、请求/流超时、传输重试次数、历史图片缓存优化)。工作目录已不在页面上显示,配置中的 `workingDir` 仍然有效。
|
|
187
188
|
|
|
188
189
|
同一组选项也位于 `$DSH_HOME/settings.yaml`(修改即刻生效,无需重启):
|
|
189
190
|
|
|
@@ -193,12 +194,17 @@ llm-commandcode:
|
|
|
193
194
|
apiBase: https://api.commandcode.ai
|
|
194
195
|
workingDir: /path/to/project # 可选
|
|
195
196
|
modelsCachePath: ~/.commandcode/models-cache.json
|
|
196
|
-
requestTimeoutMs:
|
|
197
|
+
requestTimeoutMs: 300000 # 默认 300s(与官方 CLI 一致)
|
|
197
198
|
streamIdleTimeoutMs: 300000 # 默认 300s
|
|
199
|
+
# offloadSeenImagesForCache: true # 可选:模型回复后不再重发旧图片,默认关闭
|
|
198
200
|
showSidebarQuota: true # 可选:在侧边栏显示套餐与配额卡片(默认关闭)
|
|
199
201
|
zdr: true # 可选:请求只经由零数据保留上游(默认关闭)
|
|
200
202
|
```
|
|
201
203
|
|
|
204
|
+
### 连续图片导致的缓存回退
|
|
205
|
+
|
|
206
|
+
在 CLI 传输(`/alpha/generate`)上,即使此前所有请求消息逐字节一致,新图片也可能让服务端报告的缓存命中量退回第一张历史图片处。可在「高级设置」打开「已看过的图片不再重复发送」(`offloadSeenImagesForCache`):同一模型看过图片并回复后,插件通过 dsh 持久的 `image/offload` 事件把旧图替换成稳定文字占位;当前新图仍会送给模型,后续文本更容易保持缓存。**默认关闭**,因为模型如需重新查看已 offload 的图片,必须重新读取原文件或由用户再次附加。这是费用缓解方案,未修复 Command Code 服务端的多模态缓存行为。[实测证据与限制](docs/issue-64-cache-review.md)。
|
|
207
|
+
|
|
202
208
|
## 联网搜索
|
|
203
209
|
|
|
204
210
|
当你的 dsh 部署加载了 web 能力(`@deepseek-ai/dsh-web` + `@deepseek-ai/dsh-tool-web`)时,模型所用的 `web_search` 工具会由本插件的 `commandcode` 搜索 provider 承载——它用**与聊天相同的 API key 与 base URL** 调用 Command Code Provider API 的 `/alpha/web-search` 端点。你无需另外配置搜索 key、端点或模型。
|
|
@@ -217,7 +223,7 @@ Command Code 可以让请求只经由「不留存提示词与回复、也不用
|
|
|
217
223
|
|
|
218
224
|
**默认关闭。** 在「隐私与安全」卡片里打开「零数据保留(ZDR)」(`zdr`),或写进 profile 配置。本插件的实现方式:
|
|
219
225
|
|
|
220
|
-
- 开启后,**每次聊天请求**都会带上 ZDR 请求头。插件仍维护官方 CLI 的例外名单(`KNOWN_NON_ZDR_MODELS
|
|
226
|
+
- 开启后,**每次聊天请求**都会带上 ZDR 请求头。插件仍维护官方 CLI 的例外名单(`KNOWN_NON_ZDR_MODELS`,截至 2026-09-29 共 23 个模型,例如 `xai/grok-4.5`、`stepfun/Step-3.7-Flash`、`meta/muse-spark-1.3`)供查询。没有可用 ZDR 上游时,服务端返回 `422 cmd_zdr_no_providers`;插件不会去掉请求头重试。
|
|
221
227
|
- 万一仍被拒绝(名单过期,或那一刻没有空闲的 ZDR 上游容量),错误信息会说明原因并给出关闭 ZDR 的办法,而不是抛出一个光秃秃的 HTTP 422。
|
|
222
228
|
- **ZDR 通常更贵**:容量有限,按各上游实价透传计费,且每次请求落在哪个上游可能不同。会话费用读数仍按常规目录价估算;真实单价见 Command Code Studio 的用量页。
|
|
223
229
|
- 各套餐均可使用;ZDR 请求按套餐的默认额度(而非提升额度)计量。
|