155 lines
6.4 KiB
TypeScript
155 lines
6.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { withSpokenPrompt } from "../src/lib/rectification-agentic/v9/spoken-prompt.ts";
|
|
import { projectCurrentQuestion } from "../src/lib/rectification-agentic/v9/turn-decision.ts";
|
|
import {
|
|
TARGETED_YEAR_PROMPT,
|
|
isYearStageQuestionId,
|
|
pendingTargetedYearDomain,
|
|
} from "../src/lib/rectification-agentic/v9/collection-question-pool.ts";
|
|
import {
|
|
collectFocusSchema,
|
|
isCollectFocusSchema,
|
|
persistServerOwnedFocus,
|
|
shouldResolveCollectFocusAfterEvidence,
|
|
} from "../src/lib/rectification-agentic/v9/server-focus.ts";
|
|
import { shouldHostReaskYearEntry, userMessageHasYear } from "../src/lib/rectification-agentic/v9/year-entry-host.ts";
|
|
import { TARGETED_COLLECT_OPTION_A } from "../src/lib/rectification-agentic/v9/choice-card.ts";
|
|
import { targetedCollectYearFollowup as yearFollowup } from "../src/lib/rectification-agentic/v9/method-followup.ts";
|
|
import {
|
|
CASE_ID,
|
|
FOCUS_ID,
|
|
USER_ID,
|
|
fakeAccounting,
|
|
} from "./rectification-v9-test-support.ts";
|
|
|
|
const YEAR_Q = "collect:targeted:health_pressure:year";
|
|
const SERVER_PROMPT = TARGETED_YEAR_PROMPT;
|
|
const FOLLOWUP = "2019年3月这次手术,是你本人做的吗?";
|
|
|
|
test("year-stage set-focus overlay keeps the server prompt (BUG-908)", () => {
|
|
const schema = {
|
|
collect: true,
|
|
prompt: SERVER_PROMPT,
|
|
};
|
|
const next = withSpokenPrompt(schema, FOLLOWUP, YEAR_Q);
|
|
assert.equal(next.prompt, SERVER_PROMPT);
|
|
assert.equal(next.spoken_prompt, FOLLOWUP);
|
|
const question = projectCurrentQuestion({
|
|
id: FOCUS_ID,
|
|
questionId: YEAR_Q,
|
|
intent: "collect_method_evidence",
|
|
targetDomain: "health_pressure",
|
|
expectedAnswerSchema: next,
|
|
});
|
|
assert.equal(question?.prompt, SERVER_PROMPT);
|
|
assert.equal(question?.kind, "collect_spoken");
|
|
});
|
|
|
|
test("year-stage questions are typed collect, not an entry card (T0)", () => {
|
|
assert.equal(isYearStageQuestionId(YEAR_Q), true);
|
|
assert.equal(isYearStageQuestionId("collect:targeted:health_pressure"), false);
|
|
assert.equal(TARGETED_COLLECT_OPTION_A, "有,我来说");
|
|
const chat = readFileSync(new URL("../src/components/rectification-agentic-chat.tsx", import.meta.url), "utf8");
|
|
assert.doesNotMatch(chat, /EventDateEntryCard|event_date_entry/);
|
|
const followup = yearFollowup("health_pressure");
|
|
const schema = collectFocusSchema(followup);
|
|
assert.ok(isCollectFocusSchema(schema));
|
|
assert.equal(schema?.event_date_entry, undefined);
|
|
assert.equal(followup.spoken_prompt, TARGETED_YEAR_PROMPT);
|
|
});
|
|
|
|
test("batch and propose-evidence share the same collect-focus resolve (BUG-909)", () => {
|
|
const tools = readFileSync(new URL("../src/mastra/rectification-v9-tools.ts", import.meta.url), "utf8");
|
|
const first = tools.indexOf("await resolveActiveCollectFocusAfterEvidence(");
|
|
const second = tools.indexOf("await resolveActiveCollectFocusAfterEvidence(", first + 1);
|
|
assert.ok(first > 0 && second > first);
|
|
assert.equal(tools.indexOf("await resolveActiveCollectFocusAfterEvidence(", second + 1), -1);
|
|
});
|
|
|
|
test("dated evidence closes the year stage for that domain (BUG-909)", () => {
|
|
const topics = [{
|
|
questionId: "collect:targeted:health_pressure",
|
|
target_domain: "health_pressure",
|
|
status: "resolved",
|
|
intent: "collect_method_evidence",
|
|
}];
|
|
assert.equal(pendingTargetedYearDomain(topics, []), "health_pressure");
|
|
assert.equal(pendingTargetedYearDomain(topics, [{
|
|
status: "confirmed",
|
|
domain: "health",
|
|
datePrecision: "month",
|
|
occurredFrom: "2019-03-01",
|
|
occurredTo: "2019-03-01",
|
|
}]), null);
|
|
const schema = collectFocusSchema(yearFollowup("health_pressure"));
|
|
assert.equal(shouldResolveCollectFocusAfterEvidence({
|
|
intent: "collect_method_evidence",
|
|
questionId: YEAR_Q,
|
|
expectedAnswerSchema: schema ?? { collect: true, prompt: SERVER_PROMPT },
|
|
}), true);
|
|
});
|
|
|
|
test("persist year followup writes a collect schema that batch can resolve (BUG-909 a)", async () => {
|
|
const accounting = fakeAccounting({
|
|
set_agentic_rectification_conversation_focus: (_fn, args) => ({
|
|
focus: {
|
|
id: FOCUS_ID,
|
|
case_id: CASE_ID,
|
|
question_id: args.p_question_id,
|
|
intent: args.p_intent,
|
|
target_domain: args.p_target_domain,
|
|
expected_answer_schema: args.p_expected_answer_schema,
|
|
status: "active",
|
|
asked_at: "2026-09-16T00:00:00.000Z",
|
|
},
|
|
idempotent: false,
|
|
}),
|
|
});
|
|
const result = await persistServerOwnedFocus({
|
|
accounting: accounting.client,
|
|
userId: USER_ID,
|
|
caseId: CASE_ID,
|
|
activeFocus: null,
|
|
decisionReceipt: null,
|
|
followup: yearFollowup("health_pressure"),
|
|
});
|
|
assert.equal(result.status, "created");
|
|
assert.equal(isCollectFocusSchema(result.focus?.expectedAnswerSchema ?? null), true);
|
|
assert.equal(result.focus?.expectedAnswerSchema.prompt, TARGETED_YEAR_PROMPT);
|
|
assert.equal(result.focus?.expectedAnswerSchema.event_date_entry, undefined);
|
|
});
|
|
|
|
test("yearless short replies are held by the host pre-step (BUG-910)", () => {
|
|
assert.equal(userMessageHasYear("是"), false);
|
|
assert.equal(userMessageHasYear("不是本人"), false);
|
|
assert.equal(userMessageHasYear("2019年3月做过手术"), true);
|
|
assert.equal(userMessageHasYear("2020 年住院"), true);
|
|
const focus = {
|
|
questionId: YEAR_Q,
|
|
expectedAnswerSchema: { collect: true, prompt: SERVER_PROMPT },
|
|
};
|
|
assert.equal(shouldHostReaskYearEntry(focus, "是"), SERVER_PROMPT);
|
|
assert.equal(shouldHostReaskYearEntry(focus, "2019年3月做过手术"), null);
|
|
const agentRun = readFileSync(new URL("../src/lib/rectification-agentic/v9/agent-run.ts", import.meta.url), "utf8");
|
|
const reliability = agentRun.indexOf("classifyDateReliabilityUtterance");
|
|
const yearHost = agentRun.indexOf("shouldHostReaskYearEntry");
|
|
const reserve = agentRun.indexOf("billing.reserve");
|
|
assert.ok(reliability > 0 && yearHost > reliability && reserve > yearHost);
|
|
});
|
|
|
|
test("standalone persisted question shares the assistant inset (BUG-911)", () => {
|
|
const styles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
|
assert.match(
|
|
styles,
|
|
/\.rectification-message-question\.is-standalone \{[\s\S]*margin-inline-start: var\(--assistant-content-inset\)/,
|
|
);
|
|
assert.match(
|
|
styles,
|
|
/\.rectification-message-question\.is-standalone \.rectification-choice-card\.is-embedded \{[\s\S]*margin-inline-start: 0/,
|
|
);
|
|
assert.doesNotMatch(styles, /\.rectification-event-entry \{/);
|
|
});
|