import assert from "node:assert/strict"; import test from "node:test"; import { chartCalculationProgressLabel } from "../src/lib/consultation-activity-labels.ts"; import { generalConsultationThinkingPlan, natalConsultationThinkingPlan } from "../src/lib/consultation-thinking-plan.ts"; import { consultationTimelineFromSettled, emptyConsultationTimeline, reduceConsultationTimelineEvents, } from "../src/lib/consultation-run-timeline.ts"; test("career and wealth events append method, calculate 1/2, think, then the first write", () => { const [foundation] = natalConsultationThinkingPlan({ domains: ["career", "wealth"] }); assert.ok(foundation); const afterProgress = reduceConsultationTimelineEvents([ { type: "skill.started", name: "jyotish-vedic-astrology" }, { type: "skill.completed", name: "jyotish-vedic-astrology" }, { type: "tool.started", callId: "tool-1", tool: "run-jyotish-consultation", label: "正在计算本命盘…", }, { type: "activity", phase: "chart-calculation", label: chartCalculationProgressLabel(1, 2), }, ], emptyConsultationTimeline()); assert.deepEqual(afterProgress.rows.map((row) => row.kind), ["method", "calculate"]); assert.equal(afterProgress.rows[1]?.status, "live"); assert.equal(afterProgress.rows[1]?.label, "正在计算本命盘(第 1/2 项)…"); const state = reduceConsultationTimelineEvents([ { type: "thinking.section", ...foundation }, { type: "answer.delta", text: "## 统一参数与原始结构\n岁差 Lahiri。\n" }, ], afterProgress); assert.deepEqual(state.rows.map((row) => row.kind), ["method", "calculate", "think", "write"]); assert.equal(state.rows[1]?.status, "done"); assert.equal(state.rows[2]?.label, "先整理本盘的统一参数"); assert.equal(state.rows[2]?.status, "done"); assert.equal(state.rows[3]?.id, "write-统一参数与原始结构"); assert.equal(state.rows[3]?.status, "live"); assert.match(state.rows[3]?.label ?? "", /正在写统一参数与原始结构/); }); test("thinking after a tool starts a new think row instead of reopening the first", () => { const state = reduceConsultationTimelineEvents([ { type: "thinking.delta", text: "先确认用户说的是入职当天。" }, { type: "tool.started", callId: "tool-1", tool: "run-jyotish-consultation", label: "正在计算本命盘…", }, { type: "thinking.delta", text: "再按宫位写。" }, ]); assert.deepEqual(state.rows.map((row) => row.kind), ["think", "calculate", "think"]); assert.equal(state.rows[0]?.status, "done"); assert.equal(state.rows[0]?.thinkingText, "先确认用户说的是入职当天。"); assert.equal(state.rows[2]?.status, "live"); assert.equal(state.rows[2]?.thinkingText, "再按宫位写。"); assert.notEqual(state.rows[0]?.id, state.rows[2]?.id); }); test("idle chat without a natal calculation has no calculate row", () => { const [section] = generalConsultationThinkingPlan(); assert.ok(section); const state = reduceConsultationTimelineEvents([ { type: "skill.started", name: "jyotish-vedic-astrology" }, { type: "skill.completed", name: "jyotish-vedic-astrology" }, { type: "thinking.section", ...section }, { type: "thinking.delta", text: "先按问题组织回答。" }, { type: "answer.delta", text: "今日宜稳,不宜强推。" }, { type: "run.completed", receipt: { runId: "settled", runtime: "mastra-agentic", skill: { name: "jyotish-vedic-astrology", loaded: true, referenceReads: 0, methodologySections: 0 }, steps: [], workflow: { route: "general-no-birth-time", status: "ready", preciseTiming: "blocked", missingLayers: ["birth-minute"] }, }, }, ]); assert.equal(state.rows.some((row) => row.kind === "calculate"), false); assert.deepEqual(state.rows.map((row) => row.kind), ["method", "think", "write"]); assert.equal(state.rows[1]?.thinkingText, "先按问题组织回答。"); }); test("settled natal messages hydrate a calculate row from domain sections", () => { const sections = natalConsultationThinkingPlan({ domains: ["career", "wealth"] }); const rows = consultationTimelineFromSettled({ text: "## 统一参数与原始结构\n岁差。\n## 事业\n方向稳定。\n", thinkingSections: sections, thinkingText: "先对照 D10。", }); assert.ok(rows.some((row) => row.kind === "calculate")); assert.ok(rows.some((row) => row.kind === "think" && row.label.includes("事业"))); const calculate = rows.find((row) => row.kind === "calculate"); assert.ok(calculate?.queries?.includes("事业")); assert.ok(calculate?.queries?.includes("D10")); assert.ok(calculate?.queries?.includes("财富")); });