- 零第三方依赖,Node >=20 原生 ESM - 团队式编排引擎:拆解/路由/执行/审查/合并全真实 LLM - 阶段心跳、单一权威清单守卫、all-keys-failed 如实上报 - H4 会话视图/amend/watchdog 有界重试/产物区 artifacts.json - H5 零依赖三栏控制台
52 lines
3.2 KiB
JavaScript
52 lines
3.2 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* R6 H4-3 现场演示:失败 → watchdog 有界自动重试 → 纠偏/成功(真实 LLM 编排)。
|
||
* 通过 GW_TEAM_FAIL_ONCE=first-cli 让第一个外部 CLI 子任务的第 1 次尝试确定性失败,
|
||
* 引擎 watchdog 记录 auto-retry(injected:true)并退避重试,后续尝试成功。
|
||
* 结束校验:①watchdog.json 含 injected 自动重试 ②该子任务 attempts≥2(先 dead 后 done)
|
||
* ③整体无 dead 子任务(评审若打回则走 correction 纠偏,同样计入证据)。EXIT=0 闭环。
|
||
*/
|
||
import { readFileSync } from "node:fs";
|
||
import { resolve, dirname, join } from "node:path";
|
||
import { fileURLToPath } from "node:url";
|
||
import { TeamOrchestrator } from "../src/team/orchestrate.js";
|
||
|
||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||
const GOAL = [
|
||
"用 Node.js(零第三方依赖)做一个 Markdown 词频统计命令行小工具,团队分工完成三件事:",
|
||
"①编写可运行的实现脚本 wordcount.mjs:读取 .md 文件,按词统计中文/英文词频,支持 --top=N 参数输出前 N 个高频词,并能对 samples 目录里的样例真实跑出结果;",
|
||
"②编写 README.md:含功能说明、用法示例(node wordcount.mjs --top=5 samples/sample.txt)、输出格式说明;",
|
||
"③准备 samples/sample.txt:一份用于演示的 Markdown 样例文本(含若干重复词)。",
|
||
].join("");
|
||
|
||
const runId = `run-watchdog-${Date.now().toString(36)}`;
|
||
process.env.GW_TEAM_FAIL_ONCE = "first-cli";
|
||
process.env.GW_INJECT_RUN_ID = runId;
|
||
|
||
const orch = new TeamOrchestrator({ root: ROOT });
|
||
const t0 = Date.now();
|
||
const result = await orch.run(GOAL, { runId });
|
||
const wall = Date.now() - t0;
|
||
|
||
const evDir = resolve(ROOT, "evidence", "team-orch", runId);
|
||
const watchdog = JSON.parse(readFileSync(join(evDir, "watchdog.json"), "utf8"));
|
||
const injectedRetries = watchdog.filter((w) => w.type === "auto-retry" && w.injected);
|
||
const retriedSub = result.executions.find((e) => e.attempts.length >= 2 && e.attempts.some((a) => a.state === "dead") && e.state === "done");
|
||
|
||
const problems = [];
|
||
if (!injectedRetries.length) problems.push("watchdog.json 未记录 injected:true 的 auto-retry");
|
||
if (!retriedSub) problems.push("没有子任务呈现『首次失败→重试成功』(attempts 先 dead 后 done)");
|
||
if (result.deadSubtasks.length) problems.push(`仍有 dead 子任务:${JSON.stringify(result.deadSubtasks)}`);
|
||
|
||
console.log("\n===== watchdog-demo 验收 =====");
|
||
console.log(`runId=${runId} verdict=${result.verdict}/${result.finalScore} 耗时=${wall}ms`);
|
||
console.log(`watchdog 事件:${watchdog.map((w) => w.type + (w.subtaskId ? "@" + w.subtaskId : "") + (w.injected ? "(注入)" : "")).join(",") || "无"}`);
|
||
if (retriedSub) console.log(`重试子任务 ${retriedSub.subtaskId}:attempts=${retriedSub.attempts.map((a) => a.state).join("→")}`);
|
||
console.log(`评审轮次=${result.reviewSummary?.reviewRounds} 纠偏=${result.reviewSummary?.corrections} 自动重试=${result.reviewSummary?.autoRetries}`);
|
||
if (problems.length) {
|
||
console.error("[watchdog-demo] 未闭环:\n - " + problems.join("\n - "));
|
||
process.exit(2);
|
||
}
|
||
console.log("[watchdog-demo] 闭环成功 EXIT=0(失败→自动重试→成功,证据齐全)");
|
||
process.exit(0);
|