返回 DeepSeek-Reasonix
chat-file-reference-fixture.tsx
根目录 / desktop / frontend / bench / chat-file-reference-fixture.tsx
1 // Fixture for bench/chat-file-reference.mjs: one assistant answer that names a
2 // file in inline code and shows an SVG fence, wired to the same providers the
3 // transcript uses.
4 import { Fragment, useSyncExternalStore } from "react";
5 import { createRoot } from "react-dom/client";
6 import { LocaleProvider } from "../src/lib/i18n";
7 import { parseMarkdownToBlocks } from "../src/lib/markdownPipeline";
8 import { hastBlockToJsx } from "../src/lib/hastJsx";
9 import { createComponents } from "../src/components/markdownComponents";
10 import { ChatFileScopeProvider, ChatFileTurnProvider, useChatFileCandidateReport } from "../src/components/ChatFileLinkContext";
11 import { fileNavigationOwner } from "../src/lib/fileNavigationCommands";
12 import { useActivityBarStore } from "../src/store/activityBar";
13 import { installDesktopHostStub } from "../src/__tests__/desktopHostStub";
14 import type { AppBindings } from "../src/lib/bridge";
15
16 // Deliberately namespace-free: the model's usual spelling, and the one
17 // that used to fail to render as an image.
18 const SVG = `<svg viewBox="0 0 20 10">
19 <defs><linearGradient id="g"><stop offset="0" stop-color="#f60"/></linearGradient></defs>
20 <rect width="20" height="10" fill="url(#g)"/>
21 <text x="2" y="7">preview</text>
22 </svg>`;
23
24 // The sanitizer runs in the Go host, which this browser fixture cannot call.
25 // SANITIZED is therefore the host's real output for SVG above, captured byte
26 // for byte and pinned by TestMarkdownSVGBenchFixtureMatchesTheSanitizer: if the
27 // host stops producing these bytes that Go test fails and this fixture must be
28 // updated. Rendering a hand-written stand-in instead is exactly how a preview
29 // that never loads in a browser still passes.
30 const SANITIZED = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 10">
31 <defs><linearGradient id="g"><stop offset="0" stop-color="#f60"></stop></linearGradient></defs>
32 <rect width="20" height="10" fill="url(#g)"></rect>
33 <text x="2" y="7">preview</text>
34 </svg>`;
35
36 installDesktopHostStub(({
37 main: {
38 App: {
39 ResolveChatFileReferencesForTab: async (_tabId: string, turnKey: string, candidates: Array<{ key: string; path: string }>) => ({
40 turnKey,
41 references: candidates.map(candidate => candidate.path === "/repo/out/diagram.svg"
42 ? { key: candidate.key, path: candidate.path, status: "resolved", displayPath: "out/diagram.svg", kind: "image", actions: ["preview", "reveal-tree", "copy-path", "save-copy", "source", "open-native", "reveal-native"] }
43 : { key: candidate.key, path: candidate.path, status: "unavailable", actions: [], reason: "not-found" }),
44 }),
45 SanitizeMarkdownSVG: async (content: string) => ({ ok: true, svg: content.includes("linearGradient id=\"g\"") && content.includes("/>") ? SANITIZED : content }),
46 ResolveReferencePathForTab: async (_tabId: string, path: string) => path.startsWith("/") ? path : `/repo/${path}`,
47 ReadReferenceFileForTab: async (_tabId: string, path: string) => ({ path, body: "PREVIEW BODY", size: 12, truncated: false, binary: false }),
48 } as Partial<AppBindings> as AppBindings,
49 },
50 }).main.App);
51
52 const blocks = parseMarkdownToBlocks(`Wrote \`/repo/out/diagram.svg\` and used \`/repo/out/missing.svg\`.\n\n\`\`\`svg\n${SVG}\n\`\`\`\n`);
53 const components = createComponents(false);
54
55 /** Surfaces the running owner's committed navigation result. */
56 function RequestProbe() {
57 const owner = fileNavigationOwner();
58 const snapshot = useSyncExternalStore(owner.subscribe, () => {
59 const dock = useActivityBarStore.getState().tabs.find(tab => tab.type === "file");
60 return dock ? owner.getSnapshot(dock.id) : null;
61 });
62 const navigation = snapshot?.navigation;
63 return <pre id="request" hidden>{navigation ? JSON.stringify({
64 source: navigation.resource.access.source,
65 path: navigation.resource.requestedPath,
66 action: navigation.params.action,
67 }) : ""}</pre>;
68 }
69
70 function Reporter() {
71 useChatFileCandidateReport(blocks, 1);
72 return null;
73 }
74
75 createRoot(document.getElementById("root")!).render(
76 <LocaleProvider>
77 <ChatFileScopeProvider scopeKey="bench" tabId="tab-bench">
78 <ChatFileTurnProvider turnKey="turn-bench" factsVersion={1} presentedFiles={[]} modifiedFiles={[]} tabId="tab-bench">
79 <Reporter />
80 <div className="md">{blocks.map(block => <Fragment key={block.key}>{hastBlockToJsx(block, components)}</Fragment>)}</div>
81 </ChatFileTurnProvider>
82 </ChatFileScopeProvider>
83 <RequestProbe />
84 </LocaleProvider>,
85 );
86
86 lines Plain Text