Make the range card row-select, drop the composer 先这样 control and adopt status bar, keep delivery copy to three sentences with a folded verification report, and skip a second no-message agent run after a terminal delivery turn. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
4.5 KiB
TypeScript
99 lines
4.5 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { readFileSync } from "node:fs";
|
||
import test from "node:test";
|
||
import { createElement } from "react";
|
||
import { renderToStaticMarkup } from "react-dom/server";
|
||
|
||
import {
|
||
deliveryTurnNarration,
|
||
postAdoptVerifyDoneCopy,
|
||
RECTIFICATION_USER_COPY,
|
||
} from "../src/lib/rectification-agentic/user-copy.ts";
|
||
import {
|
||
alreadyDelivered,
|
||
markDeliveryTurn,
|
||
resetDeliveryTurnGuardForTests,
|
||
} from "../src/lib/rectification-agentic/v9/delivery-turn-guard.ts";
|
||
import { RectificationVerificationReport } from "../src/components/rectification-verification-report.tsx";
|
||
|
||
test("delivery body is three sentences and omits the eight-method report", () => {
|
||
const text = deliveryTurnNarration({
|
||
credibleRange: ["04:51", "04:59"],
|
||
representativeTime: "04:53",
|
||
eventCount: 7,
|
||
fitPercent: 80,
|
||
});
|
||
assert.equal(text, "这次给出的范围 04:51–04:59,排盘用 04:53。对照了 7 件经历,事件吻合率 80%。这只是代表性候选,不是已确认的唯一出生分钟。");
|
||
assert.doesNotMatch(text, /方法1/);
|
||
assert.doesNotMatch(text, /Technique Audit/);
|
||
});
|
||
|
||
test("skipping the last reverse-verify keeps the original post-adopt sentence", () => {
|
||
assert.equal(
|
||
postAdoptVerifyDoneCopy("05:07", true),
|
||
RECTIFICATION_USER_COPY.postAdoptVerifyDone,
|
||
);
|
||
assert.equal(
|
||
postAdoptVerifyDoneCopy("05:07", false),
|
||
"已采用 05:07,新建对话即按这个时间排盘。",
|
||
);
|
||
});
|
||
|
||
test("verification report fold is closed and renders a real table", () => {
|
||
const html = renderToStaticMarkup(createElement(RectificationVerificationReport, {
|
||
markdown: "| 方法 | 结果 |\n| --- | --- |\n| 1 | 吻合 |",
|
||
}));
|
||
assert.match(html, /<details/);
|
||
assert.doesNotMatch(html, /<details[^>]*\sopen/);
|
||
assert.match(html, /查看验证报告/);
|
||
assert.match(html, /<table/);
|
||
});
|
||
|
||
test("already_delivered blocks a second no-message run for the same result within 60s", () => {
|
||
resetDeliveryTurnGuardForTests();
|
||
const caseId = "11111111-1111-4111-8111-111111111111";
|
||
const resultId = "22222222-2222-4222-8222-222222222222";
|
||
assert.equal(alreadyDelivered({ caseId, resultId, hasUserMessage: false, now: 1_000 }), false);
|
||
markDeliveryTurn({ caseId, resultId, now: 1_000 });
|
||
assert.equal(alreadyDelivered({ caseId, resultId, hasUserMessage: false, now: 1_500 }), true);
|
||
assert.equal(alreadyDelivered({ caseId, resultId, hasUserMessage: true, now: 1_500 }), false);
|
||
assert.equal(alreadyDelivered({
|
||
caseId,
|
||
resultId: "33333333-3333-4333-8333-333333333333",
|
||
hasUserMessage: false,
|
||
now: 1_500,
|
||
}), false);
|
||
assert.equal(alreadyDelivered({ caseId, resultId, hasUserMessage: false, now: 62_000 }), false);
|
||
resetDeliveryTurnGuardForTests();
|
||
});
|
||
|
||
test("agent-run returns already_delivered before billing and the route skips a second turn", () => {
|
||
const agentRun = readFileSync(new URL("../src/lib/rectification-agentic/v9/agent-run.ts", import.meta.url), "utf8");
|
||
const route = readFileSync(new URL("../src/app/api/rectification/agent/route.ts", import.meta.url), "utf8");
|
||
const exit = readFileSync(new URL("../src/lib/rectification-agentic/v9/turn-exit.ts", import.meta.url), "utf8");
|
||
const regenerate = readFileSync(
|
||
new URL("../src/app/api/rectification/cases/[caseId]/turns/[turnId]/regenerate/route.ts", import.meta.url),
|
||
"utf8",
|
||
);
|
||
const guardStart = agentRun.indexOf("alreadyDelivered({");
|
||
const reserve = agentRun.indexOf("const reserve = await billing.reserve()");
|
||
assert.ok(guardStart >= 0 && guardStart < reserve);
|
||
assert.match(agentRun, /errorCode: "already_delivered"/);
|
||
assert.match(route, /result\.errorCode === "already_delivered"/);
|
||
assert.match(route, /trigger: "opening"/);
|
||
assert.match(exit, /trigger: "finalizeSuccessfulTurnExit"/);
|
||
assert.match(regenerate, /trigger: "regenerate"/);
|
||
assert.match(route, /logRectificationDeliveryTurn/);
|
||
});
|
||
|
||
test("composer wrap no longer hosts 先这样 or the adopt status bar", () => {
|
||
const chat = readFileSync(new URL("../src/components/rectification-agentic-chat.tsx", import.meta.url), "utf8");
|
||
const wrap = chat.slice(chat.indexOf("className=\"composer-wrap\""), chat.indexOf("className=\"composer-footer\""));
|
||
assert.doesNotMatch(wrap, /CHOICE_STOP_LABEL/);
|
||
assert.doesNotMatch(wrap, /rectification-collect-stop/);
|
||
assert.doesNotMatch(wrap, /rectification-composer-meta/);
|
||
assert.doesNotMatch(wrap, /rectification-adopt-status/);
|
||
assert.match(chat, /CHOICE_STOP_LABEL/);
|
||
assert.match(chat, /postAdoptVerifyDoneCopy/);
|
||
});
|