返回 DeepSeek-Reasonix
useControllerProfileCommands.ts
根目录 / desktop / frontend / src / lib / useControllerProfileCommands.ts
1 import { useEffect, useMemo } from "react";
2 import { useCommittedSlot, type CommittedSlot } from "./useCommittedSlot";
3 import { useCommittedCommand } from "./useCommittedCommand";
4 import { CommandCancelled } from "./commandOutcome";
5 import { executeControllerModel, executeControllerProfile, type ControllerProfilePorts, type ControllerProfileResource } from "../app-runtime/controllerProfileOwner";
6 import type { SessionResource, useSessionOperations } from "../app-runtime/useSessionOperations";
7
8 function bindProfileRead(slot: CommittedSlot<readonly ControllerProfileResource[]>) {
9 return (target: SessionResource): ControllerProfileResource => {
10 if (slot.phase !== "ready") throw new CommandCancelled(slot.phase === "disposed" ? "disposed" : "not-ready");
11 const resource = slot.value?.find(value => value.target.tabId === target.tabId && value.target.sessionKey === target.sessionKey);
12 if (!resource) throw new CommandCancelled("superseded");
13 return resource;
14 };
15 }
16
17 export function useControllerProfileCommands(options: {
18 target: SessionResource; profiles: readonly ControllerProfileResource[]; ready: boolean; remote: boolean; runtimeEpoch?: string;
19 ports: ControllerProfilePorts; remoteModel(name: string): Promise<void>;
20 operations: ReturnType<typeof useSessionOperations>; report(error: unknown): void;
21 }) {
22 const { target, profiles, ready, remote, runtimeEpoch, operations, ports, remoteModel, report } = options;
23 const slot = useCommittedSlot(profiles);
24 const read = useMemo(() => bindProfileRead(slot), [slot]);
25 const restore = useCommittedCommand(async (source: SessionResource): Promise<boolean> => {
26 const result = await operations(source, "controller-profile", { target: source, read, ports }, executeControllerProfile);
27 if (result.status === "failed") throw result.error;
28 return result.status === "completed" && result.value;
29 });
30 const applyProfile = useCommittedCommand(async (tabId = target.tabId, propagateError = true): Promise<boolean> => {
31 const source = profiles.find(value => value.target.tabId === tabId);
32 if (!source) return false;
33 try { return await restore(source.target); } catch (error) {
34 if (propagateError) throw error;
35 return false;
36 }
37 });
38 const switchModel = useCommittedCommand(async (name: string, tabId = target.tabId): Promise<boolean> => {
39 const source = profiles.find(value => value.target.tabId === tabId);
40 if (!source || (source.remote && tabId !== target.tabId)) return false;
41 const result = await operations(source.target, "model", { target: source.target, read, ports, restore,
42 name, remote: source.remote ? remoteModel : undefined }, executeControllerModel);
43 if (result.status === "failed") throw result.error;
44 return result.status === "completed" && result.value;
45 });
46 const reportError = useCommittedCommand(report);
47 const switchModelFromUi = useCommittedCommand(async (name: string): Promise<boolean> => {
48 try { return await switchModel(name); } catch (error) { reportError(error); return false; }
49 });
50 const active = profiles.find(value => value.target.tabId === target.tabId)?.profile;
51 useEffect(() => {
52 if (ready && target.tabId && !remote) void applyProfile().catch(reportError);
53 }, [ready, remote, runtimeEpoch, target.tabId, target.sessionKey, active?.collaboration, active?.approval, active?.goal, applyProfile, reportError]);
54 return { applyProfile, switchModel, switchModelFromUi };
55 }
56
56 lines TYPESCRIPT