dsh-advisor 0.4.1 → 0.5.1
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/README.i18n.yaml +2 -2
- package/README.md +31 -22
- package/README.zh.md +31 -22
- package/lib/client/advisor-card.d.ts +18 -14
- package/lib/client/advisor-session.d.ts +75 -0
- package/lib/client/advisor-store.d.ts +131 -0
- package/lib/client/index.d.ts +18 -13
- package/lib/client/locales.d.ts +15 -0
- package/lib/client.js +375 -14
- package/lib/commands.d.ts +220 -27
- package/lib/commands.js +260 -34
- package/lib/commands.js.map +1 -1
- package/lib/config.d.ts +74 -20
- package/lib/config.js +74 -20
- package/lib/config.js.map +1 -1
- package/lib/delivery.d.ts +9 -9
- package/lib/delivery.js +10 -12
- package/lib/delivery.js.map +1 -1
- package/lib/gateway.d.ts +139 -24
- package/lib/gateway.js +138 -27
- package/lib/gateway.js.map +1 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.js +483 -82
- package/lib/index.js.map +1 -1
- package/lib/kinds.d.ts +79 -51
- package/lib/kinds.js +60 -43
- package/lib/kinds.js.map +1 -1
- package/lib/settings.d.ts +56 -86
- package/lib/settings.js +48 -91
- package/lib/settings.js.map +1 -1
- package/lib/transcript.d.ts +11 -9
- package/lib/transcript.js +25 -16
- package/lib/transcript.js.map +1 -1
- package/lib/tui-settings.d.ts +10 -10
- package/lib/tui-settings.js +10 -10
- package/lib/tui-settings.js.map +1 -1
- package/lib/tui.js +39 -5
- package/lib/tui.js.map +1 -1
- package/package.json +25 -24
package/README.i18n.yaml
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
# editing either side, bring the other along and re-record with:
|
|
4
4
|
# git hash-object README.md
|
|
5
5
|
# git hash-object README.zh.md
|
|
6
|
-
README.md:
|
|
7
|
-
README.zh.md:
|
|
6
|
+
README.md: ce87847dc44cf80fe0afe72fb7d166eef9e8084e
|
|
7
|
+
README.zh.md: 4092cedf85c5ad7643a772b1ac2df6388c4f63a6
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/dsh-advisor)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
[](https://dshfind.com/plugins/omdsh-dev/dsh-advisor?ref=badge)
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ A standalone dsh (DeepSeek Harness) plugin bundle porting the omp "advisor" subs
|
|
|
13
13
|
|
|
14
14
|
**Advisory only.** The advisor never approves or rejects the primary agent's actions, and never issues commands as if it were the primary agent. Every delivered message is self-described advisory content, and a misbehaving reviewer is bounded end to end (emission guard, immuneTurns cooldown, failure policy) so it can never stall or pollute the primary loop.
|
|
15
15
|
|
|
16
|
-
Works in both dsh front ends: the **web** profile (
|
|
16
|
+
Works in both dsh front ends: the **web** profile (sidebar → Plugins → dsh-advisor → Advisor card) and the **dsh-tui** terminal profile (`/advisor` + `/advisor config`).
|
|
17
17
|
|
|
18
18
|
## Quick start
|
|
19
19
|
|
|
@@ -28,29 +28,31 @@ Same plugin, either front end — the only difference is the `--profile` flag. P
|
|
|
28
28
|
|
|
29
29
|
### Configuration
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Edit the `config` of the `advisor` row in your profile's patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`). All six fields are schema-volatile live fields (dsh ≥ 0.1.7-rc.1): the web card and the TUI `/settings` screen write this same entry config — persisted in the profile patch, committed without a remount. (A pre-0.1.7 `$DSH_HOME/settings.yaml` `advisor:` section no longer exists: dsh imports it into the active profile once and renames the file `.imported`.)
|
|
32
32
|
|
|
33
33
|
```yaml
|
|
34
|
-
advisor
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
# ~/.dsh/profiles/<profile>/cordis.patch.yml — the advisor row's config
|
|
35
|
+
- id: advisor
|
|
36
|
+
config:
|
|
37
|
+
enabled: true # master switch (default false) — set explicitly to enable
|
|
38
|
+
provider: deepseek-official # REQUIRED when enabled
|
|
39
|
+
model: deepseek-flash # REQUIRED when enabled; fallback: deepseek-v4-flash (or another V4 id) until the gateway enables the V41 route
|
|
40
|
+
systemPrompt: "" # optional; "" = built-in reviewer prompt
|
|
41
|
+
immuneTurns: 3 # int ≥ 0, default 3 — cooldown after a delivered steer
|
|
42
|
+
maxDeltaMessages: 60 # int ≥ 0, default 60 — delta window; 0 = unbounded
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
The advisor is off by default. When enabled, `provider` and `model` are **mandatory**: `enabled: true` without both is a hard gate — the advisor never starts a model call and reports a disabled-with-reason status; unknown config keys are rejected.
|
|
44
46
|
|
|
45
|
-
The same keys
|
|
47
|
+
The same keys are read and edited from **three surfaces** (one store — the advisor entry config above; every surface shares the same key set and the same hard gate, with the host-side gate as the final line of defense on every path):
|
|
46
48
|
|
|
47
|
-
1. **Plugin-row config** — the profile patch layer (
|
|
48
|
-
2. **dsh web
|
|
49
|
-
3. **`/advisor` command** — per-session and ephemeral: it flips a session override, never the persisted config (see [Verify](#verify)).
|
|
49
|
+
1. **Plugin-row config** — the profile patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`). This is where the config lives.
|
|
50
|
+
2. **dsh web Plugins page — the dsh-advisor bundle's own page** — the Advisor **card** (bundle key `dsh-advisor`) with the enabled toggle, provider / model selects restricted to system-configured providers and their models, and the optional fields. Saving writes the advisor entry's config (landed through the config editor into the profile patch) and applies to running sessions immediately — no restart. The card requires a dsh web build whose shell declares the `plugins.bundle.config` card slot (dsh ≥ 0.1.7-rc.1) and loads packages that declare `dsh.client`; it reads and writes the config through the official `GatewayService` RPC channel (`/api/advisor/get` + `/api/advisor/set`), which is not gated by the settings exposure allowlist. It additionally blocks saving while enabled with a required field empty.
|
|
51
|
+
3. **`/advisor` command** — per-session and ephemeral: it flips a session override and pins a per-session reviewer model, never the persisted config (see [Verify](#verify)).
|
|
50
52
|
|
|
51
|
-
In a **dsh-tui** profile the same five keys are editable in the TUI `/settings` screen: run `dsh --profile dsh-tui`, open `/settings`, and edit the **Advisor** section (`enabled` / `provider` / `model` / `immuneTurns` / `maxDeltaMessages`, each with zh/en label + hint). Edits are staged and written on save through the revision-fenced `settings.mutate` into the same
|
|
53
|
+
In a **dsh-tui** profile the same five keys are editable in the TUI `/settings` screen: run `dsh --profile dsh-tui`, open `/settings`, and edit the **Advisor** section (`enabled` / `provider` / `model` / `immuneTurns` / `maxDeltaMessages`, each with zh/en label + hint). Edits are staged and written on save through the revision-fenced `settings.mutate` into the same advisor entry config the web card writes, and re-apply live without a restart. `systemPrompt` is NOT a TUI field (the TUI text control is single-line; a multi-line prompt would be truncated) — edit it via the web card or the profile patch layer. The section requires dsh-tui ≥ v0.8.0 (shipped in the `dsh-tui-settings-sections` row of the v0.8.0+ bundle); older dsh-tui versions no-op it cleanly and the profile patch layer remains the edit path. `/advisor config` stays a read-only readback whose edit hint names the `/settings` screen when the seam is mounted. Save behavior differs from the web card: the TUI seam has no cross-field validation, so a save may set `enabled: true` with empty `provider`/`model` — the explicit model gate resolves that to disabled-with-reason at runtime (visible via `/advisor status` and `/advisor config`); the web card blocks such a save outright. Full reference → [docs/configuration.md](docs/configuration.md).
|
|
52
54
|
|
|
53
|
-

|
|
54
56
|
|
|
55
57
|
### Verify
|
|
56
58
|
|
|
@@ -65,31 +67,38 @@ With the advisor installed and enabled, control it in-session with the `/advisor
|
|
|
65
67
|
/advisor on enable the advisor for this session
|
|
66
68
|
/advisor off disable the advisor for this session
|
|
67
69
|
/advisor status show state, model, runtime status, pending count, last activity
|
|
70
|
+
/advisor model show the effective reviewer model and its source (session override or global default)
|
|
71
|
+
/advisor model set <provider> <model> pin a reviewer model for this session only
|
|
72
|
+
/advisor model reset drop the session pin and re-inherit the global defaults
|
|
68
73
|
```
|
|
69
74
|
|
|
70
75
|
`/advisor on|off|toggle` are session-scoped and ephemeral: they flip a per-session override, never the persisted config. Enabling a session whose config lacks `provider`/`model` starts no model call — `/advisor status` (and the `/advisor on` reply) shows the gate reason: the advisor runs only when enabled **with** both configured. `/advisor on` is also the manual recovery path: a session advisor paused by a quota/rate-limit (`quota_exhausted` — no auto-resume timer) resumes in place, and a halted advisor (permanent model error, e.g. invalid credentials) is rebuilt fresh for the session.
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
`/advisor model set` pins a reviewer model for the **invoking session only** — an in-memory, atomic `provider + model` pair that lives for the live session (cleared on dispose, owner teardown, cold resume, or restart; a forked/new session inherits the global defaults). It rides above the persisted global defaults without rewriting them: a complete session pair is used even when the global config has no pair yet, a malformed global config still blocks every session, half-pairs are never merged, and setting/resetting never touches the enable switch. Validation resolves the pair through the LLM service before commit (60 s bound, cancellable, no auto-retry); on failure the previous selection stays untouched. `/advisor config` remains the readback of the **global defaults**, not the session state.
|
|
78
|
+
|
|
79
|
+
In a **dsh-tui** profile, `/advisor config` additionally reads back the composed configuration — the global defaults, read-only, with edit hints naming the real write paths: the TUI `/settings` screen (Advisor section, dsh-tui ≥ v0.8.0) and the profile patch layer. The `/advisor` / `on|off|status|config|model` commands are listed in the TUI `/` menu with subcommand completion (command discovery requires the `dsh-tui-command-trees` row — the shipped dsh-tui bundle has it).
|
|
80
|
+
|
|
81
|
+
On the **web**, the same session model controls ride the session header's **Advisor action** (requires a dsh web build whose shell declares the `conversation.session.header.actions` slot — dsh ≥ 0.1.7-rc.1). The action is bound to the session it sits on: it shows the effective reviewer pair, its source (`session override` / `global default`), and the live-session lifetime; **Pin this model** pins a provider + model for that session, and **Use global default** drops the pin (the reset path). It writes ONLY through the plugin's session endpoints (`/api/advisor/getSession` + `/api/advisor/setSessionModel`) — the same controller, validation, and fencing as `/advisor model`, never the persisted config — and it never falls back to the global config write when the session surface is unavailable. The control refreshes when you open it (plus on reconnect/focus while open); there is no background polling. The global card on the Plugins page stays global-only.
|
|
73
82
|
|
|
74
83
|
## Features
|
|
75
84
|
|
|
76
|
-
- **Independent reviewer per session**: a separate model call observes the primary transcript and reviews each stepped primary turn; advisor messages are excluded from later deltas, so the advisor does not read its own advice back.
|
|
85
|
+
- **Independent reviewer per session**: a separate model call observes the primary transcript and reviews each stepped primary turn; advisor messages are excluded from later deltas, so the advisor does not read its own advice back. The exclusion recognizes the advisor's current producer kind (`advisor`) AND both historical shapes a still-openable log can carry: the prehistoric direct `{ kind: 'advisor' }` note and the 0.1.6-era note as the V3→V4 in-memory migration rewrote it (`kind: 'plugin:advisor'`) — no generation of persisted notes is orphaned by the identity migration.
|
|
77
86
|
- **Severity-ranked advice with inject/steer semantics**: at most one note per review — **nit** (a minor style, clarity, or quality suggestion; delivered via non-waking `agent.inject`, consumed at the next pre-step boundary), **concern** (a material risk or clearly better direction to weigh before continuing; delivered via waking `agent.steer`, subject to the `immuneTurns` cooldown), **blocker** (continuing clearly wastes work — contradicts an explicit user instruction, going in circles, fundamentally unsound; delivered via `agent.steer`). Delivered messages carry the `[advisor:{severity}]` prefix and are self-described advisory content:
|
|
78
87
|
|
|
79
88
|
```
|
|
80
89
|
[advisor:concern] extract the helper into a module and unit-test it
|
|
81
90
|
```
|
|
82
91
|
|
|
83
|
-
- **Explicit model gate**: `enabled` defaults to off; `enabled: true` without `provider` + `model` never starts a model call — status reports disabled-with-reason. Unknown config keys are rejected.
|
|
92
|
+
- **Explicit model gate**: `enabled` defaults to off; `enabled: true` without `provider` + `model` never starts a model call — status reports disabled-with-reason. The gate applies to the *effective* route after session resolution: a complete per-session override pair satisfies it for that session; a malformed global config cannot be bypassed. Unknown config keys are rejected.
|
|
84
93
|
- **Zero-tool minimal start**: the reviewer is an independent model call only — no advisor tools, nothing it can do to the session besides advisory messages.
|
|
85
94
|
- **No-stall failure policy**: a failing or quota-limited advisor only drops its own bounded backlog — it can never park or pollute the primary loop.
|
|
86
|
-
- **Session-scoped controls**: `/advisor on|off|status|config` work per session; the toggles are ephemeral overrides, never persisted config.
|
|
95
|
+
- **Session-scoped controls**: `/advisor on|off|status|config|model` work per session; the toggles and the per-session model pin are ephemeral overrides, never persisted config — `/advisor config` always reports the global defaults. On the web, the session header's **Advisor action** drives the same per-session pin through dedicated session endpoints (see [Verify](#verify)).
|
|
87
96
|
|
|
88
97
|

|
|
89
98
|
|
|
90
99
|
## Mount-only (no dsh modification)
|
|
91
100
|
|
|
92
|
-
The plugin installs as a **pure mount**: bundle insert + client card (web
|
|
101
|
+
The plugin installs as a **pure mount**: bundle insert + client card (the web Plugins page) + its own gateway channel (`/api/advisor/get|set` for the global config plus `/api/advisor/getSession|setSessionModel` for the per-session model surface, claimed by the host's typertGateway — the same mechanism the dsh `goals` service uses, not gated by the settings exposure allowlist) + the `/advisor` commands — no dsh patches, no postinstall step, and dsh upgrades never require re-patching.
|
|
93
102
|
|
|
94
103
|
## Limitations & roadmap
|
|
95
104
|
|
|
@@ -111,7 +120,7 @@ The MVP deliberately drops full omp parity. Accepted gaps (tracked in the harnes
|
|
|
111
120
|
| Doc | Content |
|
|
112
121
|
|---|---|
|
|
113
122
|
| [docs/install.md](docs/install.md) | profile install (web + dsh-tui) / registry / git / tarball / local-directory variants / web Settings exposure / uninstall / `--dump-config` verification |
|
|
114
|
-
| [docs/configuration.md](docs/configuration.md) | full
|
|
123
|
+
| [docs/configuration.md](docs/configuration.md) | full advisor config reference: keys & defaults, explicit model gate (S4), config surfaces (web card / TUI `/settings` / patch layer), example YAML, live re-apply behavior |
|
|
115
124
|
| [docs/consumer-api.md](docs/consumer-api.md) | developer consumption contract: package-root library API, `dsh-advisor/client` entry, `/advisor` command surface, export inventory, lifecycle |
|
|
116
125
|
| [docs/verification.md](docs/verification.md) | verification records: test matrix (16 files / 319 cases), typecheck/build, CI contract, real-environment steps |
|
|
117
126
|
| [docs/release.md](docs/release.md) | release process: PR-driven Release prep + Release workflows, OIDC trusted publishing, version strategy, rollback |
|
package/README.zh.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/dsh-advisor)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
[](https://dshfind.com/zh/plugins/omdsh-dev/dsh-advisor?ref=badge)
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
**仅作建议。** advisor 从不批准或否决主 agent 的动作,也绝不会像主 agent 那样发出命令。每条送达的消息都是自我描述的 advisory 内容;一个行为异常的评审者会被端到端约束(emission guard、immuneTurns 冷却、failure policy),因此它永远不会卡住或污染主循环。
|
|
15
15
|
|
|
16
|
-
两个 dsh 前端均可用:**web** profile
|
|
16
|
+
两个 dsh 前端均可用:**web** profile(侧边栏 → 插件 → dsh-advisor → Advisor 卡片)与 **dsh-tui** 终端 profile(`/advisor` + `/advisor config`)。
|
|
17
17
|
|
|
18
18
|
## 快速开始
|
|
19
19
|
|
|
@@ -28,29 +28,31 @@ dsh plugin --profile dsh-tui add dsh-advisor # dsh-tui 终端 profile
|
|
|
28
28
|
|
|
29
29
|
### 配置
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
编辑 profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)里 `advisor` 行的 `config`。六个字段全部是 schema-volatile 的 live 字段(dsh ≥ 0.1.7-rc.1):web 卡片与 TUI `/settings` 屏幕写入的就是这同一份 entry config——持久化在 profile 补丁层,无需重挂载即生效。(pre-0.1.7 的 `$DSH_HOME/settings.yaml` `advisor:` 分节已不存在:dsh 会在首次启动时把它导入活跃 profile 一次,并将该文件改名为 `.imported`。)
|
|
32
32
|
|
|
33
33
|
```yaml
|
|
34
|
-
advisor
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
# ~/.dsh/profiles/<profile>/cordis.patch.yml —— advisor 行的 config
|
|
35
|
+
- id: advisor
|
|
36
|
+
config:
|
|
37
|
+
enabled: true # 总开关(默认 false)——需显式打开后生效
|
|
38
|
+
provider: deepseek-official # enabled: true 时必填(非空)
|
|
39
|
+
model: deepseek-flash # enabled: true 时必填(非空);网关未开放 V41 路由时回退 deepseek-v4-flash(或其它 V4 id)
|
|
40
|
+
systemPrompt: "" # 可选;"" = 内置评审 prompt
|
|
41
|
+
immuneTurns: 3 # 整数 ≥ 0,默认 3 —— 打断性送达后的冷却步数
|
|
42
|
+
maxDeltaMessages: 60 # 整数 ≥ 0,默认 60 —— delta 窗口;0 = 无上限
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
advisor 默认关闭。启用后,`provider` 与 `model` 为**必填**:`enabled: true` 而缺少两者之一是一个硬门禁——advisor 不会发起任何模型调用,并报告带原因的禁用状态(disabled-with-reason);未知配置键会被拒绝。
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
同一组键可在**三个配置面**读取与编辑(只有一份存储——上面的 advisor entry config;各处使用同一组键与同一个硬门禁,宿主侧门禁始终是所有路径上的最后防线):
|
|
46
48
|
|
|
47
|
-
1. **插件行 config** —— profile
|
|
48
|
-
2. **dsh web
|
|
49
|
-
3. **`/advisor` 指令** —— 按会话且临时:翻转的是会话级 override
|
|
49
|
+
1. **插件行 config** —— profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)。配置就存放在这里。
|
|
50
|
+
2. **dsh web 的「插件」页 —— dsh-advisor 组合包自己的页面** —— Advisor **卡片**(bundle key `dsh-advisor`),含 enabled 开关、只列出系统内已配置 provider 及其模型的 provider/model 选择框与可选字段。保存写入 advisor entry 的 config(经 config editor 落入 profile 补丁层),运行中的会话立即生效,无需重启。卡片要求 dsh web 构建的 shell 声明了 `plugins.bundle.config` 卡片 slot(dsh ≥ 0.1.7-rc.1)并能加载 `dsh.client` 声明包;它通过官方 `GatewayService` RPC 通道读写该配置(`/api/advisor/get` + `/api/advisor/set`),不受 settings 暴露白名单门控。卡片还会在 enabled 且必填字段为空时阻止保存。
|
|
51
|
+
3. **`/advisor` 指令** —— 按会话且临时:翻转的是会话级 override、并为会话钉住评审模型,从不修改持久化配置(见[验证](#验证))。
|
|
50
52
|
|
|
51
|
-
在 **dsh-tui** profile 中,同样的五个键可在 TUI `/settings` 屏幕编辑:运行 `dsh --profile dsh-tui`、打开 `/settings`,编辑 **Advisor** 分节(`enabled` / `provider` / `model` / `immuneTurns` / `maxDeltaMessages`,每项均带中英文标签与提示)。编辑先暂存,保存时经 revision 栅栏保护的 `settings.mutate` 写入 web
|
|
53
|
+
在 **dsh-tui** profile 中,同样的五个键可在 TUI `/settings` 屏幕编辑:运行 `dsh --profile dsh-tui`、打开 `/settings`,编辑 **Advisor** 分节(`enabled` / `provider` / `model` / `immuneTurns` / `maxDeltaMessages`,每项均带中英文标签与提示)。编辑先暂存,保存时经 revision 栅栏保护的 `settings.mutate` 写入 web 卡片所写的同一份 advisor entry config,并 live 重应用、无需重启。`systemPrompt` **不是** TUI 字段(TUI text 控件为单行;多行 prompt 会被截断)——请经 web 卡片或 profile 补丁层编辑。该分节要求 dsh-tui ≥ v0.8.0(随 v0.8.0+ 组合包的 `dsh-tui-settings-sections` 行提供);旧版 dsh-tui 会干净地 no-op,profile 补丁层仍是编辑路径。`/advisor config` 仍是只读回读,seam 挂载时其编辑提示指向 `/settings` 屏幕。保存行为与 web 卡片不同:TUI seam 没有跨字段校验,一次保存可能把 `enabled: true` 与空 `provider`/`model` 一起写入——显式模型门禁会在运行时把它解析为 disabled-with-reason(可见于 `/advisor status` 与 `/advisor config`);web 卡片则会直接阻止这样的保存。完整参考 → [docs/configuration.md](docs/configuration.md)。
|
|
52
54
|
|
|
53
|
-

|
|
54
56
|
|
|
55
57
|
### 验证
|
|
56
58
|
|
|
@@ -65,31 +67,38 @@ dsh --profile web --dump-config # 显示带 advisor 配置行的 "# == dsh-adv
|
|
|
65
67
|
/advisor on enable the advisor for this session
|
|
66
68
|
/advisor off disable the advisor for this session
|
|
67
69
|
/advisor status show state, model, runtime status, pending count, last activity
|
|
70
|
+
/advisor model show the effective reviewer model and its source (session override or global default)
|
|
71
|
+
/advisor model set <provider> <model> pin a reviewer model for this session only
|
|
72
|
+
/advisor model reset drop the session pin and re-inherit the global defaults
|
|
68
73
|
```
|
|
69
74
|
|
|
70
75
|
`/advisor on|off|toggle` 是会话级且临时的:它们翻转的是按会话的 override,从不修改持久化配置。启用一个 config 缺少 `provider`/`model` 的会话不会发起模型调用——`/advisor status`(以及 `/advisor on` 的回复)会显示门禁原因:advisor 只有在启用**且**两者均已配置时才运行。`/advisor on` 也是手动恢复路径:被 quota/rate-limit 暂停的会话 advisor(`quota_exhausted`——无自动恢复定时器)会在原地恢复;被终止的 advisor(永久性模型错误,如凭据无效)会为该会话全新重建。
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
`/advisor model set` 只为**发起调用的会话**钉住一个评审模型——一个内存中的原子 `provider + model` 对,生存期为活跃会话(dispose、owner 卸载、冷恢复或重启时清除;fork 的新会话继承全局默认值)。它叠加在持久化的全局默认值之上而不改写它们:全局配置还没有 pair 时,完整的会话对即可生效;全局配置非法时所有会话照旧被阻挡;两级之间的半个 pair 永不拼接;set/reset 从不触碰启用开关。提交前会经 LLM 服务解析校验该对(60 秒上界、可取消、无自动重试);失败时先前选择保持不变。`/advisor config` 始终是**全局默认值**的回读,不是会话状态。
|
|
78
|
+
|
|
79
|
+
在 **dsh-tui** profile 中,`/advisor config` 额外回读组合配置——即全局默认值,只读,编辑提示指向真实的写路径:TUI `/settings` 屏幕(Advisor 分节,dsh-tui ≥ v0.8.0)与 profile 补丁层。`/advisor` / `on|off|status|config|model` 指令出现在 TUI 的 `/` 菜单中并带子命令补全(指令发现要求 `dsh-tui-command-trees` 行——随附的 dsh-tui 组合包自带)。
|
|
80
|
+
|
|
81
|
+
在 **web** 端,同样的会话级模型控制由会话头部的 **Advisor 动作**承载(要求 dsh web 构建的 shell 声明 `conversation.session.header.actions` 插槽——dsh ≥ 0.1.7-rc.1)。该动作绑定在它所在的会话上:显示生效的评审 pair、其来源(`session override` / `global default`)与 live-session 生存期;**Pin this model** 为该会话钉住 provider + model,**Use global default** 去除钉住(即 reset 路径)。它只通过插件会话端点(`/api/advisor/getSession` + `/api/advisor/setSessionModel`)写入——与 `/advisor model` 同一控制器、同一校验与栅栏,从不写持久化配置——并且当会话控制面不可用时,绝不回退到全局配置写通道。控件在打开时刷新(打开期间断连/聚焦也会刷新);没有后台轮询。插件页上的全局卡片保持仅全局。
|
|
73
82
|
|
|
74
83
|
## 能力一览
|
|
75
84
|
|
|
76
|
-
- **每个会话一个独立评审者**:独立的模型调用观察主 transcript 并评审每个 stepped 主 turn;advisor 消息被排除在此后的 delta 之外,因此 advisor
|
|
85
|
+
- **每个会话一个独立评审者**:独立的模型调用观察主 transcript 并评审每个 stepped 主 turn;advisor 消息被排除在此后的 delta 之外,因此 advisor 不会读回自己的建议。自审排除同时识别 advisor 当前的 producer kind(`advisor`)与仍可打开日志中可能出现的两种历史形状:史前直接 `{ kind: 'advisor' }` 的 note,以及 0.1.6 时代的 note 经 V3→V4 内存迁移后的形状(`kind: 'plugin:advisor'`)——身份迁移不会孤儿化任何一代已持久化的 note。
|
|
77
86
|
- **按严重度排序的建议 + inject/steer 语义**:每次评审至多发出一条 note——**nit**(轻微的样式、清晰度或质量建议;经非唤醒的 `agent.inject` 送达,在下一个 pre-step 边界消费)、**concern**(继续之前值得权衡的重大风险或明显更优的方向;经唤醒的 `agent.steer` 送达,受 `immuneTurns` 冷却约束)、**blocker**(继续下去明显是在浪费工作——与显式用户指令矛盾、原地打转、根本性不可行;经 `agent.steer` 送达)。送达的消息携带 `[advisor:{severity}]` 前缀且为自我描述的 advisory 内容:
|
|
78
87
|
|
|
79
88
|
```
|
|
80
89
|
[advisor:concern] extract the helper into a module and unit-test it
|
|
81
90
|
```
|
|
82
91
|
|
|
83
|
-
- **显式模型门禁**:`enabled` 默认关闭;`enabled: true` 而缺少 `provider` + `model` 时绝不发起模型调用——状态报告 disabled-with-reason
|
|
92
|
+
- **显式模型门禁**:`enabled` 默认关闭;`enabled: true` 而缺少 `provider` + `model` 时绝不发起模型调用——状态报告 disabled-with-reason。门禁在会话解析**之后**作用于*有效*路由:完整的会话级覆盖对可为其会话满足门禁;非法的全局配置不可被绕过。未知配置键会被拒绝。
|
|
84
93
|
- **零工具的最小启动**:评审者只是一个独立的模型调用——无 advisor tools,除了 advisory 消息之外它无法对会话做任何事。
|
|
85
94
|
- **不卡主循环的失败策略**:失败或 quota 耗尽的 advisor 只会丢弃自己有界的 backlog——永远不会卡住或污染主循环。
|
|
86
|
-
- **会话级控制**:`/advisor on|off|status|config`
|
|
95
|
+
- **会话级控制**:`/advisor on|off|status|config|model` 按会话工作;开关与会话级模型钉住都是临时的 override,从不修改持久化配置——`/advisor config` 始终报告全局默认值。在 web 端,会话头部的 **Advisor 动作**经由专属会话端点驱动同一个会话级钉住(见 [Verify](#verify))。
|
|
87
96
|
|
|
88
97
|

|
|
89
98
|
|
|
90
99
|
## 纯挂载(零 dsh 修改)
|
|
91
100
|
|
|
92
|
-
插件以**纯挂载**方式安装:bundle 插入 + 客户端卡片(web
|
|
101
|
+
插件以**纯挂载**方式安装:bundle 插入 + 客户端卡片(web「插件」页)+ 自有 gateway 通道(`/api/advisor/get|set` 承载全局配置,`/api/advisor/getSession|setSessionModel` 承载会话级模型面,由宿主 typertGateway 认领——与 dsh 内建 `goals` 服务同一机制,不受 settings 暴露白名单门控)+ `/advisor` 指令——无 dsh 补丁、无 postinstall 步骤,dsh 升级永不需重打。
|
|
93
102
|
|
|
94
103
|
## 限制与路线图
|
|
95
104
|
|
|
@@ -111,7 +120,7 @@ MVP 有意放弃与 omp 的完整对等。已接受的差距(在 harness 迭
|
|
|
111
120
|
| 文档 | 内容 |
|
|
112
121
|
|---|---|
|
|
113
122
|
| [docs/install.zh.md](docs/install.zh.md) | profile 安装(web + dsh-tui)/ registry / git / tarball / 本地目录变体 / web Settings 暴露 / 卸载 / `--dump-config` 验证 |
|
|
114
|
-
| [docs/configuration.md](docs/configuration.md) |
|
|
123
|
+
| [docs/configuration.md](docs/configuration.md) | advisor 配置全字段:键与默认值、显式模型门禁(S4)、配置面(web 卡片 / TUI `/settings` / 补丁层)、示例 YAML、live 重应用行为 |
|
|
115
124
|
| [docs/consumer-api.md](docs/consumer-api.md) | 开发者消费契约:包根库 API、`dsh-advisor/client` 入口、`/advisor` 指令面、导出清单、生命周期 |
|
|
116
125
|
| [docs/verification.md](docs/verification.md) | 验证记录:测试矩阵(16 文件 / 319 用例)、typecheck/build、CI 契约、真实环境步骤 |
|
|
117
126
|
| [docs/release.md](docs/release.md) | 发布流程:PR 驱动的 Release prep + Release 工作流、OIDC trusted publishing、版本策略、回滚 |
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Advisor settings card (plan dsh-advisor-plugin-config-card-ux, task 1): the
|
|
3
|
-
* card registered into the
|
|
4
|
-
*
|
|
3
|
+
* card registered into the Plugins page's `plugins.bundle.config` keyed slot
|
|
4
|
+
* (key `dsh-advisor` — the bundle's package name the page dispatches). It keeps
|
|
5
5
|
* the n5 gateway channel — the store
|
|
6
6
|
* reads/writes the advisor config through `/api/advisor/get` +
|
|
7
7
|
* `/api/advisor/set` (KD-G3) — while the card chrome is rebuilt to replicate
|
|
8
8
|
* the upstream `PluginCard` contract (self-drawn: the upstream client value
|
|
9
9
|
* face exports no reusable card). The chrome: a collapsible box whose header
|
|
10
10
|
* is a button stacking the plugin name over its description, with a dirty
|
|
11
|
-
* "unsaved" pill and a rotating chevron (`
|
|
12
|
-
* ui-primitives
|
|
11
|
+
* "unsaved" pill and a rotating chevron (`IconChevronDownOutlineRegular` from
|
|
12
|
+
* ui-primitives — 0.1.7-rc.1 moved the rendered size out of the icon name
|
|
13
|
+
* into the `size` prop; the chevron's drawn size is still 14),
|
|
14
|
+
* `aria-expanded`/`aria-label` like the upstream header; a
|
|
13
15
|
* divider under the header; then the form content; then a footer with the
|
|
14
16
|
* failed message + Discard/Save carrying the upstream disabled semantics —
|
|
15
17
|
* save = `!dirty || invalid || saving`, discard = `!dirty || saving` (KD-U1,
|
|
@@ -77,18 +79,20 @@ export interface AdvisorCardInjected {
|
|
|
77
79
|
};
|
|
78
80
|
}
|
|
79
81
|
/**
|
|
80
|
-
* Props the renderer binds for the card: the `
|
|
81
|
-
* share (
|
|
82
|
-
*
|
|
83
|
-
*
|
|
82
|
+
* Props the renderer binds for the card: the `plugins.bundle.config` runtime
|
|
83
|
+
* share (the owner passes the `view` the page asks for — this seat is
|
|
84
|
+
* `page`-only, so the self-chromed card needs no branch for it), the
|
|
85
|
+
* framework-synthesized `t` seat for the declared `settings.advisor` namespace
|
|
86
|
+
* (KD-1 — `t` is NOT part of the inject face), and the registrant's business
|
|
87
|
+
* face.
|
|
84
88
|
*/
|
|
85
|
-
export type AdvisorCardProps = PropsRuntime<'
|
|
89
|
+
export type AdvisorCardProps = PropsRuntime<'plugins.bundle.config'> & PropsLocale<'settings.advisor'> & InjectFace<AdvisorCardInjected>;
|
|
86
90
|
/**
|
|
87
|
-
* Render the advisor card inside
|
|
88
|
-
* upstream PluginCard chrome (KD-U1): a
|
|
89
|
-
* button (name over description, dirty pill,
|
|
90
|
-
* when open, a divided body holding the readOnly
|
|
91
|
-
* footer (failed message + Discard/Save).
|
|
91
|
+
* Render the advisor card inside its bundle's configuration section on the
|
|
92
|
+
* Plugins page, replicating the upstream PluginCard chrome (KD-U1): a
|
|
93
|
+
* collapsible block with a header button (name over description, dirty pill,
|
|
94
|
+
* rotating chevron, aria) and, when open, a divided body holding the readOnly
|
|
95
|
+
* notice, the form, and the footer (failed message + Discard/Save).
|
|
92
96
|
* @param props - slot-delivered injected dependencies and the synthesized t seat.
|
|
93
97
|
* @returns the card.
|
|
94
98
|
*/
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor session header action (B2 — issue #88 web session control): the
|
|
3
|
+
* entry registered into the shell-declared `conversation.session.header.actions`
|
|
4
|
+
* list slot (title-adjacent Session actions — NOT the singleton
|
|
5
|
+
* primary-model slot, NOT the root plugin card; the global card stays
|
|
6
|
+
* global-only). The slot is session-scoped, so the framework resolves the
|
|
7
|
+
* bound SessionId into the inject factory (src/client/index.ts), which builds
|
|
8
|
+
* ONE {@link AdvisorSessionModelController} per session scope binding — the
|
|
9
|
+
* renderer memoizes that face per (entry × session binding), so the instance
|
|
10
|
+
* lives and dies with the binding and every fetch/write carries its own
|
|
11
|
+
* sessionId (a late response for an old binding can never render another
|
|
12
|
+
* session's state).
|
|
13
|
+
*
|
|
14
|
+
* The control shows the authoritative session snapshot — the effective
|
|
15
|
+
* reviewer pair, its source (`session`/`global`), the live-session lifetime,
|
|
16
|
+
* the effective switch, and the S4 gate reason when blocked — and supports
|
|
17
|
+
* set (provider + model, staged through the shared provider directory) and
|
|
18
|
+
* **Use global default** (reset). It rides ONLY the plugin session endpoints
|
|
19
|
+
* (`/api/advisor/getSession` + `/api/advisor/setSessionModel`); when the
|
|
20
|
+
* surface is unavailable the menu renders a notice and offers NO writes — it
|
|
21
|
+
* never falls back to the global `advisor/set` channel.
|
|
22
|
+
*
|
|
23
|
+
* Fetch discipline: fetch on menu open, on binding change (a new binding gets
|
|
24
|
+
* a fresh controller whose first open fetches), and on refresh signals while
|
|
25
|
+
* open (connection reset / window focus — the epoch store bumps, the watcher
|
|
26
|
+
* refetches). Every response settles through the controller's request fence,
|
|
27
|
+
* so a superseded (stale) response is discarded wholesale. NO push-event
|
|
28
|
+
* contract, NO polling: an open menu is a refreshable snapshot, and the
|
|
29
|
+
* closed trigger is NEUTRAL — the plugin name only, never a model label
|
|
30
|
+
* falsely claiming continuous synchronization.
|
|
31
|
+
*/
|
|
32
|
+
import { type ReactNode } from 'react';
|
|
33
|
+
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
34
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
35
|
+
import type { AdvisorSessionMenuState, AdvisorSessionModelController, AdvisorSettingsState, AdvisorSettingsStore } from './advisor-store.ts';
|
|
36
|
+
/**
|
|
37
|
+
* Injected dependencies of {@link AdvisorSessionAction} (slot `inject`,
|
|
38
|
+
* built per session binding by the registration's inject factory). The
|
|
39
|
+
* `hooks` compartment carries the bare snapshot sources; the renderer binds
|
|
40
|
+
* each as a `use<Name>` selector hook the component consumes.
|
|
41
|
+
*/
|
|
42
|
+
export interface AdvisorSessionActionInjected {
|
|
43
|
+
/** The session this occurrence is bound to (framework-resolved). */
|
|
44
|
+
readonly sessionId: string;
|
|
45
|
+
/** The per-session session-model controller (one per binding). */
|
|
46
|
+
readonly controller: AdvisorSessionModelController;
|
|
47
|
+
/** The shared provider/model directory (READ-only reuse of the card's store). */
|
|
48
|
+
readonly directory: AdvisorSettingsStore;
|
|
49
|
+
/** Bare snapshot sources the renderer binds as selector hooks. */
|
|
50
|
+
readonly hooks: {
|
|
51
|
+
/** The per-session menu snapshot. */
|
|
52
|
+
readonly snapshot: SnapshotStore<AdvisorSessionMenuState>;
|
|
53
|
+
/** Refresh-signal epoch (bumped on connection reset / window focus). */
|
|
54
|
+
readonly refreshSignal: SnapshotStore<{
|
|
55
|
+
epoch: number;
|
|
56
|
+
}>;
|
|
57
|
+
/** The shared provider/model directory state. */
|
|
58
|
+
readonly directory: SnapshotStore<AdvisorSettingsState>;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Props the renderer binds for the action: the session-scoped runtime share
|
|
63
|
+
* (the slot's owner is a marker — no owner-specific values), the
|
|
64
|
+
* framework-synthesized `t` seat for the declared `settings.advisor`
|
|
65
|
+
* namespace, and the registrant's per-binding business face.
|
|
66
|
+
*/
|
|
67
|
+
export type AdvisorSessionActionProps = PropsRuntime<'conversation.session.header.actions'> & PropsLocale<'settings.advisor'> & InjectFace<AdvisorSessionActionInjected>;
|
|
68
|
+
/**
|
|
69
|
+
* Render the session header's Advisor action: a neutral trigger plus, when
|
|
70
|
+
* open, a popover panel holding the refreshable snapshot and the pin/reset
|
|
71
|
+
* controls.
|
|
72
|
+
* @param props - slot-delivered injected dependencies and the synthesized t seat.
|
|
73
|
+
* @returns the action.
|
|
74
|
+
*/
|
|
75
|
+
export declare function AdvisorSessionAction(props: AdvisorSessionActionProps): ReactNode;
|
|
@@ -347,3 +347,134 @@ export declare class AdvisorSettingsStore {
|
|
|
347
347
|
* @param controller - the card store.
|
|
348
348
|
*/
|
|
349
349
|
export declare function refreshIfLoaded(controller: AdvisorSettingsStore): void;
|
|
350
|
+
/**
|
|
351
|
+
* The wire `snapshot` value of `/api/advisor/getSession` and of a successful
|
|
352
|
+
* `/api/advisor/setSessionModel` — client mirror of the node-side
|
|
353
|
+
* `AdvisorSessionSnapshotWire` (src/gateway.ts). Kept as a local structural
|
|
354
|
+
* type because the client bundle may not value-import the node-side module;
|
|
355
|
+
* the wire normalization omits absent keys (modelOverride / modelSource /
|
|
356
|
+
* effectiveModel / disabledReason are simply missing from the JSON).
|
|
357
|
+
*/
|
|
358
|
+
export interface AdvisorSessionSnapshotView {
|
|
359
|
+
/** The session the snapshot describes (echoes the request's binding). */
|
|
360
|
+
sessionId: string;
|
|
361
|
+
/** Effective switch for this session (session override ?? global). */
|
|
362
|
+
enabled: boolean;
|
|
363
|
+
/** Live-session lifetime marker — the snapshot is never durable. */
|
|
364
|
+
lifetime: 'live-session';
|
|
365
|
+
/** The session's pinned atomic pair; absent while it inherits. */
|
|
366
|
+
modelOverride?: {
|
|
367
|
+
provider: string;
|
|
368
|
+
model: string;
|
|
369
|
+
};
|
|
370
|
+
/** Where the effective route comes from; present iff a pair exists. */
|
|
371
|
+
modelSource?: 'session' | 'global';
|
|
372
|
+
/** The effective route; absent when neither level has a complete pair. */
|
|
373
|
+
effectiveModel?: {
|
|
374
|
+
provider: string;
|
|
375
|
+
model: string;
|
|
376
|
+
};
|
|
377
|
+
/** Present iff the S4 explicit gate blocks model calls. */
|
|
378
|
+
disabledReason?: string;
|
|
379
|
+
}
|
|
380
|
+
/** One `setSessionModel` selection on the wire: an atomic pair, or null (= reset). */
|
|
381
|
+
export type AdvisorSessionSelection = {
|
|
382
|
+
readonly provider: string;
|
|
383
|
+
readonly model: string;
|
|
384
|
+
} | null;
|
|
385
|
+
/**
|
|
386
|
+
* The RPC result union of the session endpoints: a snapshot, or a
|
|
387
|
+
* plugin-domain tagged error carried in the returned data (never a thrown
|
|
388
|
+
* coded failure — the dsh failure vocabulary stays frozen).
|
|
389
|
+
*/
|
|
390
|
+
export interface AdvisorSessionRpcPayload {
|
|
391
|
+
snapshot?: AdvisorSessionSnapshotView;
|
|
392
|
+
error?: {
|
|
393
|
+
tag: string;
|
|
394
|
+
message: string;
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/** The session header action's menu snapshot. */
|
|
398
|
+
export interface AdvisorSessionMenuState {
|
|
399
|
+
/** idle → loading (first fetch) → ready; refreshes keep `snapshot` visible. */
|
|
400
|
+
phase: 'idle' | 'loading' | 'ready';
|
|
401
|
+
/** The authoritative snapshot; null until the first successful load. */
|
|
402
|
+
snapshot: AdvisorSessionSnapshotView | null;
|
|
403
|
+
/** Last failure text for display (null when healthy). */
|
|
404
|
+
error: string | null;
|
|
405
|
+
/**
|
|
406
|
+
* Latch: the session control surface is unavailable (no elected owner on
|
|
407
|
+
* the host, the target session is unknown/disposed, or the channel failed).
|
|
408
|
+
* An unavailable menu offers NO writes — it never falls back to the global
|
|
409
|
+
* `advisor/set` channel. Recovered by a later successful refresh.
|
|
410
|
+
*/
|
|
411
|
+
unavailable: boolean;
|
|
412
|
+
/** A set/reset write is in flight. */
|
|
413
|
+
pending: boolean;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Per-session controller for the session header's Advisor action (one
|
|
417
|
+
* instance per session — the slot renderer memoizes the inject face per
|
|
418
|
+
* entry × session scope binding, so the instance lives and dies with the
|
|
419
|
+
* binding). Every call sends ITS OWN `sessionId` and commits only into its
|
|
420
|
+
* own store: a late response for an old binding can never mutate another
|
|
421
|
+
* session's state (the structural binding fence). Ordering within one session
|
|
422
|
+
* is fenced by a monotonic `requestSeq` — a newer open/refresh/write
|
|
423
|
+
* supersedes an unresolved older op, whose settle is discarded wholesale
|
|
424
|
+
* (the same generation-fence shape the host controller uses).
|
|
425
|
+
*/
|
|
426
|
+
export declare class AdvisorSessionModelController {
|
|
427
|
+
private readonly rpc;
|
|
428
|
+
readonly sessionId: string;
|
|
429
|
+
/** The snapshot the menu renders from (uSES-safe store). */
|
|
430
|
+
readonly store: SnapshotStore<AdvisorSessionMenuState>;
|
|
431
|
+
/** Fence token: a newer op makes every older settle stale. */
|
|
432
|
+
private requestSeq;
|
|
433
|
+
/** Last consumed refresh-signal epoch (reconnect / focus bumps). */
|
|
434
|
+
private lastSignal;
|
|
435
|
+
constructor(sessionId: string, rpc: ClientConnectionRpc);
|
|
436
|
+
/**
|
|
437
|
+
* Record the refresh-signal epoch and report whether it is NEW. The open
|
|
438
|
+
* handler always refetches and merely marks the signal current; the render
|
|
439
|
+
* watcher calls this while open and refetches only on a true return (a
|
|
440
|
+
* reconnect/focus bump). Idempotent per epoch, so a re-render never
|
|
441
|
+
* double-fetches.
|
|
442
|
+
*/
|
|
443
|
+
takeSignal(epoch: number): boolean;
|
|
444
|
+
/**
|
|
445
|
+
* Fetch the authoritative snapshot (`/api/advisor/getSession`). Called on
|
|
446
|
+
* menu open and on every refresh signal while open. A stale settle (a newer
|
|
447
|
+
* op superseded this fetch) touches nothing. An `advisor/unavailable` /
|
|
448
|
+
* `advisor/session-unknown` tag or a transport failure latches
|
|
449
|
+
* `unavailable` (writes stay off until a later successful refresh); other
|
|
450
|
+
* tagged outcomes leave the surface usable with the error shown.
|
|
451
|
+
*/
|
|
452
|
+
refresh(): Promise<void>;
|
|
453
|
+
/**
|
|
454
|
+
* Pin the atomic `{provider, model}` pair for THIS session
|
|
455
|
+
* (`/api/advisor/setSessionModel`, selection = the pair). Refuses outright
|
|
456
|
+
* while `unavailable` (store-side defense-in-depth — an unavailable menu
|
|
457
|
+
* must never issue a write, and must never fall back to the global
|
|
458
|
+
* `advisor/set` channel). The host validates the pair through the same
|
|
459
|
+
* rules as the `/advisor model set` command face.
|
|
460
|
+
*/
|
|
461
|
+
setSessionModel(provider: string, model: string): Promise<void>;
|
|
462
|
+
/**
|
|
463
|
+
* Drop the session pin and re-inherit the CURRENT global defaults
|
|
464
|
+
* (`selection: null`). Never touches the enable override; reset to a
|
|
465
|
+
* missing global pair still succeeds — the returned snapshot reports the
|
|
466
|
+
* gate-blocked/no-call state, which the menu renders truthfully.
|
|
467
|
+
*/
|
|
468
|
+
resetSessionModel(): Promise<void>;
|
|
469
|
+
/** Shared write path (both arms ride the same endpoint + fence + outcome mapping). */
|
|
470
|
+
private write;
|
|
471
|
+
/**
|
|
472
|
+
* Commit one settled outcome. Guards (seq checked by the callers before
|
|
473
|
+
* reaching here): tagged `advisor/unavailable` / `advisor/session-unknown`
|
|
474
|
+
* and transport failures latch `unavailable` (no writes offered, last good
|
|
475
|
+
* snapshot kept for context); other tagged outcomes keep the surface usable
|
|
476
|
+
* and surface the message (the host left the previous selection untouched);
|
|
477
|
+
* a snapshot commits as the new authoritative state.
|
|
478
|
+
*/
|
|
479
|
+
private applyOutcome;
|
|
480
|
+
}
|
package/lib/client/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Advisor settings plugin, browser half. Registers the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
2
|
+
* Advisor settings plugin, browser half. Registers the Advisor card into the
|
|
3
|
+
* shell-declared `plugins.bundle.config` keyed slot (the Plugins page's
|
|
4
|
+
* per-bundle configuration seat — key `dsh-advisor`, the bundle's package name
|
|
5
|
+
* the page dispatches, rendered on the bundle's own page between its
|
|
6
|
+
* description and its rows) and, since B2, an Advisor action into the
|
|
7
|
+
* shell-declared `conversation.session.header.actions` list slot (the
|
|
8
|
+
* per-session reviewer-model control, bound to the slot parent's SessionId —
|
|
9
|
+
* the global card stays global-only). The card's store joins the settings
|
|
10
|
+
* namespaces and the provider directory through the connection wire, and
|
|
11
|
+
* keeps fresh on pushed invalidations. Export discipline: the client half
|
|
12
|
+
* value-imports ONLY the frozen platform module table (CLIENT_EXTERNALS:
|
|
13
|
+
* react / `@deepseek-ai/cordis` / ui-slots / ui-primitives / the documented
|
|
11
14
|
* `@deepseek-ai/dsh-client-store` exemption); every other
|
|
12
15
|
* `@deepseek-ai/*` import is type-only (erased at build) — values arrive via
|
|
13
16
|
* cordis injection (`ctx.get('connection')`, slot inject faces, the
|
|
@@ -16,8 +19,9 @@
|
|
|
16
19
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
17
20
|
import { type AdvisorKey } from './locales.ts';
|
|
18
21
|
export type { AdvisorCardInjected, AdvisorCardProps } from './advisor-card.tsx';
|
|
22
|
+
export type { AdvisorSessionActionInjected, AdvisorSessionActionProps } from './advisor-session.tsx';
|
|
19
23
|
export type { AdvisorKey } from './locales.ts';
|
|
20
|
-
export type { AdvisorDraft, AdvisorSettingsState, AdvisorSettingsStore, ApplyFailure, ApplyState, ModelOption, ModelsEmptyReason, ProviderOption, } from './advisor-store.ts';
|
|
24
|
+
export type { AdvisorDraft, AdvisorSessionMenuState, AdvisorSessionModelController, AdvisorSessionRpcPayload, AdvisorSessionSelection, AdvisorSessionSnapshotView, AdvisorSettingsState, AdvisorSettingsStore, ApplyFailure, ApplyState, ModelOption, ModelsEmptyReason, ProviderOption, } from './advisor-store.ts';
|
|
21
25
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
22
26
|
interface LocaleNamespaceMap {
|
|
23
27
|
/** The Advisor settings card copy. */
|
|
@@ -27,8 +31,9 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
27
31
|
export { refreshIfLoaded } from './advisor-store.ts';
|
|
28
32
|
/**
|
|
29
33
|
* Required services (cordis fiber inject). The target slot is declared by
|
|
30
|
-
* ui-plugin-
|
|
31
|
-
* NOT constrained; registration depends on the
|
|
34
|
+
* ui-plugin-manager's apply (its `plugins` main-panel entry), whose activation
|
|
35
|
+
* order relative to this one is NOT constrained; registration depends on the
|
|
36
|
+
* slot through `slots.inject()`.
|
|
32
37
|
*
|
|
33
38
|
* rc.1 dotted-namespace contract: each client Remote namespace is a
|
|
34
39
|
* child-fiber service named `remote.<ns>` (upstream `remoteServiceKey`), and
|
|
@@ -41,7 +46,7 @@ export { refreshIfLoaded } from './advisor-store.ts';
|
|
|
41
46
|
*/
|
|
42
47
|
export declare const inject: string[];
|
|
43
48
|
/**
|
|
44
|
-
* Register the Advisor card once the `
|
|
49
|
+
* Register the Advisor card once the `plugins.bundle.config` declaration is on
|
|
45
50
|
* the ledger, wire its store to the connection, and keep it fresh on every
|
|
46
51
|
* pushed invalidation (settings or provider topology).
|
|
47
52
|
* @param ctx - client root context.
|