dsh-advisor-group 0.1.3 → 0.1.5
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.en.md +240 -108
- package/README.md +276 -147
- package/lib/client.js +1517 -705
- package/lib/index.d.mts +96 -1
- package/lib/index.mjs +4391 -463
- package/package.json +103 -100
package/README.en.md
CHANGED
|
@@ -1,144 +1,276 @@
|
|
|
1
1
|
# dsh-advisor-group
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Let one [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) session **borrow wisdom from other models** and **reuse the memory of other sessions**.
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
[中文](README.md) · [Installation](#compatibility-and-installation) · [Quick start](#quick-start) · [Core features](#core-features) · [Configuration](#configuration-reference) · [Development](#development)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/dsh-advisor-group)
|
|
8
|
+
[](https://github.com/topics/dsh-plugin)
|
|
9
|
+
[](LICENSE)
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
| Capability | What it helps you do |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| **Multi-model consultation (Advisor Group)** | For professional, high-risk, or uncertain questions, let expert advisors answer in sequence before a driver model synthesizes their conclusions. |
|
|
14
|
+
| **Cross-session collaboration (global swarm)** | Ask another existing session and reuse the code it read, the investigation it completed, and the decisions it settled instead of starting over. Beyond this session's subagent capability, it lets the model write across projects. |
|
|
15
|
+
| **Advisor Corps role cards** | Assign a name and duty to a session. You can then say “ask 小明” without remembering its title or sessionId. |
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
## Compatibility and installation
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
| Item | Details |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| DSH | The current development baseline is `0.2.1-rc.3`; the declared peer range is `>=0.1.7-rc.2 <0.3.0` |
|
|
22
|
+
| Node.js | Required for source builds: `^22.19.0 || >=24.0.0` |
|
|
23
|
+
| Applications | DSH Web and the desktop app, sharing the same client bundle |
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
- **Zero-config driver model** — the driver formulation of deep follow-ups reuses the current agent's provider/model, so no extra API key or model setup is needed; it falls back to `discussion.driverModel` when the session header is unavailable.
|
|
17
|
-
- **Three ways to activate** — `@顾问群` mention (force-start), same question repeated 3 times without resolution, or main-model self-assessed confidence below the threshold.
|
|
18
|
-
- **Optional Jev semantic pre-classification (off by default)** — when `trigger.jev.enabled` is on, a configured Jev model judges non-force-started consultations first (escalation / high-risk / web-search fit, thresholds under `trigger.jev.*`); if Jev is unavailable the local rules-based classifier still decides. With `trigger.jev.useEnglishState`, the judge reads the caller-supplied English gist (`questionEn`) instead of the Chinese question — display and session records stay Chinese.
|
|
19
|
-
- **Retro CRT chat cards** — green/amber/blue CRT themes, scanlines, LIVE/DONE headers, auto-expanded thinking panel with auto-scroll; advisor Markdown rendered with a link-protocol whitelist (headings, lists, code, quotes, links, tables).
|
|
20
|
-
- **Ask another session (`ask_session`)** — hand one question to another live session — by exact session id, exact title, or a natural partial name such as the workspace name (`极简遥控器`) — and read what that session said between the delivery receipt and its next whole-session idle. The result is explicitly **not** a one-to-one reply, and the asking side renders the exchange in the same retro chat-group card. Guards: hop ≤ 2, no self/subagent target, one wait per session, a 32 KB payload budget; the target's turn is never cancelled.
|
|
21
|
-
- **Provider presets (11 platforms · 26 presets)** — DeepSeek, Moonshot Kimi, Kimi Code, Aliyun Bailian, Zhipu AI, OpenAI, Claude, Gemini, SiliconFlow, AIHubMix, OpenRouter (OpenAI/Anthropic-compatible variants included).
|
|
22
|
-
- **Security-minded by design** — API keys use official `SecretField` semantics (never returned to the browser; `apiKeysByProvider` key history is server-side only), SSRF-guarded diagnostics (https-only / loopback, no IP literals, no redirects), per-boot token auth on `/advisor-group/*` routes, and an atomic **configurable daily consultation cap** (default 50, can be disabled) persisted across restarts.
|
|
23
|
-
- **Runtime toggle** — `toggle_advisor_group` enables/disables the plugin and persists the flag to settings.
|
|
25
|
+
Earlier versions inside the peer range have not all been re-verified on a live host. Cross-session features also require the host to provide `sessionController`; the related tools report an explicit error when it is unavailable, while multi-model consultation remains unaffected.
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
### Install from npm
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|---|---|
|
|
29
|
-
| Harness | DeepSeek Harness `0.1.7-rc.2` → `0.2.x` (incl. `0.2.0-rc.1`) |
|
|
30
|
-
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
31
|
-
| Platforms | DSH Web and the desktop app (same client bundle) + headless host logic |
|
|
32
|
-
|
|
33
|
-
## 📦 Installation
|
|
29
|
+
For DSH Web:
|
|
34
30
|
|
|
35
31
|
```sh
|
|
36
|
-
# 1. Install the plugin (one package, everything included)
|
|
37
32
|
dsh plugin --profile web add dsh-advisor-group
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Restart DSH Web the way you normally do, then hard-refresh the browser (`Ctrl+Shift+R`).
|
|
36
|
+
|
|
37
|
+
**Desktop app**: open **Plugins → Add plugin** inside the app and enter `dsh-advisor-group`. The desktop app owns its profile; `dsh plugin --profile desktop …` is refused by design, not because your permissions are insufficient.
|
|
38
|
+
|
|
39
|
+
### Install from source (main)
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
git clone https://github.com/xingzhen199186/dsh-advisor-group.git
|
|
43
|
+
cd dsh-advisor-group
|
|
44
|
+
npm install --legacy-peer-deps --no-audit --no-fund
|
|
45
|
+
npm run build
|
|
46
|
+
npm pack
|
|
47
|
+
|
|
48
|
+
# Use the actual filename printed by npm pack.
|
|
49
|
+
# The current package.json version is 0.1.5, producing:
|
|
50
|
+
dsh plugin --profile web add ./dsh-advisor-group-0.1.5.tgz
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For a source-built desktop installation, enter the `.tgz` file's absolute path under **Plugins → Add plugin**. Restart the corresponding DSH application after installation.
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
### Path 1: consult several models
|
|
58
|
+
|
|
59
|
+
1. Open **Settings → Plugins → 顾问群 (Advisor Group)**.
|
|
60
|
+
2. Add at least one advisor and select its provider route and model. Use **获取模型列表** (Fetch model list) to retrieve the route's model catalogue.
|
|
61
|
+
3. Prefix your question with `@顾问群` and include the necessary background. For example:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
@顾问群 Review this plugin's cross-session collaboration design.
|
|
65
|
+
Background: DSH Web and desktop share one codebase. The design must never deliver automatically or guess a target session.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`@顾问群` forces a consultation. The main model can also escalate ordinary professional questions under its routing rules, including when the same unresolved question appears three times or its reported confidence falls below the threshold.
|
|
69
|
+
|
|
70
|
+
<img width="720" alt="Advisor Group settings page: sections for enable and daily quota, advisors, consultation behavior, triggers and classification, global swarm, and advanced settings, all collapsed by default" src="https://raw.githubusercontent.com/xingzhen199186/dsh-advisor-group/main/docs/images/advisor-group-settings.png" />
|
|
71
|
+
|
|
72
|
+
The settings page follows the setup path, with every section folded by default; each open section has its own save row.
|
|
73
|
+
|
|
74
|
+
### Path 2: ask another session by role name
|
|
75
|
+
|
|
76
|
+
1. Open the **顾问团 (Advisor Corps)** tab in any conversation. If the tab bar runs out of space, it may appear under the **…** menu.
|
|
77
|
+
2. Fill in **身份姓名** (Role name) and **主要负责** (Main responsibility) for the target session, then click **加入顾问团** (Add to Advisor Corps) or **保存** (Save). Alternatively, click **用主模型生成** (Generate with main model), review the suggestions, and save them individually or through **保存全部更改** (Save all changes).
|
|
78
|
+
3. Return to the conversation and ask naturally:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Ask 小明: what changed in the Advisor Corps role cards today?
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or ask several members at once:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
Ask 小明 and 阿龙: review this design for desktop and Web omissions respectively, then combine both conclusions.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Generated cards only fill drafts; **they take effect only after you save them, and existing cards are never overwritten**. Session titles, working-directory names, and sessionIds remain valid target spellings.
|
|
91
|
+
|
|
92
|
+
## Core features
|
|
93
|
+
|
|
94
|
+
### Multi-model consultation: deepen the discussion automatically
|
|
95
|
+
|
|
96
|
+
One `ask_advisors` call runs the whole consultation:
|
|
38
97
|
|
|
39
|
-
|
|
40
|
-
|
|
98
|
+
```text
|
|
99
|
+
Original question
|
|
100
|
+
→ Round 1: Advisor A → Advisor B (sees A) → Advisor C (sees A and B)
|
|
101
|
+
→ Later rounds: a deeper driver question → the same advisor relay
|
|
102
|
+
→ A synthesis from the driver model
|
|
41
103
|
```
|
|
42
104
|
|
|
43
|
-
|
|
44
|
-
> ```sh
|
|
45
|
-
> npm install --legacy-peer-deps --no-audit --no-fund
|
|
46
|
-
> npm run build
|
|
47
|
-
> dsh plugin --profile web add ./dsh-advisor-group-<version>.tgz # after npm pack (version from package.json)
|
|
48
|
-
> ```
|
|
105
|
+
<img width="865" height="983" alt="An Advisor Group consultation card showing actions, thinking, tool calls, and the final response in step order" src="https://github.com/user-attachments/assets/dad2f2be-acf6-41d7-b61a-c11596e48408" />
|
|
49
106
|
|
|
50
|
-
|
|
107
|
+
- **Controlled rounds**: `maxRounds` ranges from 1 to 5 and defaults to 2. With `autoDeepen` disabled, later rounds repeat the original question; the final synthesis is still generated.
|
|
108
|
+
- **No separate driver route to configure**: the driver writes follow-ups and the synthesis through the current session's provider and model. It falls back to `discussion.driverModel` when that route cannot be read.
|
|
109
|
+
- **Advisors can use session tools**: the default scope is read-only. Calls appear in the card, and after at most four tool rounds the advisor must answer in text. Set the scope globally or override it per advisor.
|
|
110
|
+
- **A streaming card that preserves the process**: the green CRT card renders `📋 Action → 💭 Thinking → ⛭ Tool → 📄 Response`. Thinking and tool details start collapsed; the response starts expanded.
|
|
111
|
+
- **Resume from the checkpoint**: after a manual stop or host restart, **▶ 继续聊天** (Resume chat) completes only the missing advisors and rounds instead of asking completed advisors again.
|
|
112
|
+
- **Optional Jev pre-classification**: off by default. When enabled, Jev can judge whether advisors are needed, whether the request is high-risk, and whether web search is more appropriate. Failures fall back to the local rule-based classifier.
|
|
113
|
+
- **28 provider presets across 12 platforms**: DeepSeek, Moonshot Kimi, Kimi Code, Aliyun Bailian, Zhipu AI, OpenAI, Claude, Gemini, SiliconFlow, AIHubMix, OpenRouter, and OpenCode Go.
|
|
51
114
|
|
|
52
|
-
|
|
115
|
+
### Advisor Corps: give each session a durable identity
|
|
53
116
|
|
|
54
|
-
|
|
117
|
+
A session title describes a window, but it may not be a durable way to address that session. Advisor Corps binds a **name and duty** to the session id and stores it locally in `$DSH_HOME/storages/advisor-group/corps.json`; it never renames the session.
|
|
55
118
|
|
|
56
|
-
|
|
57
|
-
2. Go to **Settings → Plugins → Advisor Group**: configure your advisors (provider route + model; use *获取模型列表* to pull the authoritative model list) and tune `maxRounds`, thresholds, and the UI theme.
|
|
58
|
-
3. Just start a conversation:
|
|
59
|
-
- type `@顾问群` in your question to force a consultation, or
|
|
60
|
-
- ask a professional/uncertain question — the plugin escalates automatically when appropriate.
|
|
119
|
+
<img width="760" alt="Advisor Corps panel: one row per visible session, showing its role name, duty, copy-name action, and save controls" src="https://raw.githubusercontent.com/xingzhen199186/dsh-advisor-group/main/docs/images/advisor-corps-panel.png" />
|
|
61
120
|
|
|
62
|
-
|
|
121
|
+
- Names are globally unique and case-insensitive, with a 40-character limit. Duties can contain up to 200 characters.
|
|
122
|
+
- **Generate with main model** uses the model of the **currently open conversation**. Each pass proposes cards for at most 12 unassigned sessions, fills drafts only, and never saves automatically.
|
|
123
|
+
- Edit rows, copy role names, save in batch, or remove cards. Cards whose sessions are archived, excluded, outside every workspace, or no longer present appear under **未挂接** (Unlinked), where you can keep or delete them.
|
|
124
|
+
- `list_sessions` includes role names and duties. `ask_session` and `ask_sessions` accept an exact role name, which takes precedence over a session title with the same name.
|
|
63
125
|
|
|
64
|
-
|
|
126
|
+
### Cross-session collaboration: ask one session or a group
|
|
65
127
|
|
|
66
|
-
|
|
128
|
+
- **Single-session asks**: `ask_session` waits synchronously by default. With `detach: true`, it returns an `askId` immediately so you can read the result later through `ask_result`.
|
|
129
|
+
- **Batch asks**: `ask_sessions` sends one question to 1–8 explicit targets. `mode: 'all'` waits for every target; `mode: 'any'` returns when the first target settles while the others continue and write their own records.
|
|
130
|
+
- **Automatic answer copy-back**: `swarm.deliverBack` is enabled by default. Answers that finish as `done` are copied back into the asking session; timeouts and errors are not. A batch combines all completed answers into one copy-back message.
|
|
131
|
+
- **Traceable results**: every delivered target gets its own `askId`. An asynchronous record can be `waiting`, `done`, `timeout`, `error`, or `interrupted`; the last state means a host restart prevented the wait from completing.
|
|
132
|
+
- **No guessed targets**: when `ask_session` has no target, routing returns candidates without delivering anything. `ask_sessions` performs no routing; unresolved, ambiguous, or excluded targets are reported in its skipped list with reasons.
|
|
133
|
+
- **Explicit collaboration guards**: at most two relay hops; no self or subagent targets; one waiting `ask_session` per asking session; a 32,000-byte combined limit for question and context; and no cancellation of a target turn when the wait times out.
|
|
67
134
|
|
|
68
|
-
|
|
69
|
-
- **What you get back**: everything the target said between the **delivery receipt** and its next **whole-session idle** — "what that session said in that window", **not** a one-to-one reply to your message. On timeout (180 s by default, configurable) it returns what it already collected and does **not** interrupt the target.
|
|
70
|
-
- **What you see**: the asking side shows a chat-group card — first "已投递,等待对方回应…", then the target's answer bubble and the "📌 投递说明" note (which delivery channel was used and how the wait ended). A failed target lookup opens no card; the error stays in the tool row.
|
|
71
|
-
- **Guards**: hop ≤ 2 (no ping-pong relay), no self or subagent target, one concurrent wait per session, a 32 KB payload budget; the target's turn is **never** cancelled.
|
|
72
|
-
- **Cost**: one ordinary target turn, billed on the target session's own model; it does **not** count against the daily consultation quota.
|
|
135
|
+
> **What the returned text means**: the tool collects everything the target says between the **delivery receipt** and its next **whole-session idle**. It is not guaranteed to be a one-to-one answer to your question. The `status` field (`ok` / `partial` / `failed`) describes the reliability of that collection.
|
|
73
136
|
|
|
74
|
-
|
|
137
|
+
## Model tool reference
|
|
75
138
|
|
|
76
|
-
|
|
139
|
+
The main model calls these tools inside a conversation. **They are not slash commands, and you do not need to write tool arguments yourself.** Cross-session tools should be used only when you explicitly ask to contact another session or window.
|
|
140
|
+
|
|
141
|
+
| Tool | Purpose |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `ask_advisors` | Start a multi-model consultation, or append a round with `sessionId + followUp` |
|
|
144
|
+
| `ask_session` | Ask one existing session; supports waiting, detached delivery, and candidate routing |
|
|
145
|
+
| `ask_sessions` | Ask 1–8 explicit targets in a batch; supports `all` and `any` collection modes |
|
|
146
|
+
| `list_sessions` | Read session titles, directories, activity, and Advisor Corps names and duties without waking anyone |
|
|
147
|
+
| `ask_result` | Read one asynchronous result by `askId`, or list recent asks started by this session |
|
|
148
|
+
| `toggle_advisor_group` | Enable or disable multi-model consultation and persist the setting |
|
|
149
|
+
|
|
150
|
+
## Configuration reference
|
|
151
|
+
|
|
152
|
+
For everyday use, these are the settings you are most likely to adjust:
|
|
153
|
+
|
|
154
|
+
| Key | Default | When to adjust it |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| `discussion.maxRounds` | `2` | Lower it to reduce cost, or raise it up to 5 for a deeper discussion |
|
|
157
|
+
| `discussion.maxAdvisorsPerCall` | `3` | Control how many advisors join one consultation, from 1 to 10 |
|
|
158
|
+
| `discussion.advisorTools` | `'readonly'` | Use `'off'` to disable advisor tools; reserve `'all'` for fully trusted scenarios |
|
|
159
|
+
| `quota.enabled` / `quota.maxPerDay` | `true` / `50` | Set the daily new-consultation cap; counts continue when the cap is disabled |
|
|
160
|
+
| `swarm.defaultMode` | `'wait'` | Use `'detach'` to make cross-session asks asynchronous by default |
|
|
161
|
+
| `swarm.defaultWaitMs` | `180000` | Adjust the default wait ceiling, from 1000 to 600000 ms |
|
|
162
|
+
| `swarm.deliverBack` | `true` | Disable it to read completed answers only through `ask_result`, without automatic copy-back |
|
|
163
|
+
|
|
164
|
+
<details>
|
|
165
|
+
<summary><strong>Expand the complete configuration reference</strong></summary>
|
|
166
|
+
|
|
167
|
+
### Discussion and advisors
|
|
77
168
|
|
|
78
169
|
| Key | Type | Default | Description |
|
|
79
|
-
|
|
80
|
-
| `enabled` | boolean | `true` | Enable
|
|
81
|
-
| `discussion.maxRounds` | number | `2` | Total rounds
|
|
82
|
-
| `discussion.maxAdvisorsPerCall` | number | `3` |
|
|
83
|
-
| `discussion.autoDeepen` | boolean | `true` |
|
|
84
|
-
| `discussion.driverModel` | object | – | Fallback
|
|
85
|
-
| `discussion.advisorTimeoutMs` | number | `600000` | Per-advisor
|
|
86
|
-
| `discussion.driverTimeoutMs` | number | `600000` |
|
|
87
|
-
| `discussion.advisorTools` | string | `'readonly'` |
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
170
|
+
| --- | --- | --- | --- |
|
|
171
|
+
| `enabled` | boolean | `true` | Enable multi-model consultation |
|
|
172
|
+
| `discussion.maxRounds` | number | `2` | Total consultation rounds, 1–5 |
|
|
173
|
+
| `discussion.maxAdvisorsPerCall` | number | `3` | Maximum advisors in one consultation, 1–10 |
|
|
174
|
+
| `discussion.autoDeepen` | boolean | `true` | Generate a deeper driver question before later rounds; when off, repeat the original question and still synthesize a conclusion |
|
|
175
|
+
| `discussion.driverModel` | object | – | Fallback `{ provider, model }` when the current session route cannot be read |
|
|
176
|
+
| `discussion.advisorTimeoutMs` | number | `600000` | Per-advisor timeout, 1000–600000 ms |
|
|
177
|
+
| `discussion.driverTimeoutMs` | number | `600000` | Timeout for a follow-up or synthesis, 1000–1200000 ms |
|
|
178
|
+
| `discussion.advisorTools` | string | `'readonly'` | Default advisor tool scope: `readonly` / `all` / `off` |
|
|
179
|
+
| `advisors` | array | `[]` | Advisor list, including `provider`, `model`, `systemPrompt`, and optional `baseURL`, `apiKey`, `apiKeyEnv`, `protocol`, and related fields |
|
|
180
|
+
| `advisors[].tools` | string | – | Per-advisor tool scope; unset follows `discussion.advisorTools` |
|
|
181
|
+
| `advisors[].thinking` | string | – | `enabled` / `disabled`; unset follows the provider default |
|
|
182
|
+
| `advisors[].reasoningEffort` | string | – | `off` / `low` / `high` / `max`; unset follows the provider or model default |
|
|
183
|
+
| `advisors[].temperature` | number | – | Sampling temperature, 0–2 |
|
|
184
|
+
| `advisors[].maxTokens` | number | – | Token limit for one answer, at least 1 |
|
|
185
|
+
| `advisors[].authMode` | string | – | Anthropic direct-channel authentication header: `x-api-key` / `bearer` |
|
|
186
|
+
| `advisors[].avatar` | string | – | Short card avatar, using an emoji or ASCII text |
|
|
187
|
+
|
|
188
|
+
Advisor tool calling is supported only on direct OpenAI / Anthropic channels. The DSH built-in channel can reuse host credentials for ordinary responses, but it does not support this advisor tool loop.
|
|
189
|
+
|
|
190
|
+
### Triggers and Jev
|
|
191
|
+
|
|
192
|
+
| Key | Type | Default | Description |
|
|
193
|
+
| --- | --- | --- | --- |
|
|
194
|
+
| `trigger.requireClassifier` | boolean | `true` | Run pre-classification before a non-forced consultation |
|
|
195
|
+
| `trigger.allowWebFallback` | boolean | `true` | Return a no-consultation hint when the classifier recommends web search |
|
|
196
|
+
| `trigger.confidenceThreshold` | number | `0.6` | Allow escalation below this main-model confidence score, from 0 to 1 |
|
|
197
|
+
| `trigger.jev.enabled` | boolean | `false` | Use Jev for semantic pre-classification; failures fall back to local rules |
|
|
198
|
+
| `trigger.jev.provider` / `trigger.jev.model` | string | `'typesafe'` / `'jev-latest'` | Jev route and model; the route can also be `openrouter` |
|
|
199
|
+
| `trigger.jev.baseURL` | string | – | Optional custom Jev endpoint |
|
|
200
|
+
| `trigger.jev.apiKey` / `trigger.jev.apiKeyEnv` | string | – | Jev key or the environment variable containing it; key fields are treated as secrets |
|
|
201
|
+
| `trigger.jev.timeoutMs` | number | `10000` | Jev request timeout, 1000–60000 ms |
|
|
202
|
+
| `trigger.jev.confidenceThreshold` | number | `0.6` | Threshold for deciding that advisors are needed |
|
|
203
|
+
| `trigger.jev.highRiskThreshold` | number | follows the previous setting | High-risk threshold; unset follows `trigger.jev.confidenceThreshold` |
|
|
204
|
+
| `trigger.jev.useEnglishState` | boolean | `false` | Let Jev read the caller-provided English gist `questionEn`; cards and session records keep the original question |
|
|
205
|
+
|
|
206
|
+
### Global swarm
|
|
207
|
+
|
|
208
|
+
| Key | Type | Default | Description |
|
|
209
|
+
| --- | --- | --- | --- |
|
|
210
|
+
| `swarm.enabled` | boolean | `true` | Cross-session master switch; when off, all four cross-session tools refuse explicitly |
|
|
211
|
+
| `swarm.defaultMode` | string | `'wait'` | Default `ask_session` behavior: `wait` / `detach` |
|
|
212
|
+
| `swarm.defaultWaitMs` | number | `180000` | Default wait ceiling, 1000–600000 ms |
|
|
213
|
+
| `swarm.resultTtlHours` | number | `24` | How long asynchronous results are retained, 1–720 hours |
|
|
214
|
+
| `swarm.deliverBack` | boolean | `true` | Copy `done` answers back automatically; never auto-copy `timeout` / `error` |
|
|
215
|
+
| `swarm.rosterIncludeSubagents` | boolean | `false` | Show subagents in the roster; delivery tools still refuse subagent targets |
|
|
216
|
+
| `swarm.routingEnabled` | boolean | `true` | Suggest candidates when `ask_session` has no target; never deliver automatically |
|
|
217
|
+
| `swarm.routingTopN` | number | `3` | Number of candidates, 1–8 |
|
|
218
|
+
| `swarm.routingEngine` | string | `'local'` | `local` ordering or `jev` reranking of a closed candidate set; failures fall back to local |
|
|
219
|
+
| `swarm.routingAsk` | string | `'gated'` | Whether to suggest a cross-session ask: `off` / `gated` / `always`; a suggestion never delivers |
|
|
220
|
+
| `swarm.routingExclude` | string[] | `[]` | Sessions excluded from the swarm, its roster, and its candidates; direct asks are refused too |
|
|
221
|
+
|
|
222
|
+
### Legacy compatibility fields
|
|
223
|
+
|
|
224
|
+
`discussion.parallel` and `discussion.stopOnConsensus` are deprecated and retained only so stored configurations remain readable.
|
|
225
|
+
|
|
226
|
+
`ui.theme`, `ui.showTimestamps`, and `ui.autoExpand` are also legacy fields. The current client does not read them, so changing them has no effect on the card's appearance or expansion behavior. The current card uses a green CRT style; thinking and tool details start collapsed.
|
|
227
|
+
|
|
228
|
+
</details>
|
|
229
|
+
|
|
230
|
+
## Usage, quota, and cost
|
|
231
|
+
|
|
232
|
+
A consultation that completes `R` rounds with `N` advisors and no tool calls normally makes **`R × (N + 1)` model calls**: `R × N` advisor responses, `R - 1` deepening questions, and one final synthesis. With the default `R = 2` and three advisors actually participating, this produces 8 calls.
|
|
233
|
+
|
|
234
|
+
Actual usage also depends on these behaviors:
|
|
235
|
+
|
|
236
|
+
- Advisor tool loops add model calls. The driver and every advisor are billed through their respective routes.
|
|
237
|
+
- Generating role cards calls the current conversation's model. Jev classification or routing is also billed through its configured route when enabled.
|
|
238
|
+
- Cross-session asks do not consume the advisor-consultation quota, but they wake target sessions and consume each target's own model quota. Batch asks are accounted for per target.
|
|
239
|
+
|
|
240
|
+
The daily quota counts **new consultations per UTC calendar day**, with a default cap of 50. Resumes, follow-up rounds, and cross-session asks do not consume this quota. The counter lives in `$DSH_HOME/storages/advisor-group/daily-guard.json`; disabling the cap keeps counting without blocking requests. To control cost, reduce rounds or advisors, disable advisor tools, and set a daily cap.
|
|
241
|
+
|
|
242
|
+
## Security and privacy
|
|
243
|
+
|
|
244
|
+
- **Keys are not returned to the browser**: direct API keys are stored in the local DSH configuration under `SecretField` semantics. Use `apiKeyEnv` if you prefer not to write a key into that configuration.
|
|
245
|
+
- **Local routes require a token**: `/advisor-group/*` uses a shared token generated at startup and is designed for a local single-user setup. Add reverse-proxy authentication before exposing it to a LAN or the public internet.
|
|
246
|
+
- **Diagnostic requests are constrained**: model-list and connection-test calls run server-side and validate the target URL, protocol, and redirects. DNS rebinding remains a known architectural boundary.
|
|
247
|
+
- **Use `advisorTools: 'all'` with care**: it exposes every session-visible tool to advisors, including file writes and command execution. Calls still pass through DSH's tool pipeline and permission guards. Keep `readonly` or `off` for everyday use; non-read-only tool calls emit warning logs.
|
|
248
|
+
- **Cross-session content leaves a record**: questions and context are permanently recorded in target session logs, so send only what is necessary. Role-card generation sends session titles, working directories, and activity hints to the current main model. The cards themselves are stored locally and contain no API keys.
|
|
249
|
+
- **Local state is centralized**: consultation snapshots, asynchronous ask records, role cards, and quota data live under `$DSH_HOME/storages/advisor-group/`. Classifier shadow logs are used only for threshold tuning and do not influence runtime decisions.
|
|
250
|
+
|
|
251
|
+
## Known limitations
|
|
252
|
+
|
|
253
|
+
- After an abrupt DSH host crash, an unrefreshed card may still display **LIVE**. Refreshing restores its actual state from the persisted session log; the client already shows a disconnection notice.
|
|
254
|
+
- Risk notices are based on objective events: truncation caused by timeout or network interruption, and cancellation caused by a manual stop. The plugin no longer guesses risk by scanning advisor prose for words such as “risk” or “uncertain”.
|
|
255
|
+
- Cross-session tools have no per-session visibility switch. When `swarm.enabled` is on, all four tools are visible to sessions; when off, calls are refused explicitly. Mutual waits between two sessions are not specifically detected as deadlocks.
|
|
256
|
+
- The Advisor Corps panel displays at most 50 visible sessions. Automatic generation handles at most 12 unassigned sessions per pass; run it again to continue filling the roster.
|
|
257
|
+
|
|
258
|
+
## Development
|
|
134
259
|
|
|
135
260
|
```sh
|
|
136
261
|
npm install --legacy-peer-deps --no-audit --no-fund
|
|
137
262
|
npm run typecheck
|
|
138
|
-
npm test
|
|
139
|
-
npm run build
|
|
263
|
+
npm test
|
|
264
|
+
npm run build
|
|
265
|
+
npm pack --dry-run
|
|
140
266
|
```
|
|
141
267
|
|
|
142
|
-
|
|
268
|
+
The Vitest suite covers provider streaming contracts, cross-session delivery and waits, role cards, settings redaction, and recovery boundaries. Builds use tsdown. The client bundle **must not use `minify: true`**, because minification breaks the plugin-id form required by the startup guard.
|
|
269
|
+
|
|
270
|
+
- [Changelog](CHANGELOG.md)
|
|
271
|
+
- [Issue tracker](https://github.com/xingzhen199186/dsh-advisor-group/issues)
|
|
272
|
+
- [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
|
|
273
|
+
|
|
274
|
+
## License
|
|
143
275
|
|
|
144
276
|
[Apache License 2.0](LICENSE) © 2026 dsh-advisor-group contributors.
|