dsh-model-switch 0.4.22 → 0.4.23

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 CHANGED
@@ -1,3 +1,12 @@
1
+ ## v0.4.23
2
+
3
+ Three coordinated changes: the Main-default card is removed entirely; provider groups now apply on every switch surface of the seat session; and the subagent summary distinguishes a pinned effort from a provider default.
4
+
5
+ - **Removed: the Main model card and its protection.** The settings page no longer configures the deployment default — the provider/model/effort card, `saveMain`, the `agent-default-model` client contract (`MAIN_DEFAULT_CONFIG_ID`, `MainSettingsView`, `MainSettingsConflictError`), the Host-side `mainDefaultPort`/`currentMainSelection`/`saveMainSelection` surface (and the runtime's `agentDefaultModel` inject), and the whole pre-switch capture / revision-fenced restore module (`main-default-restore.ts`, removed with its spec) are gone. The picker switch itself is now never gated on settings state (the previous writable-Main admission guard, including the non-loopback `settings.*` notices and the Plan Review card's settings-blocking path, is deleted). **Behavior and migration:** the plugin neither reads nor writes the deployment default; like a native TUI switch, a picker switch lets the Host's own default write take effect, so a new session starts on whatever was last used. To pin a fixed default, use DSH's own **Settings → Models** page. Remaining capability switches (auto review, compaction, subagent) seed their On state from the catalog head instead of Main, and the group editor's row-enable seeds from that capability's live route with the same catalog-head fallback. `PlanCommitOutcome` is now `{ committed }` only (plugin-internal, ships together).
6
+ - **Provider groups watch the session, not just the plugin.** A new watcher (`provider-group-watch.ts`, one per seat session, shared by both slot faces) observes the official model-selection directory projection — whose only `model/selection` emitter is the `session.selectModel` RPC — so the target provider's saved group now applies whenever **this session's model provider** changes, whether the switch came from this plugin's picker, the TUI, or another client. Semantics are unchanged: a provider without a group, a model-only change within one provider, and the subscription baseline write nothing; applies are serialized with coalescing to the latest target; a failed apply logs `dsh-model-switch: provider group apply failed` and never disturbs the switch. Residual boundary: the watcher exists only for sessions open in this Web UI. Settings copy reworded from "主模型切换" to "会话模型切换" (zh/en).
7
+ - **Subagent summary effort wording.** The Default Subagent route card now shows 「已固定 · High」 (locale `effortPinned` / `Pinned`) when an effort is stored and 「Provider 默认 · High」 when the route follows the provider default, with the effort rendered through the catalog's localized name (same lookup the picker uses) instead of the raw id. Previously every fixed route read "Provider 默认 · …" regardless.
8
+ - Verification: `pnpm run check` green (`tsc` + `tsdown`, 52 test files / 370 tests, pack gate); reverse verification — restoring the picker's inline group apply turns the watcher integration red, breaking the watcher baseline/coalescing turns exactly its unit spec red; lab 3082 smoke: the settings page shows no Main card, a picker provider switch still applies the stored group, a second browser tab switching the same session drives the first tab's cards to follow, the subagent summary reads 「已固定 · High」 when pinned and 「Provider 默认 · …」 when unset, group-less providers leave routes untouched, and switching is no longer blocked by settings state.
9
+
1
10
  ## v0.4.22
2
11
 
3
12
  One addition: per-provider capability groups — save the compaction, subagent, and review routes together for a provider, and apply that group automatically when the main model's provider changes.
package/PRODUCT.md CHANGED
@@ -4,13 +4,13 @@
4
4
 
5
5
  ## Routes
6
6
 
7
- - **Default Main:** provider, model, and optional effort. It uses the public Settings namespace and is copied only into newly created sessions; existing sessions are never migrated or selected through the session picker.
7
+ - **Session model:** the active conversation's provider, model, and optional effort, switched through the official Model Directory and session-local by nature. The deployment default for new sessions belongs to DSH itself: the Host persists the last session switch as the default, and since 0.4.23 this plugin no longer configures, restores, or protects it (its Main-default card was removed; a fixed default is configured on DSH's own Models page).
8
8
  - **Default Subagent:** one optional fixed provider/model/effort, injected only when a child spawn names no provider, model, or effort. When the setting is off, stored `follow-main` is read as unset and Model Switch injects nothing; Official inherit (parent live request, then creation snapshot) and the official Allowlist remain DSH's. The default is not an Allowlist and need not be a member of one. Local spawn, fork, continuable, and workflow children use this policy unless the spawn already supplies provider, model, or effort. Remote Codex/Claude children are outside unified routing.
9
9
  - **Search Router:** does not register or replace `web_search`. Model Switch registers one public `WebSearchProvider` with id `model-switch`; the existing official `web_search` continues through `ctx.web`, whose configured search provider must be `model-switch`. The thin provider selects the configured backend adapter and model at execution time and returns the official `WebSearchResult` unchanged. v0.2.0 supports Codex Search only. `web_fetch` and its configured provider remain unchanged.
10
10
  - **Vision:** excluded. Model Switch exposes no Vision setting, does not shadow `read_image`, and does not preprocess chat attachments.
11
11
  - **Image Router:** owns a new, uniquely named stable `generate_image` tool. It selects the configured Codex or Grok adapter/model at execution time, rejects backend-incompatible fields, and returns normalized image metadata. Existing provider-specific image tools remain available as rollback paths.
12
- - **Composer Picker:** replaces the composer model seat with a suffix-grouped Model / Effort / Context / Fast / Thinking picker and submits through the official Model Directory. Variant changes preserve an effort only when the target catalog row supports it, otherwise they use the target default or omit effort. Picker changes are session-local. A submitted prompt reserves the selected runtime immediately (composer submitting, pending first turn, or running). Native Antigravity keeps its models and effort; DSH keeps LLM-provider choices and disables Agent providers. After a successful native binding, other groups stay disabled. Cancel without a binding releases the reservation; existing DSH history still cannot convert onto an External Agent. On a Host version that also persists session selection as the deployment default, the plugin restores the pre-switch Main default through the public Settings RPC with a revision fence; a concurrent Settings-page edit wins.
13
- - **Plan Review:** intercepts the official `plan-review` composer takeover with a header execution-model picker and right-aligned Discuss in chat / Reject / Set as goal and run / Confirm actions. Confirm commits the selected model before answering; a refused commit leaves the review pending and retryable, while a deployment default this plugin could not restore is announced after the answer instead of holding the human's decision back. Reject carries optional human feedback as the answer's own `custom` text, which plan mode reports to the model. **Set as goal and run** arms this Plan as the session's goal through the released `remote.goals.create` — replacing an unfinished goal with `get` + `clear` first so the new Plan receives a fresh round cap — and only then answers, so `dsh-goal-round-driver` carries the Plan after plan mode exits. The goal is set before the answer, a refusal keeps the review pending and retryable, and a deployment that mounts no goal service disables the action with an explicit reason; the plugin stores no goal state, schedules no rounds, and owns no part of the goal domain. The card body carries only the official two-part summary (first line, first paragraph); the full plan opens in the right sidebar through ui-plan's registered preview opener, which this card drives because a composer-takeover entry cannot declare the official actions slot. Discuss in chat withdraws the takeover through the Host's own verb — `dismiss()` where the Host publishes it, `cancel()` on the older generation — and names the Host when neither seam exists, so a settled review is never a dead end. The same runtime reservation applies.
12
+ - **Composer Picker:** replaces the composer model seat with a suffix-grouped Model / Effort / Context / Fast / Thinking picker and submits through the official Model Directory. Variant changes preserve an effort only when the target catalog row supports it, otherwise they use the target default or omit effort. Picker changes are session-local. A submitted prompt reserves the selected runtime immediately (composer submitting, pending first turn, or running). Native Antigravity keeps its models and effort; DSH keeps LLM-provider choices and disables Agent providers. After a successful native binding, other groups stay disabled. Cancel without a binding releases the reservation; existing DSH history still cannot convert onto an External Agent. The deployment default write a Host performs alongside a Session switch is left to DSH (since 0.4.23 the plugin no longer restores a pre-switch default).
13
+ - **Plan Review:** intercepts the official `plan-review` composer takeover with a header execution-model picker and right-aligned Discuss in chat / Reject / Set as goal and run / Confirm actions. Confirm commits the selected model before answering; a refused commit leaves the review pending and retryable. Reject carries optional human feedback as the answer's own `custom` text, which plan mode reports to the model. **Set as goal and run** arms this Plan as the session's goal through the released `remote.goals.create` — replacing an unfinished goal with `get` + `clear` first so the new Plan receives a fresh round cap — and only then answers, so `dsh-goal-round-driver` carries the Plan after plan mode exits. The goal is set before the answer, a refusal keeps the review pending and retryable, and a deployment that mounts no goal service disables the action with an explicit reason; the plugin stores no goal state, schedules no rounds, and owns no part of the goal domain. The card body carries only the official two-part summary (first line, first paragraph); the full plan opens in the right sidebar through ui-plan's registered preview opener, which this card drives because a composer-takeover entry cannot declare the official actions slot. Discuss in chat withdraws the takeover through the Host's own verb — `dismiss()` where the Host publishes it, `cancel()` on the older generation — and names the Host when neither seam exists, so a settled review is never a dead end. The same runtime reservation applies.
14
14
 
15
15
  Model choices are capability-driven. Invalid, unavailable, or unsupported selections remain visible to configuration surfaces and fail loudly at use; routing never silently falls back.
16
16
 
@@ -20,7 +20,7 @@ Official `agent-presets` stay in the process. A nested `ctx.plugin(AgentPresets)
20
20
 
21
21
  ## Settings and lifecycle
22
22
 
23
- The settings surface aggregates public Settings namespaces, reads and mutates with optimistic revisions, and saves rows independently. Changing a Main or fixed Subagent model applies only the target catalog row's default effort, so an effort never leaks across providers or models. The Subagent card is a RouteCard with an instant on/off for the Default Subagent route; turning it off keeps the last provider/model on disk. Switch compaction is a B-row in the Send protection group (发送保护), default on, written immediately. The Auto review card is a RouteCard with an instant switch defaulting **off = reviews follow the session model**; turning it on seeds the pinned reviewer route from Main and stays editable. The Compaction card mirrors it: default **off = official default = compaction follows the conversation target model**; turning it on seeds the summarization route from Main and stays editable, and the pinned pair drives `/compact` and official automatic compaction alike. Provider groups store one compaction/subagent/review route group per provider in the shared `model-switch` namespace and apply it as a full replacement whenever the main model's provider changes through either plugin-owned switch surface (the composer picker or a Main card save); the apply rewrites only the existing flat fields (an unpinned capability reverts to its own default, `subagentMode` last), a same-provider switch or a provider without a stored group writes nothing, the effect is profile-wide rather than per session, and a failed apply never fails the switch or the Main save. Search and image routes are out of scope for groups. Every registration, watcher, and dynamic tool generation has clean disposal. All visible copy lives in zh/en locale dictionaries.
23
+ The settings surface aggregates public Settings namespaces, reads and mutates with optimistic revisions, and saves rows independently. Changing a fixed Subagent model applies only the target catalog row's default effort, so an effort never leaks across providers or models. The Subagent card is a RouteCard with an instant on/off for the Default Subagent route; turning it off keeps the last provider/model on disk. Switch compaction is a B-row in the Send protection group (发送保护), default on, written immediately. The Auto review card is a RouteCard with an instant switch defaulting **off = reviews follow the session model**; turning it on pins the catalog head as an editable starting point. The Compaction card mirrors it: default **off = official default = compaction follows the conversation target model**; turning it on pins the catalog head as an editable starting point, and the pinned pair drives `/compact` and official automatic compaction alike. Provider groups store one compaction/subagent/review route group per provider in the shared `model-switch` namespace and apply it as a full replacement whenever the seat session's model provider changes on any surface — the plugin watches the session's official model-selection projection, so plugin-picker, TUI, and other-client switches share one applier (the residual boundary is a session this Web UI never opened); the apply rewrites only the existing flat fields (an unpinned capability reverts to its own default, `subagentMode` last), a same-provider switch or a provider without a stored group writes nothing, the effect is profile-wide rather than per session, and a failed apply warns without failing the switch. There is no Main-default editing surface: the Host persists the deployment default from the last session switch, and a fixed default belongs to DSH's own Models page. Search and image routes are out of scope for groups. Every registration, watcher, and dynamic tool generation has clean disposal. All visible copy lives in zh/en locale dictionaries.
24
24
 
25
25
  ## Exclusions
26
26
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [中文](README.zh.md)
4
4
 
5
- Choose one explicit route for Main, Subagents, Web Search, image generation, the active conversation, and Plan execution in DeepSeek Harness. Model Switch uses public DSH services and provider-owned adapters; it does not patch DSH Core or manage provider credentials.
5
+ Choose one explicit route for the active session, Subagents, Web Search, image generation, and Plan execution in DeepSeek Harness. Model Switch uses public DSH services and provider-owned adapters; it does not patch DSH Core or manage provider credentials.
6
6
 
7
7
  <p align="center"><img src="docs/screenshots/composer-picker.png" alt="Composer Picker with Model, Effort, Context, and Fast controls" width="314"></p>
8
8
 
@@ -12,9 +12,9 @@ The picker retains keyboard focus when changing panes or closing search, without
12
12
 
13
13
  | Route | Behavior |
14
14
  | --- | --- |
15
- | Main model | Default provider, model, and optional effort for newly created sessions. Existing sessions are not migrated. |
15
+ | Session model | The active conversation's provider/model/effort, changed by the Composer Picker or Plan Review only. The deployment default (new sessions) is DSH's own; the picker never writes it. |
16
16
  | Subagent | Follow the active parent route, or use a fixed provider/model/effort. Workflow overrides remain authoritative. |
17
- | Composer Picker | Changes only the active session and submits the exact catalog model id. Main defaults are preserved. |
17
+ | Composer Picker | Changes only the active session and submits the exact catalog model id. |
18
18
  | Plan Review | Chooses the execution model before the Plan approval response is sent. |
19
19
  | Web Search | Keeps official `web_search`; after deployment opt-in, routes through the selected, dynamically declared provider search adapter. |
20
20
  | Image generation | Provides one stable `generate_image` tool routed through a selected Codex or Grok adapter. |
@@ -25,16 +25,17 @@ Idle blank sessions may pick an External Agent. Submission, pending-first-turn,
25
25
 
26
26
  The existing 3082 lab replay probe is `node scripts/check-lab-runtime-lock.mjs [native|runtime-absent|plugin-absent]`. It checks the dedicated QA conversation under the already-established condition; it does not disable plugins, select a model, or send a turn. `node scripts/check-lab-native-execution.mjs` verifies the saved guard rejection, restored native continuation, DeepSeek-parent/Antigravity-child completion, and restoration of temporary subagent preferences through public history streams.
27
27
 
28
- ## Configure Main and Subagents
28
+ ## Configure Subagents and capability routes
29
29
 
30
- Open **Settings → Model Switch**. Main changes affect new sessions only. Subagents may follow Main or use a fixed provider, model, and effort.
31
- Official DSH `0.1.7-alpha.2` makes ConfigForms memory-only in non-loopback browsers. This page shows an unavailable message there; open Settings on the Host loopback URL instead. The composer picker refuses model changes in that mode because the published `session.selectModel` also persists the deployment default, which cannot be safely restored without a writable Main ConfigForm. Remote editing and session-only selection require an upstream authenticated ConfigForm seam and a session-only selection API; this plugin does not bypass the official policy.
30
+ Open **Settings → Model Switch**. Subagents may follow the parent request or use a fixed provider, model, and effort.
32
31
 
33
- Changing the Main or fixed Subagent provider/model replaces the previous model's effort with the target model's default. Models without reasoning support receive no effort.
32
+ Since 0.4.23 this plugin no longer configures or protects the deployment default ("Main model"). That default is DSH's own: the Host persists the last session switch as the default (including switches made through this plugin's picker or the TUI), exactly like native switching — so a new session starts on whatever was last used. To pin a fixed default, use DSH's own **Settings → Models** page. Official DSH makes ConfigForms memory-only in non-loopback browsers, so the Settings page shows an unavailable message there; open Settings on the Host loopback URL instead. As a side effect of the removal, model switching is never blocked by settings state (previously the picker waited for a writable Main ConfigForm).
33
+
34
+ Changing the fixed Subagent provider/model replaces the previous model's effort with the target model's default. Models without reasoning support receive no effort.
34
35
 
35
36
  ![Model Switch settings with a fixed Subagent route](docs/screenshots/settings-subagent.png)
36
37
 
37
- Follow Main resolves the active parent request first, then the configured Main default. A fixed route is injected before the official Subagent descriptor is created. DSH 0.1.2-alpha.4 carries provider, model, and fixed reasoning effort in that descriptor.
38
+ Follow resolves the active parent request first, then the Host's own session default. A fixed route is injected before the official Subagent descriptor is created. DSH 0.1.2-alpha.4 carries provider, model, and fixed reasoning effort in that descriptor.
38
39
 
39
40
  ## How custom models appear in the Picker
40
41
 
@@ -75,7 +76,7 @@ To support a combined selection, the provider must publish the combined row. Pub
75
76
 
76
77
  ## Plan Review
77
78
 
78
- Plan Review owns an execution-model draft separate from Main. **Confirm** first commits that model to the active session, then answers the pending Plan review. A refused commit leaves the review pending and retryable; a Session switch the Host accepted but whose deployment default could not be restored is announced after the answer instead of withholding it. **Reject** and **Discuss in chat** do not execute the Plan.
79
+ Plan Review owns an execution-model draft separate from the session's current route. **Confirm** first commits that model to the active session, then answers the pending Plan review. A refused commit leaves the review pending and retryable. **Reject** and **Discuss in chat** do not execute the Plan.
79
80
 
80
81
  **Reject** sends the option the asker offered, and any text typed in the card's feedback field as the answer's own `custom` text — plan mode reports that text back to the model as the reason to keep planning, so a rejection can carry what to change. **Discuss in chat** withdraws the takeover so the composer returns and the human speaks in their own words; it uses the Host's `dismiss()` where published and the older generation's `cancel()` otherwise, and names the Host when neither exists. Answering a settled review closes Confirm and Reject, while Discuss and the reload affordance stay reachable so the card always has a way back. Failures keep their wire code (`session/writer-held: …`) visible instead of a bare localized sentence.
81
82
 
@@ -91,11 +92,11 @@ When a sent message will use a different model or context-tier id than the last
91
92
 
92
93
  ## Auto review model
93
94
 
94
- The official `@deepseek-ai/dsh-experimental-auto-review` (the per-call reviewer for the Auto permission preset) hardwires its review requests onto the session's own route. This plugin takes that row over through a `cordis.patch.yml` row replacement: the official row is disabled and `dsh-model-switch/auto-review` mounts the **same official `apply`** under a scoped child context whose `llm.stream` `provider/model` are rewritten to the reviewer model pinned in Settings. The "Auto review model" card defaults to off = reviews follow the session model; turning it on seeds from Main and stays editable, and saved changes apply to the very next review. When the optional auto-review bundle never started with the profile the row stays unmounted and the Auto preset keeps its official off state; an official row already active elsewhere is reported explicitly instead of producing a second `registerAuto`.
95
+ The official `@deepseek-ai/dsh-experimental-auto-review` (the per-call reviewer for the Auto permission preset) hardwires its review requests onto the session's own route. This plugin takes that row over through a `cordis.patch.yml` row replacement: the official row is disabled and `dsh-model-switch/auto-review` mounts the **same official `apply`** under a scoped child context whose `llm.stream` `provider/model` are rewritten to the reviewer model pinned in Settings. The "Auto review model" card defaults to off = reviews follow the session model; turning it on pins the catalog head as an editable starting point, and saved changes apply to the very next review. When the optional auto-review bundle never started with the profile the row stays unmounted and the Auto preset keeps its official off state; an official row already active elsewhere is reported explicitly instead of producing a second `registerAuto`.
95
96
 
96
97
  ## Compaction model
97
98
 
98
- Official compaction — `/compact` and DSH's automatic compaction — summarizes history with the conversation's target model by default. The "Compaction model" card (default off) pins that summarization route instead: turning it on seeds from Main and stays editable, and saved changes apply to the very next compaction. Leaving both fields empty returns to the official default. Saving while a compaction is running may interrupt it; it retries next time.
99
+ Official compaction — `/compact` and DSH's automatic compaction — summarizes history with the conversation's target model by default. The "Compaction model" card (default off) pins that summarization route instead: turning it on pins the catalog head as an editable starting point, and saved changes apply to the very next compaction. Leaving both fields empty returns to the official default. Saving while a compaction is running may interrupt it; it retries next time.
99
100
 
100
101
  How the route reaches the engine depends on where the deployment runs its agent plane. The Web surface moves compaction into each agent preset's isolated `compaction` group, and profile patches cannot address rows inside a preset's `plugins` list — so this plugin replaces each shipped preset row wholesale (the same id-targeted mechanism the Web preset editor saves with) and swaps that group's official `compaction-basic` for `model-switch-compaction`, which mounts the **same official `BasicCompactionEngine`** with only `summarizationProvider`/`summarizationModel` overlaid (either field alone is ignored). Surfaces that compose the agent process-wide (the TUI) use the top-level row replacement instead. Two consequences: a DSH release that edits those presets needs the copies re-synced (this plugin's per-release verification covers it), and a deployment that edits presets in the Web editor writes its own wholesale row that then owns the merge.
101
102
 
@@ -103,7 +104,7 @@ Known issue (upstream; recorded in `docs/seam-gap.md`): while the working set st
103
104
 
104
105
  ## Provider groups
105
106
 
106
- The "Provider groups" card stores one route group per provider — the compaction, subagent, and review routes saved together — and applies it automatically whenever the main model's **provider** changes, whether through the composer picker or by saving a different provider on the Main card. Applying a group is one full replacement: all three routes are written into the cards above in a single decision, overwriting their current values **including manual edits**, while anything the group does not pin reverts to that capability's default (compaction and review follow the conversation model, subagent follows main). Switching to a provider without a stored group leaves the current routes untouched, and a switch within one provider never rewrites them. The stored effect is profile-wide (the shared settings namespace), not per session, and only these two switch surfaces trigger it — a TUI or other switch leaves the routes alone. In the editor, a provider's draft seeds from the active routes the first time you configure it, each capability row's off state means "use the capability default" and is stored as such, and **Delete group** removes the provider's group entirely (clearing the stored field when the last group goes). Search and image routes are out of scope. A failed apply never fails the switch or the Main save: the picker logs a warning and commits anyway, and the Main card reports "Main model saved, but applying the provider group failed …" while the routes stay as they were.
107
+ The "Provider groups" card stores one route group per provider — the compaction, subagent, and review routes saved together — and applies it automatically whenever **this session's model provider** changes, on any surface: this plugin's composer picker, the TUI, or another client — the plugin observes the official model-selection projection of the session, so every switch lands in the same watcher. Applying a group is one full replacement: all three routes are written into the cards above in a single decision, overwriting their current values **including manual edits**, while anything the group does not pin reverts to that capability's default (compaction and review follow the conversation model, subagent follows the parent). Switching to a provider without a stored group leaves the current routes untouched, and a switch within one provider never rewrites them. The stored effect is profile-wide (the shared settings namespace), not per session; the residual boundary is that the watcher only exists while the session is open in this Web UI — a switch on a session this browser never opened leaves the routes alone. In the editor, a provider's draft seeds from the active routes the first time you configure it, each capability row's off state means "use the capability default" and is stored as such, and **Delete group** removes the provider's group entirely (clearing the stored field when the last group goes). Search and image routes are out of scope. A failed apply never fails the switch: the watcher logs a warning and the routes stay as they were.
107
108
 
108
109
  ## What Model Switch does not change
109
110
 
@@ -112,7 +113,7 @@ The "Provider groups" card stores one route group per provider — the compactio
112
113
  - Provider login, credentials, or provider settings cards
113
114
  - Official Agent Presets
114
115
  - Existing provider-specific image tools
115
- - Existing sessions when the Main default changes
116
+ - The deployment default model (DSH persists the last session switch itself, same as native TUI switching)
116
117
  - Global compaction policy, titles, or DSH Core
117
118
 
118
119
  ## Installation
package/README.zh.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | 中文
4
4
 
5
- 在 DeepSeek Harness 中为 Main、Subagent、Web Search、图像生成、当前会话和 Plan 执行模型配置明确路由。Model Switch 只使用 DSH 公开服务和 Provider 自有 Adapter;不修改 DSH Core,也不管理 Provider 登录凭证。
5
+ 在 DeepSeek Harness 中为当前会话、Subagent、Web Search、图像生成和 Plan 执行模型配置明确路由。Model Switch 只使用 DSH 公开服务和 Provider 自有 Adapter;不修改 DSH Core,也不管理 Provider 登录凭证。
6
6
 
7
7
  <p align="center"><img src="docs/screenshots/composer-picker.png" alt="包含 Model、Effort、Context 和 Fast 的 Composer Picker" width="314"></p>
8
8
 
@@ -12,9 +12,9 @@ Picker 在切换页面或关闭搜索时保留键盘焦点,不覆盖搜索框
12
12
 
13
13
  | 路由 | 行为 |
14
14
  | --- | --- |
15
- | Main 模型 | 新建会话的默认 provider、model 和可选 effort;不迁移已有会话。 |
15
+ | 会话模型 | 当前对话的 provider/model/effort,只由 Composer Picker 或 Plan Review 修改。部署默认模型(新建会话)归 DSH 自己管理;选择器从不写它。 |
16
16
  | Subagent | 跟随当前父请求,或使用固定 provider/model/effort;Workflow 显式覆盖始终优先。 |
17
- | Composer Picker | 只修改当前会话,并提交 catalog 中的原始 model id;Main 默认值保持不变。 |
17
+ | Composer Picker | 只修改当前会话,并提交 catalog 中的原始 model id。 |
18
18
  | Plan Review | 在发送 Plan 审核确认前,先提交执行模型。 |
19
19
  | Web Search | 保留官方 `web_search`;部署显式启用后,通过 Provider 动态声明的独立搜索适配器路由。 |
20
20
  | 图像生成 | 提供一个稳定的 `generate_image` 工具,通过选定的 Codex 或 Grok Adapter 路由。 |
@@ -23,16 +23,17 @@ Picker 在切换页面或关闭搜索时保留键盘焦点,不覆盖搜索框
23
23
 
24
24
  空闲的空白会话可以选择 External Agent。提交中、等待首个 turn 以及运行期间,从请求开始就锁定所选执行运行时,不等待首 token 或原生绑定:Antigravity 保留其模型和 effort 选择;DSH 保留 LLM provider 选择,但禁用 Agent provider。会话一旦有过用户消息,Composer 和 Plan Review 仍显示 Agent 角色行但将其禁用,除非该会话已经绑定原生运行时。当前会话成功打开 Antigravity 原生会话后,Picker 会在该会话内禁用其他 provider,同时保留 Antigravity 模型与 effort 控件。DSH 全局 Picker 锁仍拥有最高优先级。
25
25
 
26
- ## 配置 Main 和 Subagent
26
+ ## 配置 Subagent 与能力路由
27
27
 
28
- 打开 **设置 → Model Switch**。Main 修改只影响新建会话。Subagent 可以跟随 Main,也可以使用固定 provider、model 和 effort。
29
- 官方 DSH `0.1.7-alpha.2` 在非本机浏览器将 ConfigForms 设为仅内存模式,页面会明确显示不可用;请在 Host 的 127.0.0.1 页面打开设置。此模式下 Picker 也拒绝模型切换:已发布的 `session.selectModel` 会同时写入全局默认模型,但只读 Main 表单无法安全恢复。远端编辑与真正仅会话的切换需要上游提供受鉴权的 ConfigForm 通道及仅会话的选择接口;本插件不会绕过官方策略。
28
+ 打开 **设置 → Model Switch**。Subagent 可以跟随父请求,也可以使用固定 provider、model 和 effort。
30
29
 
31
- 切换 Main 或固定 Subagent 的 provider/model 时,会用目标模型的默认 effort 替换旧模型的 effort;目标模型不支持推理时不传 effort。
30
+ 自 0.4.23 起本插件不再配置、也不再保护部署默认模型(原「主模型」卡片)。默认模型归 DSH 自己:Host 会把最后一次会话切换写成默认值(包括经本插件选择器或 TUI 的切换),与原生切换行为一致——新会话从"上次用过的模型"开始。需要固定默认值时,请使用 DSH 自带的 **设置 → 模型** 页面。官方 DSH 在非本机浏览器将 ConfigForms 设为仅内存模式,设置页会明确显示不可用;请在 Host 的 127.0.0.1 页面打开设置。移除主卡片的附带收益:模型切换从此不再依赖设置可写状态(此前选择器要等 Main 表单可写才允许切换)。
31
+
32
+ 切换固定 Subagent 的 provider/model 时,会用目标模型的默认 effort 替换旧模型的 effort;目标模型不支持推理时不传 effort。
32
33
 
33
34
  ![Model Switch 设置中的固定 Subagent 路由](docs/screenshots/settings-subagent.png)
34
35
 
35
- Follow Main 先读取当前父请求,再读取配置的 Main 默认值。固定路由会在官方 Subagent descriptor 创建前注入。DSH 0.1.2-alpha.4 会在该 descriptor 中携带 provider、model 和固定 reasoning effort。
36
+ Follow 先读取当前父请求,再读取 Host 自身的会话默认模型。固定路由会在官方 Subagent descriptor 创建前注入。DSH 0.1.2-alpha.4 会在该 descriptor 中携带 provider、model 和固定 reasoning effort。
36
37
 
37
38
  ## 自定义模型如何出现在 Picker
38
39
 
@@ -73,7 +74,7 @@ Model Switch 按 provider,以及剥离以下后缀后的 model id 对 Catalog
73
74
 
74
75
  ## Plan Review
75
76
 
76
- Plan Review 拥有独立于 Main 的执行模型草稿。**确认执行**会先把该模型提交到当前会话,再回答待处理的 Plan 审核。提交被拒绝时,审核保持待处理并允许重试;若会话模型已切换但部署默认模型未能还原,提示会在答复之后给出,而不是扣住你的决定。**拒绝**和**去聊天里说**不会执行 Plan。
77
+ Plan Review 拥有独立于会话当前路由的执行模型草稿。**确认执行**会先把该模型提交到当前会话,再回答待处理的 Plan 审核。提交被拒绝时,审核保持待处理并允许重试。**拒绝**和**去聊天里说**不会执行 Plan。
77
78
 
78
79
  **拒绝**会发送提问方给出的选项,并把卡片反馈框里的文字作为答复自身的 `custom` 文本一并提交 —— plan 模式会把它作为"继续规划"的理由回报给模型,所以打回时可以带上要改什么。**去聊天里说**会撤下这张卡、把输入框还给你,用你自己的话说明;它在 Host 提供 `dismiss()` 时用它,在旧代际用 `cancel()`,两者都没有时明确指出这一点。审核一旦落定,**确认执行**与**拒绝**关闭,而**去聊天里说**与"重新加载"始终可达,卡片不会变成死路。失败会保留线上错误码(如 `session/writer-held: …`),而不是只给一句本地化文案。
79
80
 
@@ -89,11 +90,11 @@ Plan Review 拥有独立于 Main 的执行模型草稿。**确认执行**会先
89
90
 
90
91
  ## 自动审查模型(Auto review)
91
92
 
92
- 官方 `@deepseek-ai/dsh-experimental-auto-review`(Auto 权限预设的逐调用审查)把审查请求固定在会话自身的路由上。本插件通过 `cordis.patch.yml` 的行替换接管这一行:官方行被禁用,改挂 `dsh-model-switch/auto-review`,它在作用域子上下文里运行**同一份官方 `apply`**,只把 `llm.stream` 的 `provider/model` 改写为设置里固定的审查模型。设置页「自动审查模型」默认关闭 = 审查跟随当前会话模型;打开时从主模型种子化、可再改成任意 Provider/模型,保存后对下一次审查立即生效。审查未配置官方能力包(`@deepseek-ai/dsh-experimental-auto-review` 未随 profile 启动)时本行不挂载,Auto 预设保持官方的关闭状态;官方行若已在别处注册,本行明确报错而不产生第二个 `registerAuto`。
93
+ 官方 `@deepseek-ai/dsh-experimental-auto-review`(Auto 权限预设的逐调用审查)把审查请求固定在会话自身的路由上。本插件通过 `cordis.patch.yml` 的行替换接管这一行:官方行被禁用,改挂 `dsh-model-switch/auto-review`,它在作用域子上下文里运行**同一份官方 `apply`**,只把 `llm.stream` 的 `provider/model` 改写为设置里固定的审查模型。设置页「自动审查模型」默认关闭 = 审查跟随当前会话模型;打开时以目录首位模型作为可再改的固定起点,保存后对下一次审查立即生效。审查未配置官方能力包(`@deepseek-ai/dsh-experimental-auto-review` 未随 profile 启动)时本行不挂载,Auto 预设保持官方的关闭状态;官方行若已在别处注册,本行明确报错而不产生第二个 `registerAuto`。
93
94
 
94
95
  ## 压缩模型(Compaction model)
95
96
 
96
- 官方压缩——`/compact` 与 DSH 的自动压缩——默认使用会话当前的目标模型做摘要。「压缩模型」卡片(默认关闭)改为固定摘要路由:打开时从主模型种子化、可再改成任意 Provider/模型,保存后对下一次压缩立即生效。两个字段都留空即回到官方默认。保存时若恰有压缩进行中,可能被打断并在下次重试。
97
+ 官方压缩——`/compact` 与 DSH 的自动压缩——默认使用会话当前的目标模型做摘要。「压缩模型」卡片(默认关闭)改为固定摘要路由:打开时以目录首位模型作为可再改的固定起点,保存后对下一次压缩立即生效。两个字段都留空即回到官方默认。保存时若恰有压缩进行中,可能被打断并在下次重试。
97
98
 
98
99
  路由如何到达压缩引擎取决于部署在哪一层组合 agent。Web 面把压缩放进每个 Agent 预设的隔离 `compaction` 组里,而 profile patch 无法寻址 preset `plugins` 列表内部的行——因此本插件整表替换各预设行(与 Web 预设编辑器保存修改用的是同一套 id 定位机制),把该组的官方 `compaction-basic` 换成 `model-switch-compaction`,由它挂载**同一份官方 `BasicCompactionEngine`**、只覆盖 `summarizationProvider`/`summarizationModel`(只填其一忽略)。进程级组合 agent 的面(如 TUI)则走顶层行替换。两个后果:DSH 发布若改动这些预设,随包副本需要同步(本插件的逐版本核对覆盖这一步);部署若用 Web 编辑器改预设,会写出自己的整表行、并从那之后自行负责合并。
99
100
 
@@ -101,7 +102,7 @@ Plan Review 拥有独立于 Main 的执行模型草稿。**确认执行**会先
101
102
 
102
103
  ## 供应商配置组(Provider groups)
103
104
 
104
- 「供应商配置组」卡片为每个供应商保存一组路由——压缩、子代理、审查三条路由一起存;当**主模型的供应商**发生变化时自动应用,无论变化来自输入框选择器选模型、还是在 Main 卡片上保存成别的供应商。应用是一次完整替换:三条路由一次性写入上方对应卡片,覆盖卡片当前值**(包括手动修改)**;组里没有固定的项回到该能力的默认值(压缩/审查跟随会话模型、子代理跟随主模型)。切换到没有配置组的供应商时现有路由保持不变,同一供应商内部切换不会重写路由。存储是 profile 级的(共享设置命名空间),不按会话生效,且只由这两个切换面触发——TUI 等其他切换不会动路由。编辑器里首次配置某供应商时从当前生效路由种子化;每行能力开关的关闭态表示"用该能力的默认值"并按默认存储;「删除该组」彻底移除该组(删掉最后一组时同时清掉存储字段)。搜索与图片路由不在本功能范围内。应用失败不会让切换或主模型保存失败:选择器侧记录警告并照常完成切换,Main 卡片侧提示"主模型已保存,但供应商组应用失败 …",路由保持原样。
105
+ 「供应商配置组」卡片为每个供应商保存一组路由——压缩、子代理、审查三条路由一起存;当**本会话模型的供应商**发生变化时自动应用,且无论变化来自插件的选择器、TUI 还是其他客户端——插件观察的是该会话的官方模型选择投影,所有切换都会落到同一个 watcher。应用是一次完整替换:三条路由一次性写入上方对应卡片,覆盖卡片当前值**(包括手动修改)**;组里没有固定的项回到该能力的默认值(压缩/审查跟随会话模型、子代理跟随父请求)。切换到没有配置组的供应商时现有路由保持不变,同一供应商内部切换不会重写路由。存储是 profile 级的(共享设置命名空间),不按会话生效;剩余边界是 watcher 只存在于本 Web 打开过的会话——从未在本浏览器打开的会话上的切换不会动路由。编辑器里首次配置某供应商时从当前生效路由种子化;每行能力开关的关闭态表示"用该能力的默认值"并按默认存储;「删除该组」彻底移除该组(删掉最后一组时同时清掉存储字段)。搜索与图片路由不在本功能范围内。应用失败不会让切换失败:watcher 记录一条警告,路由保持原样。
105
106
 
106
107
  ## Model Switch 不会改变什么
107
108
 
@@ -110,7 +111,7 @@ Plan Review 拥有独立于 Main 的执行模型草稿。**确认执行**会先
110
111
  - Provider 登录、凭证或 Provider 设置卡
111
112
  - 官方 Agent Presets
112
113
  - 已有的 Provider 专属图像工具
113
- - Main 默认值修改前已经存在的会话
114
+ - 部署默认模型本身(DSH 自己把最后一次会话切换写成默认值,与原生 TUI 切换一致)
114
115
  - 全局压缩策略、标题或 DSH Core
115
116
 
116
117
  ## 安装