aws-runtime-bridge 1.9.58 → 1.9.61
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/dist/routes/sub-agents.js +14 -6
- package/package/acode/dist/fs-utils.d.ts +21 -0
- package/package/acode/dist/fs-utils.d.ts.map +1 -0
- package/package/acode/dist/fs-utils.js +79 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +67 -8
- package/package/acode/dist/sub-agent-manager.d.ts +36 -0
- package/package/acode/dist/sub-agent-manager.d.ts.map +1 -1
- package/package/acode/dist/sub-agent-manager.js +184 -45
- package/package/acode/dist/sub-agent-store.d.ts +44 -5
- package/package/acode/dist/sub-agent-store.d.ts.map +1 -1
- package/package/acode/dist/sub-agent-store.js +88 -16
- package/package/acode/dist/todo-store.d.ts +1 -0
- package/package/acode/dist/todo-store.d.ts.map +1 -1
- package/package/acode/dist/todo-store.js +6 -1
- package/package/acode/dist/types.d.ts +11 -0
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +5 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +12 -2
- package/package/aws-client-agent-mcp/dist/logger.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.js +53 -12
- package/package/aws-client-agent-mcp/dist/logger.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.test.js +5 -8
- package/package/aws-client-agent-mcp/dist/logger.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +21 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +105 -7
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +4 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +26 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -30,9 +30,13 @@ subAgentsRouter.get("/sub-agents/:agentId", validateToken, async (req, res) => {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
try {
|
|
33
|
-
//
|
|
33
|
+
// ★ 内存态是运行态的唯一真相源:pending/running 只信 SubAgentManager。
|
|
34
|
+
// 磁盘 store 只做历史归档,不再参与运行态判定。
|
|
35
|
+
// 之前在列表接口里做"磁盘 running/pending + 内存无 → 改写 failed"的兜底,
|
|
36
|
+
// 会把"终态写入超时/EPERM 失败但内存已 completed"的 sub-agent 误判为 failed,
|
|
37
|
+
// 覆盖真实结果。现在直接从 history 过滤掉这类残留,磁盘不写、前端不展示,
|
|
38
|
+
// 由 bridge 启动时的 reconcileZombies() 一次性清理(已存在逻辑)。
|
|
34
39
|
const allRecords = await subAgentStore.list(agentId);
|
|
35
|
-
// 从 manager 读取活跃 entry(pending / running),已完成但未 TTL 清理的不计入
|
|
36
40
|
const runningEntries = subAgentManager.listActiveByParent(agentId);
|
|
37
41
|
const runningIds = new Set(runningEntries.map((e) => e.subId));
|
|
38
42
|
// 合并:运行中的用 manager 的实时状态覆盖 store 的记录
|
|
@@ -48,7 +52,11 @@ subAgentsRouter.get("/sub-agents/:agentId", validateToken, async (req, res) => {
|
|
|
48
52
|
contextSnapshot: e.contextSnapshot,
|
|
49
53
|
availableTools: e.availableTools,
|
|
50
54
|
}));
|
|
51
|
-
|
|
55
|
+
// history 过滤逻辑:
|
|
56
|
+
// - runningIds 中的(运行中)已挪到 running 数组,不重复进 history
|
|
57
|
+
// - 磁盘上残留的 running/pending(终态写入失败/进程重启残留)直接丢弃,
|
|
58
|
+
// 不展示为 failed——真实状态未知,不能编造错误信息
|
|
59
|
+
const history = allRecords.filter((r) => !runningIds.has(r.subId) && r.status !== "running" && r.status !== "pending");
|
|
52
60
|
const doc = await subAgentStore.read(agentId);
|
|
53
61
|
res.json({
|
|
54
62
|
ok: true,
|
|
@@ -203,10 +211,10 @@ subAgentsRouter.get("/sub-agents/:agentId/:subId/events", validateToken, async (
|
|
|
203
211
|
"X-Accel-Buffering": "no", // nginx 关闭缓冲
|
|
204
212
|
});
|
|
205
213
|
res.write(": connected\n\n");
|
|
206
|
-
// 1. 补发历史 tool
|
|
214
|
+
// 1. 补发历史 tool 事件(从独立 jsonl 事件文件读取,按时间升序)
|
|
215
|
+
// 事件文件与主记录文件分离,避免高频 appendEvent 阻塞终态 updateStatus
|
|
207
216
|
try {
|
|
208
|
-
const
|
|
209
|
-
const historyEvents = record?.events ?? [];
|
|
217
|
+
const historyEvents = await subAgentStore.readEvents(agentId, subId);
|
|
210
218
|
for (const ev of historyEvents) {
|
|
211
219
|
res.write(`data: ${JSON.stringify(ev)}\n\n`);
|
|
212
220
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 对 `fs.rename` 做指数退避重试,仅针对 Windows 上目标被打开时
|
|
3
|
+
* 的瞬时错误(EPERM/EBUSY/EACCES/ENOTEMPTY)。
|
|
4
|
+
*
|
|
5
|
+
* 其他错误(ENOENT 源不存在、ENOSPC 磁盘满等)直接抛出,不重试。
|
|
6
|
+
*
|
|
7
|
+
* ★ Windows EPERM 终极兜底:若全部重试仍失败(target 持续被 reader 持有 fd),
|
|
8
|
+
* fallback 到 `fs.copyFile(src, dest) + fs.unlink(src)`。
|
|
9
|
+
* - `fs.copyFile` 在 Windows 上走 `CopyFileEx` API,允许覆盖被其他进程打开的
|
|
10
|
+
* target(只要 reader 共享模式允许读,fs.readFile 默认如此),能绕开 EPERM。
|
|
11
|
+
* - 代价是失去原子性:写入过程中崩溃可能产生半成品 dest。
|
|
12
|
+
* 但 sub-agent 记录非关键数据,配合 SubAgentStore.read() 的
|
|
13
|
+
* `SyntaxError → empty` 容错已够用(最坏情况是列表暂时少一条历史)。
|
|
14
|
+
* - POSIX 上 rename 重试一般不会失败(原子操作),fallback 路径极少触发。
|
|
15
|
+
*
|
|
16
|
+
* @param src 源文件路径(通常是 `.tmp` 临时文件)
|
|
17
|
+
* @param dest 目标文件路径
|
|
18
|
+
* @returns 成功时 resolve,全部重试都失败时 reject 最后一次错误
|
|
19
|
+
*/
|
|
20
|
+
export declare function renameWithRetry(src: string, dest: string): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=fs-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-utils.d.ts","sourceRoot":"","sources":["../src/fs-utils.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC9E"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* 文件系统原子写入相关的辅助工具。
|
|
4
|
+
*
|
|
5
|
+
* 主要解决 Windows 上 `fs.rename` 在目标文件被其他进程/句柄打开时
|
|
6
|
+
* 抛出 EPERM/EBUSY/EACCES 的问题(POSIX 上 rename 是真原子的,
|
|
7
|
+
* 不会触发此类错误)。这些错误通常是瞬时的——等 reader 释放 fd
|
|
8
|
+
* 后重试即可成功。
|
|
9
|
+
*
|
|
10
|
+
* 不引入 fs-ext/native 依赖,纯 JS 退避重试实现。
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* 视为可重试的瞬时错误码。
|
|
14
|
+
*
|
|
15
|
+
* - EPERM: Windows 上目标被另一进程打开时 rename 常见错误
|
|
16
|
+
* - EBUSY: 资源忙(Linux/Windows 均可能出现)
|
|
17
|
+
* - EACCES: 权限瞬时不可用(如杀软扫描中)
|
|
18
|
+
* - ENOTEMPTY: 极少数情况下 rename 目标存在残留
|
|
19
|
+
*/
|
|
20
|
+
const RENAME_RETRYABLE_CODES = ["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"];
|
|
21
|
+
/**
|
|
22
|
+
* 退避序列(毫秒)。总退避 ≈ 50+150+400+800 = 1400ms,
|
|
23
|
+
* 留充足余量给 5s 的 STORE_WRITE_TIMEOUT_MS。
|
|
24
|
+
*/
|
|
25
|
+
const RENAME_BACKOFF_MS = [50, 150, 400, 800];
|
|
26
|
+
/**
|
|
27
|
+
* 对 `fs.rename` 做指数退避重试,仅针对 Windows 上目标被打开时
|
|
28
|
+
* 的瞬时错误(EPERM/EBUSY/EACCES/ENOTEMPTY)。
|
|
29
|
+
*
|
|
30
|
+
* 其他错误(ENOENT 源不存在、ENOSPC 磁盘满等)直接抛出,不重试。
|
|
31
|
+
*
|
|
32
|
+
* ★ Windows EPERM 终极兜底:若全部重试仍失败(target 持续被 reader 持有 fd),
|
|
33
|
+
* fallback 到 `fs.copyFile(src, dest) + fs.unlink(src)`。
|
|
34
|
+
* - `fs.copyFile` 在 Windows 上走 `CopyFileEx` API,允许覆盖被其他进程打开的
|
|
35
|
+
* target(只要 reader 共享模式允许读,fs.readFile 默认如此),能绕开 EPERM。
|
|
36
|
+
* - 代价是失去原子性:写入过程中崩溃可能产生半成品 dest。
|
|
37
|
+
* 但 sub-agent 记录非关键数据,配合 SubAgentStore.read() 的
|
|
38
|
+
* `SyntaxError → empty` 容错已够用(最坏情况是列表暂时少一条历史)。
|
|
39
|
+
* - POSIX 上 rename 重试一般不会失败(原子操作),fallback 路径极少触发。
|
|
40
|
+
*
|
|
41
|
+
* @param src 源文件路径(通常是 `.tmp` 临时文件)
|
|
42
|
+
* @param dest 目标文件路径
|
|
43
|
+
* @returns 成功时 resolve,全部重试都失败时 reject 最后一次错误
|
|
44
|
+
*/
|
|
45
|
+
export async function renameWithRetry(src, dest) {
|
|
46
|
+
let lastErr;
|
|
47
|
+
// 尝试次数 = 1(初始)+ RENAME_BACKOFF_MS.length(重试)
|
|
48
|
+
const maxAttempts = 1 + RENAME_BACKOFF_MS.length;
|
|
49
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
50
|
+
try {
|
|
51
|
+
await fs.rename(src, dest);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
lastErr = err;
|
|
56
|
+
const code = err?.code ?? "";
|
|
57
|
+
if (!RENAME_RETRYABLE_CODES.includes(code)) {
|
|
58
|
+
// 非瞬时错误,直接抛出避免无谓重试
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
if (attempt < RENAME_BACKOFF_MS.length) {
|
|
62
|
+
await new Promise((r) => setTimeout(r, RENAME_BACKOFF_MS[attempt]));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ★ rename 重试都失败(Windows target 持续被持有 fd),fallback 到 copyFile + unlink。
|
|
67
|
+
// copyFile 不要求 target 未被打开,能绕开 EPERM/EBUSY/EACCES。
|
|
68
|
+
try {
|
|
69
|
+
await fs.copyFile(src, dest);
|
|
70
|
+
await fs.unlink(src).catch(() => {
|
|
71
|
+
/* src 删除失败不影响 dest 已写入,下次写会覆盖 tmp */
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (copyErr) {
|
|
75
|
+
// copyFile 也失败(极少见,如磁盘满/权限问题),抛出最后一次 rename 错误
|
|
76
|
+
// (保持原有错误语义,调用方按 RENAME_RETRYABLE_CODES 判断)
|
|
77
|
+
throw lastErr;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAInE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AA+BlC,OAAO,KAAK,EAOV,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,UAAU,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -105,6 +105,24 @@ const SUB_AGENT_ALLOWED_MCP_TOOLS = new Set([
|
|
|
105
105
|
"memory_recurrence",
|
|
106
106
|
"memory_recurrence_complete",
|
|
107
107
|
]);
|
|
108
|
+
/**
|
|
109
|
+
* explore 类型 sub-agent 被禁用的内建工具(只读模式黑名单)。
|
|
110
|
+
*
|
|
111
|
+
* 'explore' 语义上不修改主工作区文件,仅用于代码探索 / memory 整理等只读任务。
|
|
112
|
+
* 此处过滤直接写工作区文件的内建工具:
|
|
113
|
+
* - write_file / edit_file / delete_file:直接写工作区文件
|
|
114
|
+
*
|
|
115
|
+
* Bash 保留:只读探索常用(git diff / git log / ripgrep 高级查询等),
|
|
116
|
+
* 风险由工具内部的 workingDirectory 限制 + 用户授权流程管控。
|
|
117
|
+
*
|
|
118
|
+
* read_file / grep / symbols / Bash / ask_user_question / skill / todo_* 等只读工具保留。
|
|
119
|
+
* MCP 工具白名单由 SUB_AGENT_ALLOWED_MCP_TOOLS 独立施加,此处不重复。
|
|
120
|
+
*/
|
|
121
|
+
const EXPLORE_READONLY_DENIED_TOOLS = new Set([
|
|
122
|
+
"write_file",
|
|
123
|
+
"edit_file",
|
|
124
|
+
"delete_file",
|
|
125
|
+
]);
|
|
108
126
|
const DEFAULT_BASH_BUILT_IN_TOOL_TIMEOUT_MS = 10 * 60_000 + 2000;
|
|
109
127
|
const DEFAULT_RUNTIME_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
110
128
|
/**
|
|
@@ -1172,6 +1190,15 @@ export class ACodeRuntime extends EventEmitter {
|
|
|
1172
1190
|
...subAgentTools,
|
|
1173
1191
|
...mcpConnections.flatMap((connection) => connection.tools),
|
|
1174
1192
|
];
|
|
1193
|
+
// ★ explore 类型 sub-agent 只读模式:过滤掉会修改主工作区文件的内建工具。
|
|
1194
|
+
// 'explore' 语义上不修改主工作区文件(见 SubAgentManager.spawn 注释),
|
|
1195
|
+
// 原设计仅靠 SUB_AGENT_ALLOWED_MCP_TOOLS 白名单限制 MCP 工具,
|
|
1196
|
+
// 内建工具(write_file/edit_file/delete_file)未被过滤,
|
|
1197
|
+
// 导致 explore 子 agent 仍能改写工作区文件,违背只读语义。
|
|
1198
|
+
// Bash 保留:只读探索常用(git diff/log 等)。
|
|
1199
|
+
const filteredExposedTools = this.config.subagentType === "explore"
|
|
1200
|
+
? exposedTools.filter((tool) => !EXPLORE_READONLY_DENIED_TOOLS.has(tool.exposedName))
|
|
1201
|
+
: exposedTools;
|
|
1175
1202
|
const commandDirs = this.resolveCommandDirs(acodeConfig);
|
|
1176
1203
|
this.emitAcodeEvent("startup_phase", { phase: "loading_commands" });
|
|
1177
1204
|
const commands = await loadAcodeCommands(commandDirs);
|
|
@@ -1214,7 +1241,7 @@ export class ACodeRuntime extends EventEmitter {
|
|
|
1214
1241
|
permissions,
|
|
1215
1242
|
mcpConnections,
|
|
1216
1243
|
ownsMcpConnections,
|
|
1217
|
-
exposedTools,
|
|
1244
|
+
exposedTools: filteredExposedTools,
|
|
1218
1245
|
commands,
|
|
1219
1246
|
commandRegistry,
|
|
1220
1247
|
conversation: cloneChatConversation(initialConversation),
|
|
@@ -1236,7 +1263,7 @@ export class ACodeRuntime extends EventEmitter {
|
|
|
1236
1263
|
workingDirectory: this.config.workingDirectory,
|
|
1237
1264
|
model: provider.model,
|
|
1238
1265
|
commandCount: commands.length,
|
|
1239
|
-
estimatedContextTokens: estimateContextTokens(systemMessagesPlainText,
|
|
1266
|
+
estimatedContextTokens: estimateContextTokens(systemMessagesPlainText, filteredExposedTools),
|
|
1240
1267
|
contextLimit: compactionConfig.contextLimit,
|
|
1241
1268
|
maxOutput: compactionConfig.maxOutput,
|
|
1242
1269
|
...(compactionConfig.inputLimit !== undefined
|
|
@@ -1250,11 +1277,11 @@ export class ACodeRuntime extends EventEmitter {
|
|
|
1250
1277
|
servers: Object.keys(acodeConfig.mcpServers ?? {}),
|
|
1251
1278
|
connectedCount: mcpConnections.length,
|
|
1252
1279
|
builtInToolCount: builtInTools.length,
|
|
1253
|
-
toolCount:
|
|
1280
|
+
toolCount: filteredExposedTools.length,
|
|
1254
1281
|
permissionMode: permissions.mode,
|
|
1255
1282
|
allowedToolRules: permissions.allow,
|
|
1256
1283
|
deniedToolRules: permissions.deny,
|
|
1257
|
-
tools:
|
|
1284
|
+
tools: filteredExposedTools.map((tool) => ({
|
|
1258
1285
|
name: tool.exposedName,
|
|
1259
1286
|
source: tool.kind === "mcp"
|
|
1260
1287
|
? `${tool.serverName}.${tool.toolName}`
|
|
@@ -3148,13 +3175,34 @@ ${urisText}
|
|
|
3148
3175
|
return `你是一条专门处理永久记忆文件变更更新的子 agent。
|
|
3149
3176
|
|
|
3150
3177
|
以下 ${delegate.uris.length} 个永久记忆绑定的文件已发生变更:
|
|
3151
|
-
${
|
|
3178
|
+
${delegate.uris.map(uri => {
|
|
3179
|
+
const fc = delegate.fileChanges?.find(f => f.uri === uri);
|
|
3180
|
+
if (!fc) {
|
|
3181
|
+
return `- ${uri}`;
|
|
3182
|
+
}
|
|
3183
|
+
const statusLabel = {
|
|
3184
|
+
no_change: '无变更',
|
|
3185
|
+
content_changed: '内容变更',
|
|
3186
|
+
not_found: '文件找不到',
|
|
3187
|
+
};
|
|
3188
|
+
// 逐文件状态:优先用 fileStatuses(含被删除文件),回退到 boundFiles 清单
|
|
3189
|
+
const fileStatuses = fc.fileStatuses && fc.fileStatuses.length > 0 ? fc.fileStatuses : [];
|
|
3190
|
+
// 展示全部绑定文件:无变更的仅列路径不加标注,内容变更/文件找不到的在路径后标注状态
|
|
3191
|
+
const bound = fileStatuses.length > 0
|
|
3192
|
+
? fileStatuses.map(s => s.status === 'no_change'
|
|
3193
|
+
? ` · ${s.path}`
|
|
3194
|
+
: ` · ${s.path}(${statusLabel[s.status] ?? s.status})`).join('\n')
|
|
3195
|
+
: (fc.boundFiles && fc.boundFiles.length > 0
|
|
3196
|
+
? fc.boundFiles.map(f => ` · ${f}`).join('\n')
|
|
3197
|
+
: ' 无(请通过 read_memory 查看 bound_files)');
|
|
3198
|
+
return `- ${uri}\n - 绑定文件:\n${bound}`;
|
|
3199
|
+
}).join('\n')}
|
|
3152
3200
|
|
|
3153
3201
|
请执行以下步骤(核心逻辑:更新 → 验证 → 未完成则继续):
|
|
3154
3202
|
|
|
3155
3203
|
=== 更新阶段 ===
|
|
3156
|
-
1. 调用 read_memory 读取这些 memory
|
|
3157
|
-
2.
|
|
3204
|
+
1. 调用 read_memory 读取这些 memory 的当前内容(上方已列出每个 memory 的绑定文件,有变更/找不到的已在路径后标注状态,可直接定位读取,无需等待 read_memory 返回 bound_files)
|
|
3205
|
+
2. 重点查看带(内容变更)/(文件找不到)标注的绑定文件,理解变更点;若列出的绑定文件均无标注,则表示本轮均无变更,可调用 read_memory 核对确认
|
|
3158
3206
|
3. 调用 update_memory 更新 memory 内容,确保与文件最新状态同步
|
|
3159
3207
|
|
|
3160
3208
|
=== 验证阶段(关键,不可跳过) ===
|
|
@@ -3222,15 +3270,26 @@ ${urisText}
|
|
|
3222
3270
|
continue;
|
|
3223
3271
|
}
|
|
3224
3272
|
// 用过滤后的 URI 构造 prompt
|
|
3273
|
+
// 若 delegate 携带了 fileChanges(memory_file_change 类型),同步过滤到 newUris,
|
|
3274
|
+
// 让子 agent 无需先 read_memory 即可知晓每个 memory 绑定/变更了哪些文件。
|
|
3275
|
+
const filteredFileChanges = Array.isArray(delegate.fileChanges)
|
|
3276
|
+
? delegate.fileChanges.filter(fc => newUris.includes(fc.uri))
|
|
3277
|
+
: undefined;
|
|
3225
3278
|
const prompt = this.buildMemoryDelegatePrompt({
|
|
3226
3279
|
type: delegate.type,
|
|
3227
3280
|
uris: newUris,
|
|
3281
|
+
fileChanges: filteredFileChanges,
|
|
3228
3282
|
});
|
|
3229
3283
|
try {
|
|
3230
3284
|
const subId = await manager.spawn({
|
|
3231
3285
|
parentAgentId: this.config.agentId || 'unknown',
|
|
3232
3286
|
parentSessionId: this.config.sessionId,
|
|
3233
|
-
|
|
3287
|
+
// 使用只读类型 'explore':
|
|
3288
|
+
// - MCP 工具由 SUB_AGENT_ALLOWED_MCP_TOOLS 白名单施加(仅 memory 工具)
|
|
3289
|
+
// - 内建工具由 runtime.start() 的 EXPLORE_READONLY_DENIED_TOOLS
|
|
3290
|
+
// 黑名单过滤(禁用 write_file/edit_file/delete_file,保留 Bash 用于 git diff 等)
|
|
3291
|
+
// 'explore' 语义上表示该子 agent 不修改主工作区文件,仅处理 memory 整理任务。
|
|
3292
|
+
subagentType: 'explore',
|
|
3234
3293
|
description: `Memory ${delegate.type} auto-delegate (${newUris.length} items)`,
|
|
3235
3294
|
prompt,
|
|
3236
3295
|
workingDirectory: this.config.workingDirectory,
|
|
@@ -125,6 +125,16 @@ export declare class SubAgentManager {
|
|
|
125
125
|
* null 表示当前没有等待者。
|
|
126
126
|
*/
|
|
127
127
|
private completionWaiterResolve;
|
|
128
|
+
/**
|
|
129
|
+
* 正在执行的异步终态落盘 Promise 集合。
|
|
130
|
+
*
|
|
131
|
+
* 用于:
|
|
132
|
+
* - 测试等待异步落盘完成后再读取 store 验证状态
|
|
133
|
+
* - dispose 时确保所有落盘完成后再清理(避免文件句柄占用导致目录非空)
|
|
134
|
+
*
|
|
135
|
+
* persistFinalStatus 启动时入集,resolve/reject 后出集。
|
|
136
|
+
*/
|
|
137
|
+
private readonly pendingPersists;
|
|
128
138
|
constructor(opts: SubAgentManagerOptions);
|
|
129
139
|
/** 创建 sub-agent(不立即运行;调 start 才执行) */
|
|
130
140
|
spawn(opts: SubAgentSpawnOptions): Promise<string>;
|
|
@@ -239,6 +249,32 @@ export declare class SubAgentManager {
|
|
|
239
249
|
subscribe(subId: string, cb: EventSubscriber): () => void;
|
|
240
250
|
/** 清理所有运行中的 sub-agent(bridge 关闭时调用) */
|
|
241
251
|
dispose(): Promise<void>;
|
|
252
|
+
/**
|
|
253
|
+
* 异步落盘终态记录(指数退避重试),不阻塞主流程。
|
|
254
|
+
*
|
|
255
|
+
* 设计要点:
|
|
256
|
+
* - 内存态已是终态(completed/failed/cancelled),落盘只做历史归档
|
|
257
|
+
* - 落盘失败不回滚内存态,前端看到的是真实终态
|
|
258
|
+
* - 重试覆盖瞬时错误:Windows fs.rename EPERM、writeChain 拥堵、磁盘瞬时不可用
|
|
259
|
+
* - 全部重试失败后仅打日志,下次 bridge 启动时 reconcileZombies 会清理残留
|
|
260
|
+
*
|
|
261
|
+
* 调用方约定:必须用 `void this.persistFinalStatus(...)` 触发,不 await。
|
|
262
|
+
* entry.completionResolve 与 enqueueCompletion 应在此调用之前完成,
|
|
263
|
+
* 保证主流程不被落盘 IO 阻塞。
|
|
264
|
+
*
|
|
265
|
+
* Promise 加入 pendingPersists 集合,供 flushPendingPersists / dispose 等待。
|
|
266
|
+
*/
|
|
267
|
+
private persistFinalStatus;
|
|
268
|
+
/**
|
|
269
|
+
* 等待所有正在执行的异步终态落盘完成。
|
|
270
|
+
*
|
|
271
|
+
* 主要用途:
|
|
272
|
+
* - 测试在终态后读取 store 前调用,确保落盘已完成
|
|
273
|
+
* - dispose 前调用,避免文件句柄占用导致目录清理失败
|
|
274
|
+
*
|
|
275
|
+
* 生产环境一般不需要调用——落盘失败不影响内存态正确性。
|
|
276
|
+
*/
|
|
277
|
+
flushPendingPersists(): Promise<void>;
|
|
242
278
|
/**
|
|
243
279
|
* 将子 agent 终态事件入队并通知等待者。
|
|
244
280
|
* 主流程:构建通知对象 -> 入队 completionQueue -> 若有 waitForAnyCompletion 等待者则立即 resolve。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sub-agent-manager.d.ts","sourceRoot":"","sources":["../src/sub-agent-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EACV,uBAAuB,EACvB,aAAa,EAEb,cAAc,EACd,YAAY,EACb,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"sub-agent-manager.d.ts","sourceRoot":"","sources":["../src/sub-agent-manager.ts"],"names":[],"mappings":"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"}
|