scheduler-gateway/scripts/team-watchdog-demo.mjs
Liuxinyu176 bbb364cd69 feat: DSH 调度网关(互联网关)v6.0.0 — 四模型合并版 R1+R2+R3
- 零第三方依赖,Node >=20 原生 ESM
- 团队式编排引擎:拆解/路由/执行/审查/合并全真实 LLM
- 阶段心跳、单一权威清单守卫、all-keys-failed 如实上报
- H4 会话视图/amend/watchdog 有界重试/产物区 artifacts.json
- H5 零依赖三栏控制台
2026-10-09 23:20:27 +08:00

52 lines
3.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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);