Files
Jyotisha/frontend/tests/rectification-step-answer.test.ts
T
jesse-uxandGrok (agent loop) 1f9947a0d7 删除三个无调用方接口和约 3000 行前端死代码
关掉未登录就会触发约 20 秒计算的入口,并记下 BUG-1342。普通导出的逐字节锁保留。自测 tsc 0 错,lint 0 error / 123 warning,改到的前端测试 fail=0,两份 Python 测试通过,test:db 失败 13 条与 Windows 已知清单一致。

Co-Authored-By: Grok (agent loop)
2026-10-14 08:39:32 +08:00

253 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import {
applyStepAnswerChunk,
createStepAnswerState,
flushStepAnswerOnStreamFinish,
shouldPublishStepText,
} from "../src/lib/rectification-agentic/v9/step-answer.ts";
import { mapStreamChunkToPhase } 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<string, unknown>) {
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");
const live = applyStepAnswerChunk(
state,
chunk("text-delta", { text: "记下了,2020年4月开始实习。" }),
isPublicTool,
);
assert.deepEqual(live, { kind: "live", text: "记下了,2020年4月开始实习。" });
const finish = applyStepAnswerChunk(state, chunk("step-finish", { reason: "stop" }), isPublicTool);
assert.equal(finish.kind, "none");
});
test("never publishes reasoning-delta to the browser", () => {
// 原值:mapStreamChunkToThinking 把中文 reasoning 变成 thinking.delta
// 新值:校正流对 reasoning-delta 必须丢弃;源码不得把它映射成对外事件
// 原因:BUG-953,token 级 thinking 是死链且违反 P2(provider reasoning 永不外发)
assert.equal(mapStreamChunkToPhase(chunk("reasoning-delta", { text: "Let me" }) as never), null);
assert.equal(mapStreamChunkToPhase(chunk("text-delta", { text: "Let me" }) as never), null);
const state = createStepAnswerState();
assert.equal(
applyStepAnswerChunk(state, chunk("reasoning-delta", { text: "先核对经历。" }), isPublicTool).kind,
"none",
);
const mapping = readFileSync(new URL("../src/lib/rectification-agentic/v9/stream-mapping.ts", import.meta.url), "utf8");
assert.doesNotMatch(mapping, /function mapStreamChunkToThinking|function toPublicThinkingDelta|InternalThinkingDeltaEvent/);
});
test("consecutive Chinese reasoning fragments assemble into a visible thinking line", () => {
// 原值:createThinkingFragmentAssembler 把「先核」+「对经历。」拼成可见思考行
// 新值:分片组装器删除;连续 reasoning-delta 仍全部丢弃
// 原因:BUG-953,翻转成否定合同,测试总数不降
const state = createStepAnswerState();
assert.equal(applyStepAnswerChunk(state, chunk("reasoning-delta", { text: "先核" }), isPublicTool).kind, "none");
assert.equal(applyStepAnswerChunk(state, chunk("reasoning-delta", { text: "对经历。" }), isPublicTool).kind, "none");
// 原值: 读 think-step-gate.ts,断言没有 acceptThinkingFragment / createThinkingFragmentAssembler
// 新值: 删掉这两行。上面连续 reasoning-delta 必须丢弃的断言保留
// 原因: 思考门文件已删除;reasoning-delta 仍一律丢弃(BUG-953)
});
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);
const live = applyStepAnswerChunk(state, chunk("text-delta", { text: "已经记下实习。" }), isPublicTool);
assert.deepEqual(live, { kind: "live", text: "已经记下实习。" });
const finish = flushStepAnswerOnStreamFinish(state, "stop");
assert.equal(finish.kind, "none");
});
test("streams terminal Chinese tokens live after compare", () => {
const state = createStepAnswerState();
applyStepAnswerChunk(
state,
chunk("tool-result", { toolName: "rectification-compare-candidates" }),
isPublicTool,
);
const first = applyStepAnswerChunk(state, chunk("text-delta", { text: "记下了," }), isPublicTool);
const second = applyStepAnswerChunk(
state,
chunk("text-delta", { text: "2020年4月开始实习。" }),
isPublicTool,
);
assert.deepEqual(first, { kind: "live", text: "记下了," });
assert.deepEqual(second, { kind: "live", text: "2020年4月开始实习。" });
assert.equal(applyStepAnswerChunk(state, chunk("step-finish", { reason: "stop" }), isPublicTool).kind, "none");
});
test("retracts a live spoken prefix if that step later calls a public tool", () => {
const state = createStepAnswerState();
applyStepAnswerChunk(
state,
chunk("tool-result", { toolName: "rectification-compare-candidates" }),
isPublicTool,
);
assert.deepEqual(
applyStepAnswerChunk(state, chunk("text-delta", { text: "记下了," }), isPublicTool),
{ kind: "live", text: "记下了," },
);
const retracted = applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-read-diagnostics" }),
isPublicTool,
);
assert.equal(retracted.kind, "retract");
applyStepAnswerChunk(
state,
chunk("tool-result", { toolName: "rectification-read-diagnostics" }),
isPublicTool,
);
const spoken = applyStepAnswerChunk(
state,
chunk("text-delta", { text: "诊断已经看过。接下来确认入职年份。" }),
isPublicTool,
);
assert.deepEqual(spoken, { kind: "live", text: "诊断已经看过。接下来确认入职年份。" });
});
test("keeps a live opening greeting when the next public tool is set-focus", () => {
const state = createStepAnswerState();
assert.deepEqual(
applyStepAnswerChunk(
state,
chunk("text-delta", { text: "你好,我们从你最容易想起的经历开始就行。" }),
isPublicTool,
),
{ kind: "live", text: "你好,我们从你最容易想起的经历开始就行。" },
);
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-set-focus" }),
isPublicTool,
).kind,
"none",
);
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-result", { toolName: "rectification-set-focus" }),
isPublicTool,
).kind,
"none",
);
// 原值: set-focus 后第二段 live 发布
// 新值: discard
// 原因: BUG-584 决策 2,保留 set-focus 前的问候,丢掉工具结果后的复述
assert.equal(
applyStepAnswerChunk(
state,
chunk("text-delta", { text: "我们慢慢来就好——想到哪件就聊哪件,不用一次说完。" }),
isPublicTool,
).kind,
"discard",
);
});
test("set-focus with no prior spoken text still publishes the later greeting", () => {
const state = createStepAnswerState();
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-set-focus" }),
isPublicTool,
).kind,
"none",
);
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-result", { toolName: "rectification-set-focus" }),
isPublicTool,
).kind,
"none",
);
assert.deepEqual(
applyStepAnswerChunk(
state,
chunk("text-delta", { text: "你好,我们从你最容易想起的经历开始就行。" }),
isPublicTool,
),
{ kind: "live", text: "你好,我们从你最容易想起的经历开始就行。" },
);
});
test("set-focus publishes an unfinished CJK remainder instead of dropping it", () => {
const state = createStepAnswerState();
assert.equal(
applyStepAnswerChunk(
state,
chunk("text-delta", { text: "范围已经收到 05:00 到 05:10" }),
isPublicTool,
).kind,
"none",
);
assert.deepEqual(
applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-set-focus" }),
isPublicTool,
),
{ kind: "publish", pieces: ["范围已经收到 05:00 到 05:10"] },
);
});
test("English planning before set-focus is still discarded", () => {
const state = createStepAnswerState();
assert.equal(
applyStepAnswerChunk(state, chunk("text-delta", { text: "Let me set the next collect focus" }), isPublicTool).kind,
"none",
);
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-set-focus" }),
isPublicTool,
).kind,
"discard",
);
});
test("does not live-publish English planning before a tool-call", () => {
const state = createStepAnswerState();
assert.equal(
applyStepAnswerChunk(state, chunk("text-delta", { text: "Let me set" }), isPublicTool).kind,
"none",
);
assert.equal(
applyStepAnswerChunk(state, chunk("text-delta", { text: " _probe" }), isPublicTool).kind,
"none",
);
assert.equal(
applyStepAnswerChunk(
state,
chunk("tool-call", { toolName: "rectification-record-evidence-batch" }),
isPublicTool,
).kind,
"none",
);
});