evolclaw 3.0.0 → 3.1.1
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.md +1 -1
- package/bin/ec.js +29 -0
- package/dist/agents/baseagent-normalize.js +19 -0
- package/dist/agents/claude-runner.js +47 -12
- package/dist/agents/codex-runner.js +2 -0
- package/dist/agents/gemini-runner.js +9 -9
- package/dist/agents/kit-renderer.js +281 -0
- package/dist/aun/aid/identity.js +28 -0
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/lifecycle-log.js +33 -0
- package/dist/aun/msg/group.js +3 -1
- package/dist/aun/msg/p2p.js +42 -1
- package/dist/channels/aun.js +427 -146
- package/dist/channels/dingtalk.js +3 -1
- package/dist/channels/feishu.js +128 -7
- package/dist/channels/qqbot.js +3 -1
- package/dist/channels/wechat.js +4 -1
- package/dist/channels/wecom.js +3 -1
- package/dist/cli/bench.js +1219 -0
- package/dist/cli/index.js +418 -40
- package/dist/cli/init.js +3 -4
- package/dist/cli/link-rules.js +245 -0
- package/dist/cli/net-check.js +640 -0
- package/dist/cli/watch-msg.js +666 -0
- package/dist/config-store.js +82 -5
- package/dist/core/channel-loader.js +23 -10
- package/dist/core/command-handler.js +127 -99
- package/dist/core/evolagent.js +5 -10
- package/dist/core/message/im-renderer.js +93 -48
- package/dist/core/message/items-formatter.js +11 -4
- package/dist/core/message/message-bridge.js +11 -2
- package/dist/core/message/message-log.js +8 -1
- package/dist/core/message/message-processor.js +194 -127
- package/dist/core/message/message-queue.js +10 -3
- package/dist/core/permission.js +95 -3
- package/dist/core/relation/peer-identity.js +161 -0
- package/dist/core/session/session-manager.js +103 -65
- package/dist/core/trigger/manager.js +16 -0
- package/dist/core/trigger/parser.js +110 -0
- package/dist/core/trigger/scheduler.js +7 -1
- package/dist/data/error-dict.json +118 -0
- package/dist/eck/baseagent-caps.js +18 -0
- package/dist/eck/detect.js +47 -0
- package/dist/eck/init.js +77 -0
- package/dist/eck/rules-loader.js +28 -0
- package/dist/index.js +186 -19
- package/dist/net-check.js +640 -0
- package/dist/paths.js +31 -40
- package/dist/utils/aid-lifecycle-log.js +33 -0
- package/dist/utils/atomic-write.js +10 -0
- package/dist/utils/cross-platform.js +17 -8
- package/dist/utils/error-utils.js +27 -15
- package/dist/utils/instance-registry.js +6 -5
- package/dist/utils/log-writer.js +2 -1
- package/dist/utils/logger.js +10 -0
- package/dist/utils/npm-ops.js +35 -3
- package/dist/utils/process-introspect.js +16 -38
- package/dist/utils/stats.js +216 -2
- package/dist/watch-msg.js +26 -11
- package/evolclaw-install-aun.md +14 -2
- package/kits/docs/GUIDE.md +20 -0
- package/kits/docs/INDEX.md +52 -0
- package/kits/docs/aun/CHEATSHEET.md +17 -0
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
- package/kits/docs/channels/feishu.md +27 -0
- package/kits/docs/eck_templates/GUIDE.template.md +22 -0
- package/kits/docs/eck_templates/INDEX.template.md +28 -0
- package/kits/docs/eck_templates/path-registry.template.md +33 -0
- package/kits/docs/eck_templates/runtime.template.md +19 -0
- package/kits/docs/evolclaw/MSG_GROUP.md +30 -0
- package/kits/docs/evolclaw/MSG_PRIVATE.md +72 -0
- package/kits/docs/identity/AID_PROFILE_SPEC.md +27 -0
- package/kits/docs/identity/PATH_OPS.md +16 -0
- package/kits/docs/identity/ROLE_DETAIL.md +20 -0
- package/kits/docs/path-registry.md +43 -0
- package/kits/eck_manifest.json +95 -0
- package/kits/rules/01-overview.md +120 -0
- package/kits/rules/02-navigation.md +75 -0
- package/kits/rules/03-identity.md +34 -0
- package/kits/rules/04-relation.md +49 -0
- package/kits/rules/05-venue.md +45 -0
- package/kits/rules/06-channel.md +73 -0
- package/kits/templates/system-fragments/baseagent.md +2 -0
- package/kits/templates/system-fragments/channel.md +10 -0
- package/kits/templates/system-fragments/identity.md +12 -0
- package/kits/templates/system-fragments/relation.md +9 -0
- package/kits/templates/system-fragments/runtime.md +19 -0
- package/kits/templates/system-fragments/venue.md +5 -0
- package/package.json +7 -5
- package/dist/agents/templates.js +0 -122
- package/dist/data/prompts.md +0 -137
- package/kits/aun/meta.md +0 -25
- package/kits/aun/role.md +0 -25
- package/kits/templates/group.md +0 -20
- package/kits/templates/private.md +0 -9
- package/kits/templates/system-fragments/personal-context.md +0 -3
- package/kits/templates/system-fragments/self-intro.md +0 -5
- package/kits/templates/system-fragments/speaker-intro.md +0 -5
- package/kits/templates/system-fragments/venue-intro.md +0 -5
- /package/kits/{channels → docs/channels}/aun.md +0 -0
- /package/kits/{evolclaw/commands.md → docs/evolclaw/AGENT_CMD.md} +0 -0
- /package/kits/{evolclaw → docs/evolclaw}/self-summary.md +0 -0
- /package/kits/{evolclaw → docs/evolclaw}/tools.md +0 -0
- /package/kits/{evolclaw → docs/identity}/identity-tools.md +0 -0
|
@@ -467,7 +467,8 @@ export class DingtalkChannelPlugin {
|
|
|
467
467
|
await channel.sendImage(channelId, payload.data);
|
|
468
468
|
return;
|
|
469
469
|
case 'activity.batch': {
|
|
470
|
-
const
|
|
470
|
+
const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
|
|
471
|
+
const text = formatItemsAsText(filtered);
|
|
471
472
|
if (text)
|
|
472
473
|
await channel.sendMessage(channelId, text);
|
|
473
474
|
return;
|
|
@@ -481,6 +482,7 @@ export class DingtalkChannelPlugin {
|
|
|
481
482
|
case 'status.interrupted':
|
|
482
483
|
case 'status.error':
|
|
483
484
|
case 'status.timeout':
|
|
485
|
+
case 'status.progress':
|
|
484
486
|
case 'custom':
|
|
485
487
|
return;
|
|
486
488
|
default:
|
package/dist/channels/feishu.js
CHANGED
|
@@ -82,8 +82,6 @@ export class FeishuChannel {
|
|
|
82
82
|
if (msg.thread_id) {
|
|
83
83
|
logger.info('[Feishu] Thread message, thread_id:', msg.thread_id, 'root_id:', msg.root_id);
|
|
84
84
|
}
|
|
85
|
-
// [DEBUG] 临时:记录所有消息的 root_id/thread_id,用于排查图片回复带引用问题
|
|
86
|
-
logger.info('[Feishu][DEBUG] msg_type:', msg.message_type, 'root_id:', msg.root_id ?? '(empty)', 'thread_id:', msg.thread_id ?? '(empty)', 'parent_id:', msg.parent_id ?? '(empty)');
|
|
87
85
|
// 提取 @ 提及列表(排除机器人自身)
|
|
88
86
|
const mentions = (msg.mentions || []).map((m) => ({
|
|
89
87
|
userId: m.id?.open_id || '',
|
|
@@ -181,6 +179,16 @@ export class FeishuChannel {
|
|
|
181
179
|
quotedText = `> 以下是引用的原消息\n> ================\n> [文件消息]\n> ================\n\n`;
|
|
182
180
|
}
|
|
183
181
|
}
|
|
182
|
+
else if (quotedMsgType === 'merge_forward') {
|
|
183
|
+
const { text: mergedText, images: mergedImages } = await this.extractMergeForwardContent(msg.parent_id, msg.chat_id);
|
|
184
|
+
if (mergedText) {
|
|
185
|
+
quotedText = `> 以下是引用的原消息\n> ================\n> [合并转发消息]\n> ================\n\n${mergedText}\n\n`;
|
|
186
|
+
quotedImages.push(...mergedImages);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
quotedText = `> 以下是引用的原消息\n> ================\n> [合并转发消息]\n> ================\n\n`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
184
192
|
else {
|
|
185
193
|
quotedText = `> 以下是引用的原消息\n> ================\n> [${quotedMsgType}消息]\n> ================\n\n`;
|
|
186
194
|
}
|
|
@@ -189,6 +197,7 @@ export class FeishuChannel {
|
|
|
189
197
|
logger.warn({ err }, '[Feishu] Failed to fetch quoted message');
|
|
190
198
|
}
|
|
191
199
|
}
|
|
200
|
+
logger.info(`[Feishu] Incoming message_type=${msg.message_type} content=${msg.content?.substring(0, 200)}`);
|
|
192
201
|
// 处理文本消息
|
|
193
202
|
if (msg.message_type === 'text') {
|
|
194
203
|
const parsed = JSON.parse(msg.content);
|
|
@@ -210,7 +219,7 @@ export class FeishuChannel {
|
|
|
210
219
|
const imageData = await this.downloadAndSaveImage(imageKey, msg.chat_id, msg.message_id, projectPath);
|
|
211
220
|
if (imageData) {
|
|
212
221
|
const allImages = [...quotedImages, imageData];
|
|
213
|
-
const prompt = quotedText + '
|
|
222
|
+
const prompt = quotedText + '用户发送了一张图片,请结合上下文理解用户意图并回应。';
|
|
214
223
|
await this.messageHandler({ channelId: msg.chat_id, content: prompt, images: allImages, peerId, peerName, messageId: msg.message_id, threadId, rootId, chatType });
|
|
215
224
|
}
|
|
216
225
|
else {
|
|
@@ -269,6 +278,19 @@ export class FeishuChannel {
|
|
|
269
278
|
const allImages = [...quotedImages, ...postImages];
|
|
270
279
|
await this.messageHandler({ channelId: msg.chat_id, content: finalContent, images: allImages.length > 0 ? allImages : undefined, peerId, peerName, messageId: msg.message_id, threadId, rootId, chatType });
|
|
271
280
|
}
|
|
281
|
+
// 处理合并转发消息
|
|
282
|
+
else if (msg.message_type === 'merge_forward') {
|
|
283
|
+
const { text: mergedText, images: mergedImages } = await this.extractMergeForwardContent(msg.message_id, msg.chat_id);
|
|
284
|
+
if (mergedText) {
|
|
285
|
+
const finalContent = quotedText + mergedText;
|
|
286
|
+
const allImages = [...quotedImages, ...mergedImages];
|
|
287
|
+
await this.messageHandler({ channelId: msg.chat_id, content: finalContent, images: allImages.length > 0 ? allImages : undefined, peerId, peerName, messageId: msg.message_id, threadId, rootId, chatType });
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
const prompt = quotedText + '[合并转发消息解析失败]';
|
|
291
|
+
await this.messageHandler({ channelId: msg.chat_id, content: prompt, images: quotedImages.length > 0 ? quotedImages : undefined, peerId, peerName, messageId: msg.message_id, threadId, rootId, chatType });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
272
294
|
// 处理其他类型消息
|
|
273
295
|
else {
|
|
274
296
|
logger.debug('[Feishu] Unsupported message type:', msg.message_type);
|
|
@@ -551,7 +573,14 @@ export class FeishuChannel {
|
|
|
551
573
|
const truncated = content.slice(0, 28000) + '\n\n⚠️ 消息过长,已截断';
|
|
552
574
|
return this.sendMessage(chatId, truncated, options);
|
|
553
575
|
}
|
|
554
|
-
|
|
576
|
+
const respData = error?.response?.data;
|
|
577
|
+
const code = respData?.code;
|
|
578
|
+
logger.error('[Feishu] Failed to send message:', respData ? JSON.stringify(respData) : error?.message ?? error);
|
|
579
|
+
// post 格式相关错误(400/230001):降级为纯文本重试
|
|
580
|
+
if (!options?.forceText && (error?.response?.status === 400 || code === 230001)) {
|
|
581
|
+
logger.warn('[Feishu] Retrying as plain text (forceText)');
|
|
582
|
+
return this.sendMessage(chatId, content, { ...options, forceText: true });
|
|
583
|
+
}
|
|
555
584
|
throw error;
|
|
556
585
|
}
|
|
557
586
|
}
|
|
@@ -802,6 +831,94 @@ export class FeishuChannel {
|
|
|
802
831
|
return null;
|
|
803
832
|
}
|
|
804
833
|
}
|
|
834
|
+
/**
|
|
835
|
+
* 提取合并转发消息的子消息内容。
|
|
836
|
+
* 调用 im.message.get 获取子消息列表,逐条解析 text/image/post/file 类型。
|
|
837
|
+
*/
|
|
838
|
+
async extractMergeForwardContent(messageId, chatId) {
|
|
839
|
+
const empty = { text: '', images: [] };
|
|
840
|
+
if (!this.client)
|
|
841
|
+
return empty;
|
|
842
|
+
try {
|
|
843
|
+
const res = await this.client.im.message.get({
|
|
844
|
+
path: { message_id: messageId }
|
|
845
|
+
});
|
|
846
|
+
const items = res.data?.items;
|
|
847
|
+
if (!items || items.length === 0) {
|
|
848
|
+
logger.warn('[Feishu] merge_forward: no sub-messages found');
|
|
849
|
+
return empty;
|
|
850
|
+
}
|
|
851
|
+
logger.info(`[Feishu] merge_forward: ${items.length} sub-messages`);
|
|
852
|
+
const projectPath = this.projectPathProvider
|
|
853
|
+
? await this.projectPathProvider(chatId)
|
|
854
|
+
: process.cwd();
|
|
855
|
+
const textParts = [];
|
|
856
|
+
const images = [];
|
|
857
|
+
const MAX_IMAGES = 10;
|
|
858
|
+
textParts.push('以下是用户转发的合并消息:\n---');
|
|
859
|
+
for (const item of items) {
|
|
860
|
+
const msgType = item.msg_type;
|
|
861
|
+
const content = item.body?.content;
|
|
862
|
+
if (!content)
|
|
863
|
+
continue;
|
|
864
|
+
try {
|
|
865
|
+
if (msgType === 'text') {
|
|
866
|
+
const parsed = JSON.parse(content);
|
|
867
|
+
textParts.push(parsed.text || '');
|
|
868
|
+
}
|
|
869
|
+
else if (msgType === 'post') {
|
|
870
|
+
const parsed = JSON.parse(content);
|
|
871
|
+
let text = '';
|
|
872
|
+
const postContent = parsed.zh_cn?.content || parsed.en_us?.content || parsed.content;
|
|
873
|
+
if (postContent) {
|
|
874
|
+
for (const line of postContent) {
|
|
875
|
+
for (const elem of line) {
|
|
876
|
+
if (elem.tag === 'img' && elem.image_key && item.message_id && images.length < MAX_IMAGES) {
|
|
877
|
+
const imageData = await this.downloadAndSaveImage(elem.image_key, chatId, item.message_id, projectPath);
|
|
878
|
+
if (imageData)
|
|
879
|
+
images.push(imageData);
|
|
880
|
+
}
|
|
881
|
+
else if (elem.text) {
|
|
882
|
+
text += elem.text;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
text += '\n';
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const title = parsed.zh_cn?.title || parsed.en_us?.title || parsed.title;
|
|
889
|
+
textParts.push(title ? `${title}\n${text.trim()}` : text.trim());
|
|
890
|
+
}
|
|
891
|
+
else if (msgType === 'image' && item.message_id) {
|
|
892
|
+
const parsed = JSON.parse(content);
|
|
893
|
+
if (parsed.image_key && images.length < MAX_IMAGES) {
|
|
894
|
+
const imageData = await this.downloadAndSaveImage(parsed.image_key, chatId, item.message_id, projectPath);
|
|
895
|
+
if (imageData) {
|
|
896
|
+
images.push(imageData);
|
|
897
|
+
textParts.push('[图片]');
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
else if (msgType === 'file') {
|
|
902
|
+
const parsed = JSON.parse(content);
|
|
903
|
+
textParts.push(`[文件: ${parsed.file_name || 'unknown'}]`);
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
textParts.push(`[${msgType}]`);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
catch (parseErr) {
|
|
910
|
+
logger.debug('[Feishu] merge_forward: failed to parse sub-message:', parseErr);
|
|
911
|
+
textParts.push(`[${msgType}: 解析失败]`);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
textParts.push('---');
|
|
915
|
+
return { text: textParts.join('\n'), images };
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
logger.error('[Feishu] Failed to extract merge_forward content:', error);
|
|
919
|
+
return empty;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
805
922
|
async downloadFile(fileKey, fileName, messageId, projectPath) {
|
|
806
923
|
if (!this.client)
|
|
807
924
|
return null;
|
|
@@ -1223,7 +1340,7 @@ export class FeishuChannelPlugin {
|
|
|
1223
1340
|
case 'result.error': {
|
|
1224
1341
|
const sendCtx = { ...(ctx ?? {}) };
|
|
1225
1342
|
if (payload.kind === 'result.text' && payload.isFinal)
|
|
1226
|
-
sendCtx.title = '
|
|
1343
|
+
sendCtx.title = '✅ 最终回复:';
|
|
1227
1344
|
await channel.sendMessage(channelId, payload.text, sendCtx);
|
|
1228
1345
|
return;
|
|
1229
1346
|
}
|
|
@@ -1234,9 +1351,12 @@ export class FeishuChannelPlugin {
|
|
|
1234
1351
|
await channel.sendImage(channelId, payload.data, ctx);
|
|
1235
1352
|
return;
|
|
1236
1353
|
case 'activity.batch': {
|
|
1237
|
-
|
|
1238
|
-
|
|
1354
|
+
// Feishu 不发送成功的 tool_result(信息密度低,刷屏)
|
|
1355
|
+
const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
|
|
1356
|
+
const text = formatItemsAsText(filtered);
|
|
1357
|
+
if (text) {
|
|
1239
1358
|
await channel.sendMessage(channelId, text, ctx);
|
|
1359
|
+
}
|
|
1240
1360
|
return;
|
|
1241
1361
|
}
|
|
1242
1362
|
case 'status.started':
|
|
@@ -1244,6 +1364,7 @@ export class FeishuChannelPlugin {
|
|
|
1244
1364
|
case 'status.interrupted':
|
|
1245
1365
|
case 'status.error':
|
|
1246
1366
|
case 'status.timeout':
|
|
1367
|
+
case 'status.progress':
|
|
1247
1368
|
// Feishu 通过 acknowledge (✓ 表情) 表达状态,由 channel 自行处理
|
|
1248
1369
|
return;
|
|
1249
1370
|
case 'interaction':
|
package/dist/channels/qqbot.js
CHANGED
|
@@ -354,7 +354,8 @@ export class QQBotChannelPlugin {
|
|
|
354
354
|
await channel.sendImage(channelId, payload.data);
|
|
355
355
|
return;
|
|
356
356
|
case 'activity.batch': {
|
|
357
|
-
const
|
|
357
|
+
const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
|
|
358
|
+
const text = formatItemsAsText(filtered);
|
|
358
359
|
if (text)
|
|
359
360
|
await channel.sendMessage(channelId, text);
|
|
360
361
|
return;
|
|
@@ -368,6 +369,7 @@ export class QQBotChannelPlugin {
|
|
|
368
369
|
case 'status.interrupted':
|
|
369
370
|
case 'status.error':
|
|
370
371
|
case 'status.timeout':
|
|
372
|
+
case 'status.progress':
|
|
371
373
|
case 'custom':
|
|
372
374
|
return;
|
|
373
375
|
default:
|
package/dist/channels/wechat.js
CHANGED
|
@@ -750,7 +750,9 @@ export class WechatChannelPlugin {
|
|
|
750
750
|
case 'result.image':
|
|
751
751
|
return;
|
|
752
752
|
case 'activity.batch': {
|
|
753
|
-
|
|
753
|
+
// WeChat 不发送成功的 tool_result
|
|
754
|
+
const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
|
|
755
|
+
const text = formatItemsAsText(filtered);
|
|
754
756
|
if (text)
|
|
755
757
|
await channel.sendMessage(channelId, text);
|
|
756
758
|
return;
|
|
@@ -764,6 +766,7 @@ export class WechatChannelPlugin {
|
|
|
764
766
|
case 'status.interrupted':
|
|
765
767
|
case 'status.error':
|
|
766
768
|
case 'status.timeout':
|
|
769
|
+
case 'status.progress':
|
|
767
770
|
case 'custom':
|
|
768
771
|
return;
|
|
769
772
|
default:
|
package/dist/channels/wecom.js
CHANGED
|
@@ -510,7 +510,8 @@ export class WecomChannelPlugin {
|
|
|
510
510
|
await channel.sendImage(channelId, payload.data);
|
|
511
511
|
return;
|
|
512
512
|
case 'activity.batch': {
|
|
513
|
-
const
|
|
513
|
+
const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
|
|
514
|
+
const text = formatItemsAsText(filtered);
|
|
514
515
|
if (text)
|
|
515
516
|
await channel.sendMessage(channelId, text);
|
|
516
517
|
return;
|
|
@@ -524,6 +525,7 @@ export class WecomChannelPlugin {
|
|
|
524
525
|
case 'status.interrupted':
|
|
525
526
|
case 'status.error':
|
|
526
527
|
case 'status.timeout':
|
|
528
|
+
case 'status.progress':
|
|
527
529
|
case 'custom':
|
|
528
530
|
return;
|
|
529
531
|
default:
|