返回 DeepSeek-Reasonix
submission-handoff.tsx
根目录 / desktop / frontend / bench / submission-handoff.tsx
1 import { useSyncExternalStore } from "react";
2 import { createRoot } from "react-dom/client";
3 import { Transcript } from "../src/components/Transcript";
4 import { Composer } from "../src/components/Composer";
5 import { LocaleProvider } from "../src/lib/i18n";
6 import { ToastProvider } from "../src/lib/toast";
7 import { initialState, reducer, createTurnSubmissionId, type Action } from "../src/lib/useController";
8 import { orderedLocalSubmissions } from "../src/lib/localSubmissionState";
9 import { getTranscriptStore } from "../src/lib/transcriptStore";
10 import { TranscriptSessionFollower } from "../src/lib/transcriptSessionFollower";
11 import { installDesktopHostStub } from "../src/__tests__/desktopHostStub";
12 import { setFrontendDiagnosticSink } from "../src/lib/frontendDiagnosticBridge";
13 import type { FollowRequest, HistoryWindowRequest, Message, TranscriptFollowResponse } from "../src/generated/desktopContract.generated";
14 import "../src/styles.css";
15
16 const tab = "handoff-integration", path = "/disposable/handoff.jsonl", store = getTranscriptStore();
17 let state = { ...initialState }, revision = 1, coverage = 1;
18 const database: Message[] = Array.from({ length: 1000 }, (_, index) => [
19 { role: "user", messageId: `user-${index}`, turnId: `turn-${index}`, content: `Question ${index}`, historyTurn: index + 1 },
20 { role: "assistant", messageId: `answer-${index}`, turnId: `turn-${index}`, content: `Answer ${index}. Stable reading paragraph.\n\nSecond paragraph.`, historyTurn: index + 1, turnFinal: true },
21 ]).flat();
22 let polls: Array<(response: TranscriptFollowResponse) => void> = [];
23 let queued: NonNullable<TranscriptFollowResponse["changes"]> = [];
24 let pending: { id: string; text: string; messageId: string; turnId: string } | undefined;
25 let presentation: Record<string, unknown> = {};
26 setFrontendDiagnosticSink((source, type, fields) => { if (source === "transcript" && type === "presentation") presentation = fields; });
27 const dispatch = (action: Action) => { state = reducer(state, action); store.setState(tab, state); };
28 function windowPage(request: HistoryWindowRequest) {
29 const limit = request.limit ?? 32;
30 let start = request.anchor === "newest" ? Math.max(0, database.length - limit)
31 : request.anchor === "message" ? Math.max(0, database.findIndex(item => item.messageId === request.messageId))
32 : Number(request.cursor);
33 if (request.anchor === "cursor" && request.direction === "older") start = Math.max(0, start - limit);
34 const end = Math.min(database.length, start + limit);
35 return { status: "ready", generation: "fixture", snapshotSequence: coverage, coverageSequence: coverage,
36 totalTurns: 1000 + (database.length > 2000 ? 1 : 0), hasOlder: start > 0, hasNewer: end < database.length,
37 olderCursor: start > 0 ? String(start) : "", newerCursor: end < database.length ? String(end) : "",
38 messages: database.slice(start, end).map((message, offset) => ({ messageId: message.messageId!, role: message.role,
39 position: start + offset, version: 1, eventSequence: coverage, visibleTurn: message.historyTurn, submissionId: message.submissionId, inline: message })) };
40 }
41 function publish(change: Omit<NonNullable<TranscriptFollowResponse["changes"]>[number], "revision" | "index" | "durableSeq" | "commitSeq">, commit = false) {
42 if (commit) coverage++;
43 queued.push({ ...change, revision: ++revision, index: 0, durableSeq: coverage, commitSeq: coverage, ...(commit ? { firstSeq: coverage } : {}) });
44 flush();
45 }
46 function flush() {
47 if (!polls.length || !queued.length) return;
48 polls.shift()!({ protocolVersion: 2, subscription: tab, changes: queued.splice(0), resetRequired: false });
49 }
50 installDesktopHostStub({
51 Commands: () => [],
52 ModelsForTab: () => [],
53 Models: () => [],
54 TranscriptFollowForTab: (_tab: string, request: FollowRequest) => {
55 if (request.close) return { protocolVersion: 2, subscription: tab, changes: [], resetRequired: false };
56 if (!request.subscription) return { protocolVersion: 2, subscription: tab, changes: [], resetRequired: false, history: windowPage({ anchor: "newest" }), snapshot: {
57 protocolVersion: 1, snapshotId: "cut", identity: { sessionId: tab, runtimeEpoch: "fixture", rewriteEpoch: 0, headId: "" },
58 projectionRevision: revision, coveredThroughSeq: coverage, durableSeq: coverage, records: [], activeRecords: [], activeAttempts: [],
59 runtime: { status: "completed", pendingEvents: [], samplingCount: 0, toolCount: 0 }, before: 0, hasOlder: true, totalRecords: database.length, totalTurns: 1000, stale: false,
60 } };
61 return new Promise<TranscriptFollowResponse>(resolve => { polls.push(resolve); flush(); });
62 },
63 SessionHistoryWindowForTab: (_tab: string, request: HistoryWindowRequest) => windowPage(request),
64 TranscriptOutlineForTab: () => ({ turns: [], hasMore: false }),
65 });
66 const follower = new TranscriptSessionFollower(tab, path, false, dispatch, () => state);
67 await follower.start();
68
69 async function page(direction: "older" | "newer" | "latest") {
70 const loaded = direction === "older" ? await store.loadOlder(tab, path)
71 : direction === "newer" ? await store.loadNewer(tab, path) : await store.loadLatest(tab, path);
72 if (!loaded) return;
73 dispatch({ type: "history_replace", ...loaded });
74 }
75 function send(text: string) {
76 const id = createTurnSubmissionId(tab, state.sessionGen, state.seq);
77 pending = { id, text, messageId: `sent-${state.seq}`, turnId: `sent-turn-${state.seq}` };
78 dispatch({ type: "user", text, submissionId: id, seq: state.seq });
79 }
80 function event() {
81 if (!pending) return;
82 publish({ event: { kind: "user_message", source: "executor", messageId: pending.messageId, submissionId: pending.id, turnId: pending.turnId } });
83 }
84 function record(withSubmission = true) {
85 if (!pending) return;
86 const message: Message = { role: "user", messageId: pending.messageId, turnId: pending.turnId, submissionId: withSubmission ? pending.id : undefined, content: pending.text, historyTurn: 1001 };
87 if (!database.some(item => item.messageId === message.messageId)) database.push(message);
88 publish({ records: [message] }, true);
89 }
90 declare global { interface Window { handoff: { page: typeof page; event: typeof event; record: typeof record; batched(): void; send: typeof send; inspect(): unknown; finish(): void; output(): void } } }
91 window.handoff = { page, event, record, send,
92 batched() { event(); record(false); },
93 output() { if (pending) publish({ event: { kind: "text", messageId: `output-${pending.messageId}`, turnId: pending.turnId, text: "Live answer with stable text." } }); },
94 finish() {
95 if (pending) {
96 dispatch({ type: "send_confirmed", submissionId: pending.id });
97 publish({ event: { kind: "message", messageId: `output-${pending.messageId}`, turnId: pending.turnId,
98 text: "Live answer with stable text.", reasoning: "Deterministic process details." } });
99 }
100 publish({ runtime: { status: "completed", submissionId: pending?.id, pendingEvents: [], samplingCount: 0, toolCount: 0 } });
101 },
102 inspect() { return { ids: state.items.map(item => item.id), locals: state.localSubmissionOrder.length, handoffs: Object.keys(state.visibleSubmissionHandoffs).length,
103 users: state.items.filter(item => item.kind === "user").length, stats: store.stats(), presentation, pending, hasNewer: state.historyHasNewer, revision: state.localSubmissionSendRevision }; },
104 };
105 function Fixture() {
106 const current = useSyncExternalStore(listener => store.subscribeState(tab, listener), () => store.states.get(tab)!);
107 return <div style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
108 <div><button onClick={() => void page("older")}>Older</button><button onClick={() => void page("newer")}>Newer</button><button onClick={() => void page("latest")}>Latest</button>
109 <button onClick={() => pending && dispatch({ type: "send_confirmed", submissionId: pending.id })}>Accept</button>
110 <button onClick={event}>Identity</button><button onClick={() => record()}>Commit</button><button onClick={() => window.handoff.batched()}>Batched</button></div>
111 <Transcript items={current.items} tabId={tab} running={current.running} localSubmissions={orderedLocalSubmissions(current)}
112 visibleSubmissionHandoffs={current.visibleSubmissionHandoffs} localSubmissionSendRevision={current.localSubmissionSendRevision}
113 hasOlderHistory={current.historyHasOlder} hasNewerHistory={current.historyHasNewer} onPrompt={() => {}} onFork={() => {}} />
114 <Composer running={current.running} collaborationMode="normal" toolApprovalMode="ask" modelLabel="Fixture" tabId={tab}
115 onSend={send} onCancel={async () => ({ discardedItemIds: [] })} onCycleMode={() => {}} onSetMode={() => {}} onSetCollaborationMode={() => {}}
116 onSetToolApprovalMode={() => {}} onClearGoal={() => {}} onPauseGoal={() => {}} onResumeGoal={() => {}}
117 onEditGoal={() => {}}
118 onSwitchModel={() => true} onSetEffort={() => {}} />
119 </div>;
120 }
121 createRoot(document.getElementById("root")!).render(<LocaleProvider><ToastProvider><Fixture /></ToastProvider></LocaleProvider>);
122
122 lines Plain Text