import assert from "node:assert/strict"; import test from "node:test"; import { applyStepAnswerChunk, createStepAnswerState, flushStepAnswerOnStreamFinish, shouldPublishStepText, } from "../src/lib/rectification-agentic/v9/step-answer.ts"; import { mapStreamChunkToPhase, mapStreamChunkToThinking } from "../src/lib/rectification-agentic/v9/stream-mapping.ts"; import { PUBLIC_RECTIFICATION_TOOLS } from "../src/lib/rectification-agentic/v9/public-receipt.ts"; function isPublicTool(name: string): boolean { return (PUBLIC_RECTIFICATION_TOOLS as readonly string[]).includes(name); } function chunk(type: string, payload?: Record) { return { type, payload }; } test("does not publish intermediate tool-step text as answer.delta", () => { const state = createStepAnswerState(); applyStepAnswerChunk(state, chunk("text-delta", { text: "Let me set" }), isPublicTool); applyStepAnswerChunk(state, chunk("tool-call", { toolName: "rectification-record-evidence-batch" }), isPublicTool); const afterTool = applyStepAnswerChunk( state, chunk("tool-result", { toolName: "rectification-record-evidence-batch" }), isPublicTool, ); assert.equal(afterTool.kind, "discard"); applyStepAnswerChunk(state, chunk("text-delta", { text: "记下了,2020年4月开始实习。" }), isPublicTool); const finish = applyStepAnswerChunk(state, chunk("step-finish", { reason: "stop" }), isPublicTool); assert.deepEqual(finish, { kind: "publish", pieces: ["记下了,2020年4月开始实习。"] }); }); test("never publishes reasoning-delta to the browser", () => { assert.equal(mapStreamChunkToPhase(chunk("reasoning-delta", { text: "Let me" }) as never), null); assert.equal(mapStreamChunkToPhase(chunk("text-delta", { text: "Let me" }) as never), null); assert.ok(mapStreamChunkToThinking(chunk("reasoning-delta", { text: "先核对经历。" }) as never)); }); test("publishes only the terminal no-tool step as assistant text", () => { const state = createStepAnswerState(); applyStepAnswerChunk(state, chunk("step-start"), isPublicTool); applyStepAnswerChunk(state, chunk("text-delta", { text: "_probe" }), isPublicTool); applyStepAnswerChunk(state, chunk("tool-call", { toolName: "rectification-compare-candidates" }), isPublicTool); applyStepAnswerChunk(state, chunk("step-finish", { stepResult: { reason: "tool-calls" } }), isPublicTool); assert.equal(shouldPublishStepText({ calledTool: true, text: "_probe" }, "tool-calls"), false); applyStepAnswerChunk(state, chunk("step-start"), isPublicTool); applyStepAnswerChunk(state, chunk("text-delta", { text: "已经记下实习。" }), isPublicTool); const finish = flushStepAnswerOnStreamFinish(state, "stop"); assert.deepEqual(finish, { kind: "publish", pieces: ["已经记下实习。"] }); });