import assert from "node:assert/strict"; import { join } from "node:path"; import { test } from "node:test"; import { Ledger } from "../src/ledger/index.ts"; import { callStart, exited, freshLedger, notStarted, planRun, tempDir, usage } from "./ledger-helpers.ts"; // 未完成的动作(方法.md 第九部分"中断与恢复时的记账含义":先登记、再执行、再登记结果): // 登记了但没有结果的运行、开始了但没有结束的模型调用能被找出来;写了结果之后就不再出现。 test("运行:登记了没结果的被找出来,带着有没有确认启动;写了结果就不再出现", (t) => { const { ledger } = freshLedger(t); planRun(ledger, "base", "baseline", 0); planRun(ledger, "run1", "forward", 1); planRun(ledger, "run2", "forward", 1); ledger.append("runStarted", { run: "base" }); ledger.append("runStarted", { run: "run1" }); ledger.append("runResult", { run: "base", process: exited, judged: null }); assert.deepEqual( ledger.pending().runs.map((r) => [r.plan.content.run, r.started]), [ ["run1", true], ["run2", false], ], ); ledger.append("runResult", { run: "run2", process: notStarted, judged: null }); assert.deepEqual(ledger.pending().runs.map((r) => r.plan.content.run), ["run1"]); ledger.append("runResult", { run: "run1", process: exited, judged: null }); assert.deepEqual(ledger.pending().runs, []); }); test("模型调用:开始了没结束的被找出来,带着这次任务的全部材料;有用量也还算没结束;结束后不再出现", (t) => { const { ledger } = freshLedger(t); ledger.append("callStarted", callStart("k1", "r1", "s1")); ledger.append("callStarted", callStart("k2", "e1")); ledger.append("callUsage", { call: "k1", reply: 1, usage }); ledger.append("callEnded", { call: "k2", wallSeconds: { status: "measured", value: 30 }, status: "failed", reason: "接口超时" }); const calls = ledger.pending().calls; assert.deepEqual(calls.map((c) => c.content.call), ["k1"]); assert.deepEqual(calls[0]!.content.materials, callStart("k1").materials); ledger.append("callEnded", { call: "k1", wallSeconds: { status: "measured", value: 600 }, status: "notSubmitted", reason: "模型自己停下了" }); assert.deepEqual(ledger.pending(), { runs: [], calls: [] }); }); test("中断后恢复:给没结束的旧调用补写出错加测不到(进程中断),补写后不再算未完成", (t) => { const path = join(tempDir(t), "ledger.db"); const ledger = Ledger.open(path); ledger.append("callStarted", callStart("k1", "r1", "s1")); ledger.append("callUsage", { call: "k1", reply: 1, usage }); ledger.close(); // 控制进程被系统杀掉 const reopened = Ledger.open(path); t.after(() => reopened.close()); assert.deepEqual(reopened.pending().calls.map((c) => c.content.call), ["k1"]); reopened.append("callEnded", { call: "k1", wallSeconds: { status: "unmeasured", reason: "进程中断" }, status: "failed", reason: "进程中断", }); assert.deepEqual(reopened.pending(), { runs: [], calls: [] }); assert.deepEqual(reopened.records().at(-1)!.content, { call: "k1", wallSeconds: { status: "unmeasured", reason: "进程中断" }, status: "failed", reason: "进程中断", }); }); test("关掉再打开:未完成的动作照样找得出来", (t) => { const path = join(tempDir(t), "ledger.db"); const ledger = Ledger.open(path); planRun(ledger, "run1", "forward", 1); ledger.append("runStarted", { run: "run1" }); ledger.append("callStarted", callStart("k1")); const before = ledger.pending(); ledger.close(); const reopened = Ledger.open(path); t.after(() => reopened.close()); assert.deepEqual(reopened.pending(), before); assert.equal(before.runs.length, 1); assert.equal(before.calls.length, 1); });