7e3b6cdc7a
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>
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { PROBE_EXPLAIN_COPY } from "../src/lib/rectification-agentic/v9/probe-explain.ts";
|
|
import { projectRectificationStepState, STEP_STATE_COPY } from "../src/lib/rectification-agentic/v9/step-state.ts";
|
|
import { parseRectificationStepState } from "../src/lib/rectification-candidate-result.ts";
|
|
|
|
test("step state covers collect, discriminate, deliver, and post-adopt", () => {
|
|
const collect = projectRectificationStepState({
|
|
nextAction: "ask_fact_collection",
|
|
methodsCovered: false,
|
|
});
|
|
assert.equal(collect.stage, "collect");
|
|
assert.equal(collect.index, 1);
|
|
assert.match(collect.headline, /第 1 步/);
|
|
|
|
const discriminate = projectRectificationStepState({
|
|
nextAction: "ask_candidate_discriminator",
|
|
methodsCovered: true,
|
|
});
|
|
assert.equal(discriminate.stage, "discriminate");
|
|
assert.equal(discriminate.index, 2);
|
|
assert.match(discriminate.next, /先这样/);
|
|
|
|
const exhausted = projectRectificationStepState({
|
|
nextAction: "complete_with_range",
|
|
methodsCovered: true,
|
|
stopReason: "probe_pool_exhausted",
|
|
});
|
|
assert.equal(exhausted.stage, "deliver");
|
|
assert.match(exhausted.reason, /已经问完/);
|
|
|
|
const uncertain = projectRectificationStepState({
|
|
nextAction: "complete_with_range",
|
|
stopReason: "user_uncertainty_too_high",
|
|
});
|
|
assert.equal(uncertain.stage, "deliver");
|
|
assert.match(uncertain.reason, /说不好/);
|
|
|
|
const adopted = projectRectificationStepState({
|
|
accepted: true,
|
|
nextAction: "ask_holdout_validation",
|
|
});
|
|
assert.equal(adopted.stage, "post_adopt");
|
|
assert.equal(adopted.index, 4);
|
|
});
|
|
|
|
test("step state parser rejects forbidden certainty words", () => {
|
|
const parsed = parseRectificationStepState(projectRectificationStepState({
|
|
nextAction: "offer_provisional_range",
|
|
}));
|
|
assert.ok(parsed);
|
|
const blob = `${parsed.headline}${parsed.reason}${parsed.next}`;
|
|
assert.doesNotMatch(blob, /概率|置信度|确定/);
|
|
});
|
|
|
|
test("chat does not render the step-state strip above the composer", () => {
|
|
const chat = readFileSync(new URL("../src/components/rectification-agentic-chat.tsx", import.meta.url), "utf8");
|
|
const route = readFileSync(new URL("../src/app/api/rectification/cases/[caseId]/route.ts", import.meta.url), "utf8");
|
|
assert.doesNotMatch(chat, /rectification-step-state/);
|
|
assert.doesNotMatch(chat, /下一步:\{stepState\.next\}/);
|
|
// 原值: 「再补一件经历」后 composer-meta 显示收集提示
|
|
// 新值: 无 composer-meta;再补经历动作已删
|
|
// 原因: BUG-595 决策 1/2
|
|
assert.doesNotMatch(chat, /rectification-composer-meta/);
|
|
assert.match(route, /step_state: stepStateFromCaseDossier/);
|
|
});
|
|
|
|
test("explain-layer copy avoids probability words", () => {
|
|
const blob = [
|
|
...Object.values(PROBE_EXPLAIN_COPY),
|
|
...Object.values(STEP_STATE_COPY).flatMap((item) => Object.values(item)),
|
|
].join("\n");
|
|
assert.doesNotMatch(blob, /概率|置信度|确定/);
|
|
});
|