evolclaw 3.1.2 → 3.1.3
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 +21 -0
- package/README.md +2 -6
- package/dist/agents/claude-runner.js +1 -1
- package/dist/agents/codex-runner.js +75 -19
- package/dist/agents/gemini-runner.js +0 -2
- package/dist/agents/kit-renderer.js +59 -10
- package/dist/aun/aid/agentmd.js +49 -27
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/rpc/connection.js +3 -0
- package/dist/channels/aun.js +67 -14
- package/dist/cli/agent.js +13 -6
- package/dist/cli/index.js +27 -37
- package/dist/cli/init.js +13 -6
- package/dist/core/command-handler.js +615 -534
- package/dist/core/evolagent.js +31 -0
- package/dist/core/message/im-renderer.js +10 -0
- package/dist/core/message/message-bridge.js +123 -24
- package/dist/core/message/message-processor.js +43 -14
- package/dist/core/session/session-manager.js +185 -42
- package/kits/eck_manifest.json +3 -3
- package/kits/rules/02-navigation.md +1 -0
- package/kits/rules/06-channel.md +2 -18
- package/kits/templates/system-fragments/baseagent.md +2 -2
- package/kits/templates/system-fragments/channel.md +18 -9
- package/kits/templates/system-fragments/eckruntime.md +14 -0
- package/kits/templates/system-fragments/identity.md +5 -6
- package/kits/templates/system-fragments/relation.md +7 -5
- package/kits/templates/system-fragments/venue.md +2 -3
- package/package.json +1 -1
- package/kits/templates/system-fragments/runtime.md +0 -19
package/dist/core/evolagent.js
CHANGED
|
@@ -159,6 +159,15 @@ export class EvolAgent {
|
|
|
159
159
|
this.persist();
|
|
160
160
|
}
|
|
161
161
|
// ── Baseagent 字段写入 ────────────────────────────────────────────────
|
|
162
|
+
/** 切换当前活跃 baseagent(写顶层 active_baseagent)。 */
|
|
163
|
+
setActiveBaseagent(value) {
|
|
164
|
+
if (value === undefined)
|
|
165
|
+
delete this.rawAgent.active_baseagent;
|
|
166
|
+
else
|
|
167
|
+
this.rawAgent.active_baseagent = value;
|
|
168
|
+
this.merged.active_baseagent = value;
|
|
169
|
+
this.persist();
|
|
170
|
+
}
|
|
162
171
|
setBaseagentModel(value) {
|
|
163
172
|
const ba = this.baseagent;
|
|
164
173
|
if (!this.rawAgent.baseagents)
|
|
@@ -182,6 +191,28 @@ export class EvolAgent {
|
|
|
182
191
|
block[fieldName] = value;
|
|
183
192
|
this.persist();
|
|
184
193
|
}
|
|
194
|
+
/** 设置私聊 chatmode(群聊/非 human 强制 proactive,无可写入项)。 */
|
|
195
|
+
setChatmodePrivate(value) {
|
|
196
|
+
if (!this.rawAgent.chatmode)
|
|
197
|
+
this.rawAgent.chatmode = {};
|
|
198
|
+
if (value === undefined)
|
|
199
|
+
delete this.rawAgent.chatmode.private;
|
|
200
|
+
else
|
|
201
|
+
this.rawAgent.chatmode.private = value;
|
|
202
|
+
if (!this.merged.chatmode)
|
|
203
|
+
this.merged.chatmode = {};
|
|
204
|
+
this.merged.chatmode.private = value;
|
|
205
|
+
this.persist();
|
|
206
|
+
}
|
|
207
|
+
/** 设置群聊 dispatch 默认值(mention | broadcast)。 */
|
|
208
|
+
setDispatch(value) {
|
|
209
|
+
if (value === undefined)
|
|
210
|
+
delete this.rawAgent.dispatch;
|
|
211
|
+
else
|
|
212
|
+
this.rawAgent.dispatch = value;
|
|
213
|
+
this.merged.dispatch = value;
|
|
214
|
+
this.persist();
|
|
215
|
+
}
|
|
185
216
|
// ── Projects ──────────────────────────────────────────────────────────
|
|
186
217
|
getProjects() {
|
|
187
218
|
const list = this.merged.projects?.list;
|
|
@@ -142,6 +142,16 @@ export class IMRenderer {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
/** 清除上下文过长错误文本(从 buffer + allText 中移除) */
|
|
146
|
+
stripContextError(pattern) {
|
|
147
|
+
this.textBuffer = this.textBuffer.replace(pattern, '').trim();
|
|
148
|
+
this.allText = this.allText.replace(pattern, '').trim();
|
|
149
|
+
for (const item of this.itemsQueue) {
|
|
150
|
+
if (item.kind === 'text') {
|
|
151
|
+
item.text = item.text.replace(pattern, '');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
145
155
|
// ── 文本/活动注入(替代 StreamFlusher.addText/addActivity)──
|
|
146
156
|
/** 添加文本片段(流式 text) */
|
|
147
157
|
addText(text, outputTokens, turn) {
|
|
@@ -207,7 +207,28 @@ export class MessageBridge {
|
|
|
207
207
|
}
|
|
208
208
|
});
|
|
209
209
|
}
|
|
210
|
-
|
|
210
|
+
// ── Menu Protocol ──
|
|
211
|
+
static MENU_NAME_MAP = {
|
|
212
|
+
pwd: '/pwd',
|
|
213
|
+
session: '/session',
|
|
214
|
+
baseagent: '/baseagent',
|
|
215
|
+
model: '/model',
|
|
216
|
+
effort: '/effort',
|
|
217
|
+
chatmode: '/chatmode',
|
|
218
|
+
dispatch: '/dispatch',
|
|
219
|
+
permission: '/perm',
|
|
220
|
+
activity: '/activity',
|
|
221
|
+
system: '/system',
|
|
222
|
+
};
|
|
223
|
+
resolveCmd(name, cmd) {
|
|
224
|
+
if (cmd)
|
|
225
|
+
return cmd;
|
|
226
|
+
const mapped = MessageBridge.MENU_NAME_MAP[name];
|
|
227
|
+
if (!mapped)
|
|
228
|
+
throw { code: 'UNKNOWN_NAME', message: `未知操作: ${name}` };
|
|
229
|
+
return mapped;
|
|
230
|
+
}
|
|
231
|
+
/** 自定义消息快速路径:拦截 menu.* 协议 */
|
|
211
232
|
async handleCustomPayload(content, channel, msg, sendReply, adapter) {
|
|
212
233
|
let parsed;
|
|
213
234
|
try {
|
|
@@ -218,30 +239,108 @@ export class MessageBridge {
|
|
|
218
239
|
}
|
|
219
240
|
if (!parsed || typeof parsed !== 'object' || !parsed.type)
|
|
220
241
|
return false;
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
switch (parsed.type) {
|
|
243
|
+
case 'menu.list':
|
|
244
|
+
await this.handleMenuList(parsed, channel, msg, adapter, sendReply);
|
|
245
|
+
return true;
|
|
246
|
+
case 'menu.query':
|
|
247
|
+
await this.handleMenuQuery(parsed, channel, msg, adapter, sendReply);
|
|
248
|
+
return true;
|
|
249
|
+
case 'menu.options':
|
|
250
|
+
await this.handleMenuOptions(parsed, channel, msg, adapter, sendReply);
|
|
251
|
+
return true;
|
|
252
|
+
case 'menu.update':
|
|
253
|
+
await this.handleMenuUpdate(parsed, channel, msg, adapter, sendReply);
|
|
254
|
+
return true;
|
|
255
|
+
case 'menu.action':
|
|
256
|
+
await this.handleMenuAction(parsed, channel, msg, adapter, sendReply);
|
|
257
|
+
return true;
|
|
258
|
+
default:
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async handleMenuList(req, channel, msg, adapter, sendReply) {
|
|
263
|
+
const { id } = req;
|
|
264
|
+
try {
|
|
265
|
+
const identity = this.sessionManager.resolveIdentity(channel, msg.peerId);
|
|
266
|
+
const data = this.cmdHandler.getMenuItems(identity.role, msg.chatType || 'private');
|
|
267
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, data }, sendReply);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, {
|
|
271
|
+
type: 'menu.response', id,
|
|
272
|
+
error: { code: err?.code || 'INTERNAL', message: err?.message || String(err) }
|
|
273
|
+
}, sendReply);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async handleMenuQuery(req, channel, msg, adapter, sendReply) {
|
|
277
|
+
const { id, name, cmd } = req;
|
|
278
|
+
try {
|
|
279
|
+
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
280
|
+
const result = await this.cmdHandler.execMenuQuery(resolvedCmd, channel, msg.channelId, msg.peerId);
|
|
281
|
+
if ('error' in result)
|
|
282
|
+
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
283
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, {
|
|
287
|
+
type: 'menu.response', id, name,
|
|
288
|
+
error: { code: err?.code || 'INTERNAL', message: err?.message || String(err) }
|
|
289
|
+
}, sendReply);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async handleMenuOptions(req, channel, msg, adapter, sendReply) {
|
|
293
|
+
const { id, name, cmd } = req;
|
|
294
|
+
try {
|
|
295
|
+
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
296
|
+
const data = await this.cmdHandler.getSubMenuItems(resolvedCmd, channel, msg.channelId, msg.peerId) ?? [];
|
|
297
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data }, sendReply);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, {
|
|
301
|
+
type: 'menu.response', id, name,
|
|
302
|
+
error: { code: err?.code || 'INTERNAL', message: err?.message || String(err) }
|
|
303
|
+
}, sendReply);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async handleMenuUpdate(req, channel, msg, adapter, sendReply) {
|
|
307
|
+
const { id, name, cmd, value } = req;
|
|
308
|
+
try {
|
|
309
|
+
if (!value)
|
|
310
|
+
throw { code: 'MISSING_VALUE', message: '缺少 value 参数' };
|
|
311
|
+
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
312
|
+
const result = await this.cmdHandler.execMenuUpdate(resolvedCmd, value, channel, msg.channelId, msg.peerId);
|
|
313
|
+
if ('error' in result)
|
|
314
|
+
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
315
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, {
|
|
319
|
+
type: 'menu.response', id, name,
|
|
320
|
+
error: { code: err?.code || 'INTERNAL', message: err?.message || String(err) }
|
|
321
|
+
}, sendReply);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async handleMenuAction(req, channel, msg, adapter, sendReply) {
|
|
325
|
+
const { id, name, cmd, action, args } = req;
|
|
326
|
+
try {
|
|
327
|
+
if (!action)
|
|
328
|
+
throw { code: 'MISSING_VALUE', message: '缺少 action 参数' };
|
|
329
|
+
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
330
|
+
const result = await this.cmdHandler.execMenuAction(resolvedCmd, action, args, channel, msg.channelId, msg.peerId);
|
|
331
|
+
if ('error' in result)
|
|
332
|
+
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
333
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|
|
243
334
|
}
|
|
244
|
-
|
|
335
|
+
catch (err) {
|
|
336
|
+
await this.sendMenuResponse(adapter, channel, msg.channelId, {
|
|
337
|
+
type: 'menu.response', id, name,
|
|
338
|
+
error: { code: err?.code || 'INTERNAL', message: err?.message || String(err) }
|
|
339
|
+
}, sendReply);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async sendMenuResponse(adapter, channel, channelId, response, sendReply) {
|
|
343
|
+
await this.sendCustomResponse(adapter, channel, channelId, JSON.stringify(response), sendReply);
|
|
245
344
|
}
|
|
246
345
|
/** menu.query 响应:优先走 adapter.send(custom),降级 sendReply */
|
|
247
346
|
async sendCustomResponse(adapter, channel, channelId, response, sendReply) {
|
|
@@ -12,6 +12,21 @@ import { getPackageRoot, resolveRoot } from '../../paths.js';
|
|
|
12
12
|
import { renderKitSections } from '../../agents/kit-renderer.js';
|
|
13
13
|
import { normalizeBaseagent } from '../../agents/baseagent-normalize.js';
|
|
14
14
|
import { renderActionAsText, renderCommandCardAsText } from '../interaction-router.js';
|
|
15
|
+
function getContextTooLongHint(agent) {
|
|
16
|
+
if (canCompactAgent(agent)) {
|
|
17
|
+
return '上下文过长,请精简提问或使用 /compact 压缩上下文';
|
|
18
|
+
}
|
|
19
|
+
return '上下文过长,请精简提问,或使用 /new 新建会话后继续';
|
|
20
|
+
}
|
|
21
|
+
function getContextCompactFailedHint(agent) {
|
|
22
|
+
if (canCompactAgent(agent)) {
|
|
23
|
+
return '上下文过长,自动压缩失败,请手动输入 /compact 重试';
|
|
24
|
+
}
|
|
25
|
+
return '上下文过长,请精简提问,或使用 /new 新建会话后继续';
|
|
26
|
+
}
|
|
27
|
+
function canCompactAgent(agent) {
|
|
28
|
+
return hasCompact(agent) && agent.capabilities?.compact !== false;
|
|
29
|
+
}
|
|
15
30
|
/**
|
|
16
31
|
* 构造 OutboundEnvelope —— 出站三件套的信封部分。
|
|
17
32
|
*
|
|
@@ -183,7 +198,7 @@ export class MessageProcessor {
|
|
|
183
198
|
'/model', '/effort', '/agent', '/slist', '/session', '/rename', '/repair', '/fork',
|
|
184
199
|
'/stop', '/clear', '/compact', '/safe', '/del', '/perm', '/file', '/check',
|
|
185
200
|
'/p ', '/s ', '/name ', '/rewind', '/rw', '/rw ', '/activity', '/chatmode',
|
|
186
|
-
'/aid', '/
|
|
201
|
+
'/aid', '/upgrade', '/evolagent',
|
|
187
202
|
];
|
|
188
203
|
/** 判断消息内容是否为已知命令 */
|
|
189
204
|
isKnownCommand(content) {
|
|
@@ -549,7 +564,7 @@ export class MessageProcessor {
|
|
|
549
564
|
venueUid: undefined,
|
|
550
565
|
project: path.basename(absoluteProjectPath),
|
|
551
566
|
sessionName: session.name || undefined,
|
|
552
|
-
|
|
567
|
+
chatmode: isProactive ? 'proactive' : 'interactive',
|
|
553
568
|
readonly: session.metadata?.permissionMode === 'readonly',
|
|
554
569
|
canSendFile: !isProactive && currentCanSend,
|
|
555
570
|
capabilities: capParts.length > 0 ? capParts.join('、') : undefined,
|
|
@@ -571,7 +586,7 @@ export class MessageProcessor {
|
|
|
571
586
|
const stream = await agent.runQuery(session.id, effectivePrompt, absoluteProjectPath, session.agentSessionId, message.images, effectiveSystemPrompt, this.sessionManager);
|
|
572
587
|
agent.registerStream(streamKey, stream);
|
|
573
588
|
streamRegistered = true;
|
|
574
|
-
streamResult = await this.processEventStream(stream, session, renderer, resetTimer, shouldSuppress);
|
|
589
|
+
streamResult = await this.processEventStream(stream, session, agent, renderer, resetTimer, shouldSuppress);
|
|
575
590
|
break; // 成功,跳出重试循环
|
|
576
591
|
}
|
|
577
592
|
catch (retryError) {
|
|
@@ -591,7 +606,7 @@ export class MessageProcessor {
|
|
|
591
606
|
}
|
|
592
607
|
}
|
|
593
608
|
catch (error) {
|
|
594
|
-
if (classifyError(error) === ErrorType.CONTEXT_TOO_LONG && session.agentSessionId &&
|
|
609
|
+
if (classifyError(error) === ErrorType.CONTEXT_TOO_LONG && session.agentSessionId && canCompactAgent(agent)) {
|
|
595
610
|
// 尝试 compact 压缩会话
|
|
596
611
|
renderer.addNotice('上下文过长,正在压缩会话...', 'warn', 'compact-trigger', true);
|
|
597
612
|
await renderer.flush();
|
|
@@ -601,7 +616,7 @@ export class MessageProcessor {
|
|
|
601
616
|
renderer.addNotice('✅ 压缩完成,继续处理...', 'info', 'compact-retry', true);
|
|
602
617
|
const retryStream = await agent.runQuery(session.id, '上下文已自动压缩,请继续之前未完成的任务。', absoluteProjectPath, session.agentSessionId, undefined, effectiveSystemPrompt, this.sessionManager);
|
|
603
618
|
agent.registerStream(streamKey, retryStream);
|
|
604
|
-
streamResult = await this.processEventStream(retryStream, session, renderer, resetTimer, shouldSuppress);
|
|
619
|
+
streamResult = await this.processEventStream(retryStream, session, agent, renderer, resetTimer, shouldSuppress);
|
|
605
620
|
}
|
|
606
621
|
else {
|
|
607
622
|
throw new Error('CONTEXT_COMPACT_FAILED');
|
|
@@ -615,7 +630,7 @@ export class MessageProcessor {
|
|
|
615
630
|
// 检测条件:terminalReason 明确为 prompt_too_long,或文本/errors 包含相关错误文本
|
|
616
631
|
const contextTooLongPattern = /prompt is too long|input is too long|上下文过长/i;
|
|
617
632
|
const errorsText = streamResult.errors?.join(' ') || '';
|
|
618
|
-
const isPromptTooLong = streamResult.isError && session.agentSessionId &&
|
|
633
|
+
const isPromptTooLong = streamResult.isError && session.agentSessionId && canCompactAgent(agent) && (streamResult.terminalReason === 'prompt_too_long' ||
|
|
619
634
|
contextTooLongPattern.test(streamResult.lastReplyText) ||
|
|
620
635
|
contextTooLongPattern.test(errorsText) ||
|
|
621
636
|
contextTooLongPattern.test(streamResult.fullText));
|
|
@@ -627,7 +642,17 @@ export class MessageProcessor {
|
|
|
627
642
|
renderer.addNotice('✅ 压缩完成,继续处理...', 'info', 'compact-retry', true);
|
|
628
643
|
const retryStream = await agent.runQuery(session.id, '上下文已自动压缩,请继续之前未完成的任务。', absoluteProjectPath, session.agentSessionId, undefined, effectiveSystemPrompt, this.sessionManager);
|
|
629
644
|
agent.registerStream(streamKey, retryStream);
|
|
630
|
-
streamResult = await this.processEventStream(retryStream, session, renderer, resetTimer, shouldSuppress);
|
|
645
|
+
streamResult = await this.processEventStream(retryStream, session, agent, renderer, resetTimer, shouldSuppress);
|
|
646
|
+
// 重试后仍然 prompt_too_long:清理 renderer 中可能混入的错误文本,显示友好提示
|
|
647
|
+
const retryErrorsText = streamResult.errors?.join(' ') || '';
|
|
648
|
+
const retryStillTooLong = streamResult.isError && (streamResult.terminalReason === 'prompt_too_long' ||
|
|
649
|
+
contextTooLongPattern.test(streamResult.lastReplyText) ||
|
|
650
|
+
contextTooLongPattern.test(retryErrorsText) ||
|
|
651
|
+
contextTooLongPattern.test(streamResult.fullText));
|
|
652
|
+
if (retryStillTooLong) {
|
|
653
|
+
renderer.stripContextError(contextTooLongPattern);
|
|
654
|
+
renderer.addNotice(getContextTooLongHint(agent), 'warn', 'context-too-long', true);
|
|
655
|
+
}
|
|
631
656
|
}
|
|
632
657
|
else {
|
|
633
658
|
throw new Error('CONTEXT_COMPACT_FAILED');
|
|
@@ -638,7 +663,7 @@ export class MessageProcessor {
|
|
|
638
663
|
contextTooLongPattern.test(errorsText) ||
|
|
639
664
|
contextTooLongPattern.test(streamResult.fullText))) {
|
|
640
665
|
// 上下文过长但无法 auto-compact(无 session ID 或 agent 不支持),显示友好提示
|
|
641
|
-
renderer.addNotice(
|
|
666
|
+
renderer.addNotice(getContextTooLongHint(agent), 'warn', 'context-too-long', true);
|
|
642
667
|
}
|
|
643
668
|
// 处理文件标记 - 支持 [SEND_FILE:path] 和 [SEND_FILE:channel:path]
|
|
644
669
|
// 注意:始终扫描全部文本(含中间轮),因为文件标记可能出现在任意轮次
|
|
@@ -927,7 +952,7 @@ export class MessageProcessor {
|
|
|
927
952
|
// 获取 session 用于话题回复(如果 resolveSession 已执行)
|
|
928
953
|
let sendOpts;
|
|
929
954
|
try {
|
|
930
|
-
await this.sessionManager.getOrCreateSession(message.channel, message.channelId, this.agentRegistry?.resolveByChannel(message.channel)?.projectPath || process.cwd(), message.threadId);
|
|
955
|
+
await this.sessionManager.getOrCreateSession(message.channel, message.channelId, this.agentRegistry?.resolveByChannel(message.channel)?.projectPath || process.cwd(), message.threadId, undefined, undefined, message.peerId, message.chatType, undefined, message.selfId, message.channelType, message.peerType);
|
|
931
956
|
sendOpts = this.getReplyContext(message);
|
|
932
957
|
}
|
|
933
958
|
catch { }
|
|
@@ -964,7 +989,7 @@ export class MessageProcessor {
|
|
|
964
989
|
: path.resolve(process.cwd(), session.projectPath);
|
|
965
990
|
return { session, absoluteProjectPath };
|
|
966
991
|
}
|
|
967
|
-
const session = await this.sessionManager.getOrCreateSession(message.channel, message.channelId, projectPath, message.threadId, metadata, undefined, message.peerId,
|
|
992
|
+
const session = await this.sessionManager.getOrCreateSession(message.channel, message.channelId, projectPath, message.threadId, metadata, undefined, message.peerId, message.chatType, undefined, message.selfId, message.channelType, message.peerType);
|
|
968
993
|
// 兜底纠正1:群聊强制 proactive
|
|
969
994
|
if (message.chatType === 'group' && session.sessionMode !== 'proactive') {
|
|
970
995
|
logger.info(`[MessageProcessor] group proactive upgrade: sessionId=${session.id} ${session.sessionMode} -> proactive`);
|
|
@@ -990,7 +1015,7 @@ export class MessageProcessor {
|
|
|
990
1015
|
* 此方法只消费标准 AgentEvent 类型,不引用任何 SDK 特有事件。
|
|
991
1016
|
* SDK 事件 → AgentEvent 的转换在 AgentRunner.transformStream() 中完成。
|
|
992
1017
|
*/
|
|
993
|
-
async processEventStream(stream, session, renderer, resetTimer, shouldSuppress) {
|
|
1018
|
+
async processEventStream(stream, session, agent, renderer, resetTimer, shouldSuppress) {
|
|
994
1019
|
// Per-session agent name for stats bucketing
|
|
995
1020
|
const agentNameForStats = this.agentRegistry?.resolveByChannel(session.metadata?.channelName || session.channel)?.name ?? '<unknown>';
|
|
996
1021
|
let hasReceivedText = false;
|
|
@@ -1173,9 +1198,13 @@ export class MessageProcessor {
|
|
|
1173
1198
|
if (event.isError && !hasErrorResult && !shouldSuppress() && !isUserInterrupt && !isContextTooLong) {
|
|
1174
1199
|
const errorSummary = event.errors?.join('; ') || '任务执行失败';
|
|
1175
1200
|
// 使用 terminalReason 提供更友好的错误提示(不带 emoji,由 formatter 统一加)
|
|
1176
|
-
const userFriendlyMessage = event.terminalReason
|
|
1177
|
-
?
|
|
1178
|
-
:
|
|
1201
|
+
const userFriendlyMessage = event.terminalReason === 'prompt_too_long'
|
|
1202
|
+
? getContextTooLongHint(agent)
|
|
1203
|
+
: event.terminalReason === 'context_compact_failed'
|
|
1204
|
+
? getContextCompactFailedHint(agent)
|
|
1205
|
+
: event.terminalReason
|
|
1206
|
+
? getErrorMessage(null, event.terminalReason, false)
|
|
1207
|
+
: errorSummary;
|
|
1179
1208
|
renderer.addNotice(userFriendlyMessage, 'warn', 'task-error', true);
|
|
1180
1209
|
}
|
|
1181
1210
|
// 中间 complete:flush 掉已有 activities(不带 isFinal),让中间结果及时显示
|