返回 DeepSeek-Reasonix
canonical-user-display.test.ts
根目录 / desktop / frontend / src / __tests__ / canonical-user-display.test.ts
1 import assert from "node:assert/strict";
2 import { readFileSync } from "node:fs";
3 import { canonicalMessage } from "../lib/canonicalTranscriptBackend";
4 import { transientUserTags } from "../lib/canonicalUserDisplay";
5 import { applyResolvedField, entryToRecord } from "../lib/transcriptRecordProjection";
6 import { historyMessagesToItems } from "../lib/useController";
7 import type { HistoryContentRef } from "../lib/types";
8
9 const persistent = { messageId: "user-1", position: 2, version: 1, role: "user", eventSequence: 2, visibleTurn: 1 };
10 const context = '<session-context version="1">\nThis host-generated snapshot supersedes every earlier session-context snapshot.\nEnvironment: private host context\n</session-context>';
11 const wrapped = "<response-language>prefer Chinese</response-language>\n<reasoning-language>中文</reasoning-language>\n你是谁";
12 const visible = (raw: Record<string, unknown>) => canonicalMessage(persistent, raw);
13 const items = (raw: Record<string, unknown>) => historyMessagesToItems([visible(raw)], "test").items;
14
15 // The existing Go display vocabulary remains authoritative for host wrappers.
16 const goSource = readFileSync(new URL("../../../../internal/agent/preview.go", import.meta.url), "utf8");
17 const goTags = [...goSource.match(/var TransientUserBlockTags = \[\]string\{([\s\S]*?)\n\}/)![1].matchAll(/"([\w-]+)"/g)].map(match => match[1]);
18 assert.deepEqual([...transientUserTags], goTags);
19 for (const tag of transientUserTags) {
20 assert.equal(visible({ role: "user", content: `<${tag} version="1">internal</${tag}>\n你是谁` }).content, "你是谁");
21 }
22 assert.equal(visible({ role: "user", content: wrapped }).content, "你是谁");
23 assert.equal(visible({ role: "user", content: wrapped, raw_content: "用户原文" }).content, "用户原文");
24 assert.equal(visible({ role: "user", raw_content: "只有原文" }).content, "只有原文");
25 for (const raw of [
26 { role: "user", origin: "host", content: context },
27 { role: "user", origin: "host", content: "background job protocol", raw_content: "also internal" },
28 { role: "user", content: context },
29 { role: "user", content: "<response-language>internal only</response-language>" },
30 ]) assert.equal(items(raw).length, 0, JSON.stringify(raw));
31 for (const literal of [context, "<response-language>user example</response-language>", "```xml\n" + context + "\n```", "Explain <reasoning-language> in XML"]) {
32 assert.equal(visible({ role: "user", origin: "user", content: wrapped, raw_content: literal }).content, literal);
33 }
34 for (const role of ["assistant", "tool"]) assert.equal(canonicalMessage({ ...persistent, role }, { role, content: context }).content, context);
35 const steerPrefix = "[Mid-turn steer queued by the user. Do not treat this as a new task; use it only as additional guidance for the current task after completing the current step.]";
36 assert.equal(visible({ role: "user", content: `${steerPrefix}\n补充说明` }).content, "↪ 补充说明");
37 assert.equal(visible({ role: "user", content: `${steerPrefix}\n补充说明` }).role, "notice");
38 assert.equal(items({ role: "user", content: `${steerPrefix}\nA tool failed. Use read-only diagnosis as needed` }).length, 0);
39 const compiler = `<memory-compiler-execution>${JSON.stringify({ planner_ir: { source_event: wrapped } })}</memory-compiler-execution>`;
40 assert.equal(visible({ role: "user", content: compiler }).content, "你是谁");
41 for (const suffix of ["<execution-policy>policy</execution-policy>", "<memory-recall>memory</memory-recall>"]) {
42 assert.equal(visible({ role: "user", content: `你是谁\n${suffix}` }).content, "你是谁");
43 }
44 assert.equal(visible({ role: "user", content: `# Reasonix executor handoff\n\nOriginal task:\n${wrapped}\n\nPlanner output:\nprivate plan` }).content, "你是谁");
45
46 // Lazy full-body hydration must use the same projection as inline history.
47 for (const [origin, expected] of [["host", ""], ["user", "你是谁"]]) {
48 const raw = { id: persistent.messageId, role: "user", origin, content: `<capability-route>${"x".repeat(40000)}</capability-route>\n你是谁`, raw_content: origin === "user" ? "你是谁" : undefined };
49 const original = JSON.stringify(raw);
50 const ref: HistoryContentRef = { entryId: "m:user-1", field: "canonicalMessage", size: original.length, chunks: 1, revision: 1, digest: "fixture" };
51 const record = entryToRecord({ entryId: "m:user-1", turn: 1, order: 2, message: canonicalMessage({ ...persistent, preview: expected }, undefined), refs: [ref] });
52 const data = [...new TextEncoder().encode(original)].map(byte => String.fromCharCode(byte)).join("");
53 assert.equal(applyResolvedField(record, ref, data), true);
54 assert.equal(record.message.content, expected);
55 assert.equal(record.message.messageId, persistent.messageId);
56 assert.equal(JSON.stringify(raw), original, "display never mutates source content");
57 assert.equal(historyMessagesToItems([record.message], "test").items.length, origin === "host" ? 0 : 1);
58 }
59 console.log("PASS authored chat text, host filtering, literal markup, legacy wrappers, steers and lazy hydration");
60
60 lines TYPESCRIPT