import { writeFileSync } from "node:fs"; import { join } from "node:path"; import { ofKind, readLedger } from "../lib/ledger.ts"; import { replayModels, startReplay } from "../lib/replay.ts"; import { containers, launch, newEvalDir, sleep, writeConfig } from "../lib/study.ts"; // 两份研究同时跑(任务书 12 第 5.4 节):两个研究编号同时启动,都跑到基线结束,查两边各扣各的、容器不撞名。 // node eval/round-zero/concurrent.ts // 研究者用一份空清单的回放:基线跑完、派写入口任务时模型一份不交,flow 按"交不出合格提交"停下,不花钱。 const out = newEvalDir("r0-concurrent"); const ids = ["r0-conc-a", "r0-conc-b"]; const researchers = ["researcher-1", "researcher-2", "researcher-3"]; const replay = await startReplay({ source: "空清单", models: Object.fromEntries([...researchers, "experimenter", "verifier"].map((m) => [m, []])) }, join(out, "pi-agent"), 0); const studies = ids.map((id) => { const dir = join(out, id); const config = writeConfig("eval/round-zero/research.json", join(out, `${id}.research.json`), id, replayModels(researchers, "jev-latest")); return { id, dir, run: launch(config, dir, replay.env) }; }); // 跑的时候每 100 毫秒看一次本机 inforsi- 开头的容器,记下见过的名字。 const seen = new Set(); let running = true; const watcher = (async () => { while (running) { for (const n of containers("inforsi-")) seen.add(n); await sleep(100); } })(); const results = await Promise.all(studies.map((s) => s.run.done)); running = false; await watcher; await replay.close(); const report = studies.map((s, i) => { const r = readLedger(s.dir); const base = new Set(ofKind(r, "runPlanned").filter((p) => p.content.purpose === "baseline").map((p) => p.content.run)); return { id: s.id, outcome: results[i]!.outcome, baseStarted: ofKind(r, "runStarted").filter((x) => base.has(x.content.run)).length, baseResults: ofKind(r, "runResult").filter((x) => base.has(x.content.run)).map((x) => x.content), containersSeen: [...seen].filter((n) => n.startsWith(`inforsi-${s.id}-`)), }; }); const shared = report[0]!.containersSeen.filter((n) => report[1]!.containersSeen.includes(n)); const pass = report.every((s) => s.baseStarted === 1 && s.baseResults.length === 1 && s.baseResults[0]!.judged !== null) && shared.length === 0; writeFileSync(join(out, "concurrent-report.json"), `${JSON.stringify({ pass, report, allContainersSeen: [...seen], shared }, null, 2)}\n`); for (const s of report) { console.log(`${s.id}:基线确认启动 ${s.baseStarted} 次;结果 ${JSON.stringify(s.baseResults.map((x) => x.judged))};见过的容器 ${s.containersSeen.join("、") || "(没看到)"};结局 ${JSON.stringify(s.outcome)}`); } console.log(`两边共用的容器名:${shared.join("、") || "没有"};${pass ? "通过" : "不通过"}`); console.log(`报告:${join(out, "concurrent-report.json")}`);