deepseeker-code 1.0.61 → 1.0.63
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/cli.mjs +1296 -166
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -624,7 +624,13 @@ var init_config = __esm({
|
|
|
624
624
|
* 之前生效——门禁/审批评估的是改写后参数)、PostToolUse 可改 resultForModel(仅模型视图,
|
|
625
625
|
* 用户视图 resultForUser 不变)。关闭时 PreToolUse 回退旧位(审批后、仅 deny),改写字段全忽略,
|
|
626
626
|
* 行为与改造前一致。env DEEP_SEEK_HOOK_REWRITE=0 回退。 */
|
|
627
|
-
hookRewrite: process.env.DEEP_SEEK_HOOK_REWRITE !== "0"
|
|
627
|
+
hookRewrite: process.env.DEEP_SEEK_HOOK_REWRITE !== "0",
|
|
628
|
+
/** ★ 外部记忆桥接开关(External Memory Bridge,2026-11-02):true 时 loader 在 bootstrap 把其他 agent 的
|
|
629
|
+
* 规则/指令文件(~/.claude/CLAUDE.md、~/.codex/AGENTS.md、~/.gemini/GEMINI.md、<cwd>/CLAUDE.md、AGENTS.md、
|
|
630
|
+
* GEMINI.md、.cursor/rules/*.md、.github/copilot-instructions.md,清单硬编码)以只读 ext- 前缀条目纳入记忆索引。
|
|
631
|
+
* 默认 false——关闭时记忆行为与未引入本功能逐字节一致。开启即意味着同意把这些文件内容随请求发给
|
|
632
|
+
* DeepSeek API(loader 首次接入时 console 提示一次)。外部条目只读:memory_save/delete 拒 ext- 前缀。 */
|
|
633
|
+
memoryExternal: false
|
|
628
634
|
};
|
|
629
635
|
MODEL_WINDOWS = {};
|
|
630
636
|
resolveModelWindow = (model) => {
|
|
@@ -657,7 +663,9 @@ var init_config = __esm({
|
|
|
657
663
|
undoBackupSensitive: (v) => v === "skip" || v === "deny" || v === "allow" ? v : void 0,
|
|
658
664
|
undoRetentionDays: (v) => typeof v === "number" && v > 0 && Number.isFinite(v) ? v : void 0,
|
|
659
665
|
traceRetentionDays: (v) => typeof v === "number" && v > 0 && Number.isFinite(v) ? v : void 0,
|
|
660
|
-
MAX_TOOL_RESULT_CHARS: (v) => typeof v === "number" && v > 0 && Number.isFinite(v) ? Math.floor(v) : void 0
|
|
666
|
+
MAX_TOOL_RESULT_CHARS: (v) => typeof v === "number" && v > 0 && Number.isFinite(v) ? Math.floor(v) : void 0,
|
|
667
|
+
memoryExternal: (v) => typeof v === "boolean" ? v : void 0
|
|
668
|
+
// 外部记忆桥接(只读接入其他 agent 规则文件;默认 false)
|
|
661
669
|
};
|
|
662
670
|
ENGINE_OVERRIDE_KEYS = Object.keys(ENGINE_OVERRIDE_VALIDATORS);
|
|
663
671
|
applyEngineOverrides = (cfg) => {
|
|
@@ -904,6 +912,7 @@ var init_ticket = __esm({
|
|
|
904
912
|
noAccept: "frontmatter \u7F3A accept\uFF08\u9A8C\u6536\u547D\u4EE4\uFF09\u3002\u6302\u673A\u4EFB\u52A1\u5FC5\u987B\u5E26\u53EF\u6267\u884C\u9A8C\u6536\uFF0C\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\u3002",
|
|
905
913
|
badBudget: (v) => `budget-yuan \u975E\u6CD5\uFF08"${v}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6570\uFF08\u5143\uFF09\u3002`,
|
|
906
914
|
badTimeout: (v) => `timeout-min \u975E\u6CD5\uFF08"${v}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6574\u6570\uFF08\u5206\u949F\uFF09\u3002`,
|
|
915
|
+
badRetry: (v) => `retry \u975E\u6CD5\uFF08"${v}"\uFF09\uFF1A\u987B\u4E3A 0-3 \u7684\u6574\u6570\uFF08\u770B\u95E8\u72D7\u7EC8\u6B62\u540E\u5E26\u8BC1\u636E\u91CD\u8BD5\u6B21\u6570\uFF1B\u7F3A\u7701 0=\u4E0D\u91CD\u8BD5\uFF09\u3002`,
|
|
907
916
|
badTools: "tools \u4E3A\u7A7A\uFF1A\u8981\u4E48\u5220\u6389\u8BE5\u884C\uFF08\u7528\u7F3A\u7701\u7981\u7528\u6E05\u5355\uFF09\uFF0C\u8981\u4E48\u5217\u5DE5\u5177\u540D\uFF08\u9017\u53F7\u5206\u9694\uFF09\u3002",
|
|
908
917
|
emptyBody: "\u4EFB\u52A1\u6B63\u6587\u4E3A\u7A7A\uFF1Afrontmatter \u4E4B\u540E\u5E94\u5199\u4EFB\u52A1\u63CF\u8FF0\u3002",
|
|
909
918
|
untitled: "(\u672A\u547D\u540D\u4EFB\u52A1)",
|
|
@@ -914,6 +923,7 @@ var init_ticket = __esm({
|
|
|
914
923
|
noAccept: "Frontmatter is missing `accept` (acceptance command). Batch tasks must carry an executable acceptance check \u2014 rejected without one.",
|
|
915
924
|
badBudget: (v) => `Invalid budget-yuan ("${v}"): must be a positive number (yuan).`,
|
|
916
925
|
badTimeout: (v) => `Invalid timeout-min ("${v}"): must be a positive integer (minutes).`,
|
|
926
|
+
badRetry: (v) => `Invalid retry ("${v}"): must be an integer 0-3 (evidence-carrying retries after a watchdog kill; default 0 = no retry).`,
|
|
917
927
|
badTools: "Empty tools: either remove the line (use the default denylist) or list tool names (comma-separated).",
|
|
918
928
|
emptyBody: "Empty task body: write the task description after the frontmatter.",
|
|
919
929
|
untitled: "(untitled task)",
|
|
@@ -955,13 +965,19 @@ var init_ticket = __esm({
|
|
|
955
965
|
if (n === null) return { ok: false, error: ticketMsg(locale2, "badTimeout")(fm["timeout-min"]) };
|
|
956
966
|
timeoutMin = n;
|
|
957
967
|
}
|
|
968
|
+
let retry;
|
|
969
|
+
if (fm["retry"] !== void 0) {
|
|
970
|
+
const n = Number(fm["retry"].trim());
|
|
971
|
+
if (!Number.isInteger(n) || n < 0 || n > 3) return { ok: false, error: ticketMsg(locale2, "badRetry")(fm["retry"]) };
|
|
972
|
+
retry = n;
|
|
973
|
+
}
|
|
958
974
|
const tools = fm["tools"] !== void 0 ? parseToolsValue(fm["tools"]) : void 0;
|
|
959
975
|
if (tools && tools.length === 0) return { ok: false, error: ticketMsg(locale2, "badTools") };
|
|
960
976
|
const setup = (fm["setup"] ?? "").trim() || void 0;
|
|
961
977
|
const body = bodyRaw.trim();
|
|
962
978
|
if (!body) return { ok: false, error: ticketMsg(locale2, "emptyBody") };
|
|
963
979
|
const title = (fm["title"] ?? "").trim() || body.split(/\r?\n/).find((l) => l.trim())?.slice(0, 40) || ticketMsg(locale2, "untitled");
|
|
964
|
-
return { ok: true, ticket: { title, accept, setup, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
980
|
+
return { ok: true, ticket: { title, accept, setup, budgetYuan, timeoutMin, retry, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
965
981
|
};
|
|
966
982
|
readBatchTicket = async (filePath, locale2 = "zh") => {
|
|
967
983
|
let source;
|
|
@@ -1117,6 +1133,7 @@ var init_batchStrings = __esm({
|
|
|
1117
1133
|
setup: pnpm install # \u53EF\u9009\uFF1Aagent \u524D\u5728 worktree \u5185\u5907\u73AF\u5883\uFF08\u5E72\u51C0\u68C0\u51FA\u65E0 node_modules\uFF0C\u9A8C\u6536\u4F9D\u8D56\u73AF\u5883\u65F6\u5148\u88C5\uFF09
|
|
1118
1134
|
budget-yuan: 0.5 # \u53EF\u9009\uFF1A\u672C\u4EFB\u52A1\u82B1\u8D39\u4E0A\u9650\uFF08\u5143\uFF09
|
|
1119
1135
|
timeout-min: 30 # \u53EF\u9009\uFF1Aagent \u9636\u6BB5\u8D85\u65F6\uFF08\u5206\u949F\uFF0C\u7F3A\u7701 30\uFF09
|
|
1136
|
+
retry: 1 # \u53EF\u9009\uFF1A\u88AB\u770B\u95E8\u72D7\u7EC8\u6B62\u540E\u5E26\u8BC1\u636E\u91CD\u8BD5\u6B21\u6570\uFF080-3\uFF0C\u7F3A\u7701 0=\u6740\u5373\u7EC8\u6001\uFF09
|
|
1120
1137
|
tools: run_command # \u53EF\u9009\uFF1A\u663E\u5F0F\u89E3\u9501\u9AD8\u5371\u5DE5\u5177\uFF08\u7F3A\u7701\u7981 run_command/delete_path\uFF09
|
|
1121
1138
|
---
|
|
1122
1139
|
\u4EFB\u52A1\u63CF\u8FF0\u6B63\u6587\uFF08Markdown\uFF09\u2026
|
|
@@ -1143,6 +1160,10 @@ var init_batchStrings = __esm({
|
|
|
1143
1160
|
wtCreateFail: (e) => `\u521B\u5EFA worktree \u5931\u8D25\uFF08\u9700\u8981\u4E3B\u5DE5\u4F5C\u533A\u662F git \u4ED3\u5E93\uFF09\uFF1A${e}`,
|
|
1144
1161
|
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent \u5F02\u5E38\uFF1A${err}`,
|
|
1145
1162
|
timeoutLine: (id, min) => `\u23F1\uFE0F [${id}] \u8D85\u65F6\uFF08${min}min\uFF09\uFF0C\u622A\u65AD\u6536\u5C3E\uFF08\u9A8C\u6536\u4E0D\u8DD1\uFF09`,
|
|
1163
|
+
wdNudgeNote: (id, level) => `\u{1F415} [${id}] watchdog nudge-${level} \u5DF2\u6CE8\u5165\u6536\u4EF6\u7BB1\uFF08\u7EA0\u504F\u63D0\u793A\uFF09`,
|
|
1164
|
+
wdKillNote: (id, why) => `\u{1F415} [${id}] watchdog \u7EC8\u6B62\uFF1A${why}`,
|
|
1165
|
+
wdRetryNote: (id, round) => `\u{1F501} [${id}] watchdog \u5E26\u8BC1\u636E\u91CD\u8BD5\uFF1A\u7B2C ${round} \u8F6E\uFF08\u540C worktree \u7EED\u8DD1\uFF0C\u5269\u4F59\u9884\u7B97\u7EED\u7528\uFF09`,
|
|
1166
|
+
wdBudgetStopNote: (id) => `\u{1F415} [${id}] \u91CD\u8BD5\u5DF2\u8DF3\u8FC7\uFF1A\u9884\u7B97\u8DE8\u8F6E\u7D2F\u8BA1\u5DF2\u8017\u5C3D`,
|
|
1146
1167
|
acceptLine: (passed, id, code) => `${passed ? "\u2705" : "\u274C"} [${id}] \u9A8C\u6536 exit ${code}`,
|
|
1147
1168
|
acceptKilledSuffix: "\uFF08\u8D85\u65F6\u88AB\u6740\uFF09",
|
|
1148
1169
|
timeoutAbort: (min) => `\u4EFB\u52A1\u8D85\u65F6\uFF08${min} \u5206\u949F\uFF09`,
|
|
@@ -1163,7 +1184,8 @@ var init_batchStrings = __esm({
|
|
|
1163
1184
|
timeout: "\u23F1\uFE0F \u8D85\u65F6\u622A\u65AD",
|
|
1164
1185
|
error: "\u{1F4A5} agent \u5F02\u5E38",
|
|
1165
1186
|
"setup-failed": "\u{1F6E0}\uFE0F \u73AF\u5883\u51C6\u5907\u5931\u8D25",
|
|
1166
|
-
rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2"
|
|
1187
|
+
rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2",
|
|
1188
|
+
"watchdog-killed": "\u{1F415} \u770B\u95E8\u72D7\u7EC8\u6B62"
|
|
1167
1189
|
})[s],
|
|
1168
1190
|
// —— 验收命令执行(输出嵌入报告) ——
|
|
1169
1191
|
spawnFail: (e) => `\u542F\u52A8\u5931\u8D25\uFF1A${e}`,
|
|
@@ -1202,7 +1224,18 @@ var init_batchStrings = __esm({
|
|
|
1202
1224
|
deniedNone: "\u65E0\u3002",
|
|
1203
1225
|
diffH: "## Diff \u6458\u8981\uFF08worktree \u76F8\u5BF9\u57FA\u5EA7\uFF0C\u672A\u63D0\u4EA4\uFF0C\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09",
|
|
1204
1226
|
diffNote: (branch, p) => `\u6539\u52A8\u5728\u72EC\u7ACB worktree\uFF08\u5206\u652F \`${branch}\`\uFF0C\u8DEF\u5F84 ${p}\uFF09\u3002\u5904\u7F6E\uFF1A\u68C0\u67E5\u6EE1\u610F \u2192 \u5728 worktree \u5185 commit \u5E76\u5408\u56DE\u4E3B\u4ED3\uFF1B\u4E22\u5F03 \u2192 \u5220\u9664\u8BE5 worktree \u76EE\u5F55 + \`git worktree prune\` + \`git branch -D <\u5206\u652F>\`\u3002`,
|
|
1205
|
-
diffNone: "\uFF08\u65E0\uFF09"
|
|
1227
|
+
diffNone: "\uFF08\u65E0\uFF09",
|
|
1228
|
+
// —— 看门狗(进展感知)报告段与进度行 ——
|
|
1229
|
+
wdH: "## \u770B\u95E8\u72D7\uFF08\u8FDB\u5C55\u611F\u77E5\uFF09",
|
|
1230
|
+
wdRecord: (s) => `- ${s}`,
|
|
1231
|
+
wdSuspicionRec: (s) => `\u5ACC\u7591\u8BB0\u5F55\uFF08\u672A\u8FBE\u52A8\u4F5C\u7EBF\uFF09\uFF1A${s}`,
|
|
1232
|
+
wdVerdictRec: (verdict, evidence) => `\u88C1\u51B3 ${verdict}\uFF1A${evidence || "\uFF08\u65E0\u8BC1\u636E\uFF09"}`,
|
|
1233
|
+
wdNudgeRec: (level, text) => `nudge-${level} \u5DF2\u6CE8\u5165\u6536\u4EF6\u7BB1\uFF1A${text}`,
|
|
1234
|
+
wdHealthRec: (s) => `\u5065\u5EB7\u4FE1\u53F7\u77ED\u8DEF\uFF08\u8DF3\u8FC7\u88C1\u51B3\uFF09\uFF1A${s}`,
|
|
1235
|
+
wdAuxFailRec: () => `\u4E8C\u5C42\u88C1\u51B3\u8C03\u7528\u5931\u8D25\uFF0C\u964D\u7EA7 normal\uFF08\u770B\u95E8\u72D7\u81EA\u8EAB\u6545\u969C\u4E0D\u8BEF\u6740\uFF09`,
|
|
1236
|
+
wdKillRec: (verdict, evidence) => `\u26D4 \u7EC8\u6B62\uFF1A${verdict} \u2014 ${evidence}`,
|
|
1237
|
+
wdAtKillRec: (round, costYuan) => `\u7EC8\u6B62\u65F6\u523B\uFF1A\u8F6E ${round} \xB7 \xA5${costYuan}`,
|
|
1238
|
+
wdRetryRec: (n) => `\u5E26\u8BC1\u636E\u91CD\u8BD5\uFF1A\u5171 ${n + 1} \u8F6E\uFF08\u540C worktree \u7EED\u8DD1\uFF0C\u8BC1\u636E\u89C1\u5404\u8F6E\u8BB0\u5F55\uFF09`
|
|
1206
1239
|
};
|
|
1207
1240
|
EN = {
|
|
1208
1241
|
usage: `deepseeker-code batch \u2014 unattended batch runs (cost trust chain)
|
|
@@ -1220,6 +1253,7 @@ Ticket format (Markdown; frontmatter \`accept\` is required \u2014 no acceptance
|
|
|
1220
1253
|
setup: pnpm install # optional: prep env inside the worktree before the agent (fresh checkout has no node_modules)
|
|
1221
1254
|
budget-yuan: 0.5 # optional: per-task cost cap (yuan)
|
|
1222
1255
|
timeout-min: 30 # optional: agent-phase timeout (minutes, default 30)
|
|
1256
|
+
retry: 1 # optional: evidence-carrying retries after a watchdog kill (0-3, default 0 = kill is final)
|
|
1223
1257
|
tools: run_command # optional: unlock risky tools (run_command/delete_path denied by default)
|
|
1224
1258
|
---
|
|
1225
1259
|
|
|
@@ -1246,6 +1280,10 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1246
1280
|
wtCreateFail: (e) => `Failed to create worktree (the main workspace must be a git repo): ${e}`,
|
|
1247
1281
|
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent error: ${err}`,
|
|
1248
1282
|
timeoutLine: (id, min) => `\u23F1\uFE0F [${id}] Timed out (${min}min); wrapped up truncated (acceptance skipped)`,
|
|
1283
|
+
wdNudgeNote: (id, level) => `\u{1F415} [${id}] watchdog nudge-${level} injected into the inbox (course correction)`,
|
|
1284
|
+
wdKillNote: (id, why) => `\u{1F415} [${id}] watchdog killed: ${why}`,
|
|
1285
|
+
wdRetryNote: (id, round) => `\u{1F501} [${id}] watchdog evidence-carrying retry: round ${round} (same worktree, remaining budget carried over)`,
|
|
1286
|
+
wdBudgetStopNote: (id) => `\u{1F415} [${id}] retry skipped: cumulative budget exhausted across rounds`,
|
|
1249
1287
|
acceptLine: (passed, id, code) => `${passed ? "\u2705" : "\u274C"} [${id}] acceptance exit ${code}`,
|
|
1250
1288
|
acceptKilledSuffix: " (killed on timeout)",
|
|
1251
1289
|
timeoutAbort: (min) => `Task timed out (${min} minutes)`,
|
|
@@ -1265,7 +1303,8 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1265
1303
|
timeout: "\u23F1\uFE0F timed out",
|
|
1266
1304
|
error: "\u{1F4A5} agent error",
|
|
1267
1305
|
"setup-failed": "\u{1F6E0}\uFE0F setup failed",
|
|
1268
|
-
rejected: "\u{1F6AB} ticket rejected"
|
|
1306
|
+
rejected: "\u{1F6AB} ticket rejected",
|
|
1307
|
+
"watchdog-killed": "\u{1F415} watchdog killed"
|
|
1269
1308
|
})[s],
|
|
1270
1309
|
spawnFail: (e) => `Spawn failed: ${e}`,
|
|
1271
1310
|
execFail: (e) => `Execution failed: ${e}`,
|
|
@@ -1301,7 +1340,17 @@ changes are harvested onto an isolated git worktree (temp branch), kept for manu
|
|
|
1301
1340
|
deniedNone: "None.",
|
|
1302
1341
|
diffH: "## Diff summary (worktree vs base, uncommitted, awaiting manual handling)",
|
|
1303
1342
|
diffNote: (branch, p) => `Changes live in an isolated worktree (branch \`${branch}\`, path ${p}). To keep: commit inside the worktree and merge back. To discard: delete the worktree directory + \`git worktree prune\` + \`git branch -D <branch>\`.`,
|
|
1304
|
-
diffNone: "(none)"
|
|
1343
|
+
diffNone: "(none)",
|
|
1344
|
+
wdH: "## Watchdog (progress-aware)",
|
|
1345
|
+
wdRecord: (s) => `- ${s}`,
|
|
1346
|
+
wdSuspicionRec: (s) => `Suspicion logged (below action line): ${s}`,
|
|
1347
|
+
wdVerdictRec: (verdict, evidence) => `Verdict ${verdict}: ${evidence || "(no evidence)"}`,
|
|
1348
|
+
wdNudgeRec: (level, text) => `nudge-${level} injected into the inbox: ${text}`,
|
|
1349
|
+
wdHealthRec: (s) => `Health signal short-circuit (adjudication skipped): ${s}`,
|
|
1350
|
+
wdAuxFailRec: () => `Level-2 adjudication call failed; degraded to normal (a broken watchdog must not become a false-kill weapon)`,
|
|
1351
|
+
wdKillRec: (verdict, evidence) => `\u26D4 Killed: ${verdict} \u2014 ${evidence}`,
|
|
1352
|
+
wdAtKillRec: (round, costYuan) => `At kill time: round ${round} \xB7 \xA5${costYuan}`,
|
|
1353
|
+
wdRetryRec: (n) => `Evidence-carrying retries: ${n + 1} rounds total (same worktree; per-round evidence above)`
|
|
1305
1354
|
};
|
|
1306
1355
|
DICT = { zh: ZH, en: EN };
|
|
1307
1356
|
batchT = (locale2) => DICT[locale2] ?? ZH;
|
|
@@ -1975,8 +2024,19 @@ var init_replay = __esm({
|
|
|
1975
2024
|
});
|
|
1976
2025
|
|
|
1977
2026
|
// ../core/src/llm/model.ts
|
|
2027
|
+
var model_exports = {};
|
|
2028
|
+
__export(model_exports, {
|
|
2029
|
+
activeProvider: () => activeProvider,
|
|
2030
|
+
chatWithModelWithSummary: () => chatWithModelWithSummary,
|
|
2031
|
+
classifyToolRisk: () => classifyToolRisk,
|
|
2032
|
+
isContextLengthError: () => isContextLengthError2,
|
|
2033
|
+
isImageUnsupportedError: () => isImageUnsupportedError2,
|
|
2034
|
+
isTransientApiError: () => isTransientApiError,
|
|
2035
|
+
resetActiveProvider: () => resetActiveProvider,
|
|
2036
|
+
setActiveProvider: () => setActiveProvider
|
|
2037
|
+
});
|
|
1978
2038
|
import { readFileSync as readFileSync4 } from "fs";
|
|
1979
|
-
var resolveInitialProvider, activeProvider, chatWithModelWithSummary, classifyToolRisk;
|
|
2039
|
+
var resolveInitialProvider, activeProvider, setActiveProvider, resetActiveProvider, chatWithModelWithSummary, classifyToolRisk, isContextLengthError2, isTransientApiError, isImageUnsupportedError2;
|
|
1980
2040
|
var init_model = __esm({
|
|
1981
2041
|
"../core/src/llm/model.ts"() {
|
|
1982
2042
|
"use strict";
|
|
@@ -1997,8 +2057,17 @@ var init_model = __esm({
|
|
|
1997
2057
|
return createReplayProvider(Array.isArray(raw) ? { turns: raw } : raw);
|
|
1998
2058
|
};
|
|
1999
2059
|
activeProvider = resolveInitialProvider();
|
|
2060
|
+
setActiveProvider = (p) => {
|
|
2061
|
+
activeProvider = p;
|
|
2062
|
+
};
|
|
2063
|
+
resetActiveProvider = () => {
|
|
2064
|
+
activeProvider = deepseekProvider;
|
|
2065
|
+
};
|
|
2000
2066
|
chatWithModelWithSummary = (messages, tools, opts) => activeProvider.summarize(messages, tools, opts);
|
|
2001
2067
|
classifyToolRisk = (toolName, args, detail, signal, onAuxUsage) => activeProvider.classifyRisk(toolName, args, detail, signal, onAuxUsage);
|
|
2068
|
+
isContextLengthError2 = (e) => activeProvider.isContextLengthError(e);
|
|
2069
|
+
isTransientApiError = (e) => activeProvider.isTransientError(e);
|
|
2070
|
+
isImageUnsupportedError2 = (e) => activeProvider.isImageUnsupportedError(e);
|
|
2002
2071
|
}
|
|
2003
2072
|
});
|
|
2004
2073
|
|
|
@@ -5548,6 +5617,153 @@ var init_httpExecutor = __esm({
|
|
|
5548
5617
|
}
|
|
5549
5618
|
});
|
|
5550
5619
|
|
|
5620
|
+
// ../core/src/agent/agentWake.ts
|
|
5621
|
+
var AGENT_DONE_SENTINEL, SUBAGENT_REPORT_MAX_CHARS, wakeDrivers, wakeQueued, busyRuns, inFlightByParent, quiesceWaiters, registerWakeDriver, registerWakeDriverIfAbsent, unregisterWakeDriver, markRunStart, markRunEnd, pumpWake, scheduleWake, clearQueuedWake, notifySubagentDone, buildSubagentDoneReport, trackSubagentInFlight, releaseSubagentInFlight, notifyQuiesceWaiters, isQuiescent, waitSessionQuiescent;
|
|
5622
|
+
var init_agentWake = __esm({
|
|
5623
|
+
"../core/src/agent/agentWake.ts"() {
|
|
5624
|
+
"use strict";
|
|
5625
|
+
init_inbox();
|
|
5626
|
+
init_transcript();
|
|
5627
|
+
AGENT_DONE_SENTINEL = "\u27E6DSC:AGENT-DONE\u27E7 \u5B50\u4EE3\u7406\u5B8C\u6210\u5524\u9192\uFF1A\u672C\u4F1A\u8BDD\u521A\u6CE8\u5165\u4E86\u5B50\u4EE3\u7406\u5B8C\u6210\u6C47\u62A5\uFF08\u89C1\u76F8\u90BB\u6D88\u606F\uFF09\uFF0C\u8BF7\u9010\u6761\u6D88\u5316\u6C47\u62A5\u5185\u5BB9\u5E76\u7EE7\u7EED\u63A8\u8FDB\u4E3B\u4EFB\u52A1\uFF1B\u82E5\u65E0\u5F85\u7EED\u4E8B\u9879\uFF0C\u7B80\u8981\u786E\u8BA4\u5373\u53EF\u3002";
|
|
5628
|
+
SUBAGENT_REPORT_MAX_CHARS = 4096;
|
|
5629
|
+
wakeDrivers = /* @__PURE__ */ new Map();
|
|
5630
|
+
wakeQueued = /* @__PURE__ */ new Set();
|
|
5631
|
+
busyRuns = /* @__PURE__ */ new Set();
|
|
5632
|
+
inFlightByParent = /* @__PURE__ */ new Map();
|
|
5633
|
+
quiesceWaiters = /* @__PURE__ */ new Map();
|
|
5634
|
+
registerWakeDriver = (sessionId, driver) => {
|
|
5635
|
+
if (!sessionId) return;
|
|
5636
|
+
wakeDrivers.set(sessionId, driver);
|
|
5637
|
+
};
|
|
5638
|
+
registerWakeDriverIfAbsent = (sessionId, driver) => {
|
|
5639
|
+
if (!sessionId || wakeDrivers.has(sessionId)) return;
|
|
5640
|
+
wakeDrivers.set(sessionId, driver);
|
|
5641
|
+
};
|
|
5642
|
+
unregisterWakeDriver = (sessionId) => {
|
|
5643
|
+
wakeDrivers.delete(sessionId);
|
|
5644
|
+
};
|
|
5645
|
+
markRunStart = (sessionId) => {
|
|
5646
|
+
if (!sessionId) return;
|
|
5647
|
+
busyRuns.add(sessionId);
|
|
5648
|
+
};
|
|
5649
|
+
markRunEnd = (sessionId) => {
|
|
5650
|
+
if (!sessionId) return;
|
|
5651
|
+
busyRuns.delete(sessionId);
|
|
5652
|
+
pumpWake(sessionId);
|
|
5653
|
+
notifyQuiesceWaiters(sessionId);
|
|
5654
|
+
};
|
|
5655
|
+
pumpWake = (sessionId) => {
|
|
5656
|
+
if (!wakeQueued.has(sessionId)) return;
|
|
5657
|
+
if (busyRuns.has(sessionId)) return;
|
|
5658
|
+
wakeQueued.delete(sessionId);
|
|
5659
|
+
const driver = wakeDrivers.get(sessionId);
|
|
5660
|
+
if (!driver) return;
|
|
5661
|
+
busyRuns.add(sessionId);
|
|
5662
|
+
void (async () => {
|
|
5663
|
+
try {
|
|
5664
|
+
await driver();
|
|
5665
|
+
} catch (e) {
|
|
5666
|
+
console.warn(`\u26A0\uFE0F [agentWake] \u5524\u9192 run \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF0C\u94FE\u8DEF\u7EE7\u7EED\u6536\u655B\uFF09: ${e?.message ?? e}`);
|
|
5667
|
+
} finally {
|
|
5668
|
+
busyRuns.delete(sessionId);
|
|
5669
|
+
notifyQuiesceWaiters(sessionId);
|
|
5670
|
+
pumpWake(sessionId);
|
|
5671
|
+
}
|
|
5672
|
+
})();
|
|
5673
|
+
};
|
|
5674
|
+
scheduleWake = (sessionId) => {
|
|
5675
|
+
if (!sessionId || wakeQueued.has(sessionId)) return;
|
|
5676
|
+
wakeQueued.add(sessionId);
|
|
5677
|
+
pumpWake(sessionId);
|
|
5678
|
+
notifyQuiesceWaiters(sessionId);
|
|
5679
|
+
};
|
|
5680
|
+
clearQueuedWake = (sessionId) => {
|
|
5681
|
+
wakeQueued.delete(sessionId);
|
|
5682
|
+
};
|
|
5683
|
+
notifySubagentDone = async (parentSessionId, report) => {
|
|
5684
|
+
if (!parentSessionId || !report) return;
|
|
5685
|
+
const delivered = pushSessionInbox(parentSessionId, report);
|
|
5686
|
+
if (!delivered) {
|
|
5687
|
+
try {
|
|
5688
|
+
await appendMessage({ sessionId: parentSessionId, role: "user", content: report });
|
|
5689
|
+
} catch {
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
scheduleWake(parentSessionId);
|
|
5693
|
+
};
|
|
5694
|
+
buildSubagentDoneReport = (agentId, taskBrief, result) => {
|
|
5695
|
+
const status = result.status ?? (result.output ? "final" : "error");
|
|
5696
|
+
const statusLabel = status === "final" ? "final\uFF08\u6B63\u5E38\u5B8C\u6210\uFF09" : status === "aborted" ? "aborted\uFF08\u88AB\u4E2D\u6B62\uFF09" : "error\uFF08\u5F02\u5E38\uFF09";
|
|
5697
|
+
const over = result.output.length > SUBAGENT_REPORT_MAX_CHARS;
|
|
5698
|
+
const body = over ? result.output.slice(0, SUBAGENT_REPORT_MAX_CHARS) : result.output;
|
|
5699
|
+
return [
|
|
5700
|
+
`\u{1F916} [\u5B50\u4EE3\u7406\u5B8C\u6210] \u{1F194} ${agentId}${taskBrief ? `\uFF08${taskBrief}\uFF09` : ""}`,
|
|
5701
|
+
`\u72B6\u6001\uFF1A${statusLabel}`,
|
|
5702
|
+
`\u6C47\u62A5\uFF1A`,
|
|
5703
|
+
body,
|
|
5704
|
+
over ? `
|
|
5705
|
+
\uFF08\u26A0\uFE0F \u6C47\u62A5\u8D85\u957F\u5DF2\u622A\u65AD\u81F3 ${SUBAGENT_REPORT_MAX_CHARS} \u5B57\u7B26\uFF1B\u5B8C\u6574\u5185\u5BB9\u53EF spawn_agent \u4F20 resume_session_id="${agentId}" \u8FFD\u95EE\u3002\uFF09` : ""
|
|
5706
|
+
].filter((s) => s !== "").join("\n");
|
|
5707
|
+
};
|
|
5708
|
+
trackSubagentInFlight = (parentSessionId, subSessionId) => {
|
|
5709
|
+
if (!parentSessionId) return;
|
|
5710
|
+
let set = inFlightByParent.get(parentSessionId);
|
|
5711
|
+
if (!set) {
|
|
5712
|
+
set = /* @__PURE__ */ new Set();
|
|
5713
|
+
inFlightByParent.set(parentSessionId, set);
|
|
5714
|
+
}
|
|
5715
|
+
set.add(subSessionId);
|
|
5716
|
+
};
|
|
5717
|
+
releaseSubagentInFlight = (parentSessionId, subSessionId) => {
|
|
5718
|
+
const set = inFlightByParent.get(parentSessionId);
|
|
5719
|
+
if (!set) return;
|
|
5720
|
+
set.delete(subSessionId);
|
|
5721
|
+
if (set.size === 0) inFlightByParent.delete(parentSessionId);
|
|
5722
|
+
notifyQuiesceWaiters(parentSessionId);
|
|
5723
|
+
};
|
|
5724
|
+
notifyQuiesceWaiters = (sessionId) => {
|
|
5725
|
+
const waiters = quiesceWaiters.get(sessionId);
|
|
5726
|
+
if (!waiters || waiters.size === 0) return;
|
|
5727
|
+
for (const w of [...waiters]) w();
|
|
5728
|
+
};
|
|
5729
|
+
isQuiescent = (sessionId) => !inFlightByParent.get(sessionId)?.size && !busyRuns.has(sessionId) && !wakeQueued.has(sessionId);
|
|
5730
|
+
waitSessionQuiescent = (sessionId, signal, timeoutMs2) => {
|
|
5731
|
+
if (isQuiescent(sessionId)) return Promise.resolve(true);
|
|
5732
|
+
return new Promise((resolve) => {
|
|
5733
|
+
let settled = false;
|
|
5734
|
+
const finish = (ok) => {
|
|
5735
|
+
if (settled) return;
|
|
5736
|
+
settled = true;
|
|
5737
|
+
if (timer) clearTimeout(timer);
|
|
5738
|
+
if (onAbort) signal?.removeEventListener("abort", onAbort);
|
|
5739
|
+
const set = quiesceWaiters.get(sessionId);
|
|
5740
|
+
if (set) {
|
|
5741
|
+
set.delete(check);
|
|
5742
|
+
if (set.size === 0) quiesceWaiters.delete(sessionId);
|
|
5743
|
+
}
|
|
5744
|
+
resolve(ok);
|
|
5745
|
+
};
|
|
5746
|
+
const check = () => {
|
|
5747
|
+
if (isQuiescent(sessionId)) finish(true);
|
|
5748
|
+
};
|
|
5749
|
+
let timer;
|
|
5750
|
+
const onAbort = () => finish(false);
|
|
5751
|
+
if (!quiesceWaiters.has(sessionId)) quiesceWaiters.set(sessionId, /* @__PURE__ */ new Set());
|
|
5752
|
+
quiesceWaiters.get(sessionId).add(check);
|
|
5753
|
+
if (signal) {
|
|
5754
|
+
if (signal.aborted) {
|
|
5755
|
+
finish(false);
|
|
5756
|
+
return;
|
|
5757
|
+
}
|
|
5758
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5759
|
+
}
|
|
5760
|
+
if (timeoutMs2 != null && timeoutMs2 > 0) timer = setTimeout(() => finish(false), timeoutMs2);
|
|
5761
|
+
check();
|
|
5762
|
+
});
|
|
5763
|
+
};
|
|
5764
|
+
}
|
|
5765
|
+
});
|
|
5766
|
+
|
|
5551
5767
|
// ../core/src/agent/repeatBreaker.ts
|
|
5552
5768
|
var createRepeatBreaker;
|
|
5553
5769
|
var init_repeatBreaker = __esm({
|
|
@@ -5889,7 +6105,7 @@ ${style.body}`);
|
|
|
5889
6105
|
});
|
|
5890
6106
|
|
|
5891
6107
|
// ../core/src/memory/registry.ts
|
|
5892
|
-
var memories, registerMemory, listMemories, getMemory, unregisterMemory, clearMemories, memoryIndexLine, getMemoryIndex;
|
|
6108
|
+
var memories, registerMemory, listMemories, getMemory, unregisterMemory, clearMemories, memoryIndexLine, MEMORY_LIMITS, getMemoryIndex;
|
|
5893
6109
|
var init_registry6 = __esm({
|
|
5894
6110
|
"../core/src/memory/registry.ts"() {
|
|
5895
6111
|
"use strict";
|
|
@@ -5908,6 +6124,7 @@ var init_registry6 = __esm({
|
|
|
5908
6124
|
};
|
|
5909
6125
|
clearMemories = memories.clear;
|
|
5910
6126
|
memoryIndexLine = (m) => `- **${m.name}** (${m.type}) \u2014 ${m.description}`;
|
|
6127
|
+
MEMORY_LIMITS = { maxCount: 200, maxIndexBytes: 16 * 1024 };
|
|
5911
6128
|
getMemoryIndex = () => {
|
|
5912
6129
|
const all = memories.list();
|
|
5913
6130
|
if (all.length === 0) return null;
|
|
@@ -6102,7 +6319,12 @@ var init_agent = __esm({
|
|
|
6102
6319
|
type: "function",
|
|
6103
6320
|
function: {
|
|
6104
6321
|
name: "spawn_agent",
|
|
6105
|
-
description:
|
|
6322
|
+
description: [
|
|
6323
|
+
"\u5F02\u6B65\u6D3E\u751F\u62E5\u6709\u72EC\u7ACB\u6267\u884C\u73AF\u5883\u7684\u5B50 agent \u5904\u7406\u9694\u79BB\u5B50\u4EFB\u52A1\uFF1A\u8C03\u7528\u7ACB\u5373\u8FD4\u56DE agent_id\uFF0C\u4E0D\u7B49\u5F85\u5B8C\u6210\uFF1B\u5B50 agent \u5728\u540E\u53F0\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u5176\u6C47\u62A5\u4F1A\u81EA\u52A8\u6CE8\u5165\u672C\u4F1A\u8BDD\u5E76\u5524\u9192\u4F60\u7EE7\u7EED\u63A8\u8FDB\uFF08\u65E0\u9700\u8F6E\u8BE2\u3001\u65E0\u9700\u7B49\u5F85\uFF09\u3002",
|
|
6324
|
+
"\u6D3E\u51FA\u540E\u4F60\u53EF\u7ACB\u5373\u7EE7\u7EED\u6D3E\u6D3B / \u5904\u7406\u5176\u4ED6\u4E8B\u52A1 / \u56DE\u590D\u7528\u6237\uFF1B\u5F53\u524D\u65E0\u5176\u4ED6\u4E8B\u52A1\u65F6\u53EF\u7B80\u77ED\u544A\u77E5\u5DF2\u59D4\u6D3E\u5E76\u7ED3\u675F\u672C\u8F6E\u2014\u2014\u6C47\u62A5\u9001\u8FBE\u65F6\u4F60\u4F1A\u88AB\u81EA\u52A8\u5524\u9192\u3002",
|
|
6325
|
+
"name \u53EF\u6307\u5B9A\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF0C\u5957\u7528\u5176\u7CFB\u7EDF\u8BCD/\u5DE5\u5177\u767D\u540D\u5355/model\uFF09\uFF1B\u7F3A\u7701\u8D70\u901A\u7528\u6A21\u677F\u3002",
|
|
6326
|
+
"\u7EED\u8DD1\uFF1A\u4F20 resume_session_id\uFF08\u6B64\u524D\u8FD4\u56DE\u7684 agent_id\uFF09\u590D\u7528\u8BE5\u5B50 Agent \u5B8C\u6574\u5386\u53F2\u8BB0\u5FC6\uFF0C\u9002\u5408\u8FFD\u95EE/\u7EE7\u7EED\u672A\u5B8C\u4EFB\u52A1\uFF08\u540C\u6837\u5F02\u6B65\uFF0C\u5B8C\u6210\u540E\u81EA\u52A8\u5524\u9192\uFF09\u3002"
|
|
6327
|
+
].join("\n"),
|
|
6106
6328
|
parameters: {
|
|
6107
6329
|
type: "object",
|
|
6108
6330
|
properties: {
|
|
@@ -6114,30 +6336,29 @@ var init_agent = __esm({
|
|
|
6114
6336
|
required: ["task"]
|
|
6115
6337
|
},
|
|
6116
6338
|
safetyLevel: "safe" /* SAFE */,
|
|
6117
|
-
isSync:
|
|
6118
|
-
async execute(args, ctx) {
|
|
6119
|
-
if (!ctx)
|
|
6120
|
-
|
|
6339
|
+
isSync: false,
|
|
6340
|
+
async *execute(args, ctx) {
|
|
6341
|
+
if (!ctx) {
|
|
6342
|
+
yield toolFailure("[\u6D3E\u751F\u5931\u8D25]\uFF1Aspawn_agent \u7F3A\u5C11\u5FC5\u987B\u7684\u667A\u80FD\u4F53\u8FD0\u884C\u4E0A\u4E0B\u6587\u3002");
|
|
6343
|
+
return;
|
|
6344
|
+
}
|
|
6345
|
+
const prep = await prepareSubagent(
|
|
6121
6346
|
{ task: args.task, name: args.name, role: args.role, resumeSessionId: args.resume_session_id },
|
|
6122
6347
|
ctx,
|
|
6123
6348
|
getGlobalTools
|
|
6124
6349
|
);
|
|
6125
|
-
if (!
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
`,
|
|
6132
|
-
|
|
6133
|
-
`,
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
`,
|
|
6138
|
-
`\u{1F6A8}\u3010\u91CD\u8981\u540C\u6B65\u901A\u77E5\u3011: \u8BE5\u5B50 Agent \u521A\u624D\u6781\u6709\u53EF\u80FD\u5DF2\u7ECF\u9AD8\u9891\u4FEE\u6539\u3001\u521B\u5EFA\u6216\u5220\u9664\u4E86\u4F60\u7BA1\u8F96\u533A\u5185\u7684\u672C\u5730\u6E90\u7801\u6587\u4EF6\u3002`,
|
|
6139
|
-
`\u5982\u679C\u4F60\uFF08\u7236\u7EA7Agent\uFF09\u63A5\u4E0B\u6765\u9700\u8981\u5BF9\u6587\u4EF6\u7CFB\u7EDF\u7EE7\u7EED\u5B9E\u65BD edit_file\u3001write_file \u6216\u9A8C\u8BC1\uFF0C\u3010\u4F60\u5FC5\u987B\u3011\u9996\u5148\u8C03\u7528 read_file \u6216 list_dir \u91CD\u65B0\u8BFB\u53D6\u6700\u65B0\u78C1\u76D8\u72B6\u6001\uFF0C\u7981\u6B62\u76F2\u76EE\u4F9D\u8D56\u4F60\u4E4B\u524D\u7684\u8BB0\u5FC6\u7F13\u5B58\uFF0C\u5426\u5219\u5FC5\u7136\u4F1A\u5F15\u53D1\u552F\u4E00\u6027\u51B2\u7A81\u5339\u914D\u5931\u8D25\uFF01`
|
|
6140
|
-
].join("");
|
|
6350
|
+
if (!prep.ok) {
|
|
6351
|
+
yield asToolFailure(prep.error);
|
|
6352
|
+
return;
|
|
6353
|
+
}
|
|
6354
|
+
const agentId = prep.prepared.subSessionId;
|
|
6355
|
+
yield [
|
|
6356
|
+
`\u2705 \u5B50\u4EE3\u7406\u5DF2\u5F02\u6B65\u542F\u52A8 \u{1F194} ${agentId}${prep.prepared.manifest ? `\uFF08\u58F0\u660E\u5F0F=${prep.prepared.manifest.name}\uFF09` : ""}`,
|
|
6357
|
+
`\u4EFB\u52A1\u6458\u8981\uFF1A${prep.prepared.taskBrief}${args.task.length > 60 ? "\u2026" : ""}`,
|
|
6358
|
+
`\u5B83\u5B8C\u6210\u540E\u6C47\u62A5\u4F1A\u81EA\u52A8\u9001\u8FBE\u672C\u4F1A\u8BDD\u5E76\u5524\u9192\u4F60\u7EE7\u7EED\uFF1B\u671F\u95F4\u65E0\u9700\u7B49\u5F85\u2014\u2014\u53EF\u7EE7\u7EED\u6D3E\u6D3B / \u5904\u7406\u5176\u4ED6\u4E8B\u52A1\uFF0C\u65E0\u5176\u4ED6\u4E8B\u52A1\u65F6\u7B80\u77ED\u544A\u77E5\u7528\u6237\u5373\u53EF\u6536\u5C3E\u672C\u8F6E\u3002`,
|
|
6359
|
+
`\uFF08\u8FFD\u95EE/\u7EED\u8DD1\uFF1Aspawn_agent \u4F20 resume_session_id="${agentId}"\uFF0C\u5176\u5386\u53F2\u8BB0\u5FC6\u5B8C\u6574\u4FDD\u7559\u3002\uFF09`
|
|
6360
|
+
].join("\n");
|
|
6361
|
+
await runPreparedSubagent(prep.prepared, ctx, { notifyDone: true });
|
|
6141
6362
|
}
|
|
6142
6363
|
}
|
|
6143
6364
|
}
|
|
@@ -6370,6 +6591,7 @@ var init_workflow = __esm({
|
|
|
6370
6591
|
init_config();
|
|
6371
6592
|
init_guard();
|
|
6372
6593
|
init_manager();
|
|
6594
|
+
init_agentWake();
|
|
6373
6595
|
init_workflowHelpers();
|
|
6374
6596
|
createWorkflowTools = (getGlobalTools) => [
|
|
6375
6597
|
{
|
|
@@ -6377,7 +6599,8 @@ var init_workflow = __esm({
|
|
|
6377
6599
|
function: {
|
|
6378
6600
|
name: "run_workflow",
|
|
6379
6601
|
description: [
|
|
6380
|
-
"\u591A\u5B50 agent \u7F16\u6392\uFF1A\u628A\u53EF\u5206\u89E3\u7684\u5927\u4EFB\u52A1\u6D3E\u7ED9\u591A\u4E2A\u72EC\u7ACB\u5B50 agent\u3002parallel\uFF08\u9ED8\u8BA4\uFF09=\u5404\u6B65\u9AA4\u5E76\u53D1\u6267\u884C\u3001\u7ED3\u679C\u6309\u5E8F\u805A\u5408\uFF0C\u9002\u5408\u4E92\u76F8\u72EC\u7ACB\u7684\u53EA\u8BFB/\u5206\u6790\u4EFB\u52A1\uFF1Bpipeline=\u6B65\u9AA4\u4E32\u884C\uFF0C\u524D\u9636\u6BB5\u4EA7\u51FA\u81EA\u52A8\u4F5C\u4E3A\u540E\u9636\u6BB5\u8F93\u5165\uFF0C\u9002\u5408\u5206\u9636\u6BB5\u52A0\u5DE5\uFF08\u62BD\u53D6\u2192\u5F52\u7C7B\u2192\u6C47\u603B\uFF09\u3002",
|
|
6602
|
+
"\u5F02\u6B65\u591A\u5B50 agent \u7F16\u6392\uFF1A\u628A\u53EF\u5206\u89E3\u7684\u5927\u4EFB\u52A1\u6D3E\u7ED9\u591A\u4E2A\u72EC\u7ACB\u5B50 agent\uFF0C\u8C03\u7528\u7ACB\u5373\u8FD4\u56DE\uFF08\u4E0D\u7B49\u5F85\u5B8C\u6210\uFF09\uFF0C\u5168\u90E8\u6B65\u9AA4\u7ED3\u675F\u540E\u4E00\u6761\u7EC8\u6001\u6C47\u603B\u81EA\u52A8\u6CE8\u5165\u672C\u4F1A\u8BDD\u5E76\u5524\u9192\u4F60\u7EE7\u7EED\u63A8\u8FDB\uFF08\u4E2D\u95F4\u6001\u4E0D\u56DE\u6D41\uFF0C\u9632\u4E8B\u4EF6\u6D2A\u5CF0\uFF09\u3002parallel\uFF08\u9ED8\u8BA4\uFF09=\u5404\u6B65\u9AA4\u5E76\u53D1\u6267\u884C\u3001\u7ED3\u679C\u6309\u5E8F\u805A\u5408\uFF0C\u9002\u5408\u4E92\u76F8\u72EC\u7ACB\u7684\u53EA\u8BFB/\u5206\u6790\u4EFB\u52A1\uFF1Bpipeline=\u6B65\u9AA4\u4E32\u884C\uFF0C\u524D\u9636\u6BB5\u4EA7\u51FA\u81EA\u52A8\u4F5C\u4E3A\u540E\u9636\u6BB5\u8F93\u5165\uFF0C\u9002\u5408\u5206\u9636\u6BB5\u52A0\u5DE5\uFF08\u62BD\u53D6\u2192\u5F52\u7C7B\u2192\u6C47\u603B\uFF09\u3002",
|
|
6603
|
+
"\u6D3E\u51FA\u540E\u4F60\u53EF\u7ACB\u5373\u7EE7\u7EED\u6D3E\u6D3B / \u5904\u7406\u5176\u4ED6\u4E8B\u52A1 / \u56DE\u590D\u7528\u6237\uFF1B\u5F53\u524D\u65E0\u5176\u4ED6\u4E8B\u52A1\u65F6\u53EF\u7B80\u77ED\u544A\u77E5\u5DF2\u7F16\u6392\u5E76\u7ED3\u675F\u672C\u8F6E\u2014\u2014\u6C47\u603B\u9001\u8FBE\u65F6\u4F60\u4F1A\u88AB\u81EA\u52A8\u5524\u9192\u3002",
|
|
6381
6604
|
'\u6B65\u9AA4\u53EF\u7528 name \u5957\u7528\u58F0\u660E\u5F0F\u5B50 Agent\uFF08\u89C1\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\uFF09\u3001key \u4F5C\u7ED3\u679C\u6807\u7B7E\u3002parallel \u9ED8\u8BA4\u5171\u4EAB\u5DE5\u4F5C\u533A\uFF0C\u4EC5\u9002\u5408\u5E76\u884C\u8BFB/\u5206\u6790\uFF1B\u5E76\u884C\u5199/\u8FC1\u79FB\u7528 isolation="worktree"\uFF08\u6BCF\u6B65\u72EC\u7ACB git worktree\uFF0C\u7ED3\u675F\u540E\u6536\u5272\u5404\u6B65 diff\uFF09\u3002',
|
|
6382
6605
|
"\u4E0E spawn_agent \u7684\u5206\u5DE5\uFF1A\u5355\u4EFB\u52A1\u4E32\u884C\u59D4\u6D3E\u7528 spawn_agent\uFF1B\u4EFB\u52A1\u53EF\u5206\u89E3\u3001\u591A\u5206\u652F\u6216\u6D41\u6C34\u7EBF\u5F0F\u65F6\u7528\u672C\u5DE5\u5177\u3002"
|
|
6383
6606
|
].join("\n"),
|
|
@@ -6417,18 +6640,29 @@ var init_workflow = __esm({
|
|
|
6417
6640
|
required: ["steps"]
|
|
6418
6641
|
},
|
|
6419
6642
|
safetyLevel: "safe" /* SAFE */,
|
|
6420
|
-
isSync:
|
|
6643
|
+
isSync: false,
|
|
6421
6644
|
// 聚合输出整体兜底截断(各子 agent 结果已按 workflowPerStepChars 单独截断)。
|
|
6645
|
+
// ★ 异步化后工具结果 = 首个 yield 的启动回执(天然短);此上限改用于终态汇总的 inbox 报文截断。
|
|
6422
6646
|
maxOutputCharacters: 18e3,
|
|
6423
|
-
async
|
|
6424
|
-
|
|
6647
|
+
// ★ 子代理异步化(方案 §4.4):async* + 首个 yield 立即回执;全部步骤在 generator 挂起期间后台执行,
|
|
6648
|
+
// 完成后一条终态汇总经 agentWake.notifySubagentDone 回流(中间态不回流,防事件洪峰)。
|
|
6649
|
+
// 宿主中止时执行层 gen.return() 拦在 await 前 → 不产生中止后的唤醒(与 spawn_agent 同语义)。
|
|
6650
|
+
async *execute(args, ctx) {
|
|
6651
|
+
if (!ctx) {
|
|
6652
|
+
yield toolFailure("[\u5DE5\u4F5C\u6D41]\uFF1Arun_workflow \u7F3A\u5C11\u5FC5\u987B\u7684\u667A\u80FD\u4F53\u8FD0\u884C\u4E0A\u4E0B\u6587\u3002");
|
|
6653
|
+
return;
|
|
6654
|
+
}
|
|
6425
6655
|
const maxSteps = appConfig.workflowMaxSteps;
|
|
6426
6656
|
const validationError = validateWorkflowArgs(args, maxSteps);
|
|
6427
|
-
if (validationError)
|
|
6657
|
+
if (validationError) {
|
|
6658
|
+
yield validationError;
|
|
6659
|
+
return;
|
|
6660
|
+
}
|
|
6428
6661
|
const mode = args.mode === "pipeline" ? "pipeline" : "parallel";
|
|
6429
6662
|
const isolation = args.isolation === "worktree" ? "worktree" : "none";
|
|
6430
6663
|
if (isolation === "worktree" && mode === "pipeline") {
|
|
6431
|
-
|
|
6664
|
+
yield toolFailure('[\u5DE5\u4F5C\u6D41]\uFF1Aisolation="worktree" \u6682\u4EC5\u652F\u6301 parallel \u6A21\u5F0F\uFF08pipeline \u4E32\u884C\u65E0\u9700\u9694\u79BB\uFF09\u3002\u8BF7\u6539 mode=parallel \u6216 isolation=none\u3002');
|
|
6665
|
+
return;
|
|
6432
6666
|
}
|
|
6433
6667
|
const steps = args.steps.map((s) => ({
|
|
6434
6668
|
task: String(s.task),
|
|
@@ -6437,8 +6671,13 @@ var init_workflow = __esm({
|
|
|
6437
6671
|
key: s.key ? String(s.key) : void 0
|
|
6438
6672
|
}));
|
|
6439
6673
|
if (ctx.depth >= MAX_AGENT_DEPTH) {
|
|
6440
|
-
|
|
6674
|
+
yield toolFailure(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u5DF2\u8FBE\u5230\u6700\u5927 Agent \u5D4C\u5957\u6DF1\u5EA6\uFF08${MAX_AGENT_DEPTH}\u5C42\uFF09\uFF0C\u65E0\u6CD5\u6D3E\u751F\u5DE5\u4F5C\u6D41\u5B50 agent\u3002\u8BF7\u5728\u672C\u5C42\u7EA7\u81EA\u884C\u6D88\u5316\u4EFB\u52A1\u3002`);
|
|
6675
|
+
return;
|
|
6441
6676
|
}
|
|
6677
|
+
yield [
|
|
6678
|
+
`\u2705 \u5DE5\u4F5C\u6D41\u5DF2\u5F02\u6B65\u542F\u52A8\uFF08mode=${mode}\uFF0C\u5171 ${steps.length} \u6B65${isolation === "worktree" ? "\uFF0C\u6BCF\u6B65\u72EC\u7ACB git worktree \u9694\u79BB" : ""}\uFF09\u3002`,
|
|
6679
|
+
`\u5168\u90E8\u6B65\u9AA4\u540E\u53F0\u6267\u884C\u5B8C\u6BD5\u540E\uFF0C\u4E00\u6761\u7EC8\u6001\u6C47\u603B\u4F1A\u81EA\u52A8\u9001\u8FBE\u672C\u4F1A\u8BDD\u5E76\u5524\u9192\u4F60\u7EE7\u7EED\uFF08\u4E2D\u95F4\u6001\u4E0D\u56DE\u6D41\uFF09\uFF1B\u671F\u95F4\u65E0\u9700\u7B49\u5F85\u2014\u2014\u53EF\u7EE7\u7EED\u6D3E\u6D3B / \u5904\u7406\u5176\u4ED6\u4E8B\u52A1\uFF0C\u65E0\u5176\u4ED6\u4E8B\u52A1\u65F6\u7B80\u77ED\u544A\u77E5\u7528\u6237\u5373\u53EF\u6536\u5C3E\u672C\u8F6E\u3002`
|
|
6680
|
+
].join("\n");
|
|
6442
6681
|
const approvalMutex = createSemaphore(1);
|
|
6443
6682
|
const serializedApproval = ctx.requestApproval ? async (...raArgs) => {
|
|
6444
6683
|
await approvalMutex.acquire();
|
|
@@ -6521,9 +6760,25 @@ var init_workflow = __esm({
|
|
|
6521
6760
|
outcomes = await Promise.all(running);
|
|
6522
6761
|
}
|
|
6523
6762
|
} catch (err) {
|
|
6524
|
-
|
|
6763
|
+
await notifySubagentDone(ctx.sessionId, [
|
|
6764
|
+
`\u{1F916} [\u5DE5\u4F5C\u6D41\u5B8C\u6210]\uFF08mode=${mode}\uFF0C\u5171 ${steps.length} \u6B65\uFF09`,
|
|
6765
|
+
`\u72B6\u6001\uFF1Aerror\uFF08\u7F16\u6392\u5F02\u5E38\uFF09`,
|
|
6766
|
+
`\u6C47\u603B\uFF1A`,
|
|
6767
|
+
`\u26A0\uFE0F [\u5DE5\u4F5C\u6D41\u7F16\u6392\u5F02\u5E38]\uFF1A${err?.message ?? err}`
|
|
6768
|
+
].join("\n"));
|
|
6769
|
+
return;
|
|
6525
6770
|
}
|
|
6526
|
-
|
|
6771
|
+
const allOk = outcomes.every((o) => o.ok);
|
|
6772
|
+
const abortedCount = outcomes.filter((o) => !o.ok && o.output.includes("\u5DF2\u4E2D\u6B62")).length;
|
|
6773
|
+
const status = abortedCount === outcomes.length ? "aborted" : allOk ? "final" : "error";
|
|
6774
|
+
const statusLabel = status === "final" ? "final\uFF08\u5168\u90E8\u6B65\u9AA4\u6B63\u5E38\u5B8C\u6210\uFF09" : status === "aborted" ? "aborted\uFF08\u5168\u90E8\u6B65\u9AA4\u88AB\u4E2D\u6B62\uFF09" : "error\uFF08\u90E8\u5206\u6B65\u9AA4\u5931\u8D25/\u4E2D\u6B62\uFF09";
|
|
6775
|
+
await notifySubagentDone(ctx.sessionId, [
|
|
6776
|
+
`\u{1F916} [\u5DE5\u4F5C\u6D41\u5B8C\u6210]\uFF08mode=${mode}\uFF0C\u5171 ${steps.length} \u6B65\uFF09`,
|
|
6777
|
+
`\u72B6\u6001\uFF1A${statusLabel}`,
|
|
6778
|
+
`\u6C47\u603B\uFF1A`,
|
|
6779
|
+
// 截断口径与原同步返回一致(maxOutputCharacters 18000)
|
|
6780
|
+
truncateToolResult(formatWorkflowResult(mode, outcomes), 18e3)
|
|
6781
|
+
].join("\n"));
|
|
6527
6782
|
}
|
|
6528
6783
|
}
|
|
6529
6784
|
}
|
|
@@ -10797,8 +11052,9 @@ var init_frontmatter = __esm({
|
|
|
10797
11052
|
|
|
10798
11053
|
// ../core/src/memory/loader.ts
|
|
10799
11054
|
import fs28 from "fs/promises";
|
|
11055
|
+
import os5 from "os";
|
|
10800
11056
|
import path30 from "path";
|
|
10801
|
-
var GLOBAL_MEMORY_DIR, SOURCES, VALID_TYPES, parseMemoryAt, loadMemories, initMemories;
|
|
11057
|
+
var GLOBAL_MEMORY_DIR, SOURCES, VALID_TYPES, NAME_RE, parseMemoryAt, MAX_EXTERNAL_ITEMS, EXTERNAL_DESC_MAX_CHARS, EXTERNAL_BODY_MAX_BYTES, EXTERNAL_RULES, sanitizeExternalStem, extractExternalTitle, buildExternalDescription, truncateUtf8ToBytes, scanExternalRule, externalNoticeShown, loadExternalMemories, loadMemories, initMemories;
|
|
10802
11058
|
var init_loader3 = __esm({
|
|
10803
11059
|
"../core/src/memory/loader.ts"() {
|
|
10804
11060
|
"use strict";
|
|
@@ -10812,6 +11068,7 @@ var init_loader3 = __esm({
|
|
|
10812
11068
|
{ dir: path30.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
|
|
10813
11069
|
];
|
|
10814
11070
|
VALID_TYPES = ["user", "feedback", "project", "reference"];
|
|
11071
|
+
NAME_RE = /^[a-z0-9-]+$/;
|
|
10815
11072
|
parseMemoryAt = async (file, _dir, source) => {
|
|
10816
11073
|
let raw;
|
|
10817
11074
|
try {
|
|
@@ -10830,7 +11087,7 @@ var init_loader3 = __esm({
|
|
|
10830
11087
|
console.warn(`\u26A0\uFE0F [memory] \u7F3A\u5C11 name \u6216 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
10831
11088
|
return null;
|
|
10832
11089
|
}
|
|
10833
|
-
if (
|
|
11090
|
+
if (!NAME_RE.test(name)) {
|
|
10834
11091
|
console.warn(`\u26A0\uFE0F [memory] name "${name}" \u4E0D\u5408\u6CD5\uFF08\u4EC5\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
10835
11092
|
return null;
|
|
10836
11093
|
}
|
|
@@ -10845,6 +11102,128 @@ var init_loader3 = __esm({
|
|
|
10845
11102
|
}
|
|
10846
11103
|
return { name, description, type, body: parsed.body.trim(), source, file };
|
|
10847
11104
|
};
|
|
11105
|
+
MAX_EXTERNAL_ITEMS = 12;
|
|
11106
|
+
EXTERNAL_DESC_MAX_CHARS = 120;
|
|
11107
|
+
EXTERNAL_BODY_MAX_BYTES = 64 * 1024;
|
|
11108
|
+
EXTERNAL_RULES = [
|
|
11109
|
+
// 全局层(~ 下,存在才扫,缺省静默跳过)
|
|
11110
|
+
{ dir: path30.join(os5.homedir(), ".claude"), file: "CLAUDE.md", name: "ext-claude", projectLayer: false },
|
|
11111
|
+
{ dir: path30.join(os5.homedir(), ".codex"), file: "AGENTS.md", name: "ext-codex", projectLayer: false },
|
|
11112
|
+
{ dir: path30.join(os5.homedir(), ".gemini"), file: "GEMINI.md", name: "ext-gemini", projectLayer: false },
|
|
11113
|
+
// 项目层(<cwd> 下)
|
|
11114
|
+
{ dir: process.cwd(), file: "CLAUDE.md", name: "ext-claude-project", projectLayer: true },
|
|
11115
|
+
{ dir: process.cwd(), file: "AGENTS.md", name: "ext-agents", projectLayer: true },
|
|
11116
|
+
{ dir: process.cwd(), file: "GEMINI.md", name: "ext-gemini-project", projectLayer: true },
|
|
11117
|
+
{ dir: path30.join(process.cwd(), ".cursor", "rules"), name: (stem) => `ext-cursor-${stem}`, projectLayer: true },
|
|
11118
|
+
{ dir: path30.join(process.cwd(), ".github"), file: "copilot-instructions.md", name: "ext-copilot", projectLayer: true }
|
|
11119
|
+
];
|
|
11120
|
+
sanitizeExternalStem = (stem) => stem.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
11121
|
+
extractExternalTitle = (raw, fallbackStem) => {
|
|
11122
|
+
const lines = raw.split(/\r?\n/);
|
|
11123
|
+
for (const line of lines) {
|
|
11124
|
+
const m = /^#\s+(.+)$/.exec(line);
|
|
11125
|
+
if (m) return m[1].trim();
|
|
11126
|
+
}
|
|
11127
|
+
for (const line of lines) {
|
|
11128
|
+
const t = line.trim();
|
|
11129
|
+
if (t) return t.replace(/^#+\s*/, "") || fallbackStem;
|
|
11130
|
+
}
|
|
11131
|
+
return fallbackStem;
|
|
11132
|
+
};
|
|
11133
|
+
buildExternalDescription = (label, title) => {
|
|
11134
|
+
const full = `[\u5916\u90E8:${label}] ${title.replace(/\s+/g, " ").trim()}`;
|
|
11135
|
+
return full.length > EXTERNAL_DESC_MAX_CHARS ? full.slice(0, EXTERNAL_DESC_MAX_CHARS) : full;
|
|
11136
|
+
};
|
|
11137
|
+
truncateUtf8ToBytes = (text, maxBytes) => {
|
|
11138
|
+
const buf = Buffer.from(text, "utf-8");
|
|
11139
|
+
if (buf.length <= maxBytes) return { text, truncated: false };
|
|
11140
|
+
return { text: buf.subarray(0, maxBytes).toString("utf-8"), truncated: true };
|
|
11141
|
+
};
|
|
11142
|
+
scanExternalRule = async (rule) => {
|
|
11143
|
+
let entries;
|
|
11144
|
+
try {
|
|
11145
|
+
entries = await fs28.readdir(rule.dir, { withFileTypes: true });
|
|
11146
|
+
} catch {
|
|
11147
|
+
return [];
|
|
11148
|
+
}
|
|
11149
|
+
const out = [];
|
|
11150
|
+
for (const entry of entries) {
|
|
11151
|
+
if (!entry.isFile()) continue;
|
|
11152
|
+
if (rule.file ? entry.name !== rule.file : !entry.name.endsWith(".md")) continue;
|
|
11153
|
+
const stem = entry.name.replace(/\.md$/, "");
|
|
11154
|
+
const file = path30.join(rule.dir, entry.name);
|
|
11155
|
+
const name = typeof rule.name === "function" ? sanitizeExternalStem(stem) ? `ext-cursor-${sanitizeExternalStem(stem)}` : "" : rule.name;
|
|
11156
|
+
if (!name || !NAME_RE.test(name)) {
|
|
11157
|
+
console.warn(`\u26A0\uFE0F [memory] \u5916\u90E8\u6587\u4EF6\u540D\u4E3B\u5E72\u65E0\u6CD5\u751F\u6210\u5408\u6CD5\u8BB0\u5FC6\u540D\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
11158
|
+
continue;
|
|
11159
|
+
}
|
|
11160
|
+
let raw;
|
|
11161
|
+
try {
|
|
11162
|
+
raw = await fs28.readFile(file, "utf-8");
|
|
11163
|
+
} catch {
|
|
11164
|
+
continue;
|
|
11165
|
+
}
|
|
11166
|
+
const body = truncateUtf8ToBytes(raw.trim(), EXTERNAL_BODY_MAX_BYTES);
|
|
11167
|
+
if (!body.text) continue;
|
|
11168
|
+
if (body.truncated) console.warn(`\u26A0\uFE0F [memory] \u5916\u90E8\u6587\u4EF6\u8D85 ${EXTERNAL_BODY_MAX_BYTES} \u5B57\u8282\u5DF2\u622A\u65AD\uFF08${file}\uFF09`);
|
|
11169
|
+
const stat = await fs28.stat(file).catch(() => null);
|
|
11170
|
+
out.push({
|
|
11171
|
+
item: {
|
|
11172
|
+
name,
|
|
11173
|
+
description: buildExternalDescription(rule.file ?? entry.name, extractExternalTitle(raw, stem)),
|
|
11174
|
+
type: "reference",
|
|
11175
|
+
// 外部二手资料的语义即参考(§4),不冒充 user/feedback 画像
|
|
11176
|
+
body: body.text,
|
|
11177
|
+
source: "external",
|
|
11178
|
+
file
|
|
11179
|
+
},
|
|
11180
|
+
mtimeMs: stat?.mtimeMs ?? 0
|
|
11181
|
+
});
|
|
11182
|
+
}
|
|
11183
|
+
return out;
|
|
11184
|
+
};
|
|
11185
|
+
externalNoticeShown = false;
|
|
11186
|
+
loadExternalMemories = async (includeProject) => {
|
|
11187
|
+
if (!appConfig.memoryExternal) return 0;
|
|
11188
|
+
const candidates = [];
|
|
11189
|
+
for (const rule of EXTERNAL_RULES) {
|
|
11190
|
+
if (rule.projectLayer && !includeProject) continue;
|
|
11191
|
+
candidates.push(...await scanExternalRule(rule));
|
|
11192
|
+
}
|
|
11193
|
+
if (candidates.length === 0) return 0;
|
|
11194
|
+
const dropped = [];
|
|
11195
|
+
if (candidates.length > MAX_EXTERNAL_ITEMS) {
|
|
11196
|
+
candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
11197
|
+
for (const c of candidates.slice(MAX_EXTERNAL_ITEMS)) dropped.push(c.item.name);
|
|
11198
|
+
candidates.length = MAX_EXTERNAL_ITEMS;
|
|
11199
|
+
}
|
|
11200
|
+
const skipped = [];
|
|
11201
|
+
for (const { item } of candidates) {
|
|
11202
|
+
const all = listMemories();
|
|
11203
|
+
if (all.length >= MEMORY_LIMITS.maxCount) {
|
|
11204
|
+
skipped.push(item.name);
|
|
11205
|
+
continue;
|
|
11206
|
+
}
|
|
11207
|
+
const curBytes = all.length === 0 ? 0 : Buffer.byteLength(all.map(memoryIndexLine).join("\n"), "utf-8");
|
|
11208
|
+
if (curBytes + Buffer.byteLength(memoryIndexLine(item), "utf-8") > MEMORY_LIMITS.maxIndexBytes) {
|
|
11209
|
+
skipped.push(item.name);
|
|
11210
|
+
continue;
|
|
11211
|
+
}
|
|
11212
|
+
registerMemory(item);
|
|
11213
|
+
}
|
|
11214
|
+
if (dropped.length > 0) {
|
|
11215
|
+
console.warn(`\u26A0\uFE0F [memory] \u5916\u90E8\u6761\u76EE\u8D85\u8F6F\u4E0A\u9650 ${MAX_EXTERNAL_ITEMS}\uFF0C\u6309 mtime \u4E22\u5F03\u6700\u65E7 ${dropped.length} \u6761\uFF1A${dropped.join("\u3001")}`);
|
|
11216
|
+
}
|
|
11217
|
+
if (skipped.length > 0) {
|
|
11218
|
+
console.warn(`\u26A0\uFE0F [memory] \u5916\u90E8\u6761\u76EE\u8D85\u5171\u4EAB\u9884\u7B97\uFF08MEMORY_LIMITS\uFF1A${MEMORY_LIMITS.maxCount} \u6761/${MEMORY_LIMITS.maxIndexBytes} \u5B57\u8282\uFF09\uFF0C\u62D2\u8F7D\uFF1A${skipped.join("\u3001")}`);
|
|
11219
|
+
}
|
|
11220
|
+
const n = candidates.length - skipped.length;
|
|
11221
|
+
if (n > 0 && !externalNoticeShown) {
|
|
11222
|
+
externalNoticeShown = true;
|
|
11223
|
+
console.log("\u{1F310} [memory] \u5916\u90E8\u8BB0\u5FC6\u5DF2\u63A5\u5165\uFF08\u53EA\u8BFB\uFF09\uFF1A\u6765\u6E90\u6587\u4EF6\u5185\u5BB9\u5C06\u968F\u8BF7\u6C42\u53D1\u9001\u7ED9 DeepSeek API\u3002\u5173\u95ED\uFF1Asettings.json engine.memoryExternal=false");
|
|
11224
|
+
}
|
|
11225
|
+
return n;
|
|
11226
|
+
};
|
|
10848
11227
|
loadMemories = async (includeProject) => {
|
|
10849
11228
|
clearMemories();
|
|
10850
11229
|
const picked = await scanSources(
|
|
@@ -10853,6 +11232,7 @@ var init_loader3 = __esm({
|
|
|
10853
11232
|
parseMemoryAt
|
|
10854
11233
|
);
|
|
10855
11234
|
for (const { item } of picked) registerMemory(item);
|
|
11235
|
+
await loadExternalMemories(includeProject);
|
|
10856
11236
|
return listMemories().length;
|
|
10857
11237
|
};
|
|
10858
11238
|
initMemories = async (includeProject) => {
|
|
@@ -10900,7 +11280,7 @@ var init_usage = __esm({
|
|
|
10900
11280
|
// ../core/src/tool/registry/memory.ts
|
|
10901
11281
|
import fs30 from "fs/promises";
|
|
10902
11282
|
import path32 from "path";
|
|
10903
|
-
var MAX_BODY_BYTES, MAX_DESCRIPTION_CHARS,
|
|
11283
|
+
var MAX_BODY_BYTES, MAX_DESCRIPTION_CHARS, NAME_RE2, VALID_TYPES2, memoryFilePath, sanitizeLine, buildMemoryMd, writeAndRegister, indexLineBytes, memoryTools;
|
|
10904
11284
|
var init_memory = __esm({
|
|
10905
11285
|
"../core/src/tool/registry/memory.ts"() {
|
|
10906
11286
|
"use strict";
|
|
@@ -10911,8 +11291,7 @@ var init_memory = __esm({
|
|
|
10911
11291
|
init_usage();
|
|
10912
11292
|
MAX_BODY_BYTES = 64 * 1024;
|
|
10913
11293
|
MAX_DESCRIPTION_CHARS = 200;
|
|
10914
|
-
|
|
10915
|
-
NAME_RE = /^[a-z0-9-]+$/;
|
|
11294
|
+
NAME_RE2 = /^[a-z0-9-]+$/;
|
|
10916
11295
|
VALID_TYPES2 = ["user", "feedback", "project", "reference"];
|
|
10917
11296
|
memoryFilePath = (name, project) => project ? path32.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path32.join(GLOBAL_MEMORY_DIR, `${name}.md`);
|
|
10918
11297
|
sanitizeLine = (s) => String(s ?? "").replace(/[\r\n]+/g, " ").trim();
|
|
@@ -10975,7 +11354,8 @@ ${body.trim()}
|
|
|
10975
11354
|
const body = typeof args?.body === "string" ? args.body : "";
|
|
10976
11355
|
const type = sanitizeLine(args?.type) || "reference";
|
|
10977
11356
|
const project = args?.project === true;
|
|
10978
|
-
if (!
|
|
11357
|
+
if (!NAME_RE2.test(name)) return toolFailure(`[memory_save] name \u975E\u6CD5\uFF1A\u4EC5\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C\u6536\u5230 "${name}"\u3002`);
|
|
11358
|
+
if (name.startsWith("ext-")) return toolFailure(`[memory_save] "ext-" \u540D\u79F0\u524D\u7F00\u4E3A\u5916\u90E8\u8BB0\u5FC6\u4FDD\u7559\u5B57\uFF08\u8BE5\u524D\u7F00\u6761\u76EE\u7531 loader \u4ECE\u5176\u4ED6 agent \u7684\u89C4\u5219/\u6307\u4EE4\u6587\u4EF6\u53EA\u8BFB\u6865\u63A5\uFF0C\u540D\u79F0\u56FA\u5B9A\u5206\u914D\uFF09\u3002\u8BF7\u6539\u7528\u5176\u4ED6\u540D\u79F0\u3002`);
|
|
10979
11359
|
if (!description) return toolFailure("[memory_save] description \u4E0D\u80FD\u4E3A\u7A7A\u3002");
|
|
10980
11360
|
if (description.length > MAX_DESCRIPTION_CHARS) return toolFailure(`[memory_save] description \u8D85\u8FC7 ${MAX_DESCRIPTION_CHARS} \u5B57\u7B26\u4E0A\u9650\uFF08\u5F53\u524D ${description.length}\uFF09\u3002\u8BF7\u538B\u7F29\u4E3A\u4E00\u53E5\u8BDD\u3002`);
|
|
10981
11361
|
if (!body.trim()) return toolFailure("[memory_save] body \u4E0D\u80FD\u4E3A\u7A7A\u3002");
|
|
@@ -11002,7 +11382,7 @@ ${body.trim()}
|
|
|
11002
11382
|
type: "function",
|
|
11003
11383
|
function: {
|
|
11004
11384
|
name: "memory_read",
|
|
11005
|
-
description: "\u8BFB\u53D6\u6307\u5B9A\u8BB0\u5FC6\u7684\u5B8C\u6574\u6B63\u6587\u3002\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4EC5\u6CE8\u5165\u8BB0\u5FC6\u7D22\u5F15\uFF08\u4E00\u884C/\u6761\uFF0C\u7701 token\uFF09\uFF1B\u5F53\u7D22\u5F15\u4E2D\u67D0\u6761\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u3001\u9700\u8981\u5168\u6587\u7EC6\u8282\u65F6\uFF0C\u8C03\u7528\u672C\u5DE5\u5177\u6309\u9700\u53EC\u56DE\u3002",
|
|
11385
|
+
description: "\u8BFB\u53D6\u6307\u5B9A\u8BB0\u5FC6\u7684\u5B8C\u6574\u6B63\u6587\u3002\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4EC5\u6CE8\u5165\u8BB0\u5FC6\u7D22\u5F15\uFF08\u4E00\u884C/\u6761\uFF0C\u7701 token\uFF09\uFF1B\u5F53\u7D22\u5F15\u4E2D\u67D0\u6761\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u3001\u9700\u8981\u5168\u6587\u7EC6\u8282\u65F6\uFF0C\u8C03\u7528\u672C\u5DE5\u5177\u6309\u9700\u53EC\u56DE\u3002\u7D22\u5F15\u4E2D\u6807 [\u5916\u90E8:*] \u7684\u6761\u76EE\u662F\u5176\u4ED6 agent \u89C4\u5219\u6587\u4EF6\u7684\u4E8C\u624B\u6458\u5F55\uFF08type=reference\uFF09\uFF1A\u4E0E\u73B0\u573A\u5B9E\u9645\u4E0D\u7B26\u65F6\u4EE5\u73B0\u573A\u4E3A\u51C6\uFF0C\u5E76\u53EF memory_save \u4E00\u6761\u81EA\u6709\u8BB0\u5FC6\u7EA0\u504F\u3002",
|
|
11006
11386
|
parameters: {
|
|
11007
11387
|
type: "object",
|
|
11008
11388
|
properties: {
|
|
@@ -11061,6 +11441,7 @@ ${lines.join("\n")}`;
|
|
|
11061
11441
|
requireApproval: (args) => `\u5220\u9664\u6301\u4E45\u8BB0\u5FC6 **${sanitizeLine(args?.name)}**\uFF08\u8DE8\u4F1A\u8BDD\u751F\u6548\uFF0C\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\uFF09`,
|
|
11062
11442
|
async execute(args) {
|
|
11063
11443
|
const name = sanitizeLine(args?.name);
|
|
11444
|
+
if (name.startsWith("ext-")) return toolFailure(`[memory_delete] \u5916\u90E8\u6761\u76EE\u53EA\u8BFB\uFF0C\u8BF7\u5230\u6765\u6E90\u6587\u4EF6\u5904\u4FEE\u6539\uFF08ext- \u524D\u7F00\u6761\u76EE\u7531 loader \u4ECE\u5176\u4ED6 agent \u7684\u89C4\u5219/\u6307\u4EE4\u6587\u4EF6\u53EA\u8BFB\u6865\u63A5\uFF0C\u5220\u9664/\u4FEE\u6539\u8BF7\u76F4\u63A5\u7F16\u8F91\u6765\u6E90\u6587\u4EF6\u540E\u91CD\u542F\u8FDB\u7A0B\uFF09\u3002`);
|
|
11064
11445
|
const m = getMemory(name);
|
|
11065
11446
|
if (!m) return toolFailure(`\u672A\u627E\u5230\u8BB0\u5FC6\uFF1A${name}\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF09\u3002`);
|
|
11066
11447
|
try {
|
|
@@ -12189,7 +12570,7 @@ var init_toolExecution = __esm({
|
|
|
12189
12570
|
const isForegroundCommand = isCommandTool && matchedTool.function.isSync !== false;
|
|
12190
12571
|
const cmdIsScriptRunner = isCommandTool && isScriptRunnerCommand(typeof state.calledArgs?.command === "string" ? state.calledArgs.command : "");
|
|
12191
12572
|
const argCwd = typeof state.calledArgs?.cwd === "string" ? state.calledArgs.cwd.trim() : "";
|
|
12192
|
-
const
|
|
12573
|
+
const samePath2 = (a, b) => {
|
|
12193
12574
|
try {
|
|
12194
12575
|
const ra = path36.resolve(a), rb = path36.resolve(b);
|
|
12195
12576
|
return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
|
|
@@ -12197,7 +12578,7 @@ var init_toolExecution = __esm({
|
|
|
12197
12578
|
return false;
|
|
12198
12579
|
}
|
|
12199
12580
|
};
|
|
12200
|
-
const scriptRunnerCwdDrift = cmdIsScriptRunner && argCwd !== "" && !
|
|
12581
|
+
const scriptRunnerCwdDrift = cmdIsScriptRunner && argCwd !== "" && !samePath2(argCwd, toolCtx.cwd ?? process.cwd());
|
|
12201
12582
|
const scriptRunnerBlocked = cmdIsScriptRunner && (perm === null || scriptRunnerCwdDrift);
|
|
12202
12583
|
if (scriptRunnerCwdDrift) needApproval = true;
|
|
12203
12584
|
if (perm === null && needApproval && !state.denied && !scriptRunnerBlocked && isForegroundCommand && isReadOnlyCommand(typeof state.calledArgs?.command === "string" ? state.calledArgs.command : "")) {
|
|
@@ -13186,7 +13567,7 @@ var init_prices = __esm({
|
|
|
13186
13567
|
peak: { input: 9, output: 27, cacheHit: 0.3 }
|
|
13187
13568
|
}
|
|
13188
13569
|
};
|
|
13189
|
-
PRICES_VERIFIED_AT = "2026-
|
|
13570
|
+
PRICES_VERIFIED_AT = "2026-11-03";
|
|
13190
13571
|
PRICES_STALE_DAYS = 30;
|
|
13191
13572
|
pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
|
|
13192
13573
|
isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
|
|
@@ -13843,6 +14224,7 @@ async function* runAgent(message, options) {
|
|
|
13843
14224
|
}
|
|
13844
14225
|
const inboxTexts = claimSessionInbox(sessionId);
|
|
13845
14226
|
if (inboxTexts.length > 0) {
|
|
14227
|
+
clearQueuedWake(sessionId);
|
|
13846
14228
|
for (const t of inboxTexts) {
|
|
13847
14229
|
message.push({ role: "user", content: t });
|
|
13848
14230
|
await appendMessage({ sessionId, role: "user", content: t });
|
|
@@ -14112,6 +14494,7 @@ var init_runAgent = __esm({
|
|
|
14112
14494
|
"use strict";
|
|
14113
14495
|
init_transcript();
|
|
14114
14496
|
init_inbox();
|
|
14497
|
+
init_agentWake();
|
|
14115
14498
|
init_common();
|
|
14116
14499
|
init_contextCore();
|
|
14117
14500
|
init_contentParts();
|
|
@@ -14198,7 +14581,7 @@ var init_lineage = __esm({
|
|
|
14198
14581
|
});
|
|
14199
14582
|
|
|
14200
14583
|
// ../core/src/agent/subagent.ts
|
|
14201
|
-
var SUBAGENT_DENYLIST, filterToolsForSubagent, activeSubagents, failText, RESUME_NOTE, createProgressThrottler, runSubagent;
|
|
14584
|
+
var SUBAGENT_DENYLIST, filterToolsForSubagent, activeSubagents, failText, RESUME_NOTE, createProgressThrottler, prepareSubagent, runPreparedSubagent, runSubagent;
|
|
14202
14585
|
var init_subagent = __esm({
|
|
14203
14586
|
"../core/src/agent/subagent.ts"() {
|
|
14204
14587
|
"use strict";
|
|
@@ -14211,6 +14594,7 @@ var init_subagent = __esm({
|
|
|
14211
14594
|
init_registry4();
|
|
14212
14595
|
init_hooks();
|
|
14213
14596
|
init_lineage();
|
|
14597
|
+
init_agentWake();
|
|
14214
14598
|
SUBAGENT_DENYLIST = /* @__PURE__ */ new Set(["run_command", "delete_path", "run_in_background"]);
|
|
14215
14599
|
filterToolsForSubagent = (allTools, manifest) => {
|
|
14216
14600
|
if (manifest && manifest.tools.length > 0) {
|
|
@@ -14245,57 +14629,33 @@ var init_subagent = __esm({
|
|
|
14245
14629
|
}
|
|
14246
14630
|
};
|
|
14247
14631
|
};
|
|
14248
|
-
|
|
14632
|
+
prepareSubagent = async (spec, ctx, getGlobalTools) => {
|
|
14249
14633
|
const { task, name, role, resumeSessionId } = spec;
|
|
14250
14634
|
const resuming = typeof resumeSessionId === "string" && resumeSessionId.length > 0;
|
|
14251
14635
|
if (ctx.depth >= MAX_AGENT_DEPTH) {
|
|
14252
|
-
return {
|
|
14253
|
-
ok: false,
|
|
14254
|
-
output: failText(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u5DF2\u8FBE\u5230\u6700\u5927 Agent \u5D4C\u5957\u6DF1\u5EA6\uFF08${MAX_AGENT_DEPTH}\u5C42\uFF09\u3002\u7981\u6B62\u7EE7\u7EED\u65E0\u9650\u5411\u4E0B\u5D4C\u5957\uFF0C\u8BF7\u7236\u5C42\u7EA7 Agent \u81EA\u884C\u6D88\u5316\u5F53\u524D\u4EFB\u52A1\u3002`),
|
|
14255
|
-
sessionId: ""
|
|
14256
|
-
};
|
|
14636
|
+
return { ok: false, error: failText(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u5DF2\u8FBE\u5230\u6700\u5927 Agent \u5D4C\u5957\u6DF1\u5EA6\uFF08${MAX_AGENT_DEPTH}\u5C42\uFF09\u3002\u7981\u6B62\u7EE7\u7EED\u65E0\u9650\u5411\u4E0B\u5D4C\u5957\uFF0C\u8BF7\u7236\u5C42\u7EA7 Agent \u81EA\u884C\u6D88\u5316\u5F53\u524D\u4EFB\u52A1\u3002`) };
|
|
14257
14637
|
}
|
|
14258
14638
|
if (resuming) {
|
|
14259
14639
|
const target = resumeSessionId;
|
|
14260
14640
|
if (!target.includes("__sub__")) {
|
|
14261
|
-
return {
|
|
14262
|
-
ok: false,
|
|
14263
|
-
output: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A${target} \u4E0D\u662F\u5B50 Agent \u4F1A\u8BDD ID\uFF08\u5E94\u5F62\u5982 <\u4F1A\u8BDD>__sub__<uuid>\uFF0C\u6765\u81EA\u6B64\u524D spawn_agent \u8FD4\u56DE\u7684 agent_id\uFF09\u3002`),
|
|
14264
|
-
sessionId: ""
|
|
14265
|
-
};
|
|
14641
|
+
return { ok: false, error: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A${target} \u4E0D\u662F\u5B50 Agent \u4F1A\u8BDD ID\uFF08\u5E94\u5F62\u5982 <\u4F1A\u8BDD>__sub__<uuid>\uFF0C\u6765\u81EA\u6B64\u524D spawn_agent \u8FD4\u56DE\u7684 agent_id\uFF09\u3002`) };
|
|
14266
14642
|
}
|
|
14267
14643
|
if (!ownerCanApprove(target, ctx.sessionId)) {
|
|
14268
|
-
return {
|
|
14269
|
-
ok: false,
|
|
14270
|
-
output: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50\u4F1A\u8BDD ${target} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u4F1A\u8BDD\uFF08\u53CA\u5176 fork \u8840\u7F18\uFF09\uFF0C\u7981\u6B62\u8DE8\u4F1A\u8BDD\u590D\u6D3B\u3002\u8BF7\u6838\u5BF9 agent_id \u6216\u6539\u7528\u65B0\u5EFA\u6D3E\u751F\u3002`),
|
|
14271
|
-
sessionId: ""
|
|
14272
|
-
};
|
|
14644
|
+
return { ok: false, error: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50\u4F1A\u8BDD ${target} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u4F1A\u8BDD\uFF08\u53CA\u5176 fork \u8840\u7F18\uFF09\uFF0C\u7981\u6B62\u8DE8\u4F1A\u8BDD\u590D\u6D3B\u3002\u8BF7\u6838\u5BF9 agent_id \u6216\u6539\u7528\u65B0\u5EFA\u6D3E\u751F\u3002`) };
|
|
14273
14645
|
}
|
|
14274
14646
|
if (activeSubagents.has(target)) {
|
|
14275
|
-
return {
|
|
14276
|
-
ok: false,
|
|
14277
|
-
output: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50 Agent ${target} \u6B63\u5728\u6267\u884C\u4E2D\uFF0C\u7981\u6B62\u5E76\u53D1\u7EED\u8DD1\u540C\u4E00\u5B50\u4F1A\u8BDD\uFF08\u4F1A\u4EA4\u53C9\u5199\u574F\u8F6C\u5F55\uFF09\u3002\u8BF7\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u8BD5\u3002`),
|
|
14278
|
-
sessionId: ""
|
|
14279
|
-
};
|
|
14647
|
+
return { ok: false, error: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50 Agent ${target} \u6B63\u5728\u6267\u884C\u4E2D\uFF0C\u7981\u6B62\u5E76\u53D1\u7EED\u8DD1\u540C\u4E00\u5B50\u4F1A\u8BDD\uFF08\u4F1A\u4EA4\u53C9\u5199\u574F\u8F6C\u5F55\uFF09\u3002\u8BF7\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u8BD5\u3002`) };
|
|
14280
14648
|
}
|
|
14281
14649
|
const existing = await readTranscriptLines(target);
|
|
14282
14650
|
if (existing.length === 0) {
|
|
14283
|
-
return {
|
|
14284
|
-
ok: false,
|
|
14285
|
-
output: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50\u4F1A\u8BDD ${target} \u7684\u8F6C\u5F55\u4E0D\u5B58\u5728\u6216\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u7EED\u8DD1\u3002\u8BF7\u6539\u7528\u65B0\u5EFA\u6D3E\u751F\u3002`),
|
|
14286
|
-
sessionId: ""
|
|
14287
|
-
};
|
|
14651
|
+
return { ok: false, error: failText(`[\u7EED\u8DD1\u5931\u8D25]\uFF1A\u5B50\u4F1A\u8BDD ${target} \u7684\u8F6C\u5F55\u4E0D\u5B58\u5728\u6216\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u7EED\u8DD1\u3002\u8BF7\u6539\u7528\u65B0\u5EFA\u6D3E\u751F\u3002`) };
|
|
14288
14652
|
}
|
|
14289
14653
|
}
|
|
14290
14654
|
const subSessionId = resuming ? resumeSessionId : `${ctx.sessionId}__sub__${createUUID()}`;
|
|
14291
14655
|
const parentSystemPrompt = ctx.parentSystemPrompt || "";
|
|
14292
14656
|
const manifest = name ? getAgent(name) : void 0;
|
|
14293
14657
|
if (name && !manifest) {
|
|
14294
|
-
return {
|
|
14295
|
-
ok: false,
|
|
14296
|
-
output: failText(`[\u6D3E\u751F\u5931\u8D25]\uFF1A\u672A\u627E\u5230\u58F0\u660E\u5F0F\u5B50 Agent "${name}"\u3002\u8BF7\u6838\u5BF9\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\u7684\u540D\u79F0\u62FC\u5199\u3002`),
|
|
14297
|
-
sessionId: ""
|
|
14298
|
-
};
|
|
14658
|
+
return { ok: false, error: failText(`[\u6D3E\u751F\u5931\u8D25]\uFF1A\u672A\u627E\u5230\u58F0\u660E\u5F0F\u5B50 Agent "${name}"\u3002\u8BF7\u6838\u5BF9\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u3010\u53EF\u7528\u5B50 Agent \u76EE\u5F55\u3011\u7684\u540D\u79F0\u62FC\u5199\u3002`) };
|
|
14299
14659
|
}
|
|
14300
14660
|
const SUBAGENT_REPORT_REQ = `\u3010\u6C47\u62A5\u8981\u6C42\u3011\u6700\u7EC8\u6C47\u62A5\u63A7\u5236\u5728\u4E00\u5C4F\u5185\uFF1A\u5DF2\u5B8C\u6210/\u6539\u52A8\u70B9\uFF08\u6587\u4EF6\u8DEF\u5F84\uFF09/\u9A8C\u8BC1\u7ED3\u679C/\u672A\u5B8C\u6210\u9879\u3002\u4E0D\u8981\u590D\u8FF0\u8FC7\u7A0B\u4E0E\u5DE5\u5177\u8F93\u51FA\u2014\u2014\u7236\u7EA7\u53EF\u76F4\u63A5\u7ECF resume \u8FFD\u95EE\u7EC6\u8282\u3002`;
|
|
14301
14661
|
const subSystem = manifest ? [
|
|
@@ -14327,8 +14687,15 @@ var init_subagent = __esm({
|
|
|
14327
14687
|
const allTools = getGlobalTools();
|
|
14328
14688
|
const toolSchemas = filterToolsForSubagent(allTools, manifest);
|
|
14329
14689
|
console.log(`${resuming ? "\u{1F501} \u7EED\u8DD1" : "\u{1F423} \u6D3E\u751F"}\u5B50 Agent [\u6DF1\u5EA6: ${ctx.depth + 1}/${MAX_AGENT_DEPTH}][${subSessionId}]${manifest ? ` \u58F0\u660E\u5F0F=${manifest.name}` : ""} \u4EFB\u52A1: "${task.slice(0, 50)}..."`);
|
|
14690
|
+
const startCtx = { sessionId: subSessionId, parentSessionId: ctx.sessionId, task, depth: ctx.depth + 1, name: manifest?.name, cwd: ctx.cwd };
|
|
14691
|
+
return { ok: true, prepared: { subSessionId, resuming, manifest, subSystem, subTaskPrompt, toolSchemas, startCtx, taskBrief: task.slice(0, 60) } };
|
|
14692
|
+
};
|
|
14693
|
+
runPreparedSubagent = async (prepared, ctx, opts) => {
|
|
14694
|
+
const { subSessionId, manifest, subTaskPrompt, subSystem, toolSchemas, startCtx } = prepared;
|
|
14695
|
+
const manifestName = manifest?.name;
|
|
14330
14696
|
activeSubagents.add(subSessionId);
|
|
14331
|
-
ctx.
|
|
14697
|
+
trackSubagentInFlight(ctx.sessionId, subSessionId);
|
|
14698
|
+
ctx.onUIEvent?.({ type: "subagent.count", running: activeSubagents.size, phase: "start", name: manifest?.name, depth: startCtx.depth });
|
|
14332
14699
|
try {
|
|
14333
14700
|
const subMessages = await buildContextMessages(subSessionId, { role: "user", content: subTaskPrompt }, subSystem, manifest?.model);
|
|
14334
14701
|
await appendMessage({ sessionId: subSessionId, role: "user", content: subTaskPrompt });
|
|
@@ -14346,7 +14713,7 @@ var init_subagent = __esm({
|
|
|
14346
14713
|
depth: ctx.depth + 1,
|
|
14347
14714
|
keepRecentUnits: ctx.keepRecentUnits,
|
|
14348
14715
|
compactRatio: ctx.compactRatio,
|
|
14349
|
-
parentSystemPrompt,
|
|
14716
|
+
parentSystemPrompt: ctx.parentSystemPrompt,
|
|
14350
14717
|
events: ctx.events,
|
|
14351
14718
|
onUIEvent: ctx.onUIEvent,
|
|
14352
14719
|
// ★ 必须透传:否则子 agent 调用需审批工具时前端收不到弹窗,waitForUserApproval 永久挂起(死锁)
|
|
@@ -14365,14 +14732,13 @@ var init_subagent = __esm({
|
|
|
14365
14732
|
budgetCheck: ctx.budgetCheck
|
|
14366
14733
|
// ★ P1-5 预算熔断链式透传:子 runAgent 轮边界探测父预算,超支即收尾(不等烧完)
|
|
14367
14734
|
};
|
|
14368
|
-
const startCtx = { sessionId: subSessionId, parentSessionId: ctx.sessionId, task, depth: ctx.depth + 1, name: manifest?.name, cwd: ctx.cwd };
|
|
14369
14735
|
await dispatch("SubagentStart", startCtx);
|
|
14370
14736
|
let result;
|
|
14371
14737
|
const progress = createProgressThrottler((line) => ctx.onUIEvent?.({ type: "subagent.progress", text: line, agentKey: subSessionId, name: manifest?.name }));
|
|
14372
14738
|
try {
|
|
14373
14739
|
for await (const e of runAgent(subMessages, subOptions)) {
|
|
14374
14740
|
if (ctx.abortSignal?.aborted) {
|
|
14375
|
-
result = { ok: false, output: failText(`[\u5B50Agent\u4E2D\u65AD]\uFF1A\u6267\u884C\u5DF2\u88AB\u7528\u6237\u4E3B\u52A8\u53D1\u8D77\u7684 AbortSignal \u5F3A\u884C\u7194\u65AD\u3002`), sessionId: subSessionId, manifestName: manifest?.name };
|
|
14741
|
+
result = { ok: false, output: failText(`[\u5B50Agent\u4E2D\u65AD]\uFF1A\u6267\u884C\u5DF2\u88AB\u7528\u6237\u4E3B\u52A8\u53D1\u8D77\u7684 AbortSignal \u5F3A\u884C\u7194\u65AD\u3002`), sessionId: subSessionId, manifestName: manifest?.name, status: "aborted" };
|
|
14376
14742
|
break;
|
|
14377
14743
|
}
|
|
14378
14744
|
if (e.type === "final") {
|
|
@@ -14386,10 +14752,10 @@ var init_subagent = __esm({
|
|
|
14386
14752
|
if (!hasFinalResult || !subResult.trim()) {
|
|
14387
14753
|
subResult = `\uFF08\u672A\u80FD\u83B7\u53D6\u5230\u7ED3\u6784\u5316 final \u56DE\u62A5\u3002\u8BF7\u68C0\u67E5\u8BE5\u5B50 Session [${subSessionId}] \u7684\u6267\u884C\u5386\u53F2\uFF09`;
|
|
14388
14754
|
}
|
|
14389
|
-
result = { ok: true, output: subResult, sessionId: subSessionId, manifestName: manifest?.name };
|
|
14755
|
+
result = { ok: true, output: subResult, sessionId: subSessionId, manifestName: manifest?.name, status: "final" };
|
|
14390
14756
|
}
|
|
14391
14757
|
} catch (streamError) {
|
|
14392
|
-
result = { ok: false, output: failText(`[\u5B50Agent\u5D29\u6E83]\uFF1A\u5B50 Agent \u5728\u8FED\u4EE3\u63A8\u7406\u4E3B\u5FAA\u73AF\u65F6\u906D\u9047\u5E95\u5C42\u5F02\u5E38: ${streamError.message}`), sessionId: subSessionId, manifestName: manifest?.name };
|
|
14758
|
+
result = { ok: false, output: failText(`[\u5B50Agent\u5D29\u6E83]\uFF1A\u5B50 Agent \u5728\u8FED\u4EE3\u63A8\u7406\u4E3B\u5FAA\u73AF\u65F6\u906D\u9047\u5E95\u5C42\u5F02\u5E38: ${streamError.message}`), sessionId: subSessionId, manifestName: manifest?.name, status: "error" };
|
|
14393
14759
|
} finally {
|
|
14394
14760
|
try {
|
|
14395
14761
|
ctx.onUIEvent?.({ type: "subagent.progress", text: "", done: true, agentKey: subSessionId });
|
|
@@ -14399,13 +14765,27 @@ var init_subagent = __esm({
|
|
|
14399
14765
|
await dispatch("SubagentStop", { ...startCtx, ok: result.ok, output: result.output.slice(0, 2e3) }).catch((e) => console.warn(`\u26A0\uFE0F SubagentStop hook \u5F02\u5E38\uFF08\u5DF2\u5FFD\u7565\uFF09: ${e?.message ?? e}`));
|
|
14400
14766
|
}
|
|
14401
14767
|
}
|
|
14402
|
-
|
|
14768
|
+
if (opts?.notifyDone && result && result.status !== "aborted") {
|
|
14769
|
+
try {
|
|
14770
|
+
await notifySubagentDone(ctx.sessionId, buildSubagentDoneReport(subSessionId, prepared.taskBrief, { status: result.status, output: result.output }));
|
|
14771
|
+
} catch {
|
|
14772
|
+
}
|
|
14773
|
+
}
|
|
14774
|
+
return result ?? { ok: false, output: failText(`[\u6D3E\u751F\u6267\u884C\u5931\u8D25]: \u672A\u77E5\u9519\u8BEF`), sessionId: subSessionId, manifestName: manifest?.name, status: "error" };
|
|
14403
14775
|
} catch (error) {
|
|
14404
|
-
return { ok: false, output: failText(`[\u6D3E\u751F\u6267\u884C\u5931\u8D25]: ${error.message}`), sessionId: subSessionId, manifestName: manifest?.name };
|
|
14776
|
+
return { ok: false, output: failText(`[\u6D3E\u751F\u6267\u884C\u5931\u8D25]: ${error.message}`), sessionId: subSessionId, manifestName: manifest?.name, status: "error" };
|
|
14405
14777
|
} finally {
|
|
14406
14778
|
activeSubagents.delete(subSessionId);
|
|
14407
|
-
ctx.
|
|
14779
|
+
releaseSubagentInFlight(ctx.sessionId, subSessionId);
|
|
14780
|
+
ctx.onUIEvent?.({ type: "subagent.count", running: activeSubagents.size, phase: "stop", name: manifestName, depth: startCtx.depth });
|
|
14781
|
+
}
|
|
14782
|
+
};
|
|
14783
|
+
runSubagent = async (spec, ctx, getGlobalTools) => {
|
|
14784
|
+
const prep = await prepareSubagent(spec, ctx, getGlobalTools);
|
|
14785
|
+
if (!prep.ok) {
|
|
14786
|
+
return { ok: false, output: prep.error, sessionId: "", status: "error" };
|
|
14408
14787
|
}
|
|
14788
|
+
return runPreparedSubagent(prep.prepared, ctx);
|
|
14409
14789
|
};
|
|
14410
14790
|
}
|
|
14411
14791
|
});
|
|
@@ -15461,7 +15841,7 @@ var init_expand = __esm({
|
|
|
15461
15841
|
// ../core/src/serve/chatProcessing.ts
|
|
15462
15842
|
import path48 from "path";
|
|
15463
15843
|
import fs46 from "fs";
|
|
15464
|
-
var handleUnifiedChat;
|
|
15844
|
+
var handleUnifiedChat, handleUnifiedChatRun;
|
|
15465
15845
|
var init_chatProcessing = __esm({
|
|
15466
15846
|
"../core/src/serve/chatProcessing.ts"() {
|
|
15467
15847
|
"use strict";
|
|
@@ -15481,8 +15861,33 @@ var init_chatProcessing = __esm({
|
|
|
15481
15861
|
init_guard();
|
|
15482
15862
|
init_systemPrompt();
|
|
15483
15863
|
init_model();
|
|
15864
|
+
init_agentWake();
|
|
15484
15865
|
handleUnifiedChat = async (inbound, sendOutbound, sseWrite, abortSignal, opts) => {
|
|
15866
|
+
let busyKey = typeof inbound.sessionId === "string" && inbound.sessionId ? inbound.sessionId : "";
|
|
15867
|
+
markRunStart(busyKey);
|
|
15868
|
+
try {
|
|
15869
|
+
await handleUnifiedChatRun(inbound, sendOutbound, sseWrite, abortSignal, opts, (resolved) => {
|
|
15870
|
+
if (busyKey === resolved) return;
|
|
15871
|
+
markRunStart(resolved);
|
|
15872
|
+
if (busyKey) markRunEnd(busyKey);
|
|
15873
|
+
busyKey = resolved;
|
|
15874
|
+
});
|
|
15875
|
+
} finally {
|
|
15876
|
+
markRunEnd(busyKey);
|
|
15877
|
+
}
|
|
15878
|
+
};
|
|
15879
|
+
handleUnifiedChatRun = async (inbound, sendOutbound, sseWrite, abortSignal, opts, transferBusy) => {
|
|
15485
15880
|
const sessionId = await getOrCreateSessionId(inbound.sessionId);
|
|
15881
|
+
transferBusy?.(sessionId);
|
|
15882
|
+
registerWakeDriverIfAbsent(sessionId, async () => {
|
|
15883
|
+
await handleUnifiedChat(
|
|
15884
|
+
{ ...inbound, sessionId, content: AGENT_DONE_SENTINEL, attachments: void 0 },
|
|
15885
|
+
sendOutbound,
|
|
15886
|
+
sseWrite,
|
|
15887
|
+
abortSignal,
|
|
15888
|
+
opts
|
|
15889
|
+
);
|
|
15890
|
+
});
|
|
15486
15891
|
try {
|
|
15487
15892
|
inbound.content = expandSlashCommand(inbound.content);
|
|
15488
15893
|
} catch {
|
|
@@ -16162,6 +16567,7 @@ var init_useChatState = __esm({
|
|
|
16162
16567
|
init_transcript();
|
|
16163
16568
|
init_fork();
|
|
16164
16569
|
init_inbox();
|
|
16570
|
+
init_agentWake();
|
|
16165
16571
|
init_contextCore();
|
|
16166
16572
|
init_bashDirect();
|
|
16167
16573
|
init_guard();
|
|
@@ -16632,6 +17038,17 @@ var init_useChatState = __esm({
|
|
|
16632
17038
|
budgetYuan: budgetYuanRef.current
|
|
16633
17039
|
// ★ 预算制运行(成本信任链第二环 E1):/budget 设置,超限 soft nudge + 120% 硬截断
|
|
16634
17040
|
};
|
|
17041
|
+
registerWakeDriver(sid, async () => {
|
|
17042
|
+
if (sessionIdRef.current !== sid) return;
|
|
17043
|
+
const myGen = ++turnGenRef.current;
|
|
17044
|
+
setBusy(true);
|
|
17045
|
+
pushInfo("\u{1F916} \u5B50\u4EE3\u7406\u5B8C\u6210\uFF0C\u81EA\u52A8\u5524\u9192\u4E3B\u4F1A\u8BDD\u7EE7\u7EED\u2026");
|
|
17046
|
+
try {
|
|
17047
|
+
await runOnce(sid, AGENT_DONE_SENTINEL, false);
|
|
17048
|
+
} finally {
|
|
17049
|
+
if (turnGenRef.current === myGen) setBusy(false);
|
|
17050
|
+
}
|
|
17051
|
+
});
|
|
16635
17052
|
try {
|
|
16636
17053
|
await handleUnifiedChat(
|
|
16637
17054
|
{ sessionId: sid, content: body },
|
|
@@ -19164,15 +19581,595 @@ ${listText}`);
|
|
|
19164
19581
|
}
|
|
19165
19582
|
});
|
|
19166
19583
|
|
|
19584
|
+
// ../core/src/agent/stallDetector.ts
|
|
19585
|
+
import { execFile as execFile2 } from "child_process";
|
|
19586
|
+
var CHECK_INTERVAL_SEC, GRACE_MIN, R1_WINDOW_MIN, R1_MIN_HITS, R2_WINDOW_MIN, R2_MIN_CALLS, R2_MAX_DISTINCT_SIG, R3_SILENCE_MIN, R4_WINDOW_MIN, R4_COST_DIVISOR, R6_STALL_BAND, HEALTH_GROWTH_LINES, SERIES_CAP, LOCKFILE_RE, EDIT_TOOLS, READONLY_TOOLS, normPath2, samePath, sortKeysDeep, argsKeyOf, similarSigOf, editTargetOf, extractTargetPaths, parseNumstatNet, MIN, StallDetector;
|
|
19587
|
+
var init_stallDetector = __esm({
|
|
19588
|
+
"../core/src/agent/stallDetector.ts"() {
|
|
19589
|
+
"use strict";
|
|
19590
|
+
CHECK_INTERVAL_SEC = 60;
|
|
19591
|
+
GRACE_MIN = 5;
|
|
19592
|
+
R1_WINDOW_MIN = 10;
|
|
19593
|
+
R1_MIN_HITS = 3;
|
|
19594
|
+
R2_WINDOW_MIN = 15;
|
|
19595
|
+
R2_MIN_CALLS = 3;
|
|
19596
|
+
R2_MAX_DISTINCT_SIG = 2;
|
|
19597
|
+
R3_SILENCE_MIN = 5;
|
|
19598
|
+
R4_WINDOW_MIN = 5;
|
|
19599
|
+
R4_COST_DIVISOR = 4;
|
|
19600
|
+
R6_STALL_BAND = 3;
|
|
19601
|
+
HEALTH_GROWTH_LINES = 20;
|
|
19602
|
+
SERIES_CAP = 64;
|
|
19603
|
+
LOCKFILE_RE = /(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb|bun\.lock|composer\.lock|poetry\.lock|Cargo\.lock|go\.sum)$/i;
|
|
19604
|
+
EDIT_TOOLS = /* @__PURE__ */ new Set(["edit_file", "create_file", "write_file", "move_file", "notebook_edit"]);
|
|
19605
|
+
READONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
19606
|
+
"read_file",
|
|
19607
|
+
"list_dir",
|
|
19608
|
+
"glob",
|
|
19609
|
+
"search_grep",
|
|
19610
|
+
"read_image",
|
|
19611
|
+
"read_docx",
|
|
19612
|
+
"read_xlsx",
|
|
19613
|
+
"read_project_guide",
|
|
19614
|
+
"recall",
|
|
19615
|
+
"get_git_diff",
|
|
19616
|
+
"git_status",
|
|
19617
|
+
"git_log",
|
|
19618
|
+
"find_references",
|
|
19619
|
+
"get_diagnostics",
|
|
19620
|
+
"goto_definition",
|
|
19621
|
+
"view_symbol_outline",
|
|
19622
|
+
"web_search",
|
|
19623
|
+
"web_fetch"
|
|
19624
|
+
]);
|
|
19625
|
+
normPath2 = (p) => p.trim().replace(/\\/g, "/").replace(/^[A-Za-z]:/, "").replace(/^\.\/+/, "").replace(/\/+$/, "").toLowerCase();
|
|
19626
|
+
samePath = (a, b) => a === b || a.endsWith("/" + b) || b.endsWith("/" + a);
|
|
19627
|
+
sortKeysDeep = (v) => {
|
|
19628
|
+
if (Array.isArray(v)) return v.map(sortKeysDeep);
|
|
19629
|
+
if (v && typeof v === "object") {
|
|
19630
|
+
const out = {};
|
|
19631
|
+
for (const k of Object.keys(v).sort()) out[k] = sortKeysDeep(v[k]);
|
|
19632
|
+
return out;
|
|
19633
|
+
}
|
|
19634
|
+
return v;
|
|
19635
|
+
};
|
|
19636
|
+
argsKeyOf = (args) => {
|
|
19637
|
+
try {
|
|
19638
|
+
return JSON.stringify(sortKeysDeep(args ?? {})).slice(0, 200);
|
|
19639
|
+
} catch {
|
|
19640
|
+
return String(args);
|
|
19641
|
+
}
|
|
19642
|
+
};
|
|
19643
|
+
similarSigOf = (args) => {
|
|
19644
|
+
let s;
|
|
19645
|
+
try {
|
|
19646
|
+
s = JSON.stringify(sortKeysDeep(args ?? {}));
|
|
19647
|
+
} catch {
|
|
19648
|
+
return String(args);
|
|
19649
|
+
}
|
|
19650
|
+
return s.replace(/\d+/g, "").replace(/\/[^/"]+(?=")/, "");
|
|
19651
|
+
};
|
|
19652
|
+
editTargetOf = (args) => normPath2(String(args?.path ?? args?.source ?? args?.destination ?? args?.file_path ?? ""));
|
|
19653
|
+
extractTargetPaths = (text) => {
|
|
19654
|
+
const out = /* @__PURE__ */ new Set();
|
|
19655
|
+
for (const m of text.match(/(?:[A-Za-z]:)?[\w.\-一-鿿]+(?:[/\\][\w.\-一-鿿]+)+\.[A-Za-z0-9]{1,6}/g) ?? []) {
|
|
19656
|
+
out.add(normPath2(m));
|
|
19657
|
+
}
|
|
19658
|
+
return out;
|
|
19659
|
+
};
|
|
19660
|
+
parseNumstatNet = (stdout) => {
|
|
19661
|
+
let net = 0;
|
|
19662
|
+
for (const line of stdout.split("\n")) {
|
|
19663
|
+
const m = /^(\d+|-)\t(\d+|-)\t(.+)$/.exec(line.trim());
|
|
19664
|
+
if (!m) continue;
|
|
19665
|
+
if (LOCKFILE_RE.test(m[3])) continue;
|
|
19666
|
+
net += (m[1] === "-" ? 0 : parseInt(m[1], 10)) + (m[2] === "-" ? 0 : parseInt(m[2], 10));
|
|
19667
|
+
}
|
|
19668
|
+
return net;
|
|
19669
|
+
};
|
|
19670
|
+
MIN = 6e4;
|
|
19671
|
+
StallDetector = class {
|
|
19672
|
+
constructor(opts) {
|
|
19673
|
+
this.stopFn = null;
|
|
19674
|
+
this.started = false;
|
|
19675
|
+
this.stopped = false;
|
|
19676
|
+
this.paused = false;
|
|
19677
|
+
this.ticking = false;
|
|
19678
|
+
/** 宽限期基准(豁免解除时重置——豁免期不该吃掉 agent 的起步宽限)。字段名与同名 getter 刻意区分
|
|
19679
|
+
* (tsconfig 为 set 语义,私有字段与只读 getter 同名会在字段初始化时炸 "only a getter")。 */
|
|
19680
|
+
this.activeAt = 0;
|
|
19681
|
+
this.lastEventAt = 0;
|
|
19682
|
+
/** 抑制窗截止(政策层经 setSuppressUntil 设置:batch=nudge 后宽限;影子=强命中去重)。 */
|
|
19683
|
+
this.suppressUntil = 0;
|
|
19684
|
+
this.roundNo = 0;
|
|
19685
|
+
this.calls = [];
|
|
19686
|
+
this.finalSeen = false;
|
|
19687
|
+
/** R6 净变更行数时间序列(batch 基线 = setup 完成后首读;交互 run 首 tick 采样即基线)。 */
|
|
19688
|
+
this.series = [];
|
|
19689
|
+
/** R4 成本采样序列。 */
|
|
19690
|
+
this.costSeries = [];
|
|
19691
|
+
this.opts = opts;
|
|
19692
|
+
this.now = opts.now ?? Date.now;
|
|
19693
|
+
this.intervalMs = opts.intervalMs ?? CHECK_INTERVAL_SEC * 1e3;
|
|
19694
|
+
this.targetPaths = extractTargetPaths(opts.targetText ?? "");
|
|
19695
|
+
this.lastEventAt = this.now();
|
|
19696
|
+
}
|
|
19697
|
+
/** 启动旁观者心跳。判定在解除暂停前不会真正开始(batch setup 执行期挂 PAUSED)。 */
|
|
19698
|
+
start() {
|
|
19699
|
+
if (this.started || this.stopped) return;
|
|
19700
|
+
this.started = true;
|
|
19701
|
+
this.activeAt = this.now();
|
|
19702
|
+
const schedule = this.opts.schedule ?? ((fn, ms) => {
|
|
19703
|
+
const h = setInterval(fn, ms);
|
|
19704
|
+
h.unref?.();
|
|
19705
|
+
return () => clearInterval(h);
|
|
19706
|
+
});
|
|
19707
|
+
this.stopFn = schedule(() => void this.tick(), this.intervalMs);
|
|
19708
|
+
}
|
|
19709
|
+
stop() {
|
|
19710
|
+
this.stopped = true;
|
|
19711
|
+
this.stopFn?.();
|
|
19712
|
+
this.stopFn = null;
|
|
19713
|
+
}
|
|
19714
|
+
/** 暂停判定(batch setup/accept 执行期;交互审批/提问挂起期);解除时对齐事件时钟并重置起步宽限。 */
|
|
19715
|
+
setPaused(p) {
|
|
19716
|
+
if (p === this.paused || this.stopped) return;
|
|
19717
|
+
this.paused = p;
|
|
19718
|
+
if (!p) {
|
|
19719
|
+
const t = this.now();
|
|
19720
|
+
this.lastEventAt = Math.max(this.lastEventAt, t);
|
|
19721
|
+
this.activeAt = t;
|
|
19722
|
+
}
|
|
19723
|
+
}
|
|
19724
|
+
/** 抑制窗(政策层动作语义映射:batch nudge 后宽限 / 影子强命中 5 分钟去重)。 */
|
|
19725
|
+
setSuppressUntil(t) {
|
|
19726
|
+
this.suppressUntil = t;
|
|
19727
|
+
}
|
|
19728
|
+
/** R6 基线:batch 在 setup 完成后取首个读数(装依赖动 lockfile,故基线后置 + 排除 lockfile)。 */
|
|
19729
|
+
async markBaseline() {
|
|
19730
|
+
const s = await this.sampleDiffSafe();
|
|
19731
|
+
this.series = s ? [{ ...s, t: this.now() }] : [];
|
|
19732
|
+
}
|
|
19733
|
+
/**
|
|
19734
|
+
* 事件喂入口:tool.start/tool.end/round.start/text.delta/thinking.delta/final 全喂。
|
|
19735
|
+
* 任何事件都刷新 lastEventAt(R3 断流的对面);豁免期不喂不计时(resume 时对齐)。
|
|
19736
|
+
* 白名单外的事件类型静默忽略(VSCode sink 混流 UIEvent,挂起交互事件天然无害)。
|
|
19737
|
+
*/
|
|
19738
|
+
feed(evt) {
|
|
19739
|
+
if (this.stopped || this.paused || !evt?.type) return;
|
|
19740
|
+
const t = this.now();
|
|
19741
|
+
this.lastEventAt = t;
|
|
19742
|
+
if (evt.type === "round.start") {
|
|
19743
|
+
this.roundNo = Number(evt.round) || this.roundNo;
|
|
19744
|
+
return;
|
|
19745
|
+
}
|
|
19746
|
+
if (evt.type === "final") {
|
|
19747
|
+
this.finalSeen = true;
|
|
19748
|
+
return;
|
|
19749
|
+
}
|
|
19750
|
+
if (evt.type === "tool.start") {
|
|
19751
|
+
const toolName = String(evt.toolName ?? "");
|
|
19752
|
+
const args = evt.args ?? {};
|
|
19753
|
+
let digest = "";
|
|
19754
|
+
try {
|
|
19755
|
+
digest = JSON.stringify(args);
|
|
19756
|
+
} catch {
|
|
19757
|
+
digest = String(args);
|
|
19758
|
+
}
|
|
19759
|
+
this.calls.push({
|
|
19760
|
+
toolCallId: String(evt.toolCallId ?? ""),
|
|
19761
|
+
toolName,
|
|
19762
|
+
argsKey: argsKeyOf(args),
|
|
19763
|
+
sig: similarSigOf(args),
|
|
19764
|
+
isEdit: EDIT_TOOLS.has(toolName),
|
|
19765
|
+
isReadonly: READONLY_TOOLS.has(toolName),
|
|
19766
|
+
target: editTargetOf(args),
|
|
19767
|
+
argsDigest: digest.slice(0, 120),
|
|
19768
|
+
t,
|
|
19769
|
+
round: this.roundNo
|
|
19770
|
+
});
|
|
19771
|
+
if (this.calls.length > 512) this.calls.splice(0, this.calls.length - 512);
|
|
19772
|
+
}
|
|
19773
|
+
}
|
|
19774
|
+
/** 判定一步(测试可直接驱动;生产由 scheduler 每 tick 调)。自身异常绝不外泄。 */
|
|
19775
|
+
async tick() {
|
|
19776
|
+
if (!this.started || this.stopped || this.paused || this.ticking) return;
|
|
19777
|
+
this.ticking = true;
|
|
19778
|
+
try {
|
|
19779
|
+
await this.evaluate();
|
|
19780
|
+
} catch {
|
|
19781
|
+
} finally {
|
|
19782
|
+
this.ticking = false;
|
|
19783
|
+
}
|
|
19784
|
+
}
|
|
19785
|
+
// —— 政策层访问器(拼 AUX 任务书 / 日志行用;不含动作语义) ——
|
|
19786
|
+
get round() {
|
|
19787
|
+
return this.roundNo;
|
|
19788
|
+
}
|
|
19789
|
+
get activeAtMs() {
|
|
19790
|
+
return this.activeAt;
|
|
19791
|
+
}
|
|
19792
|
+
/** 最近一次 diff 采样(影子日志 netLines 字段;无采样返回 null)。 */
|
|
19793
|
+
get lastNetSample() {
|
|
19794
|
+
return this.series.length > 0 ? this.series[this.series.length - 1] : null;
|
|
19795
|
+
}
|
|
19796
|
+
/** 成本采样(不进序列——evaluate 每 tick 的采样才进,batch costLine 的即时读数与原实现同形)。 */
|
|
19797
|
+
sampleCost() {
|
|
19798
|
+
return this.sampleCostSafe();
|
|
19799
|
+
}
|
|
19800
|
+
/** 时间窗内调用记录(batch 轨迹拼装:只读合并计数、写入逐条)。 */
|
|
19801
|
+
callsWithin(t, windowMs) {
|
|
19802
|
+
return this.calls.filter((c) => t - c.t <= windowMs);
|
|
19803
|
+
}
|
|
19804
|
+
// —— 评估主体:产出 StallEvaluation 交政策层 ——
|
|
19805
|
+
async evaluate() {
|
|
19806
|
+
const t = this.now();
|
|
19807
|
+
if (t - this.activeAt < GRACE_MIN * MIN) {
|
|
19808
|
+
await this.opts.onEvaluation({ t, skipped: "grace-start", silenceMin: null, health: null, strong: [], weak: [] });
|
|
19809
|
+
return;
|
|
19810
|
+
}
|
|
19811
|
+
if (t < this.suppressUntil) {
|
|
19812
|
+
await this.opts.onEvaluation({ t, skipped: "suppressed", silenceMin: null, health: null, strong: [], weak: [] });
|
|
19813
|
+
return;
|
|
19814
|
+
}
|
|
19815
|
+
const sample = await this.sampleDiffSafe();
|
|
19816
|
+
if (sample) {
|
|
19817
|
+
this.series.push({ ...sample, t });
|
|
19818
|
+
if (this.series.length > SERIES_CAP) this.series.splice(0, this.series.length - SERIES_CAP);
|
|
19819
|
+
}
|
|
19820
|
+
const cost = await this.sampleCostSafe();
|
|
19821
|
+
if (cost) {
|
|
19822
|
+
this.costSeries.push({ costYuan: cost.costYuan, t });
|
|
19823
|
+
if (this.costSeries.length > SERIES_CAP) this.costSeries.splice(0, this.costSeries.length - SERIES_CAP);
|
|
19824
|
+
}
|
|
19825
|
+
const silenceMs = t - this.lastEventAt;
|
|
19826
|
+
if (silenceMs >= R3_SILENCE_MIN * MIN) {
|
|
19827
|
+
await this.opts.onEvaluation({ t, skipped: null, silenceMin: silenceMs / MIN, health: null, strong: [], weak: [] });
|
|
19828
|
+
return;
|
|
19829
|
+
}
|
|
19830
|
+
const health = this.healthCheck();
|
|
19831
|
+
if (health) {
|
|
19832
|
+
await this.opts.onEvaluation({ t, skipped: null, silenceMin: null, health, strong: [], weak: [] });
|
|
19833
|
+
return;
|
|
19834
|
+
}
|
|
19835
|
+
const strong = [this.r1Check(t), this.r6Check()].filter((r) => r !== null);
|
|
19836
|
+
const weak = [this.r2Check(t), this.r4Check(t), this.r5Check(t)].filter((r) => r !== null);
|
|
19837
|
+
await this.opts.onEvaluation({ t, skipped: null, silenceMin: null, health: null, strong, weak });
|
|
19838
|
+
}
|
|
19839
|
+
// —— 规则实现 ——
|
|
19840
|
+
/** R1 重复模式:同 (tool, 规范化 args) 窗口内 ≥3 次且跨轮(轮内重复 repeatBreaker 已管)。 */
|
|
19841
|
+
r1Check(t) {
|
|
19842
|
+
const groups = /* @__PURE__ */ new Map();
|
|
19843
|
+
for (const c of this.calls) {
|
|
19844
|
+
if (t - c.t > R1_WINDOW_MIN * MIN) continue;
|
|
19845
|
+
const key = `${c.toolName} ${c.argsKey}`;
|
|
19846
|
+
const g = groups.get(key) ?? { tool: c.toolName, n: 0, rounds: /* @__PURE__ */ new Set() };
|
|
19847
|
+
g.n += 1;
|
|
19848
|
+
g.rounds.add(c.round);
|
|
19849
|
+
groups.set(key, g);
|
|
19850
|
+
}
|
|
19851
|
+
for (const g of groups.values()) {
|
|
19852
|
+
if (g.n >= R1_MIN_HITS && g.rounds.size >= 2) {
|
|
19853
|
+
return { rule: "R1", evidence: `\u8FD1 ${R1_WINDOW_MIN} \u5206\u949F ${g.tool} \u540C\u53C2\u6570\u8C03\u7528 ${g.n} \u6B21\uFF08\u8DE8 ${g.rounds.size} \u8F6E\uFF09` };
|
|
19854
|
+
}
|
|
19855
|
+
}
|
|
19856
|
+
return null;
|
|
19857
|
+
}
|
|
19858
|
+
/** R2 只读空转(弱):窗口内调用全只读且朴素规范化后变体 ≤2 种(args 持续变化=调研,防误伤)。 */
|
|
19859
|
+
r2Check(t) {
|
|
19860
|
+
const recent = this.calls.filter((c) => t - c.t <= R2_WINDOW_MIN * MIN);
|
|
19861
|
+
if (recent.length < R2_MIN_CALLS || recent.some((c) => !c.isReadonly)) return null;
|
|
19862
|
+
const sigs = new Set(recent.map((c) => c.sig));
|
|
19863
|
+
if (sigs.size > R2_MAX_DISTINCT_SIG) return null;
|
|
19864
|
+
return { rule: "R2", evidence: `\u8FD1 ${R2_WINDOW_MIN} \u5206\u949F ${recent.length} \u6B21\u8C03\u7528\u5168\u4E3A\u53EA\u8BFB\u4E14\u540C\u5F62\uFF08${sigs.size} \u79CD\u53D8\u4F53\uFF09` };
|
|
19865
|
+
}
|
|
19866
|
+
/** R4 烧钱无产出(弱):窗口成本增量 > 预算 1/4 且期间零 edit、零 final。 */
|
|
19867
|
+
r4Check(t) {
|
|
19868
|
+
if (this.opts.budgetYuan === void 0) return null;
|
|
19869
|
+
const win = this.costSeries.filter((s) => t - s.t <= R4_WINDOW_MIN * MIN);
|
|
19870
|
+
if (win.length < 2) return null;
|
|
19871
|
+
const first = win[0];
|
|
19872
|
+
const last = win[win.length - 1];
|
|
19873
|
+
if (first.costYuan == null || last.costYuan == null) return null;
|
|
19874
|
+
const delta = last.costYuan - first.costYuan;
|
|
19875
|
+
if (delta <= this.opts.budgetYuan / R4_COST_DIVISOR) return null;
|
|
19876
|
+
if (this.calls.some((c) => c.isEdit && t - c.t <= R4_WINDOW_MIN * MIN) || this.finalSeen) return null;
|
|
19877
|
+
return { rule: "R4", evidence: `\u8FD1 ${R4_WINDOW_MIN} \u5206\u949F\u82B1\u8D39 \xA5${delta.toFixed(4)}\uFF08> \u9884\u7B97 1/4\uFF09\uFF0C\u671F\u95F4\u96F6 edit \u96F6 final` };
|
|
19878
|
+
}
|
|
19879
|
+
/** R5 写入方向偏差(弱):窗口内 edit 目标与任务目标集合全无交集;提取不到目标集合 → 整条关闭。 */
|
|
19880
|
+
r5Check(t) {
|
|
19881
|
+
if (this.targetPaths.size === 0) return null;
|
|
19882
|
+
const edits = this.calls.filter((c) => c.isEdit && t - c.t <= R2_WINDOW_MIN * MIN);
|
|
19883
|
+
if (edits.length === 0) return null;
|
|
19884
|
+
const hit = edits.some((c) => c.target && [...this.targetPaths].some((p) => samePath(c.target, p)));
|
|
19885
|
+
if (hit) return null;
|
|
19886
|
+
return { rule: "R5", evidence: `\u8FD1 ${R2_WINDOW_MIN} \u5206\u949F ${edits.length} \u6B21 edit \u5168\u90E8\u843D\u5728\u4EFB\u52A1\u76EE\u6807\u8DEF\u5F84\u4E4B\u5916\uFF08\u5982 ${edits[0].target || "?"}\uFF09` };
|
|
19887
|
+
}
|
|
19888
|
+
/** R6 净进展停滞(强):连续 2 窗口净变更 ≈0(±3 行)且同期 edit 调用 >0——写了又改、没沉淀。 */
|
|
19889
|
+
r6Check() {
|
|
19890
|
+
const s = this.series;
|
|
19891
|
+
if (s.length < 3) return null;
|
|
19892
|
+
const a = s[s.length - 3];
|
|
19893
|
+
const b = s[s.length - 2];
|
|
19894
|
+
const c = s[s.length - 1];
|
|
19895
|
+
if (Math.abs(b.net - a.net) > R6_STALL_BAND || Math.abs(c.net - b.net) > R6_STALL_BAND) return null;
|
|
19896
|
+
const edits = this.calls.filter((e) => e.isEdit && e.t >= a.t).length;
|
|
19897
|
+
if (edits === 0) return null;
|
|
19898
|
+
return { rule: "R6", evidence: `\u51C0\u53D8\u66F4 ${a.net}\u2192${b.net}\u2192${c.net} \u884C\uFF08\u8FDE\u7EED 2 \u7A97\u53E3 \xB1${R6_STALL_BAND} \u5185\uFF09\u671F\u95F4 ${edits} \u6B21 edit` };
|
|
19899
|
+
}
|
|
19900
|
+
/** 健康短路:净变更显著增长或新文件出现 → 直接 normal(R2/R4 弱信号的反证)。 */
|
|
19901
|
+
healthCheck() {
|
|
19902
|
+
const s = this.series;
|
|
19903
|
+
if (s.length < 2) return null;
|
|
19904
|
+
const prev = s[s.length - 2];
|
|
19905
|
+
const last = s[s.length - 1];
|
|
19906
|
+
if (last.newFiles.length > 0) return `\u65B0\u6587\u4EF6\u51FA\u73B0\uFF1A${last.newFiles.slice(0, 3).join("\u3001")}`;
|
|
19907
|
+
const delta = last.net - prev.net;
|
|
19908
|
+
if (delta > HEALTH_GROWTH_LINES) return `\u51C0\u53D8\u66F4\u589E\u957F +${delta} \u884C\uFF08> ${HEALTH_GROWTH_LINES}\uFF09`;
|
|
19909
|
+
return null;
|
|
19910
|
+
}
|
|
19911
|
+
// —— 采样 ——
|
|
19912
|
+
async sampleDiffSafe() {
|
|
19913
|
+
if (this.opts.sampleDiff) return this.opts.sampleDiff();
|
|
19914
|
+
try {
|
|
19915
|
+
const run = (args) => new Promise((resolve, reject) => {
|
|
19916
|
+
execFile2("git", ["-C", this.opts.worktreePath, ...args], { maxBuffer: 1024 * 1024 }, (err, stdout) => err ? reject(err) : resolve(String(stdout)));
|
|
19917
|
+
});
|
|
19918
|
+
const [numstat, others] = await Promise.all([
|
|
19919
|
+
run(["diff", "--numstat", "HEAD"]),
|
|
19920
|
+
run(["ls-files", "--others", "--exclude-standard"])
|
|
19921
|
+
]);
|
|
19922
|
+
const newFiles = others.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
19923
|
+
return { net: parseNumstatNet(numstat), newFiles };
|
|
19924
|
+
} catch {
|
|
19925
|
+
return null;
|
|
19926
|
+
}
|
|
19927
|
+
}
|
|
19928
|
+
async sampleCostSafe() {
|
|
19929
|
+
if (!this.opts.getCost) return null;
|
|
19930
|
+
try {
|
|
19931
|
+
return await this.opts.getCost();
|
|
19932
|
+
} catch {
|
|
19933
|
+
return null;
|
|
19934
|
+
}
|
|
19935
|
+
}
|
|
19936
|
+
};
|
|
19937
|
+
}
|
|
19938
|
+
});
|
|
19939
|
+
|
|
19940
|
+
// src/batchWatchdog.ts
|
|
19941
|
+
var MIN2, NUDGE_GRACE_MIN, FREEZE_MIN, KILL_STRIKES, AUX_TIMEOUT_MS, RETRY_MAX, NUDGE_1, NUDGE_2, RETRY_PREAMBLE, ADJUDICATE_PROMPT, parseVerdictJson, defaultAdjudicate, sharedBudgetYuan, BatchWatchdog, buildRetryTaskContent;
|
|
19942
|
+
var init_batchWatchdog = __esm({
|
|
19943
|
+
"src/batchWatchdog.ts"() {
|
|
19944
|
+
"use strict";
|
|
19945
|
+
init_stallDetector();
|
|
19946
|
+
MIN2 = 6e4;
|
|
19947
|
+
NUDGE_GRACE_MIN = 5;
|
|
19948
|
+
FREEZE_MIN = 5;
|
|
19949
|
+
KILL_STRIKES = 3;
|
|
19950
|
+
AUX_TIMEOUT_MS = 6e4;
|
|
19951
|
+
RETRY_MAX = 3;
|
|
19952
|
+
NUDGE_1 = (evidence) => `\u26A0\uFE0F [watchdog] ${evidence}\u3002\u82E5\u5728\u539F\u5730\u6253\u8F6C\u8BF7\u6362\u601D\u8DEF\u6216\u6536\u5C3E\uFF1B\u82E5\u5224\u65AD\u6709\u8BEF\u8BF7\u7EE7\u7EED\u5E76\u8BF4\u660E\u7406\u7531\u3002`;
|
|
19953
|
+
NUDGE_2 = (clause) => `\u26D4 [watchdog] \u518D\u6B21\u5224\u5B9A\uFF1A${clause}\u3002\u8BF7\u7ACB\u5373\u505C\u6B62\u63A2\u7D22\uFF0C\u5728 2-3 \u8F6E\u5185\u6536\u5C3E\uFF1A\u603B\u7ED3\u5DF2\u5B8C\u6210 / \u672A\u5B8C\u6210 / \u5361\u70B9\u4E0E\u5EFA\u8BAE\uFF0C\u4F5C\u4E3A\u6700\u7EC8\u7B54\u590D\u3002`;
|
|
19954
|
+
RETRY_PREAMBLE = (verdict, evidence, finalDigest) => `\u3010\u7CFB\u7EDF\u63D0\u793A\u3011\u4E0A\u6B21\u5C1D\u8BD5\u88AB watchdog \u7EC8\u6B62\uFF08\u5224\u5B9A ${verdict}\uFF1A${evidence}\uFF09\u3002\u4E0A\u8F6E\u6536\u5C3E\u524D\u4EA7\u51FA\u6458\u8981\uFF1A${finalDigest || "\uFF08\u65E0\uFF09"}\u3002\u8BF7\u6362\u601D\u8DEF\uFF0C\u52FF\u91CD\u590D\u4E0A\u6B21\u8DEF\u5F84\u3002
|
|
19955
|
+
|
|
19956
|
+
---
|
|
19957
|
+
|
|
19958
|
+
`;
|
|
19959
|
+
ADJUDICATE_PROMPT = (args) => `\u4F60\u662F\u6279\u5904\u7406\u7F16\u7801\u4EFB\u52A1\u7684\u770B\u95E8\u72D7\u3002\u5224\u65AD\u4EFB\u52A1\u662F\u5426\u5728\u7A7A\u8F6C\uFF08idle\uFF1A\u53CD\u590D\u8BFB\u540C\u4E00\u6279\u6587\u4EF6/\u6362\u59FF\u52BF\u641C\u540C\u4E00\u4E1C\u897F\uFF09\u6216\u65B9\u5411\u504F\u79BB\uFF08offtrack\uFF1A\u5199\u5165\u843D\u70B9\u4E0E\u4EFB\u52A1\u76EE\u6807\u65E0\u5173\uFF09\uFF1B\u6B63\u5E38\u63A8\u8FDB\uFF08\u542B\u6B63\u5F53\u7684\u957F\u65F6\u95F4\u53EA\u8BFB\u8C03\u7814\uFF09\u5224 normal\u3002\u53EA\u8F93\u51FA\u4E25\u683C JSON\uFF1A{"verdict":"normal|idle|offtrack","evidence":"\u4E00\u53E5\u8BDD\u8BC1\u636E\uFF08\u5F15\u7528\u8F68\u8FF9\u4E2D\u7684\u5177\u4F53\u4E8B\u4EF6\uFF09"}
|
|
19960
|
+
|
|
19961
|
+
[\u4EFB\u52A1\u76EE\u6807] ${args.title}
|
|
19962
|
+
\u9A8C\u6536\u547D\u4EE4\uFF1A${args.accept}
|
|
19963
|
+
[\u6D88\u8017] ${args.costLine}
|
|
19964
|
+
[\u89C4\u5219\u4FE1\u53F7]
|
|
19965
|
+
${args.rules}
|
|
19966
|
+
[\u6700\u8FD1\u8F68\u8FF9\uFF0810 \u5206\u949F\uFF09]
|
|
19967
|
+
${args.trajectory}`;
|
|
19968
|
+
parseVerdictJson = (raw) => {
|
|
19969
|
+
const m = /\{[\s\S]*\}/.exec(raw ?? "");
|
|
19970
|
+
if (!m) return null;
|
|
19971
|
+
try {
|
|
19972
|
+
const j = JSON.parse(m[0]);
|
|
19973
|
+
const v = String(j?.verdict ?? "").trim().toLowerCase();
|
|
19974
|
+
if (v !== "normal" && v !== "idle" && v !== "offtrack") return null;
|
|
19975
|
+
return { verdict: v, evidence: String(j?.evidence ?? "").trim() };
|
|
19976
|
+
} catch {
|
|
19977
|
+
return null;
|
|
19978
|
+
}
|
|
19979
|
+
};
|
|
19980
|
+
defaultAdjudicate = async (prompt, signal) => {
|
|
19981
|
+
const { chatWithModelWithSummary: chatWithModelWithSummary2 } = await Promise.resolve().then(() => (init_model(), model_exports));
|
|
19982
|
+
const resp = await chatWithModelWithSummary2([{ role: "user", content: prompt }], [], { signal });
|
|
19983
|
+
return resp?.choices?.[0]?.message?.content ?? "";
|
|
19984
|
+
};
|
|
19985
|
+
sharedBudgetYuan = (budgetYuan, spentYuan) => {
|
|
19986
|
+
if (budgetYuan === void 0) return void 0;
|
|
19987
|
+
return Math.max(0, Math.round((budgetYuan - (spentYuan ?? 0)) * 1e4) / 1e4);
|
|
19988
|
+
};
|
|
19989
|
+
BatchWatchdog = class {
|
|
19990
|
+
constructor(opts) {
|
|
19991
|
+
/** 连续非 normal 计数(normal 裁决/健康短路清零)。 */
|
|
19992
|
+
this.streak = 0;
|
|
19993
|
+
/** 收尾冻结窗口截止(nudge-2 后 FREEZE_MIN 分钟内动作冻结——采样/R3 照常,二层不调)。 */
|
|
19994
|
+
this.freezeUntil = 0;
|
|
19995
|
+
this.records = [];
|
|
19996
|
+
this.killInfo = null;
|
|
19997
|
+
this.opts = opts;
|
|
19998
|
+
this.now = opts.now ?? Date.now;
|
|
19999
|
+
this.detector = new StallDetector({
|
|
20000
|
+
worktreePath: opts.worktreePath,
|
|
20001
|
+
targetText: opts.targetText,
|
|
20002
|
+
budgetYuan: opts.budgetYuan,
|
|
20003
|
+
getCost: opts.getCost,
|
|
20004
|
+
sampleDiff: opts.sampleDiff,
|
|
20005
|
+
now: opts.now,
|
|
20006
|
+
schedule: opts.schedule,
|
|
20007
|
+
intervalMs: opts.intervalMs,
|
|
20008
|
+
onEvaluation: (e) => this.consume(e)
|
|
20009
|
+
// promise 会被 detector tick await(AUX 裁决 tick 内完成)
|
|
20010
|
+
});
|
|
20011
|
+
}
|
|
20012
|
+
/** 启动旁观者心跳。判定在解除暂停前不会真正开始(setup 执行期挂 PAUSED,batch 方案 §4)。 */
|
|
20013
|
+
start() {
|
|
20014
|
+
this.detector.start();
|
|
20015
|
+
}
|
|
20016
|
+
stop() {
|
|
20017
|
+
this.detector.stop();
|
|
20018
|
+
}
|
|
20019
|
+
/** 暂停判定(setup/accept 命令执行期豁免);解除时对齐事件时钟并重置起步宽限。 */
|
|
20020
|
+
setPaused(p) {
|
|
20021
|
+
this.detector.setPaused(p);
|
|
20022
|
+
}
|
|
20023
|
+
/** R6 基线:setup 完成后取首个读数(装依赖动 lockfile,故基线后置 + 排除 lockfile)。 */
|
|
20024
|
+
markBaseline() {
|
|
20025
|
+
return this.detector.markBaseline();
|
|
20026
|
+
}
|
|
20027
|
+
feed(evt) {
|
|
20028
|
+
this.detector.feed(evt);
|
|
20029
|
+
}
|
|
20030
|
+
/** 判定一步(测试可直接驱动;生产由 scheduler 每 tick 调)。自身异常绝不外泄。 */
|
|
20031
|
+
async tick() {
|
|
20032
|
+
return this.detector.tick();
|
|
20033
|
+
}
|
|
20034
|
+
/** 终止证据快照(runner 据此置 watchdog-killed 与重试前置锚)。 */
|
|
20035
|
+
getKill() {
|
|
20036
|
+
return this.killInfo;
|
|
20037
|
+
}
|
|
20038
|
+
/** 报告证据链快照(跨重试轮由 runner 聚合)。 */
|
|
20039
|
+
snapshot() {
|
|
20040
|
+
return { kill: this.killInfo, records: [...this.records], roundsAtKill: this.detector.round };
|
|
20041
|
+
}
|
|
20042
|
+
// —— 求值消费:StallEvaluation → batch 动作(与影子政策是同一结果的两种消费,方案 §3) ——
|
|
20043
|
+
async consume(e) {
|
|
20044
|
+
if (e.skipped) return;
|
|
20045
|
+
if (e.silenceMin !== null) {
|
|
20046
|
+
this.kill({ verdict: "stall", rule: "R3", evidence: `\u65AD\u6D41\uFF1A${R3_SILENCE_MIN} \u5206\u949F\u65E0\u4EFB\u4F55\u4E8B\u4EF6\uFF08agent \u53EF\u80FD\u5DF2\u5361\u6B7B\uFF09` });
|
|
20047
|
+
return;
|
|
20048
|
+
}
|
|
20049
|
+
if (e.health) {
|
|
20050
|
+
this.streak = 0;
|
|
20051
|
+
this.records.push({ kind: "health", at: e.t, text: e.health });
|
|
20052
|
+
return;
|
|
20053
|
+
}
|
|
20054
|
+
if (e.strong.length === 0) {
|
|
20055
|
+
if (e.weak.length > 0) this.records.push({ kind: "suspicion", at: e.t, text: e.weak.map((r) => `${r.rule} ${r.evidence}`).join("\uFF1B") });
|
|
20056
|
+
return;
|
|
20057
|
+
}
|
|
20058
|
+
if (e.t < this.freezeUntil) {
|
|
20059
|
+
this.records.push({ kind: "suspicion", at: e.t, text: `\u6536\u5C3E\u51BB\u7ED3\u7A97\u53E3\u5185\uFF08nudge-2 \u540E ${FREEZE_MIN} \u5206\u949F\uFF09\uFF0C\u4EC5\u8BB0\u5F55\uFF1A${e.strong.map((r) => r.rule).join("+")}` });
|
|
20060
|
+
return;
|
|
20061
|
+
}
|
|
20062
|
+
const verdict = await this.adjudicate(e);
|
|
20063
|
+
if (verdict === null) {
|
|
20064
|
+
this.records.push({ kind: "aux-fail", at: e.t });
|
|
20065
|
+
return;
|
|
20066
|
+
}
|
|
20067
|
+
if (verdict.verdict === "normal") {
|
|
20068
|
+
this.streak = 0;
|
|
20069
|
+
this.records.push({ kind: "verdict", at: e.t, verdict: "normal", evidence: verdict.evidence });
|
|
20070
|
+
return;
|
|
20071
|
+
}
|
|
20072
|
+
this.streak += 1;
|
|
20073
|
+
this.records.push({ kind: "verdict", at: e.t, verdict: verdict.verdict, evidence: verdict.evidence });
|
|
20074
|
+
if (this.streak >= KILL_STRIKES) {
|
|
20075
|
+
this.kill({
|
|
20076
|
+
verdict: verdict.verdict,
|
|
20077
|
+
rule: e.strong.map((r) => r.rule).join("+"),
|
|
20078
|
+
evidence: `${verdict.evidence}\uFF08\u8FDE\u7EED ${this.streak} \u6B21\u975E normal\uFF09`
|
|
20079
|
+
});
|
|
20080
|
+
return;
|
|
20081
|
+
}
|
|
20082
|
+
this.nudge(this.streak, verdict.verdict, verdict.evidence, e.t);
|
|
20083
|
+
}
|
|
20084
|
+
/** 二层裁决。返回 null = 调用失败/非法输出(降级 normal,绝不误杀)。 */
|
|
20085
|
+
async adjudicate(e) {
|
|
20086
|
+
const costLine = await this.costLine(e.t);
|
|
20087
|
+
const prompt = ADJUDICATE_PROMPT({
|
|
20088
|
+
title: this.opts.ticketTitle,
|
|
20089
|
+
accept: this.opts.acceptCmd,
|
|
20090
|
+
costLine,
|
|
20091
|
+
rules: [
|
|
20092
|
+
...e.strong.map((r) => `${r.rule}\uFF08\u5F3A\uFF09\uFF1A${r.evidence}`),
|
|
20093
|
+
...e.weak.map((r) => `${r.rule}\uFF08\u5F31\uFF0C\u4EC5\u53C2\u8003\uFF09\uFF1A${r.evidence}`)
|
|
20094
|
+
].join("\n") || "\uFF08\u65E0\uFF09",
|
|
20095
|
+
trajectory: this.trajectory(e.t)
|
|
20096
|
+
});
|
|
20097
|
+
try {
|
|
20098
|
+
const raw = await (this.opts.auxAdjudicate ?? defaultAdjudicate)(prompt, this.auxSignal());
|
|
20099
|
+
return parseVerdictJson(raw);
|
|
20100
|
+
} catch {
|
|
20101
|
+
return null;
|
|
20102
|
+
}
|
|
20103
|
+
}
|
|
20104
|
+
/** AUX 调用信号:任务 abort 或 60s 超时,先到先停(对齐 classifyRisk 合并信号形态)。 */
|
|
20105
|
+
auxSignal() {
|
|
20106
|
+
const ac = new AbortController();
|
|
20107
|
+
const timer = setTimeout(() => ac.abort(), AUX_TIMEOUT_MS);
|
|
20108
|
+
timer.unref?.();
|
|
20109
|
+
this.opts.ac.signal.addEventListener("abort", () => {
|
|
20110
|
+
clearTimeout(timer);
|
|
20111
|
+
ac.abort();
|
|
20112
|
+
}, { once: true });
|
|
20113
|
+
return ac.signal;
|
|
20114
|
+
}
|
|
20115
|
+
async costLine(t) {
|
|
20116
|
+
const cost = await this.detector.sampleCost();
|
|
20117
|
+
const mins = Math.round((t - this.detector.activeAtMs) / MIN2);
|
|
20118
|
+
const rounds = cost?.rounds ?? this.detector.round;
|
|
20119
|
+
const yuan = cost?.costYuan;
|
|
20120
|
+
return `\u5DF2\u7528\u65F6 ${mins} \u5206\u949F \xB7 \u8F6E\u6570 ${rounds}` + (yuan != null ? ` \xB7 \u82B1\u8D39 \xA5${yuan.toFixed(4)}` : "");
|
|
20121
|
+
}
|
|
20122
|
+
/** 最近 10 分钟轨迹(二层任务书):只读类按工具合并计数,写入类逐条带 args 摘要。 */
|
|
20123
|
+
trajectory(t) {
|
|
20124
|
+
const recent = this.detector.callsWithin(t, R1_WINDOW_MIN * MIN2);
|
|
20125
|
+
if (recent.length === 0) return "\uFF08\u65E0\u5DE5\u5177\u8C03\u7528\uFF09";
|
|
20126
|
+
const readonlyCounts = /* @__PURE__ */ new Map();
|
|
20127
|
+
const lines = [];
|
|
20128
|
+
for (const c of recent) {
|
|
20129
|
+
if (!c.isReadonly) {
|
|
20130
|
+
lines.push(`- ${c.toolName}${c.target ? ` \u2192 ${c.target}` : ""}\uFF08${c.argsDigest}\uFF09`);
|
|
20131
|
+
continue;
|
|
20132
|
+
}
|
|
20133
|
+
readonlyCounts.set(c.toolName, (readonlyCounts.get(c.toolName) ?? 0) + 1);
|
|
20134
|
+
}
|
|
20135
|
+
for (const [tool, n] of readonlyCounts) lines.push(`- ${tool} \xD7${n}\uFF08\u53EA\u8BFB\uFF09`);
|
|
20136
|
+
return lines.join("\n").slice(0, 2400);
|
|
20137
|
+
}
|
|
20138
|
+
nudge(streak, verdict, evidence, t) {
|
|
20139
|
+
const text = streak === 1 ? NUDGE_1(evidence) : NUDGE_2(`${verdict}\uFF1A${evidence}`);
|
|
20140
|
+
this.records.push({ kind: "nudge", at: t, level: streak, text });
|
|
20141
|
+
this.detector.setSuppressUntil(t + NUDGE_GRACE_MIN * MIN2);
|
|
20142
|
+
if (streak === 2) this.freezeUntil = t + FREEZE_MIN * MIN2;
|
|
20143
|
+
try {
|
|
20144
|
+
this.opts.onNudge(text);
|
|
20145
|
+
} catch {
|
|
20146
|
+
}
|
|
20147
|
+
}
|
|
20148
|
+
kill(info) {
|
|
20149
|
+
if (this.killInfo) return;
|
|
20150
|
+
this.killInfo = info;
|
|
20151
|
+
this.records.push({ kind: "kill", at: this.now(), verdict: info.verdict, evidence: `${info.rule} ${info.evidence}` });
|
|
20152
|
+
this.detector.stop();
|
|
20153
|
+
try {
|
|
20154
|
+
this.opts.onKill(new Error(`watchdog: ${info.verdict} \u2014 ${info.evidence}`), info);
|
|
20155
|
+
} catch {
|
|
20156
|
+
}
|
|
20157
|
+
}
|
|
20158
|
+
};
|
|
20159
|
+
buildRetryTaskContent = (body, kill, finalText) => RETRY_PREAMBLE(kill.verdict, kill.evidence, finalText.trim().replace(/\s+/g, " ").slice(0, 400)) + body;
|
|
20160
|
+
}
|
|
20161
|
+
});
|
|
20162
|
+
|
|
19167
20163
|
// src/batchRunner.ts
|
|
19168
20164
|
var batchRunner_exports = {};
|
|
19169
20165
|
__export(batchRunner_exports, {
|
|
20166
|
+
buildReport: () => buildReport,
|
|
19170
20167
|
parseWaitWindow: () => parseWaitWindow,
|
|
19171
20168
|
runBatchQueue: () => runBatchQueue
|
|
19172
20169
|
});
|
|
19173
20170
|
import fs50 from "fs";
|
|
19174
20171
|
import { spawn as spawn6 } from "child_process";
|
|
19175
|
-
var BATCH_EDIT_TOOLS, BATCH_DEFAULT_DENYLIST, ACCEPT_TIMEOUT_MIN, ACCEPT_TAIL_LINES, emit2, ts, runAcceptCommand, collectSessionCost, buildReport, runOneTask, parseWaitWindow, nowMinutes, sleep, waitUntilWindow, runBatchQueue;
|
|
20172
|
+
var BATCH_EDIT_TOOLS, BATCH_DEFAULT_DENYLIST, ACCEPT_TIMEOUT_MIN, ACCEPT_TAIL_LINES, emit2, ts, runAcceptCommand, collectSessionCost, buildWatchdogLines, buildReport, runOneTask, parseWaitWindow, nowMinutes, sleep, waitUntilWindow, runBatchQueue;
|
|
19176
20173
|
var init_batchRunner = __esm({
|
|
19177
20174
|
"src/batchRunner.ts"() {
|
|
19178
20175
|
"use strict";
|
|
@@ -19189,6 +20186,9 @@ var init_batchRunner = __esm({
|
|
|
19189
20186
|
init_queue();
|
|
19190
20187
|
init_batchStrings();
|
|
19191
20188
|
init_strings();
|
|
20189
|
+
init_batchWatchdog();
|
|
20190
|
+
init_inbox();
|
|
20191
|
+
init_agentWake();
|
|
19192
20192
|
BATCH_EDIT_TOOLS = /* @__PURE__ */ new Set(["edit_file", "create_file", "write_file", "move_file", "notebook_edit"]);
|
|
19193
20193
|
BATCH_DEFAULT_DENYLIST = /* @__PURE__ */ new Set(["run_command", "delete_path", "run_in_background"]);
|
|
19194
20194
|
ACCEPT_TIMEOUT_MIN = 10;
|
|
@@ -19258,6 +20258,33 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
19258
20258
|
if (c.costYuan === null) c.partialPrice = false;
|
|
19259
20259
|
return c;
|
|
19260
20260
|
};
|
|
20261
|
+
buildWatchdogLines = (snaps, costYuan) => {
|
|
20262
|
+
if (snaps.length === 0) return null;
|
|
20263
|
+
const T = batchT(getLocale());
|
|
20264
|
+
const render2 = (r) => {
|
|
20265
|
+
switch (r.kind) {
|
|
20266
|
+
case "suspicion":
|
|
20267
|
+
return T.wdSuspicionRec(r.text ?? "");
|
|
20268
|
+
case "verdict":
|
|
20269
|
+
return T.wdVerdictRec(r.verdict ?? "", r.evidence ?? "");
|
|
20270
|
+
case "nudge":
|
|
20271
|
+
return T.wdNudgeRec(r.level ?? 0, r.text ?? "");
|
|
20272
|
+
case "health":
|
|
20273
|
+
return T.wdHealthRec(r.text ?? "");
|
|
20274
|
+
case "aux-fail":
|
|
20275
|
+
return T.wdAuxFailRec();
|
|
20276
|
+
case "kill":
|
|
20277
|
+
return T.wdKillRec(r.verdict ?? "", r.evidence ?? "");
|
|
20278
|
+
}
|
|
20279
|
+
};
|
|
20280
|
+
const lines = [];
|
|
20281
|
+
for (const snap of snaps) {
|
|
20282
|
+
lines.push(...snap.records.map(render2));
|
|
20283
|
+
if (snap.kill) lines.push(T.wdAtKillRec(snap.roundsAtKill, costYuan !== null ? costYuan.toFixed(4) : "-"));
|
|
20284
|
+
}
|
|
20285
|
+
if (snaps.length > 1) lines.push(T.wdRetryRec(snaps.length - 1));
|
|
20286
|
+
return lines;
|
|
20287
|
+
};
|
|
19261
20288
|
buildReport = (args) => {
|
|
19262
20289
|
const { id, ticket, status, budgetTruncated, cost, receipt, finalText, accept, deniedTools, diff, wt } = args;
|
|
19263
20290
|
const T = batchT(getLocale());
|
|
@@ -19280,7 +20307,11 @@ ${T.statusEntry(`${T.statusLabel(status)}${budgetNote}`)}
|
|
|
19280
20307
|
${T.costEntry(T.costSummary(cost))}
|
|
19281
20308
|
${T.receiptEntry(receipt ? T.receiptLine(receipt) : T.noReceipt)}
|
|
19282
20309
|
${args.errorMessage ? T.errorEntry(args.errorMessage) : ""}
|
|
19283
|
-
${T.
|
|
20310
|
+
${args.watchdogLines?.length ? `${T.wdH}
|
|
20311
|
+
|
|
20312
|
+
${args.watchdogLines.map(T.wdRecord).join("\n")}
|
|
20313
|
+
|
|
20314
|
+
` : ""}${T.taskH}
|
|
19284
20315
|
|
|
19285
20316
|
${ticket.body}
|
|
19286
20317
|
|
|
@@ -19384,89 +20415,187 @@ ${parsed.error}`);
|
|
|
19384
20415
|
emit2(`\u{1F4A5} [${task.id}] ${msg}`);
|
|
19385
20416
|
return { status: "error", cost: cost2, budgetTruncated: false };
|
|
19386
20417
|
}
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
20418
|
+
const watchdogEnabled = process.env.DEEP_SEEK_BATCH_WATCHDOG !== "0";
|
|
20419
|
+
const wdSnapshots = [];
|
|
20420
|
+
const maxRounds = 1 + Math.min(Math.max(0, Math.floor(t.retry ?? 0)), RETRY_MAX);
|
|
20421
|
+
let content = t.body;
|
|
20422
|
+
let roundBudget = t.budgetYuan;
|
|
20423
|
+
let receipt;
|
|
20424
|
+
let finalText = "";
|
|
20425
|
+
let agentError;
|
|
20426
|
+
let budgetTruncated = false;
|
|
20427
|
+
let wdKill = null;
|
|
20428
|
+
let status;
|
|
20429
|
+
let accept = null;
|
|
20430
|
+
for (let round = 1; ; round++) {
|
|
20431
|
+
wdKill = null;
|
|
20432
|
+
finalText = "";
|
|
20433
|
+
receipt = void 0;
|
|
20434
|
+
agentError = void 0;
|
|
20435
|
+
let nudgeCount = 0;
|
|
20436
|
+
const roundAc = new AbortController();
|
|
20437
|
+
const wd = watchdogEnabled ? new BatchWatchdog({
|
|
20438
|
+
sessionId,
|
|
20439
|
+
ticketTitle: t.title,
|
|
20440
|
+
acceptCmd: t.accept,
|
|
20441
|
+
targetText: `${t.title}
|
|
20442
|
+
${t.body}
|
|
20443
|
+
${t.accept}${t.setup ? `
|
|
20444
|
+
${t.setup}` : ""}`,
|
|
20445
|
+
ac: roundAc,
|
|
20446
|
+
worktreePath: wt.path,
|
|
20447
|
+
budgetYuan: roundBudget,
|
|
20448
|
+
getCost: () => collectSessionCost(sessionId),
|
|
20449
|
+
onNudge: (text) => {
|
|
20450
|
+
nudgeCount++;
|
|
20451
|
+
pushSessionInbox(sessionId, text);
|
|
20452
|
+
emit2(T.wdNudgeNote(task.id, nudgeCount));
|
|
20453
|
+
},
|
|
20454
|
+
onKill: (err, info) => {
|
|
20455
|
+
wdKill = info;
|
|
20456
|
+
emit2(T.wdKillNote(task.id, `${info.verdict} \u2014 ${info.evidence}`));
|
|
20457
|
+
roundAc.abort(err);
|
|
20458
|
+
}
|
|
20459
|
+
}) : null;
|
|
20460
|
+
wd?.start();
|
|
20461
|
+
wd?.setPaused(true);
|
|
20462
|
+
if (round === 1 && t.setup) {
|
|
20463
|
+
emit2(T.setupLine(t.setup));
|
|
20464
|
+
const s = await runAcceptCommand(t.setup, wt.path);
|
|
20465
|
+
if (s.code !== 0 || s.timedOut) {
|
|
20466
|
+
wd?.stop();
|
|
20467
|
+
const msg = `${T.setupFail(t.setup, s.code)}${s.timedOut ? T.acceptTimeoutSuffix : ""}
|
|
19393
20468
|
|
|
19394
20469
|
\`\`\`
|
|
19395
20470
|
${s.output}
|
|
19396
20471
|
\`\`\``;
|
|
19397
|
-
|
|
19398
|
-
|
|
19399
|
-
|
|
19400
|
-
|
|
19401
|
-
|
|
19402
|
-
|
|
19403
|
-
|
|
19404
|
-
|
|
19405
|
-
|
|
19406
|
-
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
20472
|
+
await killBackgroundTasksUnder(wt.path).catch(() => {
|
|
20473
|
+
});
|
|
20474
|
+
const cost2 = await collectSessionCost(sessionId);
|
|
20475
|
+
await finishTicket(task.id, buildReport({
|
|
20476
|
+
id: task.id,
|
|
20477
|
+
ticket: t,
|
|
20478
|
+
status: "setup-failed",
|
|
20479
|
+
budgetTruncated: false,
|
|
20480
|
+
cost: cost2,
|
|
20481
|
+
receipt: void 0,
|
|
20482
|
+
finalText: "",
|
|
20483
|
+
accept: null,
|
|
20484
|
+
deniedTools: [],
|
|
20485
|
+
diff: T.diffNone,
|
|
20486
|
+
wt,
|
|
20487
|
+
errorMessage: msg
|
|
20488
|
+
}));
|
|
20489
|
+
emit2(`\u{1F6E0}\uFE0F [${task.id}] ${T.setupFail(t.setup, s.code)}`);
|
|
20490
|
+
return { status: "setup-failed", cost: cost2, budgetTruncated: false };
|
|
20491
|
+
}
|
|
19416
20492
|
}
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
19437
|
-
|
|
19438
|
-
|
|
19439
|
-
|
|
20493
|
+
wd?.setPaused(false);
|
|
20494
|
+
await wd?.markBaseline();
|
|
20495
|
+
const timer = setTimeout(() => roundAc.abort(new Error(T.timeoutAbort(timeoutMin))), timeoutMin * 6e4);
|
|
20496
|
+
setSessionWorktree(sessionId, wt);
|
|
20497
|
+
registerWakeDriver(sessionId, async () => {
|
|
20498
|
+
emit2(`\u{1F916} [${task.id}] \u5B50\u4EE3\u7406\u5B8C\u6210\uFF0C\u5524\u9192 run \u7EED\u8DD1\u2026`);
|
|
20499
|
+
setSessionWorktree(sessionId, wt);
|
|
20500
|
+
const wakeAc = new AbortController();
|
|
20501
|
+
const wakeTimer = setTimeout(() => wakeAc.abort(new Error(T.timeoutAbort(timeoutMin))), timeoutMin * 6e4);
|
|
20502
|
+
try {
|
|
20503
|
+
await handleUnifiedChat(
|
|
20504
|
+
{ sessionId, content: AGENT_DONE_SENTINEL },
|
|
20505
|
+
async () => {
|
|
20506
|
+
},
|
|
20507
|
+
(evt) => {
|
|
20508
|
+
if (evt?.type === "text.delta") finalText += evt.text;
|
|
20509
|
+
else if (evt?.type === "text.reset") finalText = "";
|
|
20510
|
+
else if (evt?.type === "final") finalText = evt.text || finalText;
|
|
20511
|
+
},
|
|
20512
|
+
wakeAc.signal,
|
|
20513
|
+
{
|
|
20514
|
+
requestApproval: async (detail, meta) => {
|
|
20515
|
+
if (allowApproval.has(meta.toolName)) return "allow-once";
|
|
20516
|
+
deniedTools.push({ tool: meta.toolName, detail: detail.replace(/\n+/g, " ").slice(0, 140) });
|
|
20517
|
+
return "deny";
|
|
20518
|
+
},
|
|
20519
|
+
onUIEvent: (evt) => {
|
|
20520
|
+
if (evt.type === "run.receipt") receipt = evt;
|
|
20521
|
+
},
|
|
20522
|
+
budgetYuan: roundBudget,
|
|
20523
|
+
toolSchemas: gatedSchemas
|
|
20524
|
+
}
|
|
20525
|
+
);
|
|
20526
|
+
} finally {
|
|
20527
|
+
clearTimeout(wakeTimer);
|
|
20528
|
+
clearSessionWorktree(sessionId);
|
|
20529
|
+
}
|
|
20530
|
+
});
|
|
20531
|
+
try {
|
|
20532
|
+
await handleUnifiedChat(
|
|
20533
|
+
{ sessionId, content },
|
|
20534
|
+
async () => {
|
|
19440
20535
|
},
|
|
19441
|
-
|
|
19442
|
-
|
|
20536
|
+
(evt) => {
|
|
20537
|
+
wd?.feed(evt);
|
|
20538
|
+
if (evt?.type === "text.delta") finalText += evt.text;
|
|
20539
|
+
else if (evt?.type === "text.reset") finalText = "";
|
|
20540
|
+
else if (evt?.type === "final") finalText = evt.text || finalText;
|
|
20541
|
+
else if (evt?.type === "round.start") emit2(T.roundLine(ts(), evt.round));
|
|
19443
20542
|
},
|
|
19444
|
-
|
|
19445
|
-
|
|
20543
|
+
roundAc.signal,
|
|
20544
|
+
{
|
|
20545
|
+
requestApproval: async (detail, meta) => {
|
|
20546
|
+
if (allowApproval.has(meta.toolName)) return "allow-once";
|
|
20547
|
+
deniedTools.push({ tool: meta.toolName, detail: detail.replace(/\n+/g, " ").slice(0, 140) });
|
|
20548
|
+
return "deny";
|
|
20549
|
+
},
|
|
20550
|
+
onUIEvent: (evt) => {
|
|
20551
|
+
if (evt.type === "run.receipt") receipt = evt;
|
|
20552
|
+
},
|
|
20553
|
+
budgetYuan: roundBudget,
|
|
20554
|
+
toolSchemas: gatedSchemas
|
|
20555
|
+
}
|
|
20556
|
+
);
|
|
20557
|
+
} catch (e) {
|
|
20558
|
+
agentError = e instanceof Error ? e.message : String(e);
|
|
20559
|
+
} finally {
|
|
20560
|
+
clearTimeout(timer);
|
|
20561
|
+
wd?.stop();
|
|
20562
|
+
clearSessionWorktree(sessionId);
|
|
20563
|
+
}
|
|
20564
|
+
if (wd) wdSnapshots.push(wd.snapshot());
|
|
20565
|
+
budgetTruncated = receipt?.budgetTruncated === true;
|
|
20566
|
+
if (agentError) {
|
|
20567
|
+
status = "error";
|
|
20568
|
+
emit2(T.agentErrorLine(task.id, agentError));
|
|
20569
|
+
break;
|
|
20570
|
+
}
|
|
20571
|
+
if (wdKill) {
|
|
20572
|
+
const spent = await collectSessionCost(sessionId);
|
|
20573
|
+
const nextBudget = sharedBudgetYuan(t.budgetYuan, spent.costYuan);
|
|
20574
|
+
if (round < maxRounds && (nextBudget === void 0 || nextBudget > 0)) {
|
|
20575
|
+
emit2(T.wdRetryNote(task.id, round + 1));
|
|
20576
|
+
content = buildRetryTaskContent(t.body, wdKill, finalText);
|
|
20577
|
+
roundBudget = nextBudget;
|
|
20578
|
+
continue;
|
|
19446
20579
|
}
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
|
|
19451
|
-
|
|
19452
|
-
|
|
19453
|
-
|
|
19454
|
-
|
|
19455
|
-
|
|
19456
|
-
|
|
19457
|
-
|
|
19458
|
-
|
|
19459
|
-
status = "error";
|
|
19460
|
-
emit2(T.agentErrorLine(task.id, agentError));
|
|
19461
|
-
} else if (timedOut) {
|
|
19462
|
-
status = "timeout";
|
|
19463
|
-
emit2(T.timeoutLine(task.id, timeoutMin));
|
|
19464
|
-
} else {
|
|
20580
|
+
if (round < maxRounds) emit2(T.wdBudgetStopNote(task.id));
|
|
20581
|
+
status = "watchdog-killed";
|
|
20582
|
+
break;
|
|
20583
|
+
}
|
|
20584
|
+
if (roundAc.signal.aborted) {
|
|
20585
|
+
status = "timeout";
|
|
20586
|
+
emit2(T.timeoutLine(task.id, timeoutMin));
|
|
20587
|
+
break;
|
|
20588
|
+
}
|
|
20589
|
+
const quiet = await waitSessionQuiescent(sessionId, void 0, timeoutMin * 6e4);
|
|
20590
|
+
if (!quiet) emit2(`\u23F3 [${task.id}] \u5524\u9192\u94FE\u672A\u5728\u65F6\u9650\u5185\u6536\u655B\uFF0C\u6309\u73B0\u72B6\u9A8C\u6536`);
|
|
20591
|
+
wd?.setPaused(true);
|
|
19465
20592
|
const r = await runAcceptCommand(t.accept, wt.path);
|
|
19466
20593
|
accept = { cmd: t.accept, code: r.code, output: r.output, timedOut: r.timedOut };
|
|
19467
20594
|
status = r.code === 0 && !r.timedOut ? "passed" : "accept-failed";
|
|
19468
20595
|
emit2(T.acceptLine(status === "passed", task.id, r.code) + (r.timedOut ? T.acceptKilledSuffix : ""));
|
|
20596
|
+
break;
|
|
19469
20597
|
}
|
|
20598
|
+
unregisterWakeDriver(sessionId);
|
|
19470
20599
|
await killBackgroundTasksUnder(wt.path).catch(() => {
|
|
19471
20600
|
});
|
|
19472
20601
|
const diff = await harvestDiff(wt);
|
|
@@ -19483,7 +20612,8 @@ ${s.output}
|
|
|
19483
20612
|
deniedTools,
|
|
19484
20613
|
diff,
|
|
19485
20614
|
wt,
|
|
19486
|
-
errorMessage: agentError
|
|
20615
|
+
errorMessage: agentError,
|
|
20616
|
+
watchdogLines: buildWatchdogLines(wdSnapshots, cost.costYuan) ?? void 0
|
|
19487
20617
|
}));
|
|
19488
20618
|
emit2(` ${T.statusLabel(status)} \xB7 ${T.costSummary(cost)}`);
|
|
19489
20619
|
emit2(T.artifactLine(wt.path, wt.branch));
|
|
@@ -19621,7 +20751,7 @@ init_prefs();
|
|
|
19621
20751
|
init_updateCheck();
|
|
19622
20752
|
init_trust();
|
|
19623
20753
|
import { render } from "ink";
|
|
19624
|
-
import
|
|
20754
|
+
import os6 from "os";
|
|
19625
20755
|
import path50 from "path";
|
|
19626
20756
|
import { emitKeypressEvents } from "node:readline";
|
|
19627
20757
|
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
@@ -19771,7 +20901,7 @@ var main = async () => {
|
|
|
19771
20901
|
process.stdout.write("\x1B[2J\x1B[3J\x1B[1;1H");
|
|
19772
20902
|
const cwdIsHome = () => {
|
|
19773
20903
|
try {
|
|
19774
|
-
return path50.resolve(cwd).toLowerCase() === path50.resolve(
|
|
20904
|
+
return path50.resolve(cwd).toLowerCase() === path50.resolve(os6.homedir()).toLowerCase();
|
|
19775
20905
|
} catch {
|
|
19776
20906
|
return false;
|
|
19777
20907
|
}
|