814c924e4a
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
159 lines
5.2 KiB
TypeScript
159 lines
5.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
ACCEPTED_RANGE_READING_INSTRUCTION,
|
|
createBirthTimeModeOutputGuard,
|
|
} from "../src/lib/consultation-birth-time-mode.ts";
|
|
import { RANGE_READING_COPY } from "../src/lib/rectification-agentic/v9/adopt-narration.ts";
|
|
import {
|
|
createConsultationRuntimeState,
|
|
createWindowConsultationTools,
|
|
} from "../src/mastra/consultation-tools.ts";
|
|
import {
|
|
consultationWorkflowReceipt,
|
|
minuteSensitiveThemesFromBirthTimeSensitivity,
|
|
} from "../src/mastra/consultation-workflow.ts";
|
|
|
|
const toolContext = {
|
|
observe: { span: async (_name: string, fn: () => Promise<unknown>) => fn(), log() {} },
|
|
} as never;
|
|
|
|
test("theme_sensitivity maps sensitive keys onto the consultation answer policy", () => {
|
|
const themes = minuteSensitiveThemesFromBirthTimeSensitivity({
|
|
theme_sensitivity: {
|
|
career: { status: "stable" },
|
|
marriage: { status: "sensitive" },
|
|
wealth: { status: "stable" },
|
|
},
|
|
});
|
|
assert.deepEqual(themes, ["marriage"]);
|
|
|
|
const receipt = consultationWorkflowReceipt({
|
|
consumer_context: {
|
|
route: "career",
|
|
core_status: "ready",
|
|
available_layers: [],
|
|
missing_route_layers: [],
|
|
hard_blockers: [],
|
|
answer_policy: {
|
|
can_answer_direction: true,
|
|
can_answer_precise_timing: true,
|
|
minute_sensitive_themes: ["marriage"],
|
|
},
|
|
},
|
|
});
|
|
assert.deepEqual(receipt.minuteSensitiveThemes, ["marriage"]);
|
|
});
|
|
|
|
test("minute-sensitive or timing themes use the precise-timing output guard", () => {
|
|
const text = "Rahu 大运为 2013年11月21日 至 2031年11月22日。";
|
|
const marriage = createBirthTimeModeOutputGuard("verified_chart", true, {
|
|
currentTheme: "marriage",
|
|
minuteSensitiveThemes: ["marriage"],
|
|
})(text);
|
|
assert.match(marriage, /具体时间已省略/);
|
|
|
|
const career = createBirthTimeModeOutputGuard("verified_chart", true, {
|
|
currentTheme: "career",
|
|
minuteSensitiveThemes: ["marriage"],
|
|
})(text);
|
|
assert.equal(career, text);
|
|
|
|
const timing = createBirthTimeModeOutputGuard("verified_chart", true, {
|
|
currentTheme: "timing",
|
|
minuteSensitiveThemes: [],
|
|
})(text);
|
|
assert.match(timing, /具体时间已省略/);
|
|
});
|
|
|
|
test("declared window consultation merges range-reading themes and says it is a coarse look", async () => {
|
|
const state = createConsultationRuntimeState();
|
|
const tools = createWindowConsultationTools({
|
|
userId: "u",
|
|
sessionId: "s",
|
|
requestId: "r-window",
|
|
consultationMode: "declared_birth_window",
|
|
declaredWindow: {
|
|
name: "测试",
|
|
toolInput: {
|
|
year: 1997,
|
|
month: 8,
|
|
day: 8,
|
|
city: "邯郸",
|
|
lat: 36.4,
|
|
lon: 114.2,
|
|
tz: 8,
|
|
ayanamsa: "raman",
|
|
rangeStart: "14:00",
|
|
rangeEnd: "18:00",
|
|
},
|
|
truth: {
|
|
birthDate: "1997-08-08",
|
|
birthTimeSource: "period_only",
|
|
birthTimePeriod: "afternoon",
|
|
birthTimeStatus: "reported",
|
|
wrapsMidnight: false,
|
|
placeLabel: "邯郸",
|
|
placeCodes: {
|
|
countryCode: "CN",
|
|
provinceCode: null,
|
|
cityCode: null,
|
|
districtCode: null,
|
|
},
|
|
placeId: null,
|
|
placeType: null,
|
|
placeProvider: null,
|
|
timezoneId: null,
|
|
timezoneSource: null,
|
|
latitude: 36.4,
|
|
longitude: 114.2,
|
|
timezoneOffset: 8,
|
|
},
|
|
},
|
|
state,
|
|
fetchWindowChart: async () => ({
|
|
declared_range: { start: "14:00", end: "18:00", wraps_midnight: false },
|
|
probe_count: 3,
|
|
probes: [
|
|
{ clock: "14:00", role: "range_start" as const },
|
|
{ clock: "16:00", role: "interior" as const },
|
|
{ clock: "18:00", role: "range_end" as const },
|
|
],
|
|
stable_layers: { planet_signs: { sun: "Cancer" } },
|
|
varying_layers: { ascendant_signs: ["Libra", "Scorpio"] },
|
|
blocked_layers: ["precise-timing"],
|
|
answer_policy: {
|
|
can_answer_direction: true,
|
|
can_answer_precise_timing: false as const,
|
|
birth_time_confidence: "declared_window" as const,
|
|
candidate_is_confirmed: false as const,
|
|
},
|
|
result_hash: "fictional-window",
|
|
}),
|
|
runRangeReading: async () => ({
|
|
stableThemes: ["career"],
|
|
sensitiveThemes: ["marriage"],
|
|
claimBoundary: RANGE_READING_COPY.boundary,
|
|
themeSensitivity: {},
|
|
window: null,
|
|
}),
|
|
});
|
|
const result = await tools["run-jyotish-window-consultation"].execute!(
|
|
{ question: "婚姻如何" },
|
|
toolContext,
|
|
) as {
|
|
answer_policy: { minute_sensitive_themes: string[] };
|
|
evidence_contract: { user_facing_limitation: string };
|
|
};
|
|
assert.deepEqual(result.answer_policy.minute_sensitive_themes, ["marriage"]);
|
|
assert.match(result.evidence_contract.user_facing_limitation, /这只是粗看/);
|
|
assert.deepEqual(state.workflowReceipt?.minuteSensitiveThemes, ["marriage"]);
|
|
|
|
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
|
|
assert.match(route, /这只是粗看/);
|
|
assert.match(route, /ACCEPTED_RANGE_READING_INSTRUCTION/);
|
|
assert.match(ACCEPTED_RANGE_READING_INSTRUCTION, /不是已确认的唯一出生分钟/);
|
|
});
|