返回 DeepSeek-Reasonix
sessionSubmissionOwner.ts
根目录 / desktop / frontend / src / app-runtime / sessionSubmissionOwner.ts
1 import type { CollaborationMode, ToolApprovalMode } from "../lib/types";
2 import type { StructuredInvocationSubmit } from "../lib/invocationDisplay";
3 import type { SessionOperationAuthority, SessionResource } from "./useSessionOperations";
4
5 export type InitialGoal = { goal: string; collaborationMode: CollaborationMode; toolApprovalMode: ToolApprovalMode };
6 export type SubmissionResource = {
7 target: SessionResource; remote: boolean; ready: boolean; unavailable: string; goalDraft: boolean;
8 collaboration: CollaborationMode; approval: ToolApprovalMode;
9 };
10 export type Submission = { display: string; submit?: string; structured?: StructuredInvocationSubmit; initialGoal?: InitialGoal; submissionId?: string };
11 export type SubmissionPorts = {
12 send(tab: string, display: string, submit?: string, structured?: StructuredInvocationSubmit, goal?: InitialGoal, submissionId?: string): Promise<void>;
13 clearUndo(tab: string): void;
14 setGoal(tab: string, goal: string, remote: boolean): Promise<void>;
15 patchGoal(tab: string, goal: string): void;
16 profile(tab: string, propagateError: boolean): Promise<boolean>;
17 };
18 export type SubmissionInput = {
19 target: SessionResource; read(target: SessionResource): SubmissionResource; ports: SubmissionPorts;
20 request: { kind: "direct" | "composer"; content: Submission } | { kind: "goal"; goal: string };
21 };
22
23 export function buildInitialGoalSubmission(
24 content: Submission,
25 collaborationMode: CollaborationMode,
26 toolApprovalMode: ToolApprovalMode,
27 ): Submission {
28 const display = content.display.trim();
29 const submit = (content.submit ?? content.display).trim();
30 return {
31 ...(content.submissionId ? {submissionId:content.submissionId} : {}),
32 display,
33 submit: content.structured ? submit : `/goal ${submit}`,
34 structured: content.structured,
35 initialGoal: { goal: display, collaborationMode, toolApprovalMode },
36 };
37 }
38 const legacyFlags = new Set(["--research", "--auto-research", "--deep", "--simple", "--no-research"]);
39 export function goalCommand(input: string) {
40 const match = /^\/goal(?:\s+(.*))?$/.exec(input);
41 if (!match) return undefined;
42 const parts = (match[1] ?? "").trim().split(/\s+/).filter(Boolean);
43 const legacy = legacyFlags.has(parts[0]?.toLowerCase());
44 while (legacyFlags.has(parts[0]?.toLowerCase())) parts.shift();
45 const value = parts.join(" ");
46 const action = value.toLowerCase();
47 return { value, legacy, activate: Boolean(value) && !["status", "clear", "off", "stop", "done", "pause", "resume"].includes(action),
48 clear: ["clear", "off", "stop", "done"].includes(action) };
49 }
50
51 async function applyGoal(input: SubmissionInput, goal: string, authority: SessionOperationAuthority) {
52 authority.checkpoint();
53 await input.ports.setGoal(input.target.tabId, goal, input.read(input.target).remote);
54 authority.checkpoint();
55 input.ports.patchGoal(input.target.tabId, goal);
56 }
57
58 async function send(input: SubmissionInput, content: Submission, authority: SessionOperationAuthority) {
59 authority.checkpoint();
60 const source = input.read(input.target);
61 if (!source.ready || source.unavailable) throw Error("reasonix_error:inbox_not_submitted " + source.unavailable);
62 input.ports.clearUndo(input.target.tabId);
63 if (content.submissionId) await input.ports.send(input.target.tabId, content.display, content.submit, content.structured, content.initialGoal, content.submissionId);
64 else await input.ports.send(input.target.tabId, content.display, content.submit, content.structured, content.initialGoal);
65 authority.checkpoint();
66 }
67
68 /** Only minimal source data survives awaits. No active-tab reads or render refs. */
69 export async function executeSubmission(input: SubmissionInput, authority: SessionOperationAuthority): Promise<void> {
70 authority.checkpoint();
71 if (input.request.kind === "goal") return applyGoal(input, input.request.goal.trim(), authority);
72 const { content } = input.request;
73 if (input.request.kind === "direct") return send(input, content, authority);
74 const source = input.read(input.target);
75 const display = content.display.trim();
76 const submit = content.submit ?? content.display;
77 const command = goalCommand(display);
78 if (command) {
79 if (command.activate) {
80 if (command.legacy) input.ports.patchGoal(input.target.tabId, command.value);
81 else await applyGoal(input, command.value, authority);
82 } else if (command.clear) await applyGoal(input, "", authority);
83 authority.checkpoint();
84 if (input.read(input.target).ready) await send(input, { ...content, display, submit: submit.trim() }, authority);
85 return;
86 }
87 if (!source.ready) throw new Error("reasonix_error:workspace_starting");
88 if (source.goalDraft) {
89 await send(input, buildInitialGoalSubmission(
90 { ...content, display, submit }, source.collaboration, source.approval,
91 ), authority);
92 authority.checkpoint();
93 input.ports.patchGoal(input.target.tabId, display);
94 return;
95 }
96 if (!await input.ports.profile(input.target.tabId, false)) throw new Error("reasonix_error:inbox_not_submitted — session settings could not be applied");
97 authority.checkpoint();
98 await send(input, { ...content, display, submit: submit.trim() }, authority);
99 }
100
100 lines TYPESCRIPT