evolclaw 3.1.2 → 3.1.3
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 +21 -0
- package/README.md +2 -6
- package/dist/agents/claude-runner.js +1 -1
- package/dist/agents/codex-runner.js +75 -19
- package/dist/agents/gemini-runner.js +0 -2
- package/dist/agents/kit-renderer.js +59 -10
- package/dist/aun/aid/agentmd.js +49 -27
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/rpc/connection.js +3 -0
- package/dist/channels/aun.js +67 -14
- package/dist/cli/agent.js +13 -6
- package/dist/cli/index.js +27 -37
- package/dist/cli/init.js +13 -6
- package/dist/core/command-handler.js +615 -534
- package/dist/core/evolagent.js +31 -0
- package/dist/core/message/im-renderer.js +10 -0
- package/dist/core/message/message-bridge.js +123 -24
- package/dist/core/message/message-processor.js +43 -14
- package/dist/core/session/session-manager.js +185 -42
- package/kits/eck_manifest.json +3 -3
- package/kits/rules/02-navigation.md +1 -0
- package/kits/rules/06-channel.md +2 -18
- package/kits/templates/system-fragments/baseagent.md +2 -2
- package/kits/templates/system-fragments/channel.md +18 -9
- package/kits/templates/system-fragments/eckruntime.md +14 -0
- package/kits/templates/system-fragments/identity.md +5 -6
- package/kits/templates/system-fragments/relation.md +7 -5
- package/kits/templates/system-fragments/venue.md +2 -3
- package/package.json +1 -1
- package/kits/templates/system-fragments/runtime.md +0 -19
|
@@ -92,22 +92,12 @@ export class SessionManager {
|
|
|
92
92
|
*
|
|
93
93
|
* 这样保持兼容:不知道 channelType 的 caller 仍可以用 (channel, channelId) 调用。
|
|
94
94
|
*/
|
|
95
|
-
resolveChatDir(channel, channelId) {
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (d.channelId !== channelId)
|
|
100
|
-
continue;
|
|
101
|
-
// 验证 active.json 或 meta 文件里 channel(实例名)匹配
|
|
102
|
-
const active = readJsonFile(path.join(d.dirPath, 'active.json'));
|
|
103
|
-
if (active && active.channel === channel)
|
|
104
|
-
return d.dirPath;
|
|
105
|
-
// 没 active.json 时,看 channelType 是否能匹配 channel
|
|
106
|
-
if (!active && d.channelType === channel)
|
|
107
|
-
return d.dirPath;
|
|
95
|
+
resolveChatDir(channel, channelId, channelType, selfId) {
|
|
96
|
+
// 必须有明确 channelType 才能确定路径
|
|
97
|
+
if (!channelType) {
|
|
98
|
+
throw new Error(`[SessionManager] resolveChatDir requires channelType. Got channel="${channel}" channelId="${channelId}". Caller must pass channelType (e.g. 'aun', 'feishu').`);
|
|
108
99
|
}
|
|
109
|
-
|
|
110
|
-
return chatDirPath(this.sessionsDir, channel, channelId);
|
|
100
|
+
return chatDirPath(this.sessionsDir, channelType, channelId, selfId);
|
|
111
101
|
}
|
|
112
102
|
/**
|
|
113
103
|
* 给定明确的 channelType + selfId 时直接计算路径(不扫描)。
|
|
@@ -117,7 +107,7 @@ export class SessionManager {
|
|
|
117
107
|
if (channelType) {
|
|
118
108
|
return chatDirPath(this.sessionsDir, channelType, channelId, selfId);
|
|
119
109
|
}
|
|
120
|
-
return this.
|
|
110
|
+
return this.resolveChatDirSafe(channel, channelId);
|
|
121
111
|
}
|
|
122
112
|
resolveChatDirFromSession(session) {
|
|
123
113
|
const channelType = session.channelType || session.channel;
|
|
@@ -128,25 +118,129 @@ export class SessionManager {
|
|
|
128
118
|
return this.resolveChatDirFromSession(session);
|
|
129
119
|
}
|
|
130
120
|
/** Like resolveChatDir but also ensures the dir + _threads + _trash exist. */
|
|
131
|
-
ensureResolvedChatDir(channel, channelId) {
|
|
132
|
-
const dir = this.resolveChatDir(channel, channelId);
|
|
121
|
+
ensureResolvedChatDir(channel, channelId, channelType, selfId) {
|
|
122
|
+
const dir = this.resolveChatDir(channel, channelId, channelType, selfId);
|
|
133
123
|
fs.mkdirSync(dir, { recursive: true });
|
|
134
124
|
fs.mkdirSync(path.join(dir, '_threads'), { recursive: true });
|
|
135
125
|
fs.mkdirSync(path.join(dir, '_trash'), { recursive: true });
|
|
136
126
|
return dir;
|
|
137
127
|
}
|
|
138
128
|
/** 推断给定 chat 的 channelType(优先取 active.json)。无活跃时回落到 channel 实例名。 */
|
|
139
|
-
inferChannelType(channel, channelId) {
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
inferChannelType(channel, channelId, chatDir) {
|
|
130
|
+
if (chatDir) {
|
|
131
|
+
const active = readJsonFile(path.join(chatDir, 'active.json'));
|
|
132
|
+
if (active?.channelType)
|
|
133
|
+
return active.channelType;
|
|
134
|
+
}
|
|
135
|
+
// 扫描已有目录
|
|
136
|
+
const dirs = scanChatDirs(this.sessionsDir);
|
|
137
|
+
for (const d of dirs) {
|
|
138
|
+
if (d.channelId !== channelId)
|
|
139
|
+
continue;
|
|
140
|
+
const active = readJsonFile(path.join(d.dirPath, 'active.json'));
|
|
141
|
+
if (active && active.channel === channel && active.channelType)
|
|
142
|
+
return active.channelType;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`[SessionManager] Cannot infer channelType for channel="${channel}" channelId="${channelId}". No existing session found.`);
|
|
142
145
|
}
|
|
143
146
|
/** 从 active 推断 selfId(已有 session 的复用) */
|
|
144
|
-
inferSelfId(channel, channelId) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
inferSelfId(channel, channelId, chatDir) {
|
|
148
|
+
if (chatDir) {
|
|
149
|
+
const active = readJsonFile(path.join(chatDir, 'active.json'));
|
|
150
|
+
if (active?.selfId)
|
|
151
|
+
return active.selfId;
|
|
152
|
+
}
|
|
153
|
+
// 扫描已有目录
|
|
154
|
+
const dirs = scanChatDirs(this.sessionsDir);
|
|
155
|
+
for (const d of dirs) {
|
|
156
|
+
if (d.channelId !== channelId)
|
|
157
|
+
continue;
|
|
158
|
+
const active = readJsonFile(path.join(d.dirPath, 'active.json'));
|
|
159
|
+
if (active && active.channel === channel)
|
|
160
|
+
return active.selfId || undefined;
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 扫描已有 chat 目录,找到匹配 channel+channelId 的目录并返回其 chatDir 路径。
|
|
166
|
+
* 用于不知道 channelType/selfId 的 caller 在调用 resolveChatDir 前定位已有目录。
|
|
167
|
+
*/
|
|
168
|
+
findExistingChatDir(channel, channelId) {
|
|
169
|
+
const dirs = scanChatDirs(this.sessionsDir);
|
|
170
|
+
for (const d of dirs) {
|
|
171
|
+
if (d.channelId !== channelId)
|
|
172
|
+
continue;
|
|
173
|
+
const active = readJsonFile(path.join(d.dirPath, 'active.json'));
|
|
174
|
+
if (active && active.channel === channel)
|
|
175
|
+
return d.dirPath;
|
|
176
|
+
// 即使没有 active.json,也检查 meta 文件
|
|
177
|
+
const metaFiles = scanMetaFiles(d.dirPath);
|
|
178
|
+
for (const mf of metaFiles) {
|
|
179
|
+
const meta = readLastJsonlLine(path.join(d.dirPath, mf));
|
|
180
|
+
if (meta && meta.channel === channel)
|
|
181
|
+
return d.dirPath;
|
|
182
|
+
}
|
|
183
|
+
// 仅 thread session 场景:主目录无 active.json 也无 main meta,但 _threads/ 有内容
|
|
184
|
+
const threadsDir = path.join(d.dirPath, '_threads');
|
|
185
|
+
if (fs.existsSync(threadsDir)) {
|
|
186
|
+
const threadMetas = scanMetaFiles(threadsDir);
|
|
187
|
+
for (const mf of threadMetas) {
|
|
188
|
+
const meta = readLastJsonlLine(path.join(threadsDir, mf));
|
|
189
|
+
if (meta && meta.channel === channel)
|
|
190
|
+
return d.dirPath;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 安全版 resolveChatDir:先尝试用提供的 channelType/selfId,
|
|
198
|
+
* 如果没有则扫描已有目录推断。用于操作已有 session 的公共方法。
|
|
199
|
+
*/
|
|
200
|
+
resolveChatDirSafe(channel, channelId, channelType, selfId) {
|
|
201
|
+
if (channelType) {
|
|
202
|
+
return this.resolveChatDir(channel, channelId, channelType, selfId);
|
|
203
|
+
}
|
|
204
|
+
// 尝试从已有目录推断
|
|
205
|
+
const existingDir = this.findExistingChatDir(channel, channelId);
|
|
206
|
+
if (existingDir)
|
|
207
|
+
return existingDir;
|
|
208
|
+
throw new Error(`[SessionManager] Cannot resolve chat dir for channel="${channel}" channelId="${channelId}". No channelType provided and no existing session found.`);
|
|
147
209
|
}
|
|
148
|
-
|
|
149
|
-
|
|
210
|
+
/**
|
|
211
|
+
* 安全版 ensureResolvedChatDir:先尝试用提供的 channelType/selfId,
|
|
212
|
+
* 如果没有则扫描已有目录推断。确保目录存在。
|
|
213
|
+
*/
|
|
214
|
+
ensureResolvedChatDirSafe(channel, channelId, channelType, selfId) {
|
|
215
|
+
if (channelType) {
|
|
216
|
+
return this.ensureResolvedChatDir(channel, channelId, channelType, selfId);
|
|
217
|
+
}
|
|
218
|
+
// 尝试从已有目录推断
|
|
219
|
+
const existingDir = this.findExistingChatDir(channel, channelId);
|
|
220
|
+
if (existingDir) {
|
|
221
|
+
// 确保子目录存在
|
|
222
|
+
fs.mkdirSync(existingDir, { recursive: true });
|
|
223
|
+
fs.mkdirSync(path.join(existingDir, '_threads'), { recursive: true });
|
|
224
|
+
fs.mkdirSync(path.join(existingDir, '_trash'), { recursive: true });
|
|
225
|
+
return existingDir;
|
|
226
|
+
}
|
|
227
|
+
// 回退:推断 channelType 和 selfId
|
|
228
|
+
const inferredType = this.inferChannelType(channel, channelId);
|
|
229
|
+
const inferredSelfId = this.inferSelfId(channel, channelId);
|
|
230
|
+
return this.ensureResolvedChatDir(channel, channelId, inferredType, inferredSelfId);
|
|
231
|
+
}
|
|
232
|
+
readActive(channel, channelId, channelType, selfId) {
|
|
233
|
+
let dir;
|
|
234
|
+
try {
|
|
235
|
+
dir = this.resolveChatDir(channel, channelId, channelType, selfId);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// channelType not provided — try to find existing dir
|
|
239
|
+
const existingDir = this.findExistingChatDir(channel, channelId);
|
|
240
|
+
if (!existingDir)
|
|
241
|
+
return undefined;
|
|
242
|
+
dir = existingDir;
|
|
243
|
+
}
|
|
150
244
|
const file = readJsonFile(path.join(dir, 'active.json'));
|
|
151
245
|
if (!file)
|
|
152
246
|
return undefined;
|
|
@@ -157,8 +251,17 @@ export class SessionManager {
|
|
|
157
251
|
const file = sessionToFile(session);
|
|
158
252
|
atomicWriteJson(path.join(dir, 'active.json'), file);
|
|
159
253
|
}
|
|
160
|
-
clearActive(channel, channelId) {
|
|
161
|
-
|
|
254
|
+
clearActive(channel, channelId, channelType, selfId) {
|
|
255
|
+
let dir;
|
|
256
|
+
try {
|
|
257
|
+
dir = this.resolveChatDir(channel, channelId, channelType, selfId);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
const existingDir = this.findExistingChatDir(channel, channelId);
|
|
261
|
+
if (!existingDir)
|
|
262
|
+
return;
|
|
263
|
+
dir = existingDir;
|
|
264
|
+
}
|
|
162
265
|
const activePath = path.join(dir, 'active.json');
|
|
163
266
|
try {
|
|
164
267
|
fs.unlinkSync(activePath);
|
|
@@ -459,7 +562,7 @@ export class SessionManager {
|
|
|
459
562
|
return session;
|
|
460
563
|
}
|
|
461
564
|
// Find existing session for default project path
|
|
462
|
-
const chatDir = this.resolveChatDir(channel, channelId);
|
|
565
|
+
const chatDir = this.resolveChatDir(channel, channelId, channelType, selfId);
|
|
463
566
|
const allSessions = this.findAllSessionsInChat(chatDir, false);
|
|
464
567
|
const existing = allSessions
|
|
465
568
|
.filter(s => s.projectPath === defaultProjectPath && !s.threadId)
|
|
@@ -543,7 +646,7 @@ export class SessionManager {
|
|
|
543
646
|
// 优先使用精确路径(channelType + selfId),避免 fallback 到错误目录
|
|
544
647
|
const chatDir = (channelType && selfId)
|
|
545
648
|
? (() => { const d = chatDirPath(this.sessionsDir, channelType, channelId, selfId); fs.mkdirSync(d, { recursive: true }); fs.mkdirSync(path.join(d, '_threads'), { recursive: true }); return d; })()
|
|
546
|
-
: this.
|
|
649
|
+
: this.ensureResolvedChatDirSafe(channel, channelId, channelType);
|
|
547
650
|
const threadIndex = readThreadIndex(chatDir);
|
|
548
651
|
const existingMetaId = threadIndex[threadId];
|
|
549
652
|
if (existingMetaId) {
|
|
@@ -560,7 +663,7 @@ export class SessionManager {
|
|
|
560
663
|
}
|
|
561
664
|
}
|
|
562
665
|
// Inherit project path & chatType from active main session
|
|
563
|
-
const activeMain = this.readActive(channel, channelId);
|
|
666
|
+
const activeMain = this.readActive(channel, channelId, channelType, selfId);
|
|
564
667
|
const projectPath = (activeMain && !activeMain.threadId ? activeMain.projectPath : undefined) || defaultProjectPath;
|
|
565
668
|
const inheritedChatType = (activeMain && !activeMain.threadId ? activeMain.chatType : undefined) || 'private';
|
|
566
669
|
const session = {
|
|
@@ -597,7 +700,7 @@ export class SessionManager {
|
|
|
597
700
|
const agentId = currentAgentId || 'claude';
|
|
598
701
|
logger.info(`[SessionManager] switchProject: channel=${channel} channelId=${channelId} newPath=${newProjectPath} agent=${agentId}`);
|
|
599
702
|
const inheritedChatType = this.getActiveChatType(channel, channelId);
|
|
600
|
-
const chatDir = this.
|
|
703
|
+
const chatDir = this.ensureResolvedChatDirSafe(channel, channelId);
|
|
601
704
|
const allSessions = this.findAllSessionsInChat(chatDir, false);
|
|
602
705
|
const target = allSessions
|
|
603
706
|
.filter(s => s.projectPath === newProjectPath && (s.agentId || 'claude') === agentId && !s.threadId)
|
|
@@ -660,7 +763,7 @@ export class SessionManager {
|
|
|
660
763
|
}
|
|
661
764
|
async switchAgent(channel, channelId, projectPath, newAgentId) {
|
|
662
765
|
const inheritedChatType = this.getActiveChatType(channel, channelId);
|
|
663
|
-
const chatDir = this.
|
|
766
|
+
const chatDir = this.ensureResolvedChatDirSafe(channel, channelId);
|
|
664
767
|
const allSessions = this.findAllSessionsInChat(chatDir, false);
|
|
665
768
|
const target = allSessions
|
|
666
769
|
.filter(s => s.projectPath === projectPath && (s.agentId || 'claude') === newAgentId && !s.threadId)
|
|
@@ -748,7 +851,13 @@ export class SessionManager {
|
|
|
748
851
|
return this.readActive(channel, channelId);
|
|
749
852
|
}
|
|
750
853
|
async getThreadSession(channel, channelId, threadId) {
|
|
751
|
-
|
|
854
|
+
let chatDir;
|
|
855
|
+
try {
|
|
856
|
+
chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
857
|
+
}
|
|
858
|
+
catch {
|
|
859
|
+
return undefined;
|
|
860
|
+
}
|
|
752
861
|
const threadIndex = readThreadIndex(chatDir);
|
|
753
862
|
const metaId = threadIndex[threadId];
|
|
754
863
|
if (!metaId)
|
|
@@ -761,12 +870,24 @@ export class SessionManager {
|
|
|
761
870
|
return { ...session, agentSessionId: validSessionId };
|
|
762
871
|
}
|
|
763
872
|
async listSessions(channel, channelId) {
|
|
764
|
-
|
|
873
|
+
let chatDir;
|
|
874
|
+
try {
|
|
875
|
+
chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
return [];
|
|
879
|
+
}
|
|
765
880
|
const sessions = this.findAllSessionsInChat(chatDir, true);
|
|
766
881
|
return sessions.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
767
882
|
}
|
|
768
883
|
async getSessionByProjectPath(channel, channelId, projectPath) {
|
|
769
|
-
|
|
884
|
+
let chatDir;
|
|
885
|
+
try {
|
|
886
|
+
chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
887
|
+
}
|
|
888
|
+
catch {
|
|
889
|
+
return undefined;
|
|
890
|
+
}
|
|
770
891
|
const sessions = this.findAllSessionsInChat(chatDir, false);
|
|
771
892
|
const matched = sessions.filter(s => s.projectPath === projectPath);
|
|
772
893
|
if (matched.length === 0)
|
|
@@ -781,12 +902,24 @@ export class SessionManager {
|
|
|
781
902
|
return matched[0];
|
|
782
903
|
}
|
|
783
904
|
async getSessionByName(channel, channelId, name) {
|
|
784
|
-
|
|
905
|
+
let chatDir;
|
|
906
|
+
try {
|
|
907
|
+
chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
908
|
+
}
|
|
909
|
+
catch {
|
|
910
|
+
return undefined;
|
|
911
|
+
}
|
|
785
912
|
const sessions = this.findAllSessionsInChat(chatDir, true);
|
|
786
913
|
return sessions.find(s => s.name === name);
|
|
787
914
|
}
|
|
788
915
|
async switchToSession(channel, channelId, targetSessionId) {
|
|
789
|
-
|
|
916
|
+
let chatDir;
|
|
917
|
+
try {
|
|
918
|
+
chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
919
|
+
}
|
|
920
|
+
catch {
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
790
923
|
const sessions = this.findAllSessionsInChat(chatDir, true);
|
|
791
924
|
const target = sessions.find(s => s.id === targetSessionId);
|
|
792
925
|
if (!target)
|
|
@@ -903,12 +1036,22 @@ export class SessionManager {
|
|
|
903
1036
|
}
|
|
904
1037
|
async createNewSession(channel, channelId, projectPath, name, agentId) {
|
|
905
1038
|
const inheritedChatType = this.getActiveChatType(channel, channelId);
|
|
1039
|
+
let inferredType;
|
|
1040
|
+
let inferredSelfId;
|
|
1041
|
+
try {
|
|
1042
|
+
inferredType = this.inferChannelType(channel, channelId);
|
|
1043
|
+
inferredSelfId = this.inferSelfId(channel, channelId);
|
|
1044
|
+
}
|
|
1045
|
+
catch {
|
|
1046
|
+
inferredType = channel;
|
|
1047
|
+
inferredSelfId = undefined;
|
|
1048
|
+
}
|
|
906
1049
|
const session = {
|
|
907
1050
|
id: generateSessionId(),
|
|
908
1051
|
channel,
|
|
909
|
-
channelType:
|
|
1052
|
+
channelType: inferredType,
|
|
910
1053
|
channelId,
|
|
911
|
-
selfId:
|
|
1054
|
+
selfId: inferredSelfId,
|
|
912
1055
|
projectPath,
|
|
913
1056
|
threadId: '',
|
|
914
1057
|
agentId: agentId || 'claude',
|
|
@@ -1000,7 +1143,7 @@ export class SessionManager {
|
|
|
1000
1143
|
return adapter.listSdkSessions(projectPath);
|
|
1001
1144
|
}
|
|
1002
1145
|
async getSessionByUuidPrefix(channel, channelId, uuidPrefix) {
|
|
1003
|
-
const chatDir = this.
|
|
1146
|
+
const chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
1004
1147
|
const sessions = this.findAllSessionsInChat(chatDir, true);
|
|
1005
1148
|
const matched = sessions.filter(s => s.agentSessionId && s.agentSessionId.startsWith(uuidPrefix));
|
|
1006
1149
|
if (matched.length === 0)
|
|
@@ -1046,7 +1189,7 @@ export class SessionManager {
|
|
|
1046
1189
|
}
|
|
1047
1190
|
// ─── Health status ───
|
|
1048
1191
|
healthFilePath(channel, channelId) {
|
|
1049
|
-
return path.join(this.
|
|
1192
|
+
return path.join(this.ensureResolvedChatDirSafe(channel, channelId), 'health.jsonl');
|
|
1050
1193
|
}
|
|
1051
1194
|
/** Find the chat dir containing a given session id */
|
|
1052
1195
|
chatDirForSession(sessionId) {
|
package/kits/eck_manifest.json
CHANGED
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"description": "渠道层:我通过什么通信"
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
|
-
"id": "
|
|
74
|
+
"id": "eckruntime",
|
|
75
75
|
"type": "file",
|
|
76
|
-
"file": "$PACKAGE_ROOT/kits/templates/system-fragments/
|
|
76
|
+
"file": "$PACKAGE_ROOT/kits/templates/system-fragments/eckruntime.md",
|
|
77
77
|
"order": 60,
|
|
78
78
|
"needsInjection": true,
|
|
79
79
|
"when": "always",
|
|
@@ -92,4 +92,4 @@
|
|
|
92
92
|
"description": "Base Agent 特定配置"
|
|
93
93
|
}
|
|
94
94
|
]
|
|
95
|
-
}
|
|
95
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
| `$KITS_RULES` | `$KITS/rules` | 自动载入部分(本目录) |
|
|
19
19
|
| `$KITS_DOCS` | `$KITS/docs` | 按需载入文档 |
|
|
20
20
|
| `$KITS_TEMPLATES` | `$KITS/templates` | prompt 模板 |
|
|
21
|
+
| `$KITS_FRAGMENTS` | `$KITS_TEMPLATES/system-fragments` | ECK 动态注入 fragment 模板 |
|
|
21
22
|
| `$ECK` | `$EVOLCLAW_HOME/eck` | 运行时配置 |
|
|
22
23
|
| `$AGENTS_DIR` | `$EVOLCLAW_HOME/agents` | per-agent 数据根 |
|
|
23
24
|
| `$AGENT_DIR` | `$AGENTS_DIR/<self-aid>` | 当前 agent 根 |
|
package/kits/rules/06-channel.md
CHANGED
|
@@ -13,29 +13,15 @@
|
|
|
13
13
|
|
|
14
14
|
与其他主体通信时,**必须调用 CLI 命令**发消息,不要把输出当成发送给对方的内容。
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
当前渠道的发消息命令已在上下文中注入(见 `[aun]` 或对应渠道块)。
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
# 明文
|
|
20
|
-
ec msg send <self-aid> <to-aid> "<text>"
|
|
21
|
-
|
|
22
|
-
# 密文
|
|
23
|
-
ec msg send <self-aid> <to-aid> "<text>" --encrypt
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
`<self-aid>` 是注入上下文里的 selfAid,`<to-aid>` 是 peerKey 解析出的对端 AID。
|
|
27
|
-
|
|
28
|
-
### 仅在无法获取 selfAid 时才用 `ec ctl send`
|
|
18
|
+
### 仅在无法获取 self-aid 时才用 `ec ctl send`
|
|
29
19
|
|
|
30
20
|
```bash
|
|
31
21
|
ec ctl send "<text>"
|
|
32
22
|
ec ctl send --encrypt "<text>"
|
|
33
23
|
```
|
|
34
24
|
|
|
35
|
-
### 加密策略
|
|
36
|
-
|
|
37
|
-
对端发来密文消息时回复必须加密;明文消息默认明文回复。
|
|
38
|
-
|
|
39
25
|
### 命令返回值
|
|
40
26
|
|
|
41
27
|
- 成功:`ok` 或包含 `✓ 已发送 ...` 的输出(exit 0)
|
|
@@ -43,8 +29,6 @@ ec ctl send --encrypt "<text>"
|
|
|
43
29
|
|
|
44
30
|
发送成功后**继续后续处理**。一次任务可能发 0 到多条消息,不要因为看到"已发送"就反复发送同一条消息。
|
|
45
31
|
|
|
46
|
-
不同渠道有不同的命令行工具,使用方式参见各渠道文档。
|
|
47
|
-
|
|
48
32
|
## Agent 管理命令
|
|
49
33
|
|
|
50
34
|
`evolclaw agent` — agent 全生命周期管理。
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
[
|
|
2
|
-
|
|
1
|
+
[baseagent]
|
|
2
|
+
base-agent: {{baseAgentName}}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
[
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
{{?
|
|
5
|
-
[
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{{?
|
|
9
|
-
|
|
1
|
+
[channel]
|
|
2
|
+
channel: {{channel}}
|
|
3
|
+
{{?peerId}}
|
|
4
|
+
{{?channel=aun}}
|
|
5
|
+
ec msg send {{selfAid}} {{peerId}} "<text>" [--encrypt] [--file <path> --as image|video|voice|file] [--link <url> --title "<title>"] [--payload '<json>']
|
|
6
|
+
encrypt: 跟随对端消息加密状态(密文回密文,明文回明文);本端主动发时依据会话 encrypt 配置(待实现)
|
|
7
|
+
{{/}}
|
|
8
|
+
{{?channel!=aun}}
|
|
9
|
+
非 aun 渠道:回复由 evolclaw 自动完成,无需调用 CLI
|
|
10
|
+
{{/}}
|
|
11
|
+
{{/}}
|
|
12
|
+
{{?groupId}}
|
|
13
|
+
{{?channel=aun}}
|
|
14
|
+
ec group send {{selfAid}} {{groupId}} "<text>" [--file <path> --as image|video|voice|file] [--mention <aid>]
|
|
15
|
+
{{/}}
|
|
16
|
+
{{?channel!=aun}}
|
|
17
|
+
非 aun 渠道:回复由 evolclaw 自动完成,无需调用 CLI
|
|
18
|
+
{{/}}
|
|
10
19
|
{{/}}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[runtime]
|
|
2
|
+
project: {{project}}
|
|
3
|
+
{{?sessionName}}
|
|
4
|
+
session-name: {{sessionName}}
|
|
5
|
+
{{/}}
|
|
6
|
+
chatmode: {{chatmode}}
|
|
7
|
+
chatType: {{chatType}}
|
|
8
|
+
{{?readonly}}
|
|
9
|
+
readonly: true — 禁止修改项目文件,如需生成文件请写入 .evolclaw/tmp/
|
|
10
|
+
{{/}}
|
|
11
|
+
{{?chatmode=proactive}}
|
|
12
|
+
proactive-send: evolclaw ctl send "<text>"
|
|
13
|
+
proactive-file: evolclaw ctl file <path>
|
|
14
|
+
{{/}}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
[
|
|
1
|
+
[identity]
|
|
2
2
|
{{?selfAid}}
|
|
3
|
-
|
|
3
|
+
self-name: {{selfName}}
|
|
4
|
+
self-aid: {{selfAid}}
|
|
4
5
|
{{/}}
|
|
5
|
-
|
|
6
6
|
{{?hasPersona}}
|
|
7
|
-
|
|
7
|
+
persona: loaded
|
|
8
8
|
{{/}}
|
|
9
|
-
|
|
10
9
|
{{?hasWorkingMemory}}
|
|
11
|
-
|
|
10
|
+
working-memory: loaded
|
|
12
11
|
{{/}}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{{?peerKey}}
|
|
2
|
-
[
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
[relation]
|
|
3
|
+
peer-name: {{peerName}}
|
|
4
|
+
peer-aid: {{peerId}}
|
|
5
|
+
peer-role: {{peerRole}}
|
|
6
|
+
peer-key: {{peerKey}}
|
|
5
7
|
{{/}}
|
|
6
8
|
{{?groupId}}
|
|
7
|
-
[
|
|
8
|
-
|
|
9
|
+
[relation]
|
|
10
|
+
group-id: {{groupId}}
|
|
9
11
|
{{/}}
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
[运行时]
|
|
2
|
-
项目:{{project}}
|
|
3
|
-
{{?sessionName}}
|
|
4
|
-
会话名称:{{sessionName}}
|
|
5
|
-
{{/}}
|
|
6
|
-
|
|
7
|
-
会话模式:{{sessionMode}}
|
|
8
|
-
|
|
9
|
-
{{?readonly}}
|
|
10
|
-
⚠️ 只读模式:禁止修改项目文件。如需生成文件供用户下载,请写入 .evolclaw/tmp/ 目录。
|
|
11
|
-
{{/}}
|
|
12
|
-
|
|
13
|
-
{{?sessionMode=proactive}}
|
|
14
|
-
[Proactive 模式] 你的所有文本输出都会被静默丢弃,用户永远看不到。唯一能让用户收到消息的方式:
|
|
15
|
-
调用 Bash 工具执行命令:evolclaw ctl send "<消息内容>"
|
|
16
|
-
发送文件:evolclaw ctl file <路径>
|
|
17
|
-
可多次调用发送多条消息,如果不想回复停止调用即可。
|
|
18
|
-
禁止使用 AskUserQuestion 和 ExitPlanMode 工具——proactive 模式下应由你主动用 ctl send 与用户沟通。
|
|
19
|
-
{{/}}
|