dsh-ssh-tui 0.1.6 → 0.1.7
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 +6 -0
- package/README.md +14 -4
- package/cordis.patch.yml +19 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/subagent-model.js +64 -0
- package/lib/subagent-model.js.map +1 -0
- package/lib/tui.js +194 -1
- package/lib/tui.js.map +1 -1
- package/lib/types/subagent-model.d.ts +56 -0
- package/lib/types/tui.d.ts +21 -0
- package/package.json +2 -1
package/README.en.md
CHANGED
|
@@ -155,6 +155,12 @@ configured catalog when the endpoint cannot be reached. Picking a model that
|
|
|
155
155
|
is not stored in the provider profile automatically adds it to
|
|
156
156
|
`llm-pi-ai.providers.<id>.models` so the harness can serve it.
|
|
157
157
|
|
|
158
|
+
Subagents follow the parent session's provider by default and run on the
|
|
159
|
+
lightweight `deepseek-v4-flash` model. `/submodel [model-id]` picks (or
|
|
160
|
+
directly sets) the subagent model, and `/subeffort` picks the subagent
|
|
161
|
+
reasoning effort or restores the provider default. Both commands are
|
|
162
|
+
remembered under `ssh-tui-subagent` in `$DSH_HOME/settings.yaml`.
|
|
163
|
+
|
|
158
164
|
`/usage` (alias `/quota`) works when the current provider is an OpenCode
|
|
159
165
|
source and keeps the two billing models distinct:
|
|
160
166
|
|
package/README.md
CHANGED
|
@@ -120,9 +120,14 @@ dsh --profile tui --no-color
|
|
|
120
120
|
| `Ctrl+D` | 退出 |
|
|
121
121
|
| `Ctrl+L` | 重绘 |
|
|
122
122
|
|
|
123
|
-
斜杠命令:`/help`、`/model`、`/mode`、`/resume
|
|
124
|
-
`/usage`(`/quota` 同义)、`/setup`、`/clear
|
|
125
|
-
|
|
123
|
+
斜杠命令:`/help`、`/model`、`/submodel`、`/subeffort`、`/mode`、`/resume`、
|
|
124
|
+
`/status`、`/subagents`、`/usage`(`/quota` 同义)、`/setup`、`/clear`,
|
|
125
|
+
以及 harness 自带命令(`/goal`、`/plan`、`/compact` 等)。
|
|
126
|
+
|
|
127
|
+
子代理默认跟随父会话的提供方,模型默认为轻量的 `deepseek-v4-flash`:
|
|
128
|
+
|
|
129
|
+
- `/submodel [model-id]`:打开子代理模型选择器;带参数时直接指定模型;
|
|
130
|
+
- `/subeffort`:选择子代理思考强度,或恢复为“跟随提供商默认”。
|
|
126
131
|
|
|
127
132
|
`/usage` 在当前提供商为 OpenCode 源时可用,并区分两种计费方式:
|
|
128
133
|
|
|
@@ -142,9 +147,14 @@ agent-default-model:
|
|
|
142
147
|
reasoningEffort: max
|
|
143
148
|
agent-presets:
|
|
144
149
|
default: standard
|
|
150
|
+
ssh-tui-subagent:
|
|
151
|
+
model: deepseek-v4-flash
|
|
152
|
+
# provider 可省略:省略时子代理跟随父会话提供方
|
|
153
|
+
# reasoningEffort 可省略:省略时跟随提供商/模型默认
|
|
145
154
|
```
|
|
146
155
|
|
|
147
|
-
`/model` 与 `/
|
|
156
|
+
`/model`、`/mode`、`/submodel` 与 `/subeffort` 的修改会写回这里,
|
|
157
|
+
web 端与 TUI 共用同一份设置。
|
|
148
158
|
|
|
149
159
|
对 OpenCode 和其他第三方提供商,`/model` 会先调用提供商的端点
|
|
150
160
|
(`GET {baseURL}/models`)获取实时模型列表;端点不可达时回退到已配置的
|
package/cordis.patch.yml
CHANGED
|
@@ -35,6 +35,25 @@
|
|
|
35
35
|
thinking: enabled
|
|
36
36
|
reasoningEffort: max
|
|
37
37
|
|
|
38
|
+
# Subagents follow the parent session's provider and default to the
|
|
39
|
+
# lightweight model. The TUI's /submodel and /subeffort commands can override
|
|
40
|
+
# both model and reasoning effort at runtime through the request waterfall.
|
|
41
|
+
- id: tool-subagent
|
|
42
|
+
config:
|
|
43
|
+
provider: spawn
|
|
44
|
+
toolName: subagent
|
|
45
|
+
backgroundMode: continuable
|
|
46
|
+
agentOptions:
|
|
47
|
+
model: deepseek-v4-flash
|
|
48
|
+
|
|
49
|
+
- id: tool-subagent-fork
|
|
50
|
+
config:
|
|
51
|
+
provider: fork
|
|
52
|
+
toolName: subagent_fork
|
|
53
|
+
backgroundMode: one-shot
|
|
54
|
+
agentOptions:
|
|
55
|
+
model: deepseek-v4-flash
|
|
56
|
+
|
|
38
57
|
- insert:
|
|
39
58
|
# The agent-mode roster (standard / PTC / minimal / cordis / routing-suite).
|
|
40
59
|
# The launcher injects the shipped preset root into this row when it is
|
package/lib/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
11
11
|
import { showSessionPicker } from './picker.js';
|
|
12
12
|
import { mountTui } from './tui.js';
|
|
13
13
|
import { defaultReasoningEffort } from './reasoning.js';
|
|
14
|
+
import { createSubagentSelection } from './subagent-model.js';
|
|
14
15
|
export const name = 'ssh-tui';
|
|
15
16
|
/** Core services required before the terminal channel can drive an agent. */
|
|
16
17
|
export const inject = ['agents', 'agentDefaultModel'];
|
|
@@ -24,6 +25,7 @@ export function apply(ctx, config) {
|
|
|
24
25
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
25
26
|
throw new Error('dsh-ssh-tui: both stdin and stdout must be TTYs; use a terminal/SSH session');
|
|
26
27
|
}
|
|
28
|
+
const subagentSelection = createSubagentSelection(ctx);
|
|
27
29
|
ctx.effect(() => {
|
|
28
30
|
let disposed = false;
|
|
29
31
|
let switching = false;
|
|
@@ -131,6 +133,7 @@ export function apply(ctx, config) {
|
|
|
131
133
|
provider,
|
|
132
134
|
model,
|
|
133
135
|
selectionRef,
|
|
136
|
+
subagentSelection,
|
|
134
137
|
presetId,
|
|
135
138
|
presetName,
|
|
136
139
|
goodbye: goodbyeFor(String(sessionId)),
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAiE,MAAM,wBAAwB,CAAA;AAG7H,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAsB,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent model defaults and the settings section the TUI edits with
|
|
3
|
+
* `/submodel` and `/subeffort`.
|
|
4
|
+
*
|
|
5
|
+
* The provider is deliberately inherited from the running parent session:
|
|
6
|
+
* the subagent selection only overrides the provider when the user stored an
|
|
7
|
+
* explicit route. The model defaults to the lightweight `deepseek-v4-flash`.
|
|
8
|
+
*/
|
|
9
|
+
import z from '@deepseek-ai/schemastery';
|
|
10
|
+
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
11
|
+
import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
12
|
+
/** Settings namespace carrying the TUI's subagent model selection. */
|
|
13
|
+
export const SUBAGENT_SETTINGS_NAMESPACE = settingsNamespace('ssh-tui-subagent');
|
|
14
|
+
/** Lightweight default model used for subagent children. */
|
|
15
|
+
export const DEFAULT_SUBAGENT_MODEL = 'deepseek-v4-flash';
|
|
16
|
+
/** Settings schema for `$DSH_HOME/settings.yaml`. */
|
|
17
|
+
export const SUBAGENT_SETTINGS_SCHEMA = z.object({
|
|
18
|
+
provider: z.string(),
|
|
19
|
+
model: z.string().default(DEFAULT_SUBAGENT_MODEL),
|
|
20
|
+
reasoningEffort: z.string(),
|
|
21
|
+
});
|
|
22
|
+
/** Normalize a raw settings section into a live typed selection. */
|
|
23
|
+
export function normalizeSubagentSelection(value) {
|
|
24
|
+
const raw = (typeof value === 'object' && value !== null ? value : {});
|
|
25
|
+
return {
|
|
26
|
+
...(typeof raw.provider === 'string' && raw.provider.trim() !== ''
|
|
27
|
+
? { provider: raw.provider.trim() }
|
|
28
|
+
: {}),
|
|
29
|
+
model: typeof raw.model === 'string' && raw.model.trim() !== ''
|
|
30
|
+
? raw.model.trim()
|
|
31
|
+
: DEFAULT_SUBAGENT_MODEL,
|
|
32
|
+
...(typeof raw.reasoningEffort === 'string' && raw.reasoningEffort.trim() !== ''
|
|
33
|
+
? { reasoningEffort: ReasoningEffortId(raw.reasoningEffort.trim()) }
|
|
34
|
+
: {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Install the settings-backed subagent selection for one TUI plugin fiber.
|
|
39
|
+
* Returns the mutable ref the request waterfall and the slash commands share.
|
|
40
|
+
*/
|
|
41
|
+
export function createSubagentSelection(ctx) {
|
|
42
|
+
let source = () => ({ model: DEFAULT_SUBAGENT_MODEL });
|
|
43
|
+
const ref = { current: normalizeSubagentSelection(source()) };
|
|
44
|
+
installSettingsSection(ctx, SUBAGENT_SETTINGS_NAMESPACE, SUBAGENT_SETTINGS_SCHEMA, {
|
|
45
|
+
model: DEFAULT_SUBAGENT_MODEL,
|
|
46
|
+
}, {
|
|
47
|
+
setSource: (current) => {
|
|
48
|
+
source = () => current();
|
|
49
|
+
},
|
|
50
|
+
onChange: () => {
|
|
51
|
+
ref.current = normalizeSubagentSelection(source());
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return ref;
|
|
55
|
+
}
|
|
56
|
+
/** Serialize a live selection back into the settings document shape. */
|
|
57
|
+
export function subagentSettingsValue(selection) {
|
|
58
|
+
return {
|
|
59
|
+
...(selection.provider === undefined ? {} : { provider: selection.provider }),
|
|
60
|
+
model: selection.model,
|
|
61
|
+
...(selection.reasoningEffort === undefined ? {} : { reasoningEffort: String(selection.reasoningEffort) }),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=subagent-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-model.js","sourceRoot":"","sources":["../src/subagent-model.ts"],"names":[],"mappings":"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"}
|
package/lib/tui.js
CHANGED
|
@@ -21,6 +21,7 @@ import { SessionId } from '@deepseek-ai/dsh-session';
|
|
|
21
21
|
import { settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
22
22
|
import { formatSessionTime, listResumableSessions } from './session-list.js';
|
|
23
23
|
import { defaultReasoningEffort } from './reasoning.js';
|
|
24
|
+
import { DEFAULT_SUBAGENT_MODEL, SUBAGENT_SETTINGS_NAMESPACE, subagentSettingsValue, } from './subagent-model.js';
|
|
24
25
|
import { UserQuestionError, } from '@deepseek-ai/dsh-user-questions';
|
|
25
26
|
const PROVIDER_TEMPLATES = {
|
|
26
27
|
official: {
|
|
@@ -63,6 +64,7 @@ const WAIT_INDICATOR_MS = 8000;
|
|
|
63
64
|
const STALL_WARNING_MS = 60000;
|
|
64
65
|
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
65
66
|
const QUESTION_OPTION_KEYS = '123456789abcdefghijklmnopqrstuvwxyz';
|
|
67
|
+
const SUBAGENT_DEFAULT_EFFORT_LABEL = '跟随提供商默认';
|
|
66
68
|
const RESERVED_BOTTOM_LINES = 3; // input line + stats line + status line
|
|
67
69
|
const MAX_TRANSCRIPT_ROWS = 5000;
|
|
68
70
|
const IS_WINDOWS = process.platform === 'win32';
|
|
@@ -195,6 +197,8 @@ const DEEPSEEK_LOGO_VARIANTS = [
|
|
|
195
197
|
const LOCAL_COMMANDS = [
|
|
196
198
|
{ name: 'help', description: 'show all available commands' },
|
|
197
199
|
{ name: 'model', description: 'select model and reasoning effort (same provider)' },
|
|
200
|
+
{ name: 'submodel', description: `select subagent model (default ${DEFAULT_SUBAGENT_MODEL}, same provider as parent)` },
|
|
201
|
+
{ name: 'subeffort', description: 'select subagent reasoning effort (default follows provider)' },
|
|
198
202
|
{ name: 'mode', description: 'switch agent mode / preset (standard, minimal, code, cordis, routing-suite, ...)' },
|
|
199
203
|
{ name: 'quit', description: 'exit the TUI' },
|
|
200
204
|
{ name: 'exit', description: 'exit the TUI' },
|
|
@@ -1159,6 +1163,7 @@ export class SshTui {
|
|
|
1159
1163
|
resume;
|
|
1160
1164
|
providerName;
|
|
1161
1165
|
selectionRef;
|
|
1166
|
+
subagentSelection;
|
|
1162
1167
|
onSwitchSession;
|
|
1163
1168
|
onSelectionChanged;
|
|
1164
1169
|
resumePicker;
|
|
@@ -1220,6 +1225,7 @@ export class SshTui {
|
|
|
1220
1225
|
this.resume = config.resume === true;
|
|
1221
1226
|
this.providerName = config.provider ?? 'deepseek-official';
|
|
1222
1227
|
this.selectionRef = config.selectionRef;
|
|
1228
|
+
this.subagentSelection = config.subagentSelection ?? { current: { model: DEFAULT_SUBAGENT_MODEL } };
|
|
1223
1229
|
this.onSwitchSession = config.onSwitchSession;
|
|
1224
1230
|
this.onSelectionChanged = config.onSelectionChanged;
|
|
1225
1231
|
this.resumePicker = config.resumePicker === true;
|
|
@@ -1237,7 +1243,7 @@ export class SshTui {
|
|
|
1237
1243
|
process.stdin.on('data', this.handleData);
|
|
1238
1244
|
process.stdout.on('resize', this.markDirty);
|
|
1239
1245
|
process.on('SIGWINCH', this.markDirty);
|
|
1240
|
-
this.disposers.push(this.ctx.on('session/event', this.handleSessionEvent), this.ctx.on('agent/status', this.handleStatus), this.ctx.on('agent/error', this.handleError), this.ctx.on('agent/disposed', this.handleDisposed), this.ctx.on('agent/inbox/claimed', this.handleInboxClaimed), this.ctx.on('agent/inbox/discarded', this.handleInboxDiscarded), this.ctx.on('subagent/start', this.handleSubagentStart), this.ctx.on('subagent/end', this.handleSubagentEnd), this.ctx.on('approval/request', this.handleApproval));
|
|
1246
|
+
this.disposers.push(this.ctx.on('session/event', this.handleSessionEvent), this.ctx.on('agent/status', this.handleStatus), this.ctx.on('agent/error', this.handleError), this.ctx.on('agent/disposed', this.handleDisposed), this.ctx.on('agent/inbox/claimed', this.handleInboxClaimed), this.ctx.on('agent/inbox/discarded', this.handleInboxDiscarded), this.ctx.on('agent/request', this.handleAgentRequest), this.ctx.on('subagent/start', this.handleSubagentStart), this.ctx.on('subagent/end', this.handleSubagentEnd), this.ctx.on('approval/request', this.handleApproval));
|
|
1241
1247
|
const questions = this.ctx.get('userQuestions');
|
|
1242
1248
|
if (questions !== undefined) {
|
|
1243
1249
|
this.userQuestionDisposer = questions.registerProvider({ ask: this.handleUserQuestions });
|
|
@@ -1829,6 +1835,12 @@ export class SshTui {
|
|
|
1829
1835
|
const statsText = this.statsText();
|
|
1830
1836
|
const statsLine = this.styleLine('system', fitLine(statsText === '' ? '— 尚无会话统计' : statsText));
|
|
1831
1837
|
let statusText = `${this.status} [${this.presetName}] ${this.currentSelectionLabel()}`;
|
|
1838
|
+
const sub = this.subagentSelection.current;
|
|
1839
|
+
const subProvider = sub.provider ?? this.selectionRef?.current?.provider ?? this.agent.options.provider ?? this.providerName;
|
|
1840
|
+
const subEffort = sub.reasoningEffort === undefined ? '' : `(${sub.reasoningEffort})`;
|
|
1841
|
+
statusText += sub.provider === undefined
|
|
1842
|
+
? ` · sub:${sub.model}${subEffort}`
|
|
1843
|
+
: ` · sub:${subProvider}/${sub.model}${subEffort}`;
|
|
1832
1844
|
if (inputView.folded)
|
|
1833
1845
|
statusText += ' · 输入已折叠 · Ctrl+T 展开';
|
|
1834
1846
|
else if (inputRows > 1)
|
|
@@ -2041,6 +2053,24 @@ export class SshTui {
|
|
|
2041
2053
|
return `\x1b[${code}m${safe}`;
|
|
2042
2054
|
}
|
|
2043
2055
|
// ── event handling ──────────────────────────────────────────────────────
|
|
2056
|
+
/**
|
|
2057
|
+
* Apply the TUI's subagent model selection to every child-agent request.
|
|
2058
|
+
* The parent request is left untouched (its own `/model` waterfall already
|
|
2059
|
+
* owns the route); direct children created by tool-subagent inherit the
|
|
2060
|
+
* parent provider unless `/submodel` stored an explicit subagent provider.
|
|
2061
|
+
*/
|
|
2062
|
+
handleAgentRequest = async ({ agent }, next) => {
|
|
2063
|
+
const resolved = await next();
|
|
2064
|
+
if (agent === this.agent)
|
|
2065
|
+
return resolved;
|
|
2066
|
+
const selection = this.subagentSelection.current;
|
|
2067
|
+
return {
|
|
2068
|
+
...resolved,
|
|
2069
|
+
...(selection.provider === undefined ? {} : { provider: selection.provider }),
|
|
2070
|
+
model: selection.model,
|
|
2071
|
+
...(selection.reasoningEffort === undefined ? {} : { reasoningEffort: selection.reasoningEffort }),
|
|
2072
|
+
};
|
|
2073
|
+
};
|
|
2044
2074
|
handleSessionEvent = (session, event) => {
|
|
2045
2075
|
if (session.id !== this.agent.id) {
|
|
2046
2076
|
if (this.subagentSessions.has(session.id))
|
|
@@ -2751,6 +2781,147 @@ export class SshTui {
|
|
|
2751
2781
|
this.pushRow({ kind: 'system', text: `模型已切换:${selected.id}(思考强度 ${effort ?? '默认'});下一步请求生效。` });
|
|
2752
2782
|
this.markDirty();
|
|
2753
2783
|
}
|
|
2784
|
+
/** Provider route the next subagent request should use. */
|
|
2785
|
+
effectiveSubagentProvider() {
|
|
2786
|
+
return this.subagentSelection.current.provider
|
|
2787
|
+
?? this.selectionRef?.current?.provider
|
|
2788
|
+
?? this.agent.options.provider
|
|
2789
|
+
?? this.providerName;
|
|
2790
|
+
}
|
|
2791
|
+
/** Persist one subagent selection and publish it to the live request waterfall. */
|
|
2792
|
+
async saveSubagentSelection(next) {
|
|
2793
|
+
this.subagentSelection.current = next;
|
|
2794
|
+
const settings = this.ctx.get('settings');
|
|
2795
|
+
if (settings === undefined) {
|
|
2796
|
+
this.pushRow({ kind: 'error', text: '设置服务不可用,子代理选择仅当前会话生效。' });
|
|
2797
|
+
this.markDirty();
|
|
2798
|
+
return false;
|
|
2799
|
+
}
|
|
2800
|
+
await settings.replace(SUBAGENT_SETTINGS_NAMESPACE, subagentSettingsValue(next));
|
|
2801
|
+
return true;
|
|
2802
|
+
}
|
|
2803
|
+
/** Resolve the picker model list for one provider (endpoint first, then catalog). */
|
|
2804
|
+
async subagentModelOptions(provider) {
|
|
2805
|
+
const llm = this.ctx.get('llm');
|
|
2806
|
+
let options = [];
|
|
2807
|
+
let source = '已配置列表';
|
|
2808
|
+
if (this.piAiProviderProfile(provider) !== undefined || provider === 'opencode' || provider === 'opencode-go') {
|
|
2809
|
+
const previousStatus = this.status;
|
|
2810
|
+
try {
|
|
2811
|
+
this.status = `正在从端点获取子代理模型列表(${provider})…`;
|
|
2812
|
+
this.markDirty();
|
|
2813
|
+
options = await this.discoverEndpointModels(provider);
|
|
2814
|
+
if (options.length > 0) {
|
|
2815
|
+
source = '端点实时列表';
|
|
2816
|
+
try {
|
|
2817
|
+
const listed = (await llm?.listModels(provider)) ?? [];
|
|
2818
|
+
const endpointIds = new Set(options.map(model => model.id));
|
|
2819
|
+
for (const model of listed) {
|
|
2820
|
+
if (!endpointIds.has(model.id))
|
|
2821
|
+
options.push({ id: model.id, label: model.name || model.id });
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
catch {
|
|
2825
|
+
// The endpoint list stands alone when the catalog cannot be read.
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
catch {
|
|
2830
|
+
options = [];
|
|
2831
|
+
}
|
|
2832
|
+
finally {
|
|
2833
|
+
this.status = previousStatus;
|
|
2834
|
+
this.markDirty();
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
if (options.length === 0) {
|
|
2838
|
+
try {
|
|
2839
|
+
const listed = (await llm?.listModels(provider)) ?? [];
|
|
2840
|
+
options = listed.map(model => ({ id: model.id, label: model.name || model.id }));
|
|
2841
|
+
}
|
|
2842
|
+
catch {
|
|
2843
|
+
options = [];
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
return { options, source };
|
|
2847
|
+
}
|
|
2848
|
+
/** /submodel: pick (or set) the model subagent children use. */
|
|
2849
|
+
async runSubmodelCommand(arg) {
|
|
2850
|
+
const provider = this.effectiveSubagentProvider();
|
|
2851
|
+
const current = this.subagentSelection.current;
|
|
2852
|
+
const direct = arg.trim();
|
|
2853
|
+
let selectedId = direct;
|
|
2854
|
+
if (selectedId === '') {
|
|
2855
|
+
const { options, source } = await this.subagentModelOptions(provider);
|
|
2856
|
+
if (options.length === 0) {
|
|
2857
|
+
options.push({ id: current.model, label: current.model });
|
|
2858
|
+
}
|
|
2859
|
+
const selected = await this.pickModelOption(options, provider, source, current.model);
|
|
2860
|
+
if (selected === undefined)
|
|
2861
|
+
return;
|
|
2862
|
+
selectedId = selected.id;
|
|
2863
|
+
}
|
|
2864
|
+
if (!(await this.ensureProviderModelConfigured(provider, selectedId)))
|
|
2865
|
+
return;
|
|
2866
|
+
const persisted = await this.saveSubagentSelection({ ...current, model: selectedId });
|
|
2867
|
+
this.pushRow({
|
|
2868
|
+
kind: 'system',
|
|
2869
|
+
text: `${current.provider === undefined
|
|
2870
|
+
? `子代理模型已切换:${selectedId}(提供方跟随父会话 ${provider})。`
|
|
2871
|
+
: `子代理模型已切换:${selectedId}(提供方 ${provider})。`}${persisted ? '' : '(仅当前会话)'}`,
|
|
2872
|
+
});
|
|
2873
|
+
this.markDirty();
|
|
2874
|
+
}
|
|
2875
|
+
/** /subeffort: pick the reasoning effort subagent children use. */
|
|
2876
|
+
async runSubeffortCommand() {
|
|
2877
|
+
const provider = this.effectiveSubagentProvider();
|
|
2878
|
+
const current = this.subagentSelection.current;
|
|
2879
|
+
const llm = this.ctx.get('llm');
|
|
2880
|
+
let effortOptions = [];
|
|
2881
|
+
try {
|
|
2882
|
+
const info = await llm?.resolveModelInfo(provider, current.model);
|
|
2883
|
+
effortOptions = (info?.reasoning?.efforts ?? []).map(effort => ({ id: String(effort.id), label: effort.name }));
|
|
2884
|
+
}
|
|
2885
|
+
catch {
|
|
2886
|
+
effortOptions = [];
|
|
2887
|
+
}
|
|
2888
|
+
if (effortOptions.length === 0) {
|
|
2889
|
+
effortOptions = ['off', 'high', 'max'].map(id => ({ id, label: id }));
|
|
2890
|
+
}
|
|
2891
|
+
const choices = [
|
|
2892
|
+
{ id: undefined, label: SUBAGENT_DEFAULT_EFFORT_LABEL },
|
|
2893
|
+
...effortOptions.map(option => ({ id: option.id, label: option.label })),
|
|
2894
|
+
];
|
|
2895
|
+
const answer = await this.askQuestion({
|
|
2896
|
+
id: 'subagent-effort-pick',
|
|
2897
|
+
question: `选择子代理思考强度(${provider}/${current.model})`,
|
|
2898
|
+
options: choices.map(option => ({
|
|
2899
|
+
label: option.label,
|
|
2900
|
+
description: option.id === undefined
|
|
2901
|
+
? '清空自定义强度,跟随提供商/模型默认'
|
|
2902
|
+
: option.id === String(current.reasoningEffort)
|
|
2903
|
+
? '当前'
|
|
2904
|
+
: undefined,
|
|
2905
|
+
})),
|
|
2906
|
+
});
|
|
2907
|
+
const picked = choices.find(option => option.label === answer.selected[0]);
|
|
2908
|
+
if (picked === undefined)
|
|
2909
|
+
return;
|
|
2910
|
+
const next = {
|
|
2911
|
+
...current,
|
|
2912
|
+
...(picked.id === undefined
|
|
2913
|
+
? { reasoningEffort: undefined }
|
|
2914
|
+
: { reasoningEffort: ReasoningEffortId(picked.id) }),
|
|
2915
|
+
};
|
|
2916
|
+
const persisted = await this.saveSubagentSelection(next);
|
|
2917
|
+
this.pushRow({
|
|
2918
|
+
kind: 'system',
|
|
2919
|
+
text: `${picked.id === undefined
|
|
2920
|
+
? '子代理思考强度已恢复为提供商默认。'
|
|
2921
|
+
: `子代理思考强度已切换:${picked.id}。`}${persisted ? '' : '(仅当前会话)'}`,
|
|
2922
|
+
});
|
|
2923
|
+
this.markDirty();
|
|
2924
|
+
}
|
|
2754
2925
|
/** /mode: pick an agent preset (standard / minimal / code / cordis / routing-suite / ...). */
|
|
2755
2926
|
async runModeCommand() {
|
|
2756
2927
|
const agentPresets = this.ctx.get('agentPresets');
|
|
@@ -3844,6 +4015,28 @@ export class SshTui {
|
|
|
3844
4015
|
this.markDirty();
|
|
3845
4016
|
});
|
|
3846
4017
|
break;
|
|
4018
|
+
case 'submodel':
|
|
4019
|
+
void this.runSubmodelCommand(arg).catch((error) => {
|
|
4020
|
+
if (error instanceof UserQuestionError) {
|
|
4021
|
+
this.pushRow({ kind: 'system', text: '子代理模型选择已取消。' });
|
|
4022
|
+
}
|
|
4023
|
+
else {
|
|
4024
|
+
this.pushRow({ kind: 'error', text: `/submodel failed: ${errorChain(error)}` });
|
|
4025
|
+
}
|
|
4026
|
+
this.markDirty();
|
|
4027
|
+
});
|
|
4028
|
+
break;
|
|
4029
|
+
case 'subeffort':
|
|
4030
|
+
void this.runSubeffortCommand().catch((error) => {
|
|
4031
|
+
if (error instanceof UserQuestionError) {
|
|
4032
|
+
this.pushRow({ kind: 'system', text: '子代理思考强度选择已取消。' });
|
|
4033
|
+
}
|
|
4034
|
+
else {
|
|
4035
|
+
this.pushRow({ kind: 'error', text: `/subeffort failed: ${errorChain(error)}` });
|
|
4036
|
+
}
|
|
4037
|
+
this.markDirty();
|
|
4038
|
+
});
|
|
4039
|
+
break;
|
|
3847
4040
|
case 'mode':
|
|
3848
4041
|
void this.runModeCommand().catch((error) => {
|
|
3849
4042
|
if (error instanceof UserQuestionError) {
|