evolclaw 3.2.0 → 3.3.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/CHANGELOG.md +17 -0
- package/README.md +1 -2
- package/dist/agents/{resolve.js → baseagent.js} +34 -5
- package/dist/agents/claude-runner.js +120 -27
- package/dist/agents/codex-app-server-client.js +364 -0
- package/dist/agents/codex-runner.js +1069 -141
- package/dist/agents/gemini-runner.js +2 -2
- package/dist/agents/runner-types.js +28 -0
- package/dist/aun/aid/store.js +1 -1
- package/dist/aun/storage/download.js +1 -1
- package/dist/aun/storage/upload.js +13 -1
- package/dist/channels/aun.js +406 -293
- package/dist/channels/dingtalk.js +77 -140
- package/dist/channels/feishu.js +97 -150
- package/dist/channels/qqbot.js +75 -138
- package/dist/channels/wechat.js +75 -136
- package/dist/channels/wecom.js +75 -138
- package/dist/cli/agent.js +8 -5
- package/dist/cli/index.js +177 -44
- package/dist/cli/init.js +33 -6
- package/dist/cli/model.js +1 -1
- package/dist/cli/stats.js +558 -0
- package/dist/cli/version.js +87 -0
- package/dist/cli/watch-msg.js +5 -2
- package/dist/config-store.js +12 -6
- package/dist/core/channel-loader.js +84 -82
- package/dist/core/command-handler.js +473 -114
- package/dist/core/evolagent-registry.js +1 -0
- package/dist/core/evolagent.js +1 -1
- package/dist/core/interaction-router.js +8 -0
- package/dist/core/message/command-handler-agent-control.js +63 -1
- package/dist/core/message/im-renderer.js +35 -13
- package/dist/core/message/items-formatter.js +9 -1
- package/dist/core/message/message-bridge.js +49 -21
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-processor.js +295 -35
- package/dist/core/message/message-queue.js +2 -2
- package/dist/core/message/pending-hints.js +232 -0
- package/dist/core/message/response-depth.js +56 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-scope.js +2 -2
- package/dist/core/permission.js +9 -12
- package/dist/core/relation/peer-identity.js +16 -1
- package/dist/core/session/adapters/codex-session-file-adapter.js +4 -2
- package/dist/core/session/session-manager.js +27 -13
- package/dist/core/session/session-title.js +26 -0
- package/dist/core/stats/billing.js +151 -0
- package/dist/core/stats/budget.js +93 -0
- package/dist/core/stats/db.js +314 -0
- package/dist/core/stats/eck-vars.js +84 -0
- package/dist/core/stats/index.js +10 -0
- package/dist/core/stats/normalizer.js +78 -0
- package/dist/core/stats/query.js +760 -0
- package/dist/core/stats/writer.js +115 -0
- package/dist/core/trigger/manager.js +34 -0
- package/dist/core/trigger/parser.js +9 -3
- package/dist/core/trigger/scheduler.js +20 -17
- package/dist/{agents → eck}/manifest-engine.js +20 -1
- package/dist/{agents → eck}/message-renderer.js +24 -1
- package/dist/index.js +130 -8
- package/dist/ipc.js +17 -1
- package/dist/utils/cross-platform.js +23 -5
- package/dist/utils/ecweb-pair.js +20 -0
- package/dist/utils/stats.js +14 -0
- package/kits/docs/evolclaw/INDEX.md +3 -1
- package/kits/docs/evolclaw/fs-architecture.md +1215 -0
- package/kits/docs/evolclaw/fs.md +131 -0
- package/kits/docs/evolclaw/group-fs.md +209 -0
- package/kits/docs/evolclaw/stats.md +70 -0
- package/kits/docs/venues/aun-group.md +29 -6
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +12 -0
- package/kits/eck_message_manifest.json +30 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/templates/message-fragments/inject-default.md +2 -0
- package/kits/templates/system-fragments/response-depth.md +16 -0
- package/package.json +4 -4
- package/dist/agents/baseagent-normalize.js +0 -19
- package/dist/core/relation/peer-key.js +0 -16
- package/dist/evolclaw-config.js +0 -11
- package/dist/utils/channel-helpers.js +0 -46
- /package/dist/core/{cache/file-cache.js → daemon-file-cache.js} +0 -0
- /package/dist/{agents → eck}/kit-renderer.js +0 -0
package/dist/core/evolagent.js
CHANGED
|
@@ -3,7 +3,7 @@ import { logger } from '../utils/logger.js';
|
|
|
3
3
|
import { saveAgent } from '../config-store.js';
|
|
4
4
|
import { formatChannelKey, tryParseChannelKey } from './channel-loader.js';
|
|
5
5
|
import { agentPersonalDir } from '../paths.js';
|
|
6
|
-
import { fileCache } from './
|
|
6
|
+
import { fileCache } from './daemon-file-cache.js';
|
|
7
7
|
/**
|
|
8
8
|
* EvolAgent —— 一个 self-agent 的运行时表示。
|
|
9
9
|
*
|
|
@@ -68,6 +68,14 @@ export class InteractionRouter {
|
|
|
68
68
|
const handler = this.handlers.get(response.id);
|
|
69
69
|
if (!handler)
|
|
70
70
|
return false;
|
|
71
|
+
// Initiator 校验(集中式 backstop):非发起者的操作直接丢弃,不消费 handler、不解除等待,
|
|
72
|
+
// 让真正的发起者仍可继续操作。身份只信渠道传入的已认证 operatorId(来自消息信封,非 payload 自报)。
|
|
73
|
+
// 渠道层若已自行校验(如飞书的 reject toast),此处不会重复命中(operatorId 已匹配)。
|
|
74
|
+
if (handler.initiatorId && response.operatorId
|
|
75
|
+
&& response.operatorId !== handler.initiatorId) {
|
|
76
|
+
logger.info(`[InteractionRouter] rejected non-initiator: operator=${response.operatorId} initiator=${handler.initiatorId} id=${response.id}`);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
71
79
|
if (handler.timer)
|
|
72
80
|
clearTimeout(handler.timer);
|
|
73
81
|
this.handlers.delete(response.id);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { agentCreateNonInteractive, agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, } from '../../cli/agent.js';
|
|
1
|
+
import { agentCreateNonInteractive, agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, agentReload, } from '../../cli/agent.js';
|
|
2
2
|
import { logger } from '../../utils/logger.js';
|
|
3
3
|
import { resolvePaths } from '../../paths.js';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import { loadAgent, saveAgent } from '../../config-store.js';
|
|
5
6
|
import { CreateStatusWriter, readCreateStatus } from './create-status.js';
|
|
6
7
|
/** 把 cli/agent.ts 的 error 字符串映射为结构化错误码 */
|
|
7
8
|
function classifyError(error) {
|
|
@@ -116,8 +117,69 @@ export async function execAgentAction(action, args, peerId) {
|
|
|
116
117
|
return { error: res.error, code: classifyError(res.error) };
|
|
117
118
|
return { data: { aid: res.aid, enabled: res.enabled, reloaded: res.reloaded } };
|
|
118
119
|
}
|
|
120
|
+
if (action === 'reload') {
|
|
121
|
+
if (!a.aid)
|
|
122
|
+
return { error: '缺少 aid', code: 'INVALID_ARGS' };
|
|
123
|
+
const res = await agentReload(a.aid);
|
|
124
|
+
if (!('ok' in res) || res.ok !== true)
|
|
125
|
+
return { error: res.error, code: classifyError(res.error) };
|
|
126
|
+
return { data: { aid: a.aid, reloaded: true } };
|
|
127
|
+
}
|
|
128
|
+
if (action === 'update') {
|
|
129
|
+
return await execAgentUpdate(a);
|
|
130
|
+
}
|
|
119
131
|
return { error: `不支持的 action: ${action}`, code: 'INVALID_ARGS' };
|
|
120
132
|
}
|
|
133
|
+
/** name=agent 的 menu.action=update:仅落盘 config patch,不触发 reload。
|
|
134
|
+
* 直接 loadAgent + saveAgent(不走 agentSet,避免其内部自动 evolagent.reload)——
|
|
135
|
+
* 重载由用户在 Agents 页操作列手动触发(带任务执行检查)。
|
|
136
|
+
* AUN 渠道绑定 agent 顶层 aid,不可通过 patch 编辑:拒绝改 aid、拒绝 channels 数组里出现 aun 条目。
|
|
137
|
+
* 可写字段:baseagents / projects / owners / chatmode / channels(非 aun)。 */
|
|
138
|
+
export async function execAgentUpdate(args) {
|
|
139
|
+
const a = args ?? {};
|
|
140
|
+
if (!a.aid)
|
|
141
|
+
return { error: '缺少 aid', code: 'INVALID_ARGS' };
|
|
142
|
+
const p = a.patch ?? {};
|
|
143
|
+
if (p.aid !== undefined) {
|
|
144
|
+
return { error: 'aid 不可修改(AUN 身份绑定,如需换 AID 请删除后重建)', code: 'INVALID_ARGS' };
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(p.channels) && p.channels.some((c) => c?.type === 'aun')) {
|
|
147
|
+
return { error: 'AUN 渠道不可通过 patch 编辑(由 agent aid 隐式管理)', code: 'INVALID_ARGS' };
|
|
148
|
+
}
|
|
149
|
+
const config = loadAgent(a.aid);
|
|
150
|
+
if (!config)
|
|
151
|
+
return { error: `Agent "${a.aid}" not found`, code: 'NOT_FOUND' };
|
|
152
|
+
let touched = false;
|
|
153
|
+
if (p.baseagents !== undefined) {
|
|
154
|
+
config.baseagents = p.baseagents;
|
|
155
|
+
touched = true;
|
|
156
|
+
}
|
|
157
|
+
if (p.projects !== undefined) {
|
|
158
|
+
config.projects = p.projects;
|
|
159
|
+
touched = true;
|
|
160
|
+
}
|
|
161
|
+
if (p.owners !== undefined) {
|
|
162
|
+
config.owners = p.owners;
|
|
163
|
+
touched = true;
|
|
164
|
+
}
|
|
165
|
+
if (p.chatmode !== undefined) {
|
|
166
|
+
config.chatmode = p.chatmode;
|
|
167
|
+
touched = true;
|
|
168
|
+
}
|
|
169
|
+
if (p.channels !== undefined) {
|
|
170
|
+
config.channels = p.channels;
|
|
171
|
+
touched = true;
|
|
172
|
+
}
|
|
173
|
+
if (!touched)
|
|
174
|
+
return { error: 'patch 为空,无可写字段', code: 'INVALID_ARGS' };
|
|
175
|
+
try {
|
|
176
|
+
saveAgent(config);
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
return { error: e?.message || String(e), code: classifyError(e?.message || String(e)) };
|
|
180
|
+
}
|
|
181
|
+
return { data: { aid: a.aid, saved: true } };
|
|
182
|
+
}
|
|
121
183
|
/** project 兜底:显式值 > rootPath 合成 > defaultPath > undefined */
|
|
122
184
|
export function resolveProjectPath(explicit, aid, defaults) {
|
|
123
185
|
if (explicit && explicit.trim())
|
|
@@ -308,21 +308,24 @@ export class IMRenderer {
|
|
|
308
308
|
clearTimeout(this.timer);
|
|
309
309
|
this.timer = undefined;
|
|
310
310
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
item.text = stripCtxErr(item.text);
|
|
319
|
-
}
|
|
320
|
-
// 文件标记过滤
|
|
321
|
-
if (this.opts.fileMarkerPattern) {
|
|
322
|
-
this.textBuffer = this.textBuffer.replace(this.opts.fileMarkerPattern, '').trim();
|
|
311
|
+
if (isFinal) {
|
|
312
|
+
// 上下文错误短语过滤:剔除错误关键词本身,保留前后内容。
|
|
313
|
+
// 只在最终 flush 清理,避免中间定时 flush trim 掉 Markdown 块级换行。
|
|
314
|
+
const ctxErrPattern = /prompt is too long|input is too long|context too long|context limit|context_length_exceeded|上下文过长/gi;
|
|
315
|
+
const stripCtxErr = (s) => s.replace(ctxErrPattern, '').trim();
|
|
316
|
+
this.textBuffer = stripCtxErr(this.textBuffer);
|
|
317
|
+
this.allText = stripCtxErr(this.allText);
|
|
323
318
|
for (const item of this.itemsQueue) {
|
|
324
319
|
if (item.kind === 'text')
|
|
325
|
-
item.text = item.text
|
|
320
|
+
item.text = stripCtxErr(item.text);
|
|
321
|
+
}
|
|
322
|
+
// 文件标记过滤
|
|
323
|
+
if (this.opts.fileMarkerPattern) {
|
|
324
|
+
this.textBuffer = this.textBuffer.replace(this.opts.fileMarkerPattern, '').trim();
|
|
325
|
+
for (const item of this.itemsQueue) {
|
|
326
|
+
if (item.kind === 'text')
|
|
327
|
+
item.text = item.text.replace(this.opts.fileMarkerPattern, '');
|
|
328
|
+
}
|
|
326
329
|
}
|
|
327
330
|
}
|
|
328
331
|
// 清掉空 text items
|
|
@@ -356,6 +359,25 @@ export class IMRenderer {
|
|
|
356
359
|
this.lastFlush = Date.now();
|
|
357
360
|
this.flushCount++;
|
|
358
361
|
}
|
|
362
|
+
// 1.5 非最终定时 flush:把已累积的文本块作为独立 result.text 发出。
|
|
363
|
+
// 每个 text 事件本身是完整语义块(runner 已合并流式 delta),工具调用前的
|
|
364
|
+
// 文本一向作为独立气泡发送(见 message-processor 的 flushText 调用)。
|
|
365
|
+
// 这里补上「文本块后面没有紧跟 tool_use」的情况——例如 readonly 拒绝写文件时
|
|
366
|
+
// SDK 直接拒绝、不产生 tool_use 事件,文本会一直滞留 buffer,直到下一个
|
|
367
|
+
// tool_use 才被 flushText 带出,并与其后的文本合并成一条(用户侧表现为:
|
|
368
|
+
// 第一条文本等待一分多钟后才和第二条凑成一条发出)。定时器到期即发,根除滞留。
|
|
369
|
+
if (!isFinal && this.textBuffer.length > 0) {
|
|
370
|
+
const text = this.textBuffer;
|
|
371
|
+
this.textBuffer = '';
|
|
372
|
+
const payload = { kind: 'result.text', text, isFinal: false };
|
|
373
|
+
this.sentContent = true;
|
|
374
|
+
this.sendChain = this.sendChain
|
|
375
|
+
.then(() => this.opts.send(payload))
|
|
376
|
+
.catch(e => logger.warn('[IMRenderer] timed result.text send failed:', e));
|
|
377
|
+
await this.sendChain;
|
|
378
|
+
this.lastFlush = Date.now();
|
|
379
|
+
this.flushCount++;
|
|
380
|
+
}
|
|
359
381
|
// 2. isFinal=true 时单独发最终回复文本
|
|
360
382
|
if (isFinal && finalText.length > 0) {
|
|
361
383
|
const payload = { kind: 'result.text', text: finalText, isFinal: true };
|
|
@@ -34,7 +34,7 @@ function formatItem(item) {
|
|
|
34
34
|
case 'tool_result': {
|
|
35
35
|
if (!item.ok) {
|
|
36
36
|
const errMsg = item.error || (typeof item.result === 'string' ? item.result : '执行失败');
|
|
37
|
-
return `⚠️ ${item.name}: ${errMsg}`;
|
|
37
|
+
return `⚠️ ${item.name}: ${capLines(errMsg, 5)}`;
|
|
38
38
|
}
|
|
39
39
|
return item.text ? `✓ ${item.name}: ${item.text}` : `✓ ${item.name}`;
|
|
40
40
|
}
|
|
@@ -48,6 +48,14 @@ function formatItem(item) {
|
|
|
48
48
|
return '';
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
/** 把多行文本截断到最多 maxLines 行,超出部分用省略提示替代。用于工具报错输出,避免刷屏。 */
|
|
52
|
+
function capLines(text, maxLines) {
|
|
53
|
+
const lines = text.split('\n');
|
|
54
|
+
if (lines.length <= maxLines)
|
|
55
|
+
return text;
|
|
56
|
+
const omitted = lines.length - maxLines;
|
|
57
|
+
return lines.slice(0, maxLines).join('\n') + `\n…(省略 ${omitted} 行)`;
|
|
58
|
+
}
|
|
51
59
|
function summarizeArgs(args) {
|
|
52
60
|
if (!args || typeof args !== 'object')
|
|
53
61
|
return '';
|
|
@@ -109,6 +109,10 @@ export class MessageBridge {
|
|
|
109
109
|
return;
|
|
110
110
|
// 3. session 解析(使用 Channel 层填充的 chatType)
|
|
111
111
|
const chatType = msg.chatType || 'private';
|
|
112
|
+
if (!(await this.canCreateThreadSession(channelName, msg, chatType))) {
|
|
113
|
+
await sendReply(msg.channelId, '群聊中无权限创建话题', msg.replyContext);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
112
116
|
const metadata = {};
|
|
113
117
|
// 话题会话创建时写入 replyContext(用于 threadId 路由);主会话不写(避免群聊覆盖)
|
|
114
118
|
if (msg.threadId && msg.replyContext)
|
|
@@ -134,7 +138,7 @@ export class MessageBridge {
|
|
|
134
138
|
const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
|
|
135
139
|
const effectiveProjectPath = owningAgent?.projectPath
|
|
136
140
|
?? this.defaultProjectPath;
|
|
137
|
-
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined,
|
|
141
|
+
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, this.extractTopicName(msg), msg.peerId, chatType, undefined, msg.selfAID, msg.channelType || effectiveChannelType, msg.peerType);
|
|
138
142
|
// 4. 群聊发送者标注由消息渲染层(message-renderer)逐条承担,不再在此硬编码前缀,
|
|
139
143
|
// 消息日志因此保存干净原文。policy.messagePrefix 暂保留(未来清理)。
|
|
140
144
|
// 5. 构造完整消息(channel 字段存实例名,用于 session 精确匹配)
|
|
@@ -143,6 +147,7 @@ export class MessageBridge {
|
|
|
143
147
|
channelType: msg.channelType || effectiveChannelType,
|
|
144
148
|
channelId: msg.channelId, content,
|
|
145
149
|
selfAID: msg.selfAID,
|
|
150
|
+
agentId: session.agentId,
|
|
146
151
|
chatType,
|
|
147
152
|
images: msg.images, timestamp: Date.now(),
|
|
148
153
|
peerId: msg.peerId, peerName: msg.peerName,
|
|
@@ -152,25 +157,30 @@ export class MessageBridge {
|
|
|
152
157
|
sameEgressIp: msg.sameEgressIp,
|
|
153
158
|
messageId: msg.messageId,
|
|
154
159
|
mentions: msg.mentions, mentionAids: msg.mentionAids, threadId: msg.threadId,
|
|
160
|
+
topicName: this.extractTopicName(msg),
|
|
155
161
|
replyContext: msg.replyContext,
|
|
162
|
+
source: msg.source,
|
|
163
|
+
dispatchMode: msg.dispatchMode,
|
|
156
164
|
};
|
|
157
|
-
// 5.5
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
165
|
+
// 5.5 写入消息记录(入方向)。
|
|
166
|
+
{
|
|
167
|
+
const chatDir = this.sessionManager.getChatDir(session);
|
|
168
|
+
const inboundEncrypt = msg.replyContext?.metadata?.encrypted != null ? !!(msg.replyContext.metadata.encrypted) : undefined;
|
|
169
|
+
const inboundChatmode = msg.replyContext?.metadata?.chatmode;
|
|
170
|
+
appendMessageLog(chatDir, buildInboundEntry({
|
|
171
|
+
from: msg.peerId || 'unknown',
|
|
172
|
+
to: msg.selfAID || 'self',
|
|
173
|
+
chatType,
|
|
174
|
+
groupId: msg.groupId ?? null,
|
|
175
|
+
msgId: msg.messageId ?? null,
|
|
176
|
+
content,
|
|
177
|
+
replyTo: msg.replyContext?.replyToMessageId ?? null,
|
|
178
|
+
permMode: session.identity?.role ?? null,
|
|
179
|
+
timestamp: fullMessage.timestamp,
|
|
180
|
+
encrypt: inboundEncrypt,
|
|
181
|
+
chatmode: inboundChatmode,
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
174
184
|
// 6. ACK + debounce/enqueue
|
|
175
185
|
// ACK 在到达时立即做(每条独立 ACK),不等合并
|
|
176
186
|
// Interrupt 模式(单聊)→ 入队前 debounce 合并
|
|
@@ -209,6 +219,7 @@ export class MessageBridge {
|
|
|
209
219
|
static MENU_NAME_MAP = {
|
|
210
220
|
pwd: '/pwd',
|
|
211
221
|
session: '/session',
|
|
222
|
+
topic: '/topic',
|
|
212
223
|
baseagent: '/baseagent',
|
|
213
224
|
model: '/model',
|
|
214
225
|
effort: '/effort',
|
|
@@ -221,6 +232,23 @@ export class MessageBridge {
|
|
|
221
232
|
agent: '/agent',
|
|
222
233
|
trigger: '/trigger',
|
|
223
234
|
};
|
|
235
|
+
extractTopicName(msg) {
|
|
236
|
+
const raw = msg.topicName
|
|
237
|
+
?? msg.replyContext?.title
|
|
238
|
+
?? msg.replyContext?.metadata?.topicName
|
|
239
|
+
?? msg.replyContext?.metadata?.title;
|
|
240
|
+
const name = typeof raw === 'string' ? raw.trim() : '';
|
|
241
|
+
return name || undefined;
|
|
242
|
+
}
|
|
243
|
+
async canCreateThreadSession(channel, msg, chatType) {
|
|
244
|
+
if (chatType !== 'group' || !msg.threadId)
|
|
245
|
+
return true;
|
|
246
|
+
const existing = await this.sessionManager.getThreadSession(channel, msg.channelId, msg.threadId);
|
|
247
|
+
if (existing)
|
|
248
|
+
return true;
|
|
249
|
+
const role = this.sessionManager.resolveIdentity(channel, msg.peerId).role;
|
|
250
|
+
return role === 'owner' || role === 'admin';
|
|
251
|
+
}
|
|
224
252
|
resolveCmd(name, cmd) {
|
|
225
253
|
if (cmd)
|
|
226
254
|
return cmd;
|
|
@@ -278,7 +306,7 @@ export class MessageBridge {
|
|
|
278
306
|
const { id, name, cmd } = req;
|
|
279
307
|
try {
|
|
280
308
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
281
|
-
const result = await this.cmdHandler.execMenuQuery(resolvedCmd, channel, msg.channelId, msg.peerId, req.args);
|
|
309
|
+
const result = await this.cmdHandler.execMenuQuery(resolvedCmd, channel, msg.channelId, msg.peerId, req.args, msg.chatType);
|
|
282
310
|
if ('error' in result)
|
|
283
311
|
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
284
312
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|
|
@@ -294,7 +322,7 @@ export class MessageBridge {
|
|
|
294
322
|
const { id, name, cmd } = req;
|
|
295
323
|
try {
|
|
296
324
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
297
|
-
const data = await this.cmdHandler.getSubMenuItems(resolvedCmd, channel, msg.channelId, msg.peerId, req.args) ?? [];
|
|
325
|
+
const data = await this.cmdHandler.getSubMenuItems(resolvedCmd, channel, msg.channelId, msg.peerId, req.args, undefined, msg.chatType) ?? [];
|
|
298
326
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data }, sendReply);
|
|
299
327
|
}
|
|
300
328
|
catch (err) {
|
|
@@ -328,7 +356,7 @@ export class MessageBridge {
|
|
|
328
356
|
if (!action)
|
|
329
357
|
throw { code: 'MISSING_VALUE', message: '缺少 action 参数' };
|
|
330
358
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
331
|
-
const result = await this.cmdHandler.execMenuAction(resolvedCmd, action, args, channel, msg.channelId, msg.peerId);
|
|
359
|
+
const result = await this.cmdHandler.execMenuAction(resolvedCmd, action, args, channel, msg.channelId, msg.peerId, undefined, msg.chatType);
|
|
332
360
|
if ('error' in result)
|
|
333
361
|
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
334
362
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|