import assert from "node:assert/strict"; import test from "node:test"; import { Agent } from "@mastra/core/agent"; import { validatePersonalReportAgentOutputAgainstPlan } from "../src/lib/personal-report-generation.ts"; import type { PersonalReportSectionPlan } from "../src/lib/personal-report-plan.ts"; import type { ReportEvidenceBundleV2 } from "../src/lib/report-evidence-bundle-v2.ts"; import { createPersonalReportAgent, type PersonalReportAgentOutput } from "../src/mastra/personal-report.ts"; // Writer-boundary unit inputs contain no astrological facts or fabricated engine payload. const plan: PersonalReportSectionPlan = { schemaVersion: "personal_report_section_plan.v1", depth: "standard", sections: [] }; const bundle = { claimCards: [] } as unknown as ReportEvidenceBundleV2; function prose(): PersonalReportAgentOutput { return { executiveSummary: { headline: "先把已有安排理清", summary: "把要做的事写下来,再安排下一步。", priorities: ["核对现有安排"] }, thematicNarrative: [], }; } const forbiddenCases = { "Markdown table": () => ({ ...prose(), executiveSummary: { ...prose().executiveSummary, summary: "| 项目 | 说明 |\n| --- | --- |\n| 安排 | 待核对 |" } }), "HTML table in nested array": () => ({ ...prose(), executiveSummary: { ...prose().executiveSummary, priorities: ['
待核对
'] } }), "factTables top-level key": () => ({ ...prose(), factTables: [] }), "factTables nested key": () => ({ ...prose(), executiveSummary: { ...prose().executiveSummary, factTables: [] } }), }; for (const [name, output] of Object.entries(forbiddenCases)) { test(`writer rejects ${name} with the exact fact-table error code`, () => { assert.throws(() => validatePersonalReportAgentOutputAgainstPlan(output(), plan, bundle), { name: "Error", message: "report_writer_fact_tables_forbidden", }); }); } test("writer accepts normal prose unchanged, including a non-table inline pipe", () => { const output = { ...prose(), executiveSummary: { ...prose().executiveSummary, summary: prose().executiveSummary.summary + "安排 A | 安排 B 只是两种写法,不是表格。", } }; assert.strictEqual(validatePersonalReportAgentOutputAgainstPlan(output, plan, bundle), output); }); test("actual writer agent instructions prohibit tables and assign them to the system", async (t) => { let calls = 0; t.mock.method(Agent.prototype, "generate", async function (this: Agent) { calls++; const instructions = await this.getInstructions(); assert.match(String(instructions), /不要输出表格,表格由系统提供/); assert.match(String(instructions), /Markdown 表格、HTML table 或 factTables 字段/); return { object: prose(), usage: { inputTokens: 1, outputTokens: 1 }, finishReason: "stop" }; }); const writer = createPersonalReportAgent({ id: "writer-table-contract", label: "Writer test", description: "Writer test", creditCost: 0, isDefault: false, mode: "openai", model: { specificationVersion: "v2", provider: "writer-test", modelId: "writer-test" } as never, }); assert.deepEqual(await writer.generate(bundle, plan), prose()); assert.equal(calls, 1); });