evolclaw 3.1.11 → 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 +41 -0
- package/README.md +27 -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/control-aid.js +67 -0
- package/dist/aun/aid/identity.js +20 -7
- package/dist/aun/aid/store.js +2 -2
- package/dist/aun/storage/download.js +1 -1
- package/dist/aun/storage/upload.js +13 -1
- package/dist/channels/aun.js +538 -325
- package/dist/channels/dingtalk.js +77 -140
- package/dist/channels/feishu.js +98 -151
- 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 +44 -13
- package/dist/cli/index.js +207 -46
- package/dist/cli/init-channel.js +38 -148
- package/dist/cli/init.js +192 -85
- 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 +48 -11
- package/dist/core/channel-loader.js +84 -82
- package/dist/core/command-handler.js +754 -172
- package/dist/core/daemon-file-cache.js +216 -0
- package/dist/core/evolagent-registry.js +4 -0
- package/dist/core/evolagent.js +28 -23
- package/dist/core/interaction-router.js +8 -0
- package/dist/core/message/command-handler-agent-control.js +215 -0
- package/dist/core/message/create-status.js +67 -0
- 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 +52 -22
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-processor.js +336 -68
- package/dist/core/message/message-queue.js +15 -8
- 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 +40 -7
- package/dist/core/permission.js +9 -12
- package/dist/core/relation/peer-identity.js +16 -1
- package/dist/core/session/adapters/claude-session-file-adapter.js +48 -5
- 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}/kit-renderer.js +5 -1
- package/dist/{agents → eck}/manifest-engine.js +127 -35
- package/dist/{agents → eck}/message-renderer.js +26 -1
- package/dist/index.js +185 -8
- package/dist/ipc.js +22 -0
- package/dist/paths.js +7 -3
- 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/message-fragments/item.md +1 -1
- 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/utils/channel-helpers.js +0 -46
|
@@ -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,
|
|
@@ -151,26 +156,31 @@ export class MessageBridge {
|
|
|
151
156
|
sameNetwork: msg.sameNetwork,
|
|
152
157
|
sameEgressIp: msg.sameEgressIp,
|
|
153
158
|
messageId: msg.messageId,
|
|
154
|
-
mentions: msg.mentions, threadId: msg.threadId,
|
|
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',
|
|
@@ -218,7 +229,26 @@ export class MessageBridge {
|
|
|
218
229
|
activity: '/activity',
|
|
219
230
|
system: '/system',
|
|
220
231
|
cli: '/cli',
|
|
232
|
+
agent: '/agent',
|
|
233
|
+
trigger: '/trigger',
|
|
221
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
|
+
}
|
|
222
252
|
resolveCmd(name, cmd) {
|
|
223
253
|
if (cmd)
|
|
224
254
|
return cmd;
|
|
@@ -276,7 +306,7 @@ export class MessageBridge {
|
|
|
276
306
|
const { id, name, cmd } = req;
|
|
277
307
|
try {
|
|
278
308
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
279
|
-
const result = await this.cmdHandler.execMenuQuery(resolvedCmd, channel, msg.channelId, msg.peerId);
|
|
309
|
+
const result = await this.cmdHandler.execMenuQuery(resolvedCmd, channel, msg.channelId, msg.peerId, req.args, msg.chatType);
|
|
280
310
|
if ('error' in result)
|
|
281
311
|
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
282
312
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|
|
@@ -292,7 +322,7 @@ export class MessageBridge {
|
|
|
292
322
|
const { id, name, cmd } = req;
|
|
293
323
|
try {
|
|
294
324
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
295
|
-
const data = await this.cmdHandler.getSubMenuItems(resolvedCmd, channel, msg.channelId, msg.peerId) ?? [];
|
|
325
|
+
const data = await this.cmdHandler.getSubMenuItems(resolvedCmd, channel, msg.channelId, msg.peerId, req.args, undefined, msg.chatType) ?? [];
|
|
296
326
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data }, sendReply);
|
|
297
327
|
}
|
|
298
328
|
catch (err) {
|
|
@@ -326,7 +356,7 @@ export class MessageBridge {
|
|
|
326
356
|
if (!action)
|
|
327
357
|
throw { code: 'MISSING_VALUE', message: '缺少 action 参数' };
|
|
328
358
|
const resolvedCmd = this.resolveCmd(name, cmd);
|
|
329
|
-
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);
|
|
330
360
|
if ('error' in result)
|
|
331
361
|
throw { code: result.code || 'EXEC_FAILED', message: result.error };
|
|
332
362
|
await this.sendMenuResponse(adapter, channel, msg.channelId, { type: 'menu.response', id, name, data: result.data }, sendReply);
|