@xmanrui/dsh-im 0.19.0 → 1.0.0
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 +12 -1
- package/README.md +12 -1
- package/lib/index.js +160 -154
- package/package.json +1 -1
- package/plugin-src/host/channels/dingtalk/production.mjs +5 -2
- package/plugin-src/host/channels/feishu/production.mjs +5 -2
- package/plugin-src/host/channels/qq/production.mjs +5 -2
- package/plugin-src/host/channels/shared/production.mjs +5 -2
- package/plugin-src/host/channels/slack/production.mjs +5 -2
- package/plugin-src/host/channels/wecom/production.mjs +5 -2
- package/plugin-src/host/channels/weixin/production.mjs +5 -2
- package/plugin-src/host/channels/whatsapp/production.mjs +5 -2
- package/src/channels/dingtalk/dingtalk-bridge.mjs +11 -1
- package/src/channels/discord/discord-api.mjs +1 -1
- package/src/channels/feishu/bridge.mjs +11 -1
- package/src/channels/feishu/feishu-cards.mjs +4 -0
- package/src/channels/qq/qq-bridge.mjs +11 -1
- package/src/channels/shared/bot-workspace-store.mjs +75 -4
- package/src/channels/shared/preset-command.mjs +305 -0
- package/src/channels/shared/text-harness-bridge.mjs +11 -1
- package/src/channels/telegram/telegram-runtime.mjs +2 -0
- package/src/channels/wecom/wecom-bridge.mjs +11 -1
- package/src/channels/weixin/weixin-api.mjs +1 -1
- package/src/channels/weixin/weixin-bridge.mjs +11 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeAgentPresetCatalog,
|
|
3
|
+
normalizeAgentPresetId,
|
|
4
|
+
} from './agent-preset.mjs';
|
|
5
|
+
import { withSessionBindingLock } from './session-binding-lock.mjs';
|
|
6
|
+
import { splitWorkspaceCommandMessage } from './workspace-command.mjs';
|
|
7
|
+
import { WORKSPACE_SESSION_STALE } from './workspace-session.mjs';
|
|
8
|
+
|
|
9
|
+
const PRESET_COMMAND = /^\/preset(?=$|\s)/iu;
|
|
10
|
+
const PRESET_LIST_COMMAND = /^\/presetlist(?=$|\s)/iu;
|
|
11
|
+
const PRESET_LIST_USAGE = '用法:/presetlist(不带参数)';
|
|
12
|
+
const PRESET_USAGE = [
|
|
13
|
+
'用法:',
|
|
14
|
+
'/preset 查看当前设置',
|
|
15
|
+
'/preset <序号> 按最近一次 /presetlist 的序号选择',
|
|
16
|
+
'/preset <ID> 按 Agent Preset ID 选择',
|
|
17
|
+
'/preset id:<纯数字 ID> 选择纯数字 ID',
|
|
18
|
+
'/preset --default 跟随 Host 默认',
|
|
19
|
+
].join('\n');
|
|
20
|
+
const UNSAFE_DISPLAY_TEXT_GLOBAL = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]+/gu;
|
|
21
|
+
const LIST_SNAPSHOTS = new WeakMap();
|
|
22
|
+
export const PRESET_LIST_SNAPSHOT_TTL_MS = 15 * 60_000;
|
|
23
|
+
export const PRESET_LIST_SNAPSHOT_MAX_ENTRIES = 256;
|
|
24
|
+
|
|
25
|
+
function commandResult(message) {
|
|
26
|
+
return {
|
|
27
|
+
handled: true,
|
|
28
|
+
message,
|
|
29
|
+
messages: splitWorkspaceCommandMessage(message),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function safeDisplayText(value) {
|
|
34
|
+
if (typeof value !== 'string') return '';
|
|
35
|
+
return value.replace(UNSAFE_DISPLAY_TEXT_GLOBAL, ' ').replace(/\s+/gu, ' ').trim();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function rpcOptions(signal) {
|
|
39
|
+
return signal ? { signal } : {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeSettings(value) {
|
|
43
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)
|
|
44
|
+
|| !value.agentPresetCatalog || typeof value.agentPresetCatalog !== 'object'
|
|
45
|
+
|| !Array.isArray(value.agentPresetCatalog.items)) {
|
|
46
|
+
throw new TypeError('Harness returned invalid Agent Preset settings');
|
|
47
|
+
}
|
|
48
|
+
const agentPreset = value.agentPreset === null
|
|
49
|
+
? null
|
|
50
|
+
: normalizeAgentPresetId(value.agentPreset);
|
|
51
|
+
if (value.agentPreset !== null && agentPreset === null) {
|
|
52
|
+
throw new TypeError('Harness returned an invalid current Agent Preset');
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
agentPreset,
|
|
56
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function presetItemText(item) {
|
|
61
|
+
const label = safeDisplayText(item.label) || item.id;
|
|
62
|
+
return `${label}(${item.id})`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function itemFor(catalog, id) {
|
|
66
|
+
return catalog.items.find((item) => item.id === id) ?? null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function defaultDescription(catalog) {
|
|
70
|
+
if (!catalog.defaultId) return '未设置或当前不可用';
|
|
71
|
+
const item = itemFor(catalog, catalog.defaultId);
|
|
72
|
+
return item
|
|
73
|
+
? presetItemText(item)
|
|
74
|
+
: `${catalog.defaultId}(当前不可用)`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function currentDescription(settings) {
|
|
78
|
+
const { agentPreset, agentPresetCatalog: catalog } = settings;
|
|
79
|
+
if (agentPreset === null) {
|
|
80
|
+
const item = itemFor(catalog, catalog.defaultId);
|
|
81
|
+
return item
|
|
82
|
+
? `跟随 Host 默认:${presetItemText(item)}`
|
|
83
|
+
: '跟随 Host 默认(Host 默认当前不可用)';
|
|
84
|
+
}
|
|
85
|
+
const item = itemFor(catalog, agentPreset);
|
|
86
|
+
return item
|
|
87
|
+
? presetItemText(item)
|
|
88
|
+
: `${agentPreset}(已不可用)`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function formatCurrent(settings) {
|
|
92
|
+
return [
|
|
93
|
+
'当前机器人用于新会话的 Agent Preset:',
|
|
94
|
+
currentDescription(settings),
|
|
95
|
+
'',
|
|
96
|
+
'已有会话不会受此设置影响。',
|
|
97
|
+
'查看可用项:/presetlist',
|
|
98
|
+
'恢复跟随 Host 默认:/preset --default',
|
|
99
|
+
].join('\n');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function formatList(settings) {
|
|
103
|
+
const { agentPreset, agentPresetCatalog: catalog } = settings;
|
|
104
|
+
const lines = [
|
|
105
|
+
'当前机器人用于新会话的 Agent Preset:',
|
|
106
|
+
currentDescription(settings),
|
|
107
|
+
'',
|
|
108
|
+
`Host 默认:${defaultDescription(catalog)}`,
|
|
109
|
+
'',
|
|
110
|
+
`可用 Agent Preset(${catalog.items.length}):`,
|
|
111
|
+
];
|
|
112
|
+
if (catalog.items.length === 0) {
|
|
113
|
+
lines.push('当前没有可用 Agent Preset。');
|
|
114
|
+
} else {
|
|
115
|
+
catalog.items.forEach((item, index) => {
|
|
116
|
+
const markers = [];
|
|
117
|
+
if (item.id === catalog.defaultId) markers.push('Host 默认');
|
|
118
|
+
if (item.id === agentPreset) markers.push('当前选择');
|
|
119
|
+
if (agentPreset === null && item.id === catalog.defaultId) markers.push('当前生效');
|
|
120
|
+
const annotation = markers.length > 0 ? `(${markers.join(',')})` : '';
|
|
121
|
+
lines.push(`${index + 1}. ${presetItemText(item)}${annotation}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
lines.push(
|
|
125
|
+
'',
|
|
126
|
+
'选择:/preset <序号或 ID>',
|
|
127
|
+
'纯数字 ID:/preset id:<ID>',
|
|
128
|
+
'恢复跟随 Host 默认:/preset --default',
|
|
129
|
+
);
|
|
130
|
+
return lines.join('\n');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function formatUpdated(settings) {
|
|
134
|
+
return [
|
|
135
|
+
'当前机器人用于新会话的 Agent Preset 已设置为:',
|
|
136
|
+
currentDescription(settings),
|
|
137
|
+
'',
|
|
138
|
+
'已有会话不变。若当前聊天已有会话,请先发送 /new,再发送普通消息,才会使用新设置创建会话。',
|
|
139
|
+
].join('\n');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function stateSnapshots(state, { create = false } = {}) {
|
|
143
|
+
if ((typeof state !== 'object' || state === null) && typeof state !== 'function') return null;
|
|
144
|
+
let snapshots = LIST_SNAPSHOTS.get(state);
|
|
145
|
+
if (!snapshots && create) {
|
|
146
|
+
snapshots = new Map();
|
|
147
|
+
LIST_SNAPSHOTS.set(state, snapshots);
|
|
148
|
+
}
|
|
149
|
+
return snapshots ?? null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function pruneExpiredSnapshots(snapshots, now) {
|
|
153
|
+
for (const [snapshotKey, snapshot] of snapshots) {
|
|
154
|
+
if (snapshot.expiresAt <= now) snapshots.delete(snapshotKey);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function saveSnapshot(state, key, items) {
|
|
159
|
+
const snapshots = stateSnapshots(state, { create: true });
|
|
160
|
+
if (!snapshots) return;
|
|
161
|
+
const now = Date.now();
|
|
162
|
+
pruneExpiredSnapshots(snapshots, now);
|
|
163
|
+
snapshots.delete(key);
|
|
164
|
+
snapshots.set(key, {
|
|
165
|
+
expiresAt: now + PRESET_LIST_SNAPSHOT_TTL_MS,
|
|
166
|
+
ids: items.map((item) => item.id),
|
|
167
|
+
});
|
|
168
|
+
while (snapshots.size > PRESET_LIST_SNAPSHOT_MAX_ENTRIES) {
|
|
169
|
+
const oldest = snapshots.keys().next();
|
|
170
|
+
if (oldest.done) break;
|
|
171
|
+
snapshots.delete(oldest.value);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function loadSnapshot(state, key) {
|
|
176
|
+
const snapshots = stateSnapshots(state);
|
|
177
|
+
const snapshot = snapshots?.get(key);
|
|
178
|
+
if (!snapshots || !snapshot) return null;
|
|
179
|
+
if (snapshot.expiresAt <= Date.now()) {
|
|
180
|
+
snapshots.delete(key);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
snapshots.delete(key);
|
|
184
|
+
snapshots.set(key, snapshot);
|
|
185
|
+
return snapshot.ids;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function presetFromSnapshot(state, key, requested) {
|
|
189
|
+
if (!/^\d+$/u.test(requested)) return { numeric: false, id: null };
|
|
190
|
+
const index = Number(requested);
|
|
191
|
+
if (!Number.isSafeInteger(index) || index < 1) {
|
|
192
|
+
return { numeric: true, error: 'Agent Preset 序号无效,请先执行 /presetlist。' };
|
|
193
|
+
}
|
|
194
|
+
const snapshot = loadSnapshot(state, key);
|
|
195
|
+
if (!snapshot) {
|
|
196
|
+
return { numeric: true, error: '请先执行 /presetlist,再按列表序号选择 Agent Preset。' };
|
|
197
|
+
}
|
|
198
|
+
const id = snapshot[index - 1];
|
|
199
|
+
return id
|
|
200
|
+
? { numeric: true, id }
|
|
201
|
+
: { numeric: true, error: 'Agent Preset 序号不存在,请重新执行 /presetlist。' };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function errorCode(error) {
|
|
205
|
+
return error?.code ?? error?.failure?.code;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function presetErrorMessage(error, action) {
|
|
209
|
+
const code = errorCode(error);
|
|
210
|
+
if (code === 'agent-preset-invalid') {
|
|
211
|
+
return `Agent Preset ID 格式无效。\n${PRESET_USAGE}`;
|
|
212
|
+
}
|
|
213
|
+
if (code === 'agent-preset-unavailable') {
|
|
214
|
+
return 'Agent Preset 不存在或当前不可用,请重新执行 /presetlist。';
|
|
215
|
+
}
|
|
216
|
+
if (code === WORKSPACE_SESSION_STALE || code === 'workspace-bot-not-found') {
|
|
217
|
+
return '工作区或机器人状态已发生变化,请重试。';
|
|
218
|
+
}
|
|
219
|
+
if (code === 'cancelled' || error?.name === 'AbortError') {
|
|
220
|
+
if (action === 'list') return '获取 Agent Preset 列表已取消。';
|
|
221
|
+
if (action === 'current') return '获取 Agent Preset 设置已取消。';
|
|
222
|
+
return 'Agent Preset 修改已取消。';
|
|
223
|
+
}
|
|
224
|
+
if (action === 'list') return '暂时无法获取 Agent Preset 列表,请稍后重试。';
|
|
225
|
+
if (action === 'current') return '暂时无法获取 Agent Preset 设置,请稍后重试。';
|
|
226
|
+
return 'Agent Preset 修改失败,请稍后重试。';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function settings(harness, options) {
|
|
230
|
+
if (typeof harness?.agentPresetSettings !== 'function') {
|
|
231
|
+
throw new TypeError('Harness does not support Agent Preset settings');
|
|
232
|
+
}
|
|
233
|
+
return normalizeSettings(await harness.agentPresetSettings(options));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function update(harness, value, options) {
|
|
237
|
+
if (typeof harness?.updateAgentPreset !== 'function') {
|
|
238
|
+
throw new TypeError('Harness does not support updating Agent Preset settings');
|
|
239
|
+
}
|
|
240
|
+
return normalizeSettings(await harness.updateAgentPreset(value, options));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function isPresetCommand(text) {
|
|
244
|
+
if (typeof text !== 'string') return false;
|
|
245
|
+
const command = text.trim();
|
|
246
|
+
return PRESET_LIST_COMMAND.test(command) || PRESET_COMMAND.test(command);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export async function runPresetCommand(text, harness, state, key, options = {}) {
|
|
250
|
+
if (!isPresetCommand(text)) return null;
|
|
251
|
+
const command = text.trim();
|
|
252
|
+
if (options.hasImages) {
|
|
253
|
+
return commandResult('Agent Preset 命令仅支持纯文字,请移除图片后重试。');
|
|
254
|
+
}
|
|
255
|
+
const requestOptions = rpcOptions(options.signal);
|
|
256
|
+
|
|
257
|
+
if (PRESET_LIST_COMMAND.test(command)) {
|
|
258
|
+
if (!/^\/presetlist[ \t]*$/iu.test(command)) return commandResult(PRESET_LIST_USAGE);
|
|
259
|
+
try {
|
|
260
|
+
const current = await settings(harness, requestOptions);
|
|
261
|
+
saveSnapshot(state, key, current.agentPresetCatalog.items);
|
|
262
|
+
return commandResult(formatList(current));
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return commandResult(presetErrorMessage(error, 'list'));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const match = /^\/preset(?:[ \t]+([^\s]+))?[ \t]*$/iu.exec(command);
|
|
269
|
+
if (!match) return commandResult(PRESET_USAGE);
|
|
270
|
+
const requested = match[1];
|
|
271
|
+
if (!requested) {
|
|
272
|
+
try {
|
|
273
|
+
return commandResult(formatCurrent(await settings(harness, requestOptions)));
|
|
274
|
+
} catch (error) {
|
|
275
|
+
return commandResult(presetErrorMessage(error, 'current'));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
let selected;
|
|
280
|
+
if (requested.toLowerCase() === '--default') {
|
|
281
|
+
selected = null;
|
|
282
|
+
} else {
|
|
283
|
+
const explicitNumericId = /^id:(\d+)$/iu.exec(requested);
|
|
284
|
+
if (explicitNumericId) {
|
|
285
|
+
selected = explicitNumericId[1];
|
|
286
|
+
} else {
|
|
287
|
+
const fromSnapshot = presetFromSnapshot(state, key, requested);
|
|
288
|
+
if (fromSnapshot.numeric) {
|
|
289
|
+
if (fromSnapshot.error) return commandResult(fromSnapshot.error);
|
|
290
|
+
selected = fromSnapshot.id;
|
|
291
|
+
} else {
|
|
292
|
+
selected = normalizeAgentPresetId(requested);
|
|
293
|
+
if (!selected) return commandResult(`Agent Preset ID 格式无效。\n${PRESET_USAGE}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
return await withSessionBindingLock(state, key, async () => (
|
|
300
|
+
commandResult(formatUpdated(await update(harness, selected, requestOptions)))
|
|
301
|
+
));
|
|
302
|
+
} catch (error) {
|
|
303
|
+
return commandResult(presetErrorMessage(error, 'update'));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
isModelCommand,
|
|
13
13
|
runModelCommand,
|
|
14
14
|
} from './model-command.mjs';
|
|
15
|
+
import {
|
|
16
|
+
isPresetCommand,
|
|
17
|
+
runPresetCommand,
|
|
18
|
+
} from './preset-command.mjs';
|
|
15
19
|
import { askInWorkspaceSession } from './workspace-session.mjs';
|
|
16
20
|
import { HarnessApprovalQueue } from './harness-approval.mjs';
|
|
17
21
|
import {
|
|
@@ -122,7 +126,9 @@ export class TextHarnessBridge {
|
|
|
122
126
|
const text = cleanText(normalized.content);
|
|
123
127
|
const commandRunner = isControlCommand(text)
|
|
124
128
|
? runControlCommand
|
|
125
|
-
: (isModelCommand(text)
|
|
129
|
+
: (isModelCommand(text)
|
|
130
|
+
? runModelCommand
|
|
131
|
+
: (isPresetCommand(text) ? runPresetCommand : null));
|
|
126
132
|
if (commandRunner && (normalized.kind !== 'group' || normalized.addressed === true)) {
|
|
127
133
|
let task;
|
|
128
134
|
task = this.#processFastCommand(
|
|
@@ -319,6 +325,10 @@ export class TextHarnessBridge {
|
|
|
319
325
|
'/models 按序号列出所有可用模型',
|
|
320
326
|
'/model [序号或完整模型ID] 查看或切换当前会话模型',
|
|
321
327
|
'示例:先发 /models,再发 /model 2',
|
|
328
|
+
'/presetlist 按序号列出可用 Agent Preset',
|
|
329
|
+
'/preset [序号或完整ID] 查看或设置当前机器人 Agent Preset',
|
|
330
|
+
'纯数字 ID:/preset id:<ID>',
|
|
331
|
+
'/preset --default 跟随 Host 默认',
|
|
322
332
|
'/stop 停止当前任务',
|
|
323
333
|
'/steer 补充指令 纠偏当前任务',
|
|
324
334
|
'/status 检查连接状态',
|
|
@@ -15,6 +15,8 @@ export const TELEGRAM_COMMAND_MENU = Object.freeze([
|
|
|
15
15
|
{ command: 'session', description: '将当前聊天绑定到指定会话' },
|
|
16
16
|
{ command: 'models', description: '按序号列出所有可用模型' },
|
|
17
17
|
{ command: 'model', description: '查看或切换当前会话模型' },
|
|
18
|
+
{ command: 'presetlist', description: '列出可用 Agent Preset' },
|
|
19
|
+
{ command: 'preset', description: '查看或设置新会话 Agent Preset' },
|
|
18
20
|
{ command: 'stop', description: '停止当前任务' },
|
|
19
21
|
{ command: 'steer', description: '纠偏当前任务' },
|
|
20
22
|
{ command: 'status', description: '检查连接状态' },
|
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
isModelCommand,
|
|
15
15
|
runModelCommand,
|
|
16
16
|
} from '../shared/model-command.mjs';
|
|
17
|
+
import {
|
|
18
|
+
isPresetCommand,
|
|
19
|
+
runPresetCommand,
|
|
20
|
+
} from '../shared/preset-command.mjs';
|
|
17
21
|
import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
|
|
18
22
|
import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
|
|
19
23
|
import {
|
|
@@ -37,6 +41,10 @@ const HELP_TEXT = [
|
|
|
37
41
|
'/models 按序号列出所有可用模型',
|
|
38
42
|
'/model [序号或完整模型ID] 查看或切换当前会话模型',
|
|
39
43
|
'示例:先发 /models,再发 /model 2',
|
|
44
|
+
'/presetlist 按序号列出可用 Agent Preset',
|
|
45
|
+
'/preset [序号或完整ID] 查看或设置当前机器人 Agent Preset',
|
|
46
|
+
'纯数字 ID:/preset id:<ID>',
|
|
47
|
+
'/preset --default 跟随 Host 默认',
|
|
40
48
|
'/stop 停止当前任务',
|
|
41
49
|
'/steer 补充指令 纠偏当前任务',
|
|
42
50
|
'/status 检查连接状态',
|
|
@@ -292,7 +300,9 @@ export class WecomHarnessBridge {
|
|
|
292
300
|
const commandText = nonEmptyString(commandMessage.content) ?? '';
|
|
293
301
|
const commandRunner = isControlCommand(commandText)
|
|
294
302
|
? runControlCommand
|
|
295
|
-
: (isModelCommand(commandText)
|
|
303
|
+
: (isModelCommand(commandText)
|
|
304
|
+
? runModelCommand
|
|
305
|
+
: (isPresetCommand(commandText) ? runPresetCommand : null));
|
|
296
306
|
if (commandRunner) {
|
|
297
307
|
let task;
|
|
298
308
|
task = this.#processFastCommand(
|
|
@@ -19,6 +19,10 @@ import {
|
|
|
19
19
|
isModelCommand,
|
|
20
20
|
runModelCommand,
|
|
21
21
|
} from '../shared/model-command.mjs';
|
|
22
|
+
import {
|
|
23
|
+
isPresetCommand,
|
|
24
|
+
runPresetCommand,
|
|
25
|
+
} from '../shared/preset-command.mjs';
|
|
22
26
|
import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
|
|
23
27
|
import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
|
|
24
28
|
import {
|
|
@@ -45,6 +49,10 @@ const HELP_TEXT = [
|
|
|
45
49
|
'/models 按序号列出所有可用模型',
|
|
46
50
|
'/model [序号或完整模型ID] 查看或切换当前会话模型',
|
|
47
51
|
'示例:先发 /models,再发 /model 2',
|
|
52
|
+
'/presetlist 按序号列出可用 Agent Preset',
|
|
53
|
+
'/preset [序号或完整ID] 查看或设置当前机器人 Agent Preset',
|
|
54
|
+
'纯数字 ID:/preset id:<ID>',
|
|
55
|
+
'/preset --default 跟随 Host 默认',
|
|
48
56
|
'/stop 停止当前任务',
|
|
49
57
|
'/steer 补充指令 纠偏当前任务',
|
|
50
58
|
'/status 检查连接状态',
|
|
@@ -166,7 +174,9 @@ export class WeixinHarnessBridge {
|
|
|
166
174
|
const commandText = nonEmptyString(extractWeixinText(message)) ?? '';
|
|
167
175
|
const commandRunner = isControlCommand(commandText)
|
|
168
176
|
? runControlCommand
|
|
169
|
-
: (isModelCommand(commandText)
|
|
177
|
+
: (isModelCommand(commandText)
|
|
178
|
+
? runModelCommand
|
|
179
|
+
: (isPresetCommand(commandText) ? runPresetCommand : null));
|
|
170
180
|
if (commandRunner && sender === this.#ownerUserId) {
|
|
171
181
|
let task;
|
|
172
182
|
task = this.#processFastCommand(
|