返回 DeepSeek-Reasonix
turn-result.tsx
根目录 / desktop / frontend / bench / turn-result.tsx
1 import React, { useState } from "react";
2 import { createRoot } from "react-dom/client";
3 import { Transcript } from "../src/components/Transcript";
4 import { WorkspaceTurnResult } from "../src/components/WorkspaceTurnResult";
5 import { initialState, reducer, type Item } from "../src/lib/useController";
6 import { historicalResultNotice } from "../src/lib/completionResultState";
7 import { app, type AppBindings } from "../src/lib/bridge";
8 import { installDesktopHostStub } from "../src/__tests__/desktopHostStub";
9 import { LocaleProvider, useI18n } from "../src/lib/i18n";
10 import type { TurnChanges, WireCompletionSummary, WireEvent } from "../src/lib/types";
11 import "../src/styles.css";
12
13 const path = "desktop/frontend/src/components/deeply/nested/very-long-component-name/WorkspaceTurnResult.tsx";
14 const diff: TurnChanges = { id: "0:42", turn: 0, coverage: "complete", added: 18, removed: 6, reasons: [], files: [
15 { path, kind: "modify", added: 15, removed: 6 },
16 { path: "internal/checkpoint/turn_changes.go", kind: "create", added: 3, removed: 0 },
17 ] };
18 let unavailable = false;
19 const calls: string[] = [];
20 const fallback = Object.fromEntries(["ReportFrontendDiagnostic", "ToolResultForTab", "ListDirForTab", "WorkspaceChanges"].map(k => [k, app[k as keyof AppBindings]]));
21 installDesktopHostStub(new Proxy({
22 ...fallback,
23 WorkspaceTurnChanges: async (_tab: string, _session: string, _turn: number, id: string) => { calls.push("summary:" + id); return unavailable ? { ...diff, id: undefined, coverage: "unknown", files: [] } : { ...diff, id }; },
24 WorkspaceTurnChangeDetail: async (_tab: string, _session: string, _turn: number, id: string, file: string) => { calls.push("detail:" + id); return unavailable ? null : { ...diff.files.find(f => f.path === file), patch: "@@ -1,2 +1,3 @@\n-old result\n+frozen result for " + id + "\n+confirmed changes\n context" }; },
25 TurnCheckLog: async (_tab: string, session: string, id: string) => { calls.push("log:" + session + ":" + id); return unavailable ? null : { output: "go test ./...\n--- FAIL: TestFrozenResult\nexpected 0, got 1\nFAIL\nexit status 1", truncated: false }; },
26 }, { get(target, key) { return target[key as keyof typeof target] ?? (async () => undefined); } }) as unknown as AppBindings);
27 (window as unknown as { turnResultCalls: string[] }).turnResultCalls = calls;
28
29 function snapshot(scenario: string) {
30 const event = (s: typeof initialState, e: WireEvent) => reducer(s, { type: "event", e });
31 let state = reducer(initialState, { type: "user", text: "完善本轮结果展示,保留历史差异和检查日志。" });
32 state = event(state, { kind: "turn_started", turnId: "fixture-turn", checkpointTurn: 0 });
33 state = event(state, { kind: "tool_dispatch", turnId: "fixture-turn", tool: { id: "check-1", name: "exec_command", args: '{"command":"go test ./..."}', readOnly: false } });
34 state = event(state, { kind: "tool_progress", turnId: "fixture-turn", tool: { id: "check-1", name: "exec_command", verifying: true, output: "running checkpoint tests..." } });
35 if (scenario === "running") return state;
36 const failed = scenario === "failed";
37 const checks = scenario === "none" ? [] : [{ command: "go test ./...", passed: !failed && scenario !== "interrupted", stale: scenario === "stale", interrupted: scenario === "interrupted", exitCode: failed ? 1 : 0, toolCallId: "check-1", toolResultId: "log-entry-1" }];
38 const receipt = { verdict: "partial", interrupted: scenario === "interrupted", diff: scenario === "legacy" ? undefined : { ...diff, coverage: scenario === "partial" ? "partial" as const : "complete" as const, reasons: scenario === "partial" ? ["external_change"] : [] }, verifications: checks };
39 state = event(state, { kind: "tool_result", turnId: "fixture-turn", tool: { id: "check-1", name: "exec_command", output: "check completed" } });
40 state = event(state, { kind: "message", text: "已补齐本轮差异与检查记录。文件统计只计算已确认的净变更。", turnId: "fixture-turn" });
41 state = event(state, { kind: "completion_summary", turnId: "fixture-turn", completion: { preset: "balanced", verdict: "partial", mutations: 30, checks_passed: checks.length && !failed ? 1 : 0, checks_failed: failed ? 1 : 0, checks_suppressed: 0, review: "none", attention: failed } });
42 state = event(state, { kind: "turn_done", turnId: "fixture-turn", checkpointTurn: 0, receipt: scenario === "legacy" ? undefined : receipt });
43 if (scenario === "history") {
44 const saved = historicalResultNotice({ role: "notice", content: "", completionReceipt: { ...receipt, diff: { ...diff, id: "0:historical" } }, checkpointTurn: 0, turnId: "historical" }, "old-result")!;
45 state.items = [{ kind: "user", id: "old-user", text: "这是历史轮次" }, saved, { kind: "assistant", id: "old-answer", text: "历史修改已完成。", reasoning: "", streaming: false }, { kind: "user", id: "middle-user", text: "继续说明" }, { kind: "assistant", id: "middle-answer", text: "这一轮没有文件修改。", reasoning: "", streaming: false }, ...state.items] as Item[];
46 }
47 return state;
48 }
49
50 function Fixture() {
51 const locale = useI18n();
52 const [scenario, setScenario] = useState("failed");
53 const [dark, setDark] = useState(true);
54 const [width, setWidth] = useState(410);
55 const [selection, setSelection] = useState<{ summary: WireCompletionSummary; view: "changes" | "checks"; key: number }>();
56 const [missing, setMissing] = useState(false);
57 const state = React.useMemo(() => snapshot(scenario), [scenario]);
58 React.useEffect(() => { document.documentElement.dataset.theme = dark ? "dark" : "light"; document.documentElement.dataset.themeStyle = "graphite"; }, [dark]);
59 React.useEffect(() => { locale.setPref("zh"); }, [locale.setPref]);
60 const show = (summary: WireCompletionSummary | undefined, view: "changes" | "checks") => summary && setSelection({ summary, view, key: Date.now() });
61 return <div style={{ height: "100vh", display: "grid", gridTemplateRows: "auto 1fr", background: "var(--bg)", color: "var(--fg)" }}>
62 <nav style={{ display: "flex", gap: 8, padding: 12, flexWrap: "wrap", borderBottom: "1px solid var(--border-soft)" }} aria-label="Browser fixtures">
63 <label>场景 <select aria-label="Scenario" value={scenario} onChange={e => { setScenario(e.target.value); setSelection(undefined); }}>{["failed","passed","none","stale","interrupted","running","partial","legacy","history"].map(s => <option key={s}>{s}</option>)}</select></label>
64 <button onClick={() => setDark(v => !v)}>深浅色</button>
65 <button onClick={() => setWidth(v => v === 410 ? 280 : 410)}>面板宽度 {width}</button>
66 <button aria-pressed={missing} onClick={() => { unavailable = !missing; setMissing(!missing); setSelection(undefined); }}>模拟数据已清理</button>
67 </nav>
68 <main style={{ minHeight: 0, display: "grid", gridTemplateColumns: selection ? "minmax(0,1fr) " + width + "px" : "minmax(0,1fr)" }}>
69 <div style={{ minWidth: 0, minHeight: 0, display: "flex", flexDirection: "column" }}><Transcript items={state.items} running={state.running} turnStartAt={state.turnStartAt} tabId="fixture" geometrySessionKey="fixture" onPrompt={() => {}} onOpenChanges={s => show(s, "changes")} onOpenVerification={s => show(s, "checks")} /></div>
70 {selection && <aside style={{ overflow: "auto", minWidth: 0, borderLeft: "1px solid var(--border-soft)" }}><WorkspaceTurnResult key={selection.key} summary={selection.summary} tabId="fixture" sessionPath="/fixture-session.json" initialView={selection.view} onAllChanges={() => setSelection(undefined)} /></aside>}
71 </main>
72 </div>;
73 }
74 createRoot(document.getElementById("root")!).render(<LocaleProvider><Fixture /></LocaleProvider>);
75
75 lines Plain Text