@mars-sea/dsh-commandcode-provider 0.11.1 → 0.11.3
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 +32 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +360 -319
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +80 -2
- package/lib/index.js +658 -29
- package/lib/index.js.map +1 -1
- package/package.json +42 -38
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.11.3] - 2026-09-16
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Thinking text is also read from `reasoning_details`.** The gateway does not normalize the reasoning field across model families, and the difference is per family rather than global: DeepSeek answers with the scalar `reasoning` **plus** an OpenRouter-shaped `reasoning_details` array (`[{ type: 'reasoning.text', text, format, index }]`), while GLM, Qwen and Kimi answer with the DeepSeek-native `reasoning_content` (all measured against the live API on 2026-09-16, alongside the catalog sweep below). The adapter already read the first two spellings, so nothing was broken; the array is now a third fallback, so a family whose thinking arrives only that way is not silently dropped. Entries are read by their `text` member rather than filtered on `type === 'reasoning.text'`: the sibling shapes in that protocol carry `summary` or an encrypted blob instead of `text`, so a plain read already ignores them, while a type filter would drop a text-bearing variant added later — and losing thinking is the failure this exists to prevent.
|
|
13
|
+
- **`transportMaxRetries`: how many transport failures one request absorbs before the failure surfaces** (default 5, 0–50; Settings → Command Code → Advanced). It exists because the route's retry policy cannot express this: `providerRetryPolicy()` is captured once per route, so `TRANSPORT` had to share the near-unbounded window that `RATE_LIMIT`/`SERVER` need, and a connection that cannot be established is not a failure that asks to be waited out. The retries still run on the policy's own cadence (500 ms doubling), so the default spends ~15.5 s (0.5+1+2+4+8) on a blip before reporting it.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Claude models work again on Provider API accounts** ([#46](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/46)). The Provider API serves the whole Claude family only through `/provider/v1/messages`: posted to `/provider/v1/chat/completions`, every catalog Claude id — all eight, verified by posting all 69 models to that endpoint on 2026-09-16 — answers `400 Model "<id>" must be called via /provider/v1/messages (Anthropic Messages shape)`. The adapter's only pre-stream fallback was the Go-plan `upgrade_required` 403, so the rejection surfaced to the user as `PROVIDER_HTTP_ERROR`; and because the non-Go tiers are exactly the ones `resolveProtocol()` sends to the Provider API, the accounts ENTITLED to Claude were the ones that could never use it. Those models now take the CLI transport, which routes every one of them (a lower-plan key gets the ordinary `MODEL_NOT_IN_PLAN` 403 there, never a routing error), so no Messages transport is needed in the adapter. The decision is deliberately NOT written to `protocolCache`, which is keyed by API key alone: remembering it would pin the whole ACCOUNT to the CLI transport and drag DeepSeek, GLM and Qwen — all correctly served by the Provider API — along with it, which is why `rememberProtocol()` is not called on that path. `MESSAGES_ONLY_MODELS` in `src/capabilities.ts` records the measured set, and `requiresMessagesEndpoint()` also treats any `claude-*` id as Messages-only, so a Claude model shipping after this release is routed correctly by an un-updated plugin instead of hard-failing with the 400 above. The same sweep also confirmed the neighbouring report is a non-issue for this plugin: the reasoning-replay and thinking-display paths read every field spelling the gateway emits (see Added).
|
|
17
|
+
- **A transport failure no longer retries toward the 1000-attempt budget** ([#39](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/39), second report). The report after 0.11.1 showed no context-window rejection at all: at ~710k tokens the adapter failed with undici's own `Connect Timeout Error ... timeout: 10000ms` (its default connect timeout — this plugin's `requestTimeoutMs` is 60 s and the connection phase never runs against the body upload) and, on another attempt, `read ECONNRESET` against `/alpha/generate`. Both are `TRANSPORT`, which the retry policy whitelists, so each entered the same 1000-attempt loop the 0.11.2 context-window fix left untouched: with waits doubling from 500 ms, the wait before attempt 11 alone is 512 s and the cumulative wait before it is ~500 s — the `模型请求重试已取消(11/1000)· 482s` row in the report is that 512 s countdown, 30 s in. `TRANSPORT` failures now consume a bounded budget on the `agent/request-error` hook: the first five are retried (~15.5 s of grace — 0.5+1+2+4+8 s waits, and the reporter's own first screenshot, a single `read ECONNRESET` that recovered on the next attempt, stays invisible), and the sixth surfaces the turn with a diagnosis that says what it is (connectivity, *not* a context-window or request-size rejection) and what usually fixes it. The check runs before the budget, so a cancelled turn is never retried and never spends a slot; the budget resets at each new step (one step *is* one model request, so the cap is per request and every step of a turn gets its own grace); and the accounting is keyed per agent, so one session's outage cannot disable another's retries. Everything else — the rate-limit window, a gateway 520, account rotation, the 413 image step-down — is unchanged. The report's "long context" correlation is a red herring, and this change does not depend on ruling it in or out: verified against the live endpoint, request bodies of 1/8/30 MB all returned the provider's own `401` in 1.9/2.7/5.7 s. `tests/transport-retry.test.ts` pins the budget, the per-agent isolation, the cancellation ordering and the message.
|
|
18
|
+
- **A message with no `source` tag no longer kills the whole stream** ([#47](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/47)). `messagesToCC` read `message.source.kind` at four sites to tell a tool result from a plain user message. `source` is producer-supplied and nothing validates it — dsh-llm's type declares it required, but the runtime never checks it and every adapter shipped before this one ignored the field entirely (`dsh-llm-deepseek` never reads it) — so a third-party plugin that assembles its own history can omit it and keep working everywhere else. This adapter, the first to actually read the field, was therefore the first to crash on such a message: `TypeError: Cannot read properties of undefined (reading 'kind')` in the serialization phase, 0–8 ms in, before a request was sent, with an error naming neither the message nor the producer. Both transports now classify a message through one predicate (`isToolResultMessage()`): a PRESENT tag stays authoritative, while an ABSENT one falls back to the content shape — a `user` message whose first block is a `tool-result` is still a tool result, because `pairedToolCalls()` counts such a block from ANY message and dropping it at emission would leave the assistant's tool call unanswered, which the gateway rejects. An untagged plain user message (the reported case, from dsh-mneme's memory pipeline) is now simply converted as the user message it is. Pinned by three tests in `tests/adapter.test.ts`, each run through both transports: the untagged user message, the untagged tool result, and the authoritative tag.
|
|
19
|
+
- **The plugin's stylesheet no longer reaches into other components' markup** ([#48](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/48)). Installing the plugin stacked the `ask_user_question` dialog's side-by-side buttons vertically. The cause was one rule in the panel stylesheet, `[class*="_footerActions"]{flex-direction:column}`, written for the sidebar's footer-action container so this card's full-width line and ui-cordis's chip stack instead of overflowing the shell's flex ROW. `footerActions` is not a stem the sidebar owns alone: `@deepseek-ai/dsh-client-ui-user-questions` renders that dialog's button row as `Mbwy4a_footerActions`, so the unanchored attribute-substring selector matched it too and overrode the row's `display:flex`. The rule is now anchored to the sidebar's own foot area (`[class*="_footArea"] [class*="_footerActions"]`), a stem declared by dsh-client-ui-sidebar alone — audited across every client bundle of the 0.1.6-alpha.1 engine, together with our own `cc-`/`ccp-` class names, which collide with no engine class — so the sidebar layout fix is unchanged and no other component can be reached. The settings-page stylesheet moved to `src/client/page-styles.ts` so both sheets can be audited without importing the React tree, and `tests/styles.test.ts` now enforces the containment in two layers: a structural audit of every selector compound in both sheets, and a simulation against the real foreign class stems proving the dialog's row is no longer matched while the sidebar's still is.
|
|
20
|
+
|
|
21
|
+
## [0.11.2] - 2026-09-15
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **A pre-release engine smoke test** (`npm run test:engine`, [#43](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/43)). It installs the newest release `package.json` declares compatible, stages this checkout's published surface in a scratch tree whose peers ARE that engine's, and imports the bundle there — the only check that can see a bundle which cannot link against the engine it will run on, because a `link:`-installed profile resolves the plugin's peers from the plugin's own `node_modules` instead. It also audits every static named import, the client bundle's `require()` calls, and the request-image policy the engine exposes (including that `LlmError` carries the offload count back).
|
|
25
|
+
- **Session images are now priced the way the upstream that serves them charges for them.** The plugin declares request-image pricing to the harness's token meter, so an image occurrence is charged its family's published visual-token count — Anthropic's one-token-per-750-pixels rule, OpenAI's 512-px tiles, Gemini's 768-px crops, DeepSeek's token grid — read off the model's catalog id, with the most expensive of those rules as the conservative estimate for the families whose accounting we cannot tell apart (Qwen, MiniMax, xAI, moonshot and friends). Without it the meter fell back to a structural estimate that charged a handful of tokens for a full screenshot, so an image-heavy session under-reported the context it was carrying and could walk into its own context window. Offloaded images and text-only routes are priced as the placeholder text the model actually receives. These are context estimates, not invoices: a completed request's own usage stays authoritative.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **The declared Harness range now admits every release the manifest supports.** A caret on a prerelease (`^0.1.2-rc.1`) can only ever resolve to `0.1.2-rc.1`, because semver admits a prerelease only inside the same `major.minor.patch` tuple — so a fresh generation installed a second, older copy of the Harness beside the running engine instead of pairing with it. The peer range is now an exact-version disjunction covering `0.1.2-rc.1` through `0.1.6-alpha.1`, repeated verbatim in `dsh.compatibility.dsh` and `engines.dsh`, and `dsh.compatibility.dshReleases` records `0.1.6-alpha.1` as compatible so the catalog keeps listing the plugin for the current release.
|
|
30
|
+
- **Request images now travel as request versions instead of the stored originals.** An attachment is kept normalized at the size admission accepted; every provider request now asks the attachment service for the version encoded to this route's target — a 1568-px long edge (Anthropic's ceiling, inside the high-detail band of the OpenAI and Gemini tile schemes) and at most 1 MiB per image — and that version is cached by the service and reused across occurrences. Measured on a 3600x2400 screenshot: the harness-normalized original was 2508x1672 at 2.4 MiB, and what reached the wire was 1568x1045 at 0.7 MiB, a 3.4x cut in the base64 that every subsequent request in the session re-sends — which is what pushes a long vision session toward the gateway's undocumented ~50 MB body cap. The request-image budget still accounts the stored size, so the safety margin it computes is unchanged (and conservative).
|
|
31
|
+
- **The plans & quota panel now follows the harness language.** Its copy was English on every harness by construction; both the sidebar card and the dashboard now read in the active language (`panel.commandcode` is a registered locale namespace binding the two panel slots' `t` seat, and every label, state word and the card's tooltip is composed through it). Switching the harness language re-renders the panel immediately. The composer session-cost estimate remains English by construction.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- **The plugin loads on dsh `0.1.6-alpha.1` again** ([#43](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/43)). dsh-llm 0.1.6 removed `offloadRequestImagesWithPolicy`, which the adapter imported by name, so the built bundle failed at ESM link time and the host half never instantiated: no `commandcode` route, no settings page, no panel — and 0.1.6 reports an optional plugin's failure far more quietly than 0.1.5 did. The request-image policy is now reached through a namespace import and selected at runtime, so one build serves both engine generations. On 0.1.2–0.1.5 nothing changes: the adapter still projects its own history under the same 32 MiB / 60-image budget. On 0.1.6 the offload set belongs to the session surface: the adapter renders the surface's durable `offloaded` marks as placeholder text, and an over-budget history fails with `IMAGE_OFFLOAD_REQUIRED` + the count to offload, which the default `dsh-compaction-image-offload` plugin records as one `image/offload` event before retrying. An omission therefore survives session restore and fork, and the token meter stops counting evicted images as context. A 413 asks for the stricter rung's shortfall through the same channel; when nothing is left to offload, the existing bilingual request-size diagnosis stands.
|
|
36
|
+
- **The plans & quota dashboard can be closed again** ([#41](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/41)). Opening it from the sidebar card replaces the conversation in the center column, and there was no way back: the card only re-selected the same panel, so the session stayed unreachable until the whole page was reloaded. The dashboard header now carries a **×** button (its tooltip and accessible name say "Back to the conversation") that returns to the conversation (`ctx.layout.selectPanel(null)`) without changing the current session; on a layout whose panel selection predates that `null` form it falls back to ui-conversation's reserved `main` seat.
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
- **The client-side image-gate error rewrite, which could never fire.** The plugin used to wrap the legacy `connection.api.sessions` face so a `model-unavailable` "does not accept image input" rejection came back friendlier. That face is gone (model selection moved to the remote in 0.1.2), and the rejection it looked for is not the one this harness raises: the real guard runs on the SEND path as `session/attachment-invalid` with `reason: MODEL_DOES_NOT_SUPPORT_IMAGES`, and the conversation UI already renders it in the active language ("当前模型不支持图片,请切换支持图片的模型" / "The current model does not support images; switch to a model that does"). So the wrapper, its tests and its two dictionary strings are gone rather than retargeted — a second copy of a message the harness already localizes would only be able to drift from it.
|
|
40
|
+
|
|
9
41
|
## [0.11.1] - 2026-09-15
|
|
10
42
|
|
|
11
43
|
### Changed
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Unofficial [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harnes
|
|
|
27
27
|
- **Plan-aware picker** — models above your subscription tier are hidden by default (toggleable); an optional **Model allowlist** keeps only your favorites in the picker.
|
|
28
28
|
- **Reasoning-effort support** — models with selectable reasoning effort levels expose them in the picker.
|
|
29
29
|
- **Image input** — Vision-capable models accept images.
|
|
30
|
-
- **Plans & quota panel** — an optional Command Code card at the bottom of the sidebar (directly above Settings) shows the serving account's plan and its 5-hour and weekly windows; clicking it opens a dashboard with the billing period, both windows as progress bars with reset times, monthly credit consumption, and the purchased/free balances. **Off by default** — turn on *"Show the quota card in the sidebar"* under **Settings → Command Code → Advanced** to show it, and the same switch hides it again (a hidden card draws nothing at all and runs no background usage poll); the change lands as soon as you save.
|
|
30
|
+
- **Plans & quota panel** — an optional Command Code card at the bottom of the sidebar (directly above Settings) shows the serving account's plan and its 5-hour and weekly windows; clicking it opens a dashboard with the billing period, both windows as progress bars with reset times, monthly credit consumption, and the purchased/free balances. The dashboard's **×** button hands the center column back to your conversation (the current session is untouched). **Off by default** — turn on *"Show the quota card in the sidebar"* under **Settings → Command Code → Advanced** to show it, and the same switch hides it again (a hidden card draws nothing at all and runs no background usage poll); the change lands as soon as you save. The panel follows your harness language (中文 / English) and needs dsh 0.1.5 (rc.1) or newer.
|
|
31
31
|
- **Session cost estimate** — published-rate estimates (`≈`) beside the composer token counter and in its usage dialog, using each request's model, request time and context tier from durable session history. Model switches and viewing the session later do not reprice earlier requests. Mixed-provider or unpriced usage shows a labeled subtotal (`≥`); missing history or wholly unpriceable usage stays hidden. These are estimates from the installed price snapshot, not provider invoices. Also English on every harness language.
|
|
32
32
|
- **Web search** — the dsh `web_search` tool is backed by the Command Code Provider API (`/alpha/web-search`) with the same key/endpoint as chat, so no separate search key or base URL is needed. See [Web search](#web-search).
|
|
33
33
|
|
package/README.zh-CN.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
- **按套餐过滤**:默认隐藏超出订阅套餐的模型,可一键关闭;「模型白名单」可进一步只保留常用模型。
|
|
28
28
|
- **推理强度支持**:支持推理强度的模型可在选择器中选择档位。
|
|
29
29
|
- **图片输入**:Vision 模型支持发送图片。
|
|
30
|
-
- **套餐与配额面板**:可选的 Command Code 卡片位于侧边栏底部(Settings 正上方),显示当前服务账号的套餐与 5 小时 / 每周两个配额窗口;点击后在中间栏打开面板,包含计费周期、两个窗口的进度条与重置时间、月度额度消耗,以及已购买 /
|
|
30
|
+
- **套餐与配额面板**:可选的 Command Code 卡片位于侧边栏底部(Settings 正上方),显示当前服务账号的套餐与 5 小时 / 每周两个配额窗口;点击后在中间栏打开面板,包含计费周期、两个窗口的进度条与重置时间、月度额度消耗,以及已购买 / 赠送余额。面板右上角的 **×** 按钮可随时把中间栏交还给会话(不会切换当前会话)。**默认关闭**——在 **设置 → Command Code → 高级设置** 中打开「在侧边栏显示额度卡片」即可显示,同一开关也能随时隐藏(隐藏时左侧不渲染任何内容,也不会为其后台刷新用量)。面板文案跟随 Harness 显示语言(中文 / English),需要 dsh 0.1.5(rc.1)或更高版本。
|
|
31
31
|
- **会话费用估算**:在输入框下方的 token 计数旁及用量对话框中显示估算金额(`≈`),根据持久化历史中每次请求的模型、请求时间和上下文阶梯分别计价。切换模型或稍后查看不会重新定价之前的请求。混合供应商或缺少费率时显示已定价部分的小计(`≥`);缺少历史事实或完全无法定价时不显示金额。结果基于插件内的价格快照,不等同于供应商账单。同样固定为英文。
|
|
32
32
|
- **联网搜索**:dsh 的 `web_search` 工具由 Command Code Provider API(`/alpha/web-search`)承载,复用聊天同一个 key 与端点,无需单独配置搜索 key 或地址。详见[联网搜索](#联网搜索)。
|
|
33
33
|
|