evolclaw 3.0.0 → 3.1.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.
Files changed (99) hide show
  1. package/README.md +1 -1
  2. package/bin/ec.js +29 -0
  3. package/dist/agents/baseagent-normalize.js +19 -0
  4. package/dist/agents/claude-runner.js +7 -9
  5. package/dist/agents/codex-runner.js +2 -0
  6. package/dist/agents/gemini-runner.js +9 -9
  7. package/dist/agents/kit-renderer.js +281 -0
  8. package/dist/aun/aid/identity.js +28 -0
  9. package/dist/aun/aid/index.js +1 -1
  10. package/dist/aun/aid/lifecycle-log.js +33 -0
  11. package/dist/aun/msg/group.js +3 -1
  12. package/dist/aun/msg/p2p.js +4 -1
  13. package/dist/channels/aun.js +353 -125
  14. package/dist/channels/dingtalk.js +2 -1
  15. package/dist/channels/feishu.js +118 -5
  16. package/dist/channels/qqbot.js +2 -1
  17. package/dist/channels/wechat.js +3 -1
  18. package/dist/channels/wecom.js +2 -1
  19. package/dist/cli/bench.js +1219 -0
  20. package/dist/cli/index.js +279 -19
  21. package/dist/cli/link-rules.js +245 -0
  22. package/dist/cli/net-check.js +640 -0
  23. package/dist/cli/watch-msg.js +589 -0
  24. package/dist/config-store.js +37 -5
  25. package/dist/core/channel-loader.js +23 -10
  26. package/dist/core/command-handler.js +46 -22
  27. package/dist/core/evolagent.js +5 -10
  28. package/dist/core/message/im-renderer.js +50 -44
  29. package/dist/core/message/items-formatter.js +11 -4
  30. package/dist/core/message/message-bridge.js +7 -2
  31. package/dist/core/message/message-log.js +2 -0
  32. package/dist/core/message/message-processor.js +150 -99
  33. package/dist/core/message/message-queue.js +10 -3
  34. package/dist/core/permission.js +95 -3
  35. package/dist/core/session/session-manager.js +98 -64
  36. package/dist/core/trigger/scheduler.js +1 -1
  37. package/dist/data/error-dict.json +118 -0
  38. package/dist/eck/baseagent-caps.js +18 -0
  39. package/dist/eck/detect.js +47 -0
  40. package/dist/eck/init.js +77 -0
  41. package/dist/eck/rules-loader.js +28 -0
  42. package/dist/index.js +137 -16
  43. package/dist/net-check.js +640 -0
  44. package/dist/paths.js +31 -40
  45. package/dist/utils/aid-lifecycle-log.js +33 -0
  46. package/dist/utils/atomic-write.js +10 -0
  47. package/dist/utils/cross-platform.js +17 -8
  48. package/dist/utils/error-utils.js +10 -2
  49. package/dist/utils/instance-registry.js +6 -5
  50. package/dist/utils/log-writer.js +2 -1
  51. package/dist/utils/logger.js +10 -0
  52. package/dist/utils/npm-ops.js +35 -3
  53. package/dist/utils/process-introspect.js +16 -38
  54. package/dist/watch-msg.js +26 -11
  55. package/evolclaw-install-aun.md +14 -2
  56. package/kits/docs/GUIDE.md +20 -0
  57. package/kits/docs/INDEX.md +52 -0
  58. package/kits/docs/aun/CHEATSHEET.md +17 -0
  59. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  60. package/kits/docs/channels/feishu.md +27 -0
  61. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  62. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  63. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  64. package/kits/docs/eck_templates/runtime.template.md +19 -0
  65. package/kits/docs/evolclaw/MSG_GROUP.md +30 -0
  66. package/kits/docs/evolclaw/MSG_PRIVATE.md +25 -0
  67. package/kits/docs/identity/AID_PROFILE_SPEC.md +27 -0
  68. package/kits/docs/identity/PATH_OPS.md +16 -0
  69. package/kits/docs/identity/ROLE_DETAIL.md +20 -0
  70. package/kits/docs/path-registry.md +43 -0
  71. package/kits/eck_manifest.json +95 -0
  72. package/kits/rules/01-overview.md +120 -0
  73. package/kits/rules/02-navigation.md +75 -0
  74. package/kits/rules/03-identity.md +34 -0
  75. package/kits/rules/04-relation.md +49 -0
  76. package/kits/rules/05-venue.md +45 -0
  77. package/kits/rules/06-channel.md +43 -0
  78. package/kits/templates/system-fragments/baseagent.md +2 -0
  79. package/kits/templates/system-fragments/channel.md +10 -0
  80. package/kits/templates/system-fragments/identity.md +12 -0
  81. package/kits/templates/system-fragments/relation.md +9 -0
  82. package/kits/templates/system-fragments/runtime.md +19 -0
  83. package/kits/templates/system-fragments/venue.md +5 -0
  84. package/package.json +7 -5
  85. package/dist/agents/templates.js +0 -122
  86. package/dist/data/prompts.md +0 -137
  87. package/kits/aun/meta.md +0 -25
  88. package/kits/aun/role.md +0 -25
  89. package/kits/templates/group.md +0 -20
  90. package/kits/templates/private.md +0 -9
  91. package/kits/templates/system-fragments/personal-context.md +0 -3
  92. package/kits/templates/system-fragments/self-intro.md +0 -5
  93. package/kits/templates/system-fragments/speaker-intro.md +0 -5
  94. package/kits/templates/system-fragments/venue-intro.md +0 -5
  95. /package/kits/{channels → docs/channels}/aun.md +0 -0
  96. /package/kits/{evolclaw/commands.md → docs/evolclaw/AGENT_CMD.md} +0 -0
  97. /package/kits/{evolclaw → docs/evolclaw}/self-summary.md +0 -0
  98. /package/kits/{evolclaw → docs/evolclaw}/tools.md +0 -0
  99. /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 text = formatItemsAsText(payload.items);
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;
@@ -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);
@@ -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);
@@ -802,6 +824,94 @@ export class FeishuChannel {
802
824
  return null;
803
825
  }
804
826
  }
827
+ /**
828
+ * 提取合并转发消息的子消息内容。
829
+ * 调用 im.message.get 获取子消息列表,逐条解析 text/image/post/file 类型。
830
+ */
831
+ async extractMergeForwardContent(messageId, chatId) {
832
+ const empty = { text: '', images: [] };
833
+ if (!this.client)
834
+ return empty;
835
+ try {
836
+ const res = await this.client.im.message.get({
837
+ path: { message_id: messageId }
838
+ });
839
+ const items = res.data?.items;
840
+ if (!items || items.length === 0) {
841
+ logger.warn('[Feishu] merge_forward: no sub-messages found');
842
+ return empty;
843
+ }
844
+ logger.info(`[Feishu] merge_forward: ${items.length} sub-messages`);
845
+ const projectPath = this.projectPathProvider
846
+ ? await this.projectPathProvider(chatId)
847
+ : process.cwd();
848
+ const textParts = [];
849
+ const images = [];
850
+ const MAX_IMAGES = 10;
851
+ textParts.push('以下是用户转发的合并消息:\n---');
852
+ for (const item of items) {
853
+ const msgType = item.msg_type;
854
+ const content = item.body?.content;
855
+ if (!content)
856
+ continue;
857
+ try {
858
+ if (msgType === 'text') {
859
+ const parsed = JSON.parse(content);
860
+ textParts.push(parsed.text || '');
861
+ }
862
+ else if (msgType === 'post') {
863
+ const parsed = JSON.parse(content);
864
+ let text = '';
865
+ const postContent = parsed.zh_cn?.content || parsed.en_us?.content || parsed.content;
866
+ if (postContent) {
867
+ for (const line of postContent) {
868
+ for (const elem of line) {
869
+ if (elem.tag === 'img' && elem.image_key && item.message_id && images.length < MAX_IMAGES) {
870
+ const imageData = await this.downloadAndSaveImage(elem.image_key, chatId, item.message_id, projectPath);
871
+ if (imageData)
872
+ images.push(imageData);
873
+ }
874
+ else if (elem.text) {
875
+ text += elem.text;
876
+ }
877
+ }
878
+ text += '\n';
879
+ }
880
+ }
881
+ const title = parsed.zh_cn?.title || parsed.en_us?.title || parsed.title;
882
+ textParts.push(title ? `${title}\n${text.trim()}` : text.trim());
883
+ }
884
+ else if (msgType === 'image' && item.message_id) {
885
+ const parsed = JSON.parse(content);
886
+ if (parsed.image_key && images.length < MAX_IMAGES) {
887
+ const imageData = await this.downloadAndSaveImage(parsed.image_key, chatId, item.message_id, projectPath);
888
+ if (imageData) {
889
+ images.push(imageData);
890
+ textParts.push('[图片]');
891
+ }
892
+ }
893
+ }
894
+ else if (msgType === 'file') {
895
+ const parsed = JSON.parse(content);
896
+ textParts.push(`[文件: ${parsed.file_name || 'unknown'}]`);
897
+ }
898
+ else {
899
+ textParts.push(`[${msgType}]`);
900
+ }
901
+ }
902
+ catch (parseErr) {
903
+ logger.debug('[Feishu] merge_forward: failed to parse sub-message:', parseErr);
904
+ textParts.push(`[${msgType}: 解析失败]`);
905
+ }
906
+ }
907
+ textParts.push('---');
908
+ return { text: textParts.join('\n'), images };
909
+ }
910
+ catch (error) {
911
+ logger.error('[Feishu] Failed to extract merge_forward content:', error);
912
+ return empty;
913
+ }
914
+ }
805
915
  async downloadFile(fileKey, fileName, messageId, projectPath) {
806
916
  if (!this.client)
807
917
  return null;
@@ -1223,7 +1333,7 @@ export class FeishuChannelPlugin {
1223
1333
  case 'result.error': {
1224
1334
  const sendCtx = { ...(ctx ?? {}) };
1225
1335
  if (payload.kind === 'result.text' && payload.isFinal)
1226
- sendCtx.title = ' 最终回复:';
1336
+ sendCtx.title = ' 最终回复:';
1227
1337
  await channel.sendMessage(channelId, payload.text, sendCtx);
1228
1338
  return;
1229
1339
  }
@@ -1234,9 +1344,12 @@ export class FeishuChannelPlugin {
1234
1344
  await channel.sendImage(channelId, payload.data, ctx);
1235
1345
  return;
1236
1346
  case 'activity.batch': {
1237
- const text = formatItemsAsText(payload.items);
1238
- if (text)
1347
+ // Feishu 不发送成功的 tool_result(信息密度低,刷屏)
1348
+ const filtered = payload.items.filter((i) => !(i.kind === 'tool_result' && i.ok));
1349
+ const text = formatItemsAsText(filtered);
1350
+ if (text) {
1239
1351
  await channel.sendMessage(channelId, text, ctx);
1352
+ }
1240
1353
  return;
1241
1354
  }
1242
1355
  case 'status.started':
@@ -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 text = formatItemsAsText(payload.items);
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;
@@ -750,7 +750,9 @@ export class WechatChannelPlugin {
750
750
  case 'result.image':
751
751
  return;
752
752
  case 'activity.batch': {
753
- const text = formatItemsAsText(payload.items);
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;
@@ -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 text = formatItemsAsText(payload.items);
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;