返回 DeepSeek-Reasonix
useSessionSubmission.ts
根目录 / desktop / frontend / src / lib / useSessionSubmission.ts
1 import { useMemo } from "react";
2 import { useCommittedSlot, type CommittedSlot } from "./useCommittedSlot";
3 import { useCommittedCommand } from "./useCommittedCommand";
4 import { CommandCancelled } from "./commandOutcome";
5 import { executeSubmission, type InitialGoal, type SubmissionInput, type SubmissionPorts, type SubmissionResource } from "../app-runtime/sessionSubmissionOwner";
6 import type { SessionOperationAuthority, SessionResource, useSessionOperations } from "../app-runtime/useSessionOperations";
7 import type { StructuredInvocationSubmit } from "./invocationDisplay";
8
9 function bindRead(slot: CommittedSlot<readonly SubmissionResource[]>) {
10 return (target: SessionResource) => {
11 if (slot.phase !== "ready") throw new CommandCancelled("disposed");
12 const source = slot.value?.find(value => value.target.tabId === target.tabId && value.target.sessionKey === target.sessionKey);
13 if (!source) throw new CommandCancelled("superseded");
14 return source;
15 };
16 }
17
18 export function useSessionSubmission(options: {
19 target: SessionResource; resources: readonly SubmissionResource[];
20 operations: ReturnType<typeof useSessionOperations>; ports: SubmissionPorts; missingSource: string;
21 }) {
22 const { target, resources, operations, ports, missingSource } = options;
23 const slot = useCommittedSlot(resources);
24 const read = useMemo(() => bindRead(slot), [slot]);
25 const run = useCommittedCommand(async (tab: string, request: SubmissionInput["request"]) => {
26 const source = resources.find(value => value.target.tabId === tab);
27 if (!source) throw Error(missingSource);
28 const result = await operations(source.target, request.kind === "goal" ? "composer-profile" : "send", {
29 target: source.target, request, read, ports,
30 }, executeSubmission);
31 if (result.status === "failed") throw result.error;
32 });
33 const commitThenSend = useCommittedCommand((tab: string, display: string, submit?: string,
34 structured?: StructuredInvocationSubmit, initialGoal?: InitialGoal) => run(tab, { kind: "direct", content: { display, submit, structured, initialGoal } }));
35 const submit = useCommittedCommand((tab: string, display: string, content = display, structured?: StructuredInvocationSubmit) =>
36 run(tab, { kind: "composer", content: { display, submit: content, structured } }));
37 const applyGoalForTab = useCommittedCommand((tab: string, goal: string) => run(tab, { kind: "goal", goal }));
38 const applyGoal = useCommittedCommand((goal: string) => target.tabId ? applyGoalForTab(target.tabId, goal) : Promise.resolve());
39 // A queue already owns its request and must retain resource failures before
40 // its own UI outcome boundary. Reuse the executor, not a nested UI command.
41 const sendRevision = useCommittedCommand((source: SessionResource, text: string, authority: SessionOperationAuthority) =>
42 executeSubmission({ target: source, read, ports, request: { kind: "direct", content: { display: text } } }, authority));
43 return { commitThenSend, submit, applyGoalForTab, applyGoal, sendRevision };
44 }
45
45 lines TYPESCRIPT