evolclaw 3.1.3 → 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.
- package/CHANGELOG.md +27 -0
- package/assets/.env.template +4 -0
- package/assets/config.json.template +6 -0
- package/assets/wechat-group-qr.jpeg +0 -0
- package/dist/agents/claude-runner.js +348 -156
- package/dist/agents/kit-renderer.js +211 -42
- package/dist/aun/aid/agentmd.js +75 -139
- package/dist/aun/aid/client.js +1 -14
- package/dist/aun/aid/identity.js +381 -54
- package/dist/aun/aid/index.js +3 -2
- package/dist/aun/aid/store.js +74 -0
- package/dist/aun/msg/p2p.js +26 -2
- package/dist/aun/rpc/connection.js +23 -35
- package/dist/channels/aun.js +92 -144
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +270 -190
- package/dist/channels/qqbot.js +1 -0
- package/dist/channels/wechat.js +1 -0
- package/dist/channels/wecom.js +1 -0
- package/dist/cli/agent.js +26 -27
- package/dist/cli/bench.js +45 -34
- package/dist/cli/help.js +23 -0
- package/dist/cli/index.js +538 -77
- package/dist/cli/init-channel.js +7 -4
- package/dist/cli/link-rules.js +2 -1
- package/dist/cli/model.js +324 -0
- package/dist/cli/net-check.js +138 -56
- package/dist/cli/watch-msg.js +7 -7
- package/dist/cli/watch-web/debug-log.js +18 -0
- package/dist/cli/watch-web/server.js +306 -0
- package/dist/cli/watch-web/sources/aid.js +63 -0
- package/dist/cli/watch-web/sources/msg.js +70 -0
- package/dist/cli/watch-web/sources/session.js +638 -0
- package/dist/cli/watch-web/sources/types.js +10 -0
- package/dist/cli/watch-web/static/app.js +546 -0
- package/dist/cli/watch-web/static/index.html +54 -0
- package/dist/cli/watch-web/static/style.css +247 -0
- package/dist/core/channel-loader.js +7 -4
- package/dist/core/command-handler.js +87 -93
- package/dist/core/evolagent-registry.js +1 -1
- package/dist/core/evolagent.js +4 -4
- package/dist/core/interaction-router.js +59 -0
- package/dist/core/message/message-bridge.js +6 -6
- package/dist/core/message/message-log.js +2 -2
- package/dist/core/message/message-processor.js +104 -118
- package/dist/core/message/stream-idle-monitor.js +21 -0
- package/dist/core/model/model-catalog.js +215 -0
- package/dist/core/model/model-scope.js +250 -0
- package/dist/core/relation/peer-identity.js +78 -44
- package/dist/core/relation/peer-key.js +16 -0
- package/dist/core/session/session-fs-store.js +34 -55
- package/dist/core/session/session-key.js +24 -0
- package/dist/core/session/session-manager.js +312 -251
- package/dist/core/session/session-mapper.js +9 -4
- package/dist/core/trigger/manager.js +37 -0
- package/dist/core/trigger/scheduler.js +2 -1
- package/dist/index.js +10 -3
- package/dist/ipc.js +22 -0
- package/dist/paths.js +87 -16
- package/dist/utils/npm-ops.js +18 -11
- package/kits/docs/GUIDE.md +2 -2
- package/kits/docs/INDEX.md +11 -7
- package/kits/docs/channels/aun.md +56 -17
- package/kits/docs/channels/feishu.md +41 -12
- package/kits/docs/context-assembly.md +181 -0
- package/kits/docs/evolclaw/agent.md +49 -0
- package/kits/docs/evolclaw/aid.md +49 -0
- package/kits/docs/evolclaw/ctl.md +46 -0
- package/kits/docs/evolclaw/group.md +82 -0
- package/kits/docs/evolclaw/msg.md +86 -0
- package/kits/docs/evolclaw/rpc.md +35 -0
- package/kits/docs/evolclaw/storage.md +49 -0
- package/kits/docs/venues/aun-group.md +10 -0
- package/kits/docs/venues/aun-private.md +10 -0
- package/kits/docs/venues/client-desktop.md +10 -0
- package/kits/docs/venues/client-mobile.md +10 -0
- package/kits/docs/venues/feishu-group.md +13 -0
- package/kits/docs/venues/feishu-private.md +9 -0
- package/kits/docs/venues/group.md +11 -0
- package/kits/docs/venues/private.md +10 -0
- package/kits/eck_manifest.json +75 -39
- package/kits/rules/01-overview.md +20 -10
- package/kits/rules/05-venue.md +2 -2
- package/kits/rules/06-channel.md +30 -27
- package/kits/templates/system-fragments/baseagent.md +7 -1
- package/kits/templates/system-fragments/channel.md +4 -1
- package/kits/templates/system-fragments/identity.md +4 -4
- package/kits/templates/system-fragments/relation.md +8 -5
- package/kits/templates/system-fragments/session.md +27 -0
- package/kits/templates/system-fragments/venue.md +13 -1
- package/package.json +13 -6
- package/dist/aun/aid/lifecycle-log.js +0 -33
- package/dist/net-check.js +0 -640
- package/dist/utils/aid-lifecycle-log.js +0 -33
- package/dist/watch-msg.js +0 -544
- package/kits/docs/evolclaw/AGENT_CMD.md +0 -31
- package/kits/docs/evolclaw/MSG_GROUP.md +0 -30
- package/kits/docs/evolclaw/MSG_PRIVATE.md +0 -72
- package/kits/docs/evolclaw/tools.md +0 -25
- package/kits/templates/system-fragments/eckruntime.md +0 -14
|
@@ -1,14 +1,55 @@
|
|
|
1
1
|
import { logger } from '../utils/logger.js';
|
|
2
2
|
export class InteractionRouter {
|
|
3
3
|
handlers = new Map();
|
|
4
|
+
/** sessionId → 该会话当前待应答的交互数量,用于触发 wait 生命周期钩子 */
|
|
5
|
+
pendingBySession = new Map();
|
|
6
|
+
waitHooks;
|
|
7
|
+
setWaitHooks(hooks) {
|
|
8
|
+
this.waitHooks = hooks;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 在 register() 之前提前标记 session 为等待状态(适用于发卡片有异步延迟的场景)。
|
|
12
|
+
* 必须与 unmarkWaiting() 配对使用,或后续 register() 会接管计数。
|
|
13
|
+
*/
|
|
14
|
+
markWaiting(sessionId) {
|
|
15
|
+
this.incPending(sessionId);
|
|
16
|
+
}
|
|
17
|
+
/** 取消 markWaiting() 的占位(后续若有 register() 接管则不需调用此方法) */
|
|
18
|
+
unmarkWaiting(sessionId) {
|
|
19
|
+
this.decPending(sessionId);
|
|
20
|
+
}
|
|
21
|
+
/** 登记一个待应答交互;session 计数 0→1 时触发 onWaitStart */
|
|
22
|
+
incPending(sessionId) {
|
|
23
|
+
const next = (this.pendingBySession.get(sessionId) ?? 0) + 1;
|
|
24
|
+
this.pendingBySession.set(sessionId, next);
|
|
25
|
+
if (next === 1)
|
|
26
|
+
this.waitHooks?.onWaitStart(sessionId);
|
|
27
|
+
}
|
|
28
|
+
/** 注销一个待应答交互;session 计数 1→0 时触发 onWaitEnd */
|
|
29
|
+
decPending(sessionId) {
|
|
30
|
+
const cur = this.pendingBySession.get(sessionId) ?? 0;
|
|
31
|
+
if (cur <= 0)
|
|
32
|
+
return;
|
|
33
|
+
const next = cur - 1;
|
|
34
|
+
if (next === 0) {
|
|
35
|
+
this.pendingBySession.delete(sessionId);
|
|
36
|
+
this.waitHooks?.onWaitEnd(sessionId);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.pendingBySession.set(sessionId, next);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
4
42
|
register(id, sessionId, callback, opts) {
|
|
43
|
+
// 同 id 替换:槽位本就占用,计数不变,不触发 wait 钩子
|
|
5
44
|
const existing = this.handlers.get(id);
|
|
6
45
|
if (existing?.timer)
|
|
7
46
|
clearTimeout(existing.timer);
|
|
47
|
+
const isReplacement = !!existing;
|
|
8
48
|
let timer;
|
|
9
49
|
if (opts?.timeoutMs && opts.timeoutMs > 0) {
|
|
10
50
|
timer = setTimeout(() => {
|
|
11
51
|
this.handlers.delete(id);
|
|
52
|
+
this.decPending(sessionId);
|
|
12
53
|
logger.debug(`[InteractionRouter] Timeout for interaction: ${id}`);
|
|
13
54
|
opts.onTimeout?.();
|
|
14
55
|
}, opts.timeoutMs);
|
|
@@ -20,6 +61,8 @@ export class InteractionRouter {
|
|
|
20
61
|
initiatorId: opts?.initiatorId,
|
|
21
62
|
fallbackCommand: opts?.fallbackCommand,
|
|
22
63
|
});
|
|
64
|
+
if (!isReplacement)
|
|
65
|
+
this.incPending(sessionId);
|
|
23
66
|
}
|
|
24
67
|
handle(response) {
|
|
25
68
|
const handler = this.handlers.get(response.id);
|
|
@@ -28,6 +71,7 @@ export class InteractionRouter {
|
|
|
28
71
|
if (handler.timer)
|
|
29
72
|
clearTimeout(handler.timer);
|
|
30
73
|
this.handlers.delete(response.id);
|
|
74
|
+
this.decPending(handler.sessionId);
|
|
31
75
|
try {
|
|
32
76
|
const result = handler.callback(response.action, response.values, response.operatorId);
|
|
33
77
|
if (result && typeof result.catch === 'function') {
|
|
@@ -47,6 +91,7 @@ export class InteractionRouter {
|
|
|
47
91
|
if (handler.timer)
|
|
48
92
|
clearTimeout(handler.timer);
|
|
49
93
|
this.handlers.delete(id);
|
|
94
|
+
this.decPending(handler.sessionId);
|
|
50
95
|
}
|
|
51
96
|
}
|
|
52
97
|
}
|
|
@@ -56,6 +101,7 @@ export class InteractionRouter {
|
|
|
56
101
|
if (handler.timer)
|
|
57
102
|
clearTimeout(handler.timer);
|
|
58
103
|
this.handlers.delete(id);
|
|
104
|
+
this.decPending(handler.sessionId);
|
|
59
105
|
}
|
|
60
106
|
}
|
|
61
107
|
getPending(sessionId) {
|
|
@@ -100,6 +146,16 @@ export function renderActionAsText(req) {
|
|
|
100
146
|
const lines = [action.title];
|
|
101
147
|
if (action.body)
|
|
102
148
|
lines.push(action.body);
|
|
149
|
+
// checkers 多选:渲染选项列表
|
|
150
|
+
if (action.checkers?.length) {
|
|
151
|
+
lines.push('');
|
|
152
|
+
action.checkers.forEach((chk, idx) => {
|
|
153
|
+
const desc = chk.description ? ` — ${chk.description}` : '';
|
|
154
|
+
lines.push(` ${idx + 1}. ${chk.label}${desc}`);
|
|
155
|
+
});
|
|
156
|
+
lines.push('', '回复选项编号(多选用逗号分隔),或输入自定义内容');
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
}
|
|
103
159
|
if (!fb) {
|
|
104
160
|
return lines.join('\n');
|
|
105
161
|
}
|
|
@@ -111,5 +167,8 @@ export function renderActionAsText(req) {
|
|
|
111
167
|
if (fb.acceptFreeText && fb.freeTextHint) {
|
|
112
168
|
lines.push(` ${fb.freeTextHint}`);
|
|
113
169
|
}
|
|
170
|
+
if (action.allowCustomInput) {
|
|
171
|
+
lines.push(` 或直接输入自定义内容`);
|
|
172
|
+
}
|
|
114
173
|
return lines.join('\n');
|
|
115
174
|
}
|
|
@@ -81,12 +81,12 @@ export class MessageBridge {
|
|
|
81
81
|
logger.debug(`[MessageBridge] Command detected: "${cmdContent}", routing to handler`);
|
|
82
82
|
// 命令也要记录入方向 jsonl(不创建 session,直接用 chatDirPath 计算路径)
|
|
83
83
|
try {
|
|
84
|
-
const chatDir = chatDirPath(resolvePaths().sessionsDir, msg.channelType || effectiveChannelType, msg.channelId, msg.
|
|
84
|
+
const chatDir = chatDirPath(resolvePaths().sessionsDir, msg.channelType || effectiveChannelType, msg.channelId, msg.selfAID || '');
|
|
85
85
|
const inboundEncrypt = msg.replyContext?.metadata?.encrypted != null ? !!(msg.replyContext.metadata.encrypted) : undefined;
|
|
86
86
|
const inboundChatmode = msg.replyContext?.metadata?.chatmode;
|
|
87
87
|
appendMessageLog(chatDir, buildInboundEntry({
|
|
88
88
|
from: msg.peerId || 'unknown',
|
|
89
|
-
to: msg.
|
|
89
|
+
to: msg.selfAID || 'self',
|
|
90
90
|
chatType: msg.chatType || 'private',
|
|
91
91
|
groupId: msg.groupId ?? null,
|
|
92
92
|
msgId: msg.messageId ?? null,
|
|
@@ -114,7 +114,7 @@ export class MessageBridge {
|
|
|
114
114
|
if (msg.threadId && msg.replyContext)
|
|
115
115
|
metadata.replyContext = msg.replyContext;
|
|
116
116
|
// 写入实例名(审计 + 精确出站路由)
|
|
117
|
-
metadata.
|
|
117
|
+
metadata.channelKey = channelName;
|
|
118
118
|
if (chatType === 'private' && msg.peerId) {
|
|
119
119
|
metadata.peerId = msg.peerId;
|
|
120
120
|
if (msg.peerName)
|
|
@@ -134,7 +134,7 @@ export class MessageBridge {
|
|
|
134
134
|
const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
|
|
135
135
|
const effectiveProjectPath = owningAgent?.projectPath
|
|
136
136
|
?? this.defaultProjectPath;
|
|
137
|
-
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, undefined, msg.peerId, chatType, undefined, msg.
|
|
137
|
+
const session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, undefined, msg.peerId, chatType, undefined, msg.selfAID, msg.channelType || effectiveChannelType, msg.peerType);
|
|
138
138
|
// 4. 消息前缀(由 policy 决定)
|
|
139
139
|
const channelInfo = this.processor.getChannelInfo?.(channelName);
|
|
140
140
|
if (channelInfo?.policy) {
|
|
@@ -147,7 +147,7 @@ export class MessageBridge {
|
|
|
147
147
|
channel: channelName,
|
|
148
148
|
channelType: msg.channelType || effectiveChannelType,
|
|
149
149
|
channelId: msg.channelId, content,
|
|
150
|
-
|
|
150
|
+
selfAID: msg.selfAID,
|
|
151
151
|
chatType,
|
|
152
152
|
images: msg.images, timestamp: Date.now(),
|
|
153
153
|
peerId: msg.peerId, peerName: msg.peerName,
|
|
@@ -162,7 +162,7 @@ export class MessageBridge {
|
|
|
162
162
|
const inboundChatmode = msg.replyContext?.metadata?.chatmode;
|
|
163
163
|
appendMessageLog(chatDir, buildInboundEntry({
|
|
164
164
|
from: msg.peerId || 'unknown',
|
|
165
|
-
to: msg.
|
|
165
|
+
to: msg.selfAID || 'self',
|
|
166
166
|
chatType,
|
|
167
167
|
groupId: msg.groupId ?? null,
|
|
168
168
|
msgId: msg.messageId ?? null,
|
|
@@ -31,8 +31,8 @@ function formatTimestampMs(epochMs) {
|
|
|
31
31
|
export function messageLogPath(chatDir) {
|
|
32
32
|
return path.join(chatDir, MESSAGE_LOG_FILE);
|
|
33
33
|
}
|
|
34
|
-
export function resolveChatDir(sessionsDir, channelType, channelId,
|
|
35
|
-
return chatDirPath(sessionsDir, channelType, channelId,
|
|
34
|
+
export function resolveChatDir(sessionsDir, channelType, channelId, selfAID) {
|
|
35
|
+
return chatDirPath(sessionsDir, channelType, channelId, selfAID);
|
|
36
36
|
}
|
|
37
37
|
export function appendMessageLog(chatDir, entry) {
|
|
38
38
|
if (entry.dir === 'in' && isDuplicate(entry.msgId)) {
|