evolclaw 3.1.4 → 3.1.5

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 (85) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/agents/claude-runner.js +348 -156
  3. package/dist/agents/kit-renderer.js +176 -21
  4. package/dist/aun/aid/agentmd.js +68 -103
  5. package/dist/aun/aid/client.js +1 -29
  6. package/dist/aun/aid/identity.js +105 -64
  7. package/dist/aun/aid/index.js +2 -1
  8. package/dist/aun/aid/store.js +74 -0
  9. package/dist/aun/msg/p2p.js +26 -2
  10. package/dist/aun/rpc/connection.js +23 -30
  11. package/dist/channels/aun.js +77 -88
  12. package/dist/channels/dingtalk.js +1 -0
  13. package/dist/channels/feishu.js +270 -190
  14. package/dist/channels/qqbot.js +1 -0
  15. package/dist/channels/wechat.js +1 -0
  16. package/dist/channels/wecom.js +1 -0
  17. package/dist/cli/agent.js +11 -5
  18. package/dist/cli/bench.js +40 -23
  19. package/dist/cli/index.js +170 -44
  20. package/dist/cli/init-channel.js +5 -1
  21. package/dist/cli/model.js +324 -0
  22. package/dist/cli/net-check.js +133 -50
  23. package/dist/cli/watch-msg.js +7 -7
  24. package/dist/cli/watch-web/debug-log.js +18 -0
  25. package/dist/cli/watch-web/server.js +306 -0
  26. package/dist/cli/watch-web/sources/aid.js +63 -0
  27. package/dist/cli/watch-web/sources/msg.js +70 -0
  28. package/dist/cli/watch-web/sources/session.js +638 -0
  29. package/dist/cli/watch-web/sources/types.js +10 -0
  30. package/dist/cli/watch-web/static/app.js +546 -0
  31. package/dist/cli/watch-web/static/index.html +54 -0
  32. package/dist/cli/watch-web/static/style.css +247 -0
  33. package/dist/core/channel-loader.js +7 -4
  34. package/dist/core/command-handler.js +81 -86
  35. package/dist/core/evolagent-registry.js +1 -1
  36. package/dist/core/evolagent.js +4 -4
  37. package/dist/core/interaction-router.js +59 -0
  38. package/dist/core/message/message-bridge.js +6 -6
  39. package/dist/core/message/message-log.js +2 -2
  40. package/dist/core/message/message-processor.js +86 -101
  41. package/dist/core/message/stream-idle-monitor.js +21 -0
  42. package/dist/core/model/model-catalog.js +215 -0
  43. package/dist/core/model/model-scope.js +250 -0
  44. package/dist/core/relation/peer-identity.js +40 -49
  45. package/dist/core/relation/peer-key.js +16 -0
  46. package/dist/core/session/session-fs-store.js +34 -55
  47. package/dist/core/session/session-key.js +24 -0
  48. package/dist/core/session/session-manager.js +308 -251
  49. package/dist/core/session/session-mapper.js +9 -4
  50. package/dist/core/trigger/manager.js +3 -3
  51. package/dist/core/trigger/scheduler.js +2 -1
  52. package/dist/index.js +6 -2
  53. package/dist/ipc.js +22 -0
  54. package/kits/docs/GUIDE.md +2 -2
  55. package/kits/docs/INDEX.md +11 -7
  56. package/kits/docs/channels/aun.md +56 -17
  57. package/kits/docs/channels/feishu.md +41 -12
  58. package/kits/docs/context-assembly.md +181 -0
  59. package/kits/docs/evolclaw/agent.md +49 -0
  60. package/kits/docs/evolclaw/aid.md +49 -0
  61. package/kits/docs/evolclaw/ctl.md +46 -0
  62. package/kits/docs/evolclaw/group.md +82 -0
  63. package/kits/docs/evolclaw/msg.md +86 -0
  64. package/kits/docs/evolclaw/rpc.md +35 -0
  65. package/kits/docs/evolclaw/storage.md +49 -0
  66. package/kits/docs/venues/aun-group.md +10 -0
  67. package/kits/docs/venues/aun-private.md +10 -0
  68. package/kits/docs/venues/client-desktop.md +10 -0
  69. package/kits/docs/venues/client-mobile.md +10 -0
  70. package/kits/docs/venues/feishu-group.md +13 -0
  71. package/kits/docs/venues/feishu-private.md +9 -0
  72. package/kits/docs/venues/group.md +11 -0
  73. package/kits/docs/venues/private.md +10 -0
  74. package/kits/eck_manifest.json +72 -36
  75. package/kits/rules/01-overview.md +20 -10
  76. package/kits/rules/06-channel.md +30 -27
  77. package/kits/templates/system-fragments/session.md +10 -3
  78. package/kits/templates/system-fragments/venue.md +9 -0
  79. package/package.json +11 -6
  80. package/dist/aun/aid/lifecycle-log.js +0 -33
  81. package/dist/utils/aid-lifecycle-log.js +0 -33
  82. package/kits/docs/evolclaw/AGENT_CMD.md +0 -31
  83. package/kits/docs/evolclaw/MSG_GROUP.md +0 -30
  84. package/kits/docs/evolclaw/MSG_PRIVATE.md +0 -72
  85. package/kits/docs/evolclaw/tools.md +0 -25
@@ -0,0 +1,16 @@
1
+ /**
2
+ * peerKey: 关系层路由键,格式 `<channelType>#<urlEncode(channelId)>`。
3
+ * 群聊场景下 channelId = groupId,所有发言者共用同一个 peerKey。
4
+ */
5
+ export function formatPeerKey(channelType, channelId) {
6
+ return `${channelType}#${encodeURIComponent(channelId)}`;
7
+ }
8
+ export function parsePeerKey(key) {
9
+ const idx = key.indexOf('#');
10
+ if (idx <= 0)
11
+ throw new Error(`Invalid peer key: ${key}`);
12
+ return {
13
+ channelType: key.slice(0, idx),
14
+ channelId: decodeURIComponent(key.slice(idx + 1)),
15
+ };
16
+ }
@@ -12,19 +12,16 @@ function decodeSegment(s) {
12
12
  }
13
13
  /**
14
14
  * 计算 chat 目录的完整路径。
15
- * - AUN:sessionsDir/aun/<urlEncode(selfId)>/<urlEncode(channelId)>/
16
- * - 其它:sessionsDir/<channelType>/<urlEncode(channelId)>/
17
- *
18
- * 注:channelType 自身不编码(限定枚举值,不含非法字符)。
15
+ * - aun: sessionsDir/aun/<urlEncode(selfAID|'_unknown')>/<urlEncode(channelId)>/
16
+ * - 其它: sessionsDir/<channelType>/<urlEncode(channelId)>/
19
17
  */
20
- export function chatDirPath(sessionsDir, channelType, channelId, selfId) {
18
+ export function chatDirPath(sessionsDir, channelType, channelId, selfAID) {
21
19
  if (channelType === 'aun') {
22
- const self = selfId || '_unknown';
23
- return path.join(sessionsDir, 'aun', encodeSegment(self), encodeSegment(channelId));
20
+ return path.join(sessionsDir, channelType, encodeSegment(selfAID || '_unknown'), encodeSegment(channelId));
24
21
  }
25
22
  return path.join(sessionsDir, channelType, encodeSegment(channelId));
26
23
  }
27
- /** 解码目录段(用于扫描时把目录名还原为原始 channelId/selfId) */
24
+ /** 解码目录段(用于扫描时把目录名还原为原始 channelId/selfAID) */
28
25
  export function decodeDirSegment(seg) {
29
26
  return decodeSegment(seg);
30
27
  }
@@ -128,8 +125,8 @@ export function readAllJsonlLines(filePath) {
128
125
  }
129
126
  /**
130
127
  * 扫描所有 chat 目录。
131
- * 顶层是 channelType 目录;aun 下面再有一层 selfId 目录。
132
- * 返回每个 chat 的:channelType、selfId(仅 aun 有)、channelId、dirPath。
128
+ * - aun: channelType / selfAID / channelId (3层)
129
+ * - 其它: channelType / channelId (2层)
133
130
  */
134
131
  export function scanChatDirs(sessionsDir) {
135
132
  const results = [];
@@ -146,40 +143,17 @@ export function scanChatDirs(sessionsDir) {
146
143
  if (!typeEntry.isDirectory())
147
144
  continue;
148
145
  const channelType = typeEntry.name;
149
- // 包含 '#' 的目录是旧 channelKey 格式(如 'aun#dddd.agentid.pub#main'),
150
- // 按通用 channel 布局扫描(sessionsDir/{channelKey}/{encodedChannelId}/),保持兼容
151
- if (channelType.includes('#')) {
152
- const typeDir = path.join(sessionsDir, channelType);
153
- let chatEntries;
154
- try {
155
- chatEntries = fs.readdirSync(typeDir, { withFileTypes: true });
156
- }
157
- catch {
158
- continue;
159
- }
160
- for (const chatEntry of chatEntries) {
161
- if (!chatEntry.isDirectory())
162
- continue;
163
- results.push({
164
- channelType,
165
- selfId: null,
166
- channelId: decodeSegment(chatEntry.name),
167
- dirPath: path.join(typeDir, chatEntry.name),
168
- });
169
- }
146
+ const typeDir = path.join(sessionsDir, channelType);
147
+ let level2Entries;
148
+ try {
149
+ level2Entries = fs.readdirSync(typeDir, { withFileTypes: true });
150
+ }
151
+ catch {
170
152
  continue;
171
153
  }
172
- const typeDir = path.join(sessionsDir, channelType);
173
154
  if (channelType === 'aun') {
174
- // aun 下还有一层 selfId
175
- let selfEntries;
176
- try {
177
- selfEntries = fs.readdirSync(typeDir, { withFileTypes: true });
178
- }
179
- catch {
180
- continue;
181
- }
182
- for (const selfEntry of selfEntries) {
155
+ // 3-layer: aun/selfAID/channelId
156
+ for (const selfEntry of level2Entries) {
183
157
  if (!selfEntry.isDirectory())
184
158
  continue;
185
159
  const selfDir = path.join(typeDir, selfEntry.name);
@@ -195,7 +169,7 @@ export function scanChatDirs(sessionsDir) {
195
169
  continue;
196
170
  results.push({
197
171
  channelType,
198
- selfId: decodeSegment(selfEntry.name),
172
+ selfAID: decodeSegment(selfEntry.name),
199
173
  channelId: decodeSegment(chatEntry.name),
200
174
  dirPath: path.join(selfDir, chatEntry.name),
201
175
  });
@@ -203,20 +177,13 @@ export function scanChatDirs(sessionsDir) {
203
177
  }
204
178
  }
205
179
  else {
206
- // 通用 channel:sessionsDir/{channelType}/{encodedChannelId}/
207
- let chatEntries;
208
- try {
209
- chatEntries = fs.readdirSync(typeDir, { withFileTypes: true });
210
- }
211
- catch {
212
- continue;
213
- }
214
- for (const chatEntry of chatEntries) {
180
+ // 2-layer: channelType/channelId
181
+ for (const chatEntry of level2Entries) {
215
182
  if (!chatEntry.isDirectory())
216
183
  continue;
217
184
  results.push({
218
185
  channelType,
219
- selfId: null,
186
+ selfAID: '',
220
187
  channelId: decodeSegment(chatEntry.name),
221
188
  dirPath: path.join(typeDir, chatEntry.name),
222
189
  });
@@ -238,15 +205,27 @@ export function scanMetaFiles(chatDir) {
238
205
  throw e;
239
206
  }
240
207
  }
241
- export function ensureChatDir(sessionsDir, channelType, channelId, selfId) {
242
- const dir = chatDirPath(sessionsDir, channelType, channelId, selfId);
208
+ export function ensureChatDir(sessionsDir, channelType, channelId, selfAID) {
209
+ const dir = chatDirPath(sessionsDir, channelType, channelId, selfAID);
243
210
  fs.mkdirSync(dir, { recursive: true });
244
211
  fs.mkdirSync(path.join(dir, '_threads'), { recursive: true });
245
212
  fs.mkdirSync(path.join(dir, '_trash'), { recursive: true });
246
213
  return dir;
247
214
  }
248
215
  export function readThreadIndex(chatDir) {
249
- return readJsonFile(path.join(chatDir, '_threads', 'thread-index.json')) || {};
216
+ const raw = readJsonFile(path.join(chatDir, '_threads', 'thread-index.json')) || {};
217
+ // Migrate legacy format: { threadId: sessionId } → { threadId: { sessionId, sessionKey, metaFile } }
218
+ const result = {};
219
+ for (const [tid, val] of Object.entries(raw)) {
220
+ if (typeof val === 'string') {
221
+ // Legacy: val is sessionId
222
+ result[tid] = { sessionId: val, sessionKey: '', metaFile: `${val}.jsonl` };
223
+ }
224
+ else {
225
+ result[tid] = val;
226
+ }
227
+ }
228
+ return result;
250
229
  }
251
230
  export function writeThreadIndex(chatDir, index) {
252
231
  atomicWriteJson(path.join(chatDir, '_threads', 'thread-index.json'), index);
@@ -0,0 +1,24 @@
1
+ /**
2
+ * sessionKey: agent 内部会话路由键。
3
+ * 格式: channelType#urlEncode(channelId)#urlEncode(threadId)
4
+ * 无话题时 threadId 固定为 'main'。
5
+ */
6
+ export const DEFAULT_THREAD_ID = 'main';
7
+ export function formatSessionKey(channelType, channelId, threadId) {
8
+ const tid = threadId || DEFAULT_THREAD_ID;
9
+ return `${channelType}#${encodeURIComponent(channelId)}#${encodeURIComponent(tid)}`;
10
+ }
11
+ export function parseSessionKey(key) {
12
+ const first = key.indexOf('#');
13
+ if (first <= 0)
14
+ throw new Error(`Invalid session key: ${key}`);
15
+ const rest = key.slice(first + 1);
16
+ const second = rest.indexOf('#');
17
+ if (second <= 0)
18
+ throw new Error(`Invalid session key (missing threadId): ${key}`);
19
+ return {
20
+ channelType: key.slice(0, first),
21
+ channelId: decodeURIComponent(rest.slice(0, second)),
22
+ threadId: decodeURIComponent(rest.slice(second + 1)),
23
+ };
24
+ }