返回 DeepSeek-Reasonix
useComposerProfileProjection.ts
根目录 / desktop / frontend / src / app-runtime / useComposerProfileProjection.ts
1 import { useMemo, type Dispatch, type SetStateAction } from "react";
2 import { useCommittedCommand } from "../lib/useCommittedCommand";
3 import { useRemoteComposerProfileSync } from "../lib/useRemoteComposerIntegration";
4 import {
5 composerProfileFromMeta,
6 composerProfileFromTab,
7 composerProfileMode,
8 defaultComposerProfile,
9 displayedComposerProfileCollaborationMode,
10 patchComposerProfile,
11 updateUserPlanModeIntent,
12 type ComposerProfile,
13 type ComposerProfileField,
14 type UserPlanModeIntents,
15 } from "../lib/composerProfile";
16 import type { Meta, TabMeta } from "../lib/types";
17 import type { RemoteSessionApi } from "../lib/useRemoteSession";
18
19 export type ComposerProfileProjectionInput = {
20 activeTabId: string | undefined;
21 activeTab: TabMeta | undefined;
22 meta: Meta | null | undefined;
23 profilesByTab: Record<string, ComposerProfile>;
24 setProfilesByTab: Dispatch<SetStateAction<Record<string, ComposerProfile>>>;
25 tabMetas: readonly TabMeta[];
26 remote: boolean;
27 remoteSession: RemoteSessionApi;
28 planIntentsRef: { current: UserPlanModeIntents };
29 };
30
31 /**
32 * Owns the active composer profile projection (UI override over the backend
33 * profile, remote sync) and the profile patch commands: generic per-tab
34 * patches and goal activation patches. Mode axis
35 * changes stay in useComposerModeActions; this hook owns the profile record.
36 */
37 export function useComposerProfileProjection(input: ComposerProfileProjectionInput) {
38 const { activeTabId, activeTab, meta, profilesByTab, setProfilesByTab, tabMetas, remote, remoteSession } = input;
39 const activeComposerProfile = activeTabId ? profilesByTab[activeTabId] : undefined;
40 const backendActiveComposerProfile = useMemo(() => {
41 if (meta) {
42 return composerProfileFromMeta(
43 meta,
44 activeTab ? composerProfileMode(composerProfileFromTab(activeTab, activeComposerProfile?.toolApprovalMode)) : undefined,
45 activeComposerProfile?.toolApprovalMode,
46 );
47 }
48 return composerProfileFromTab(activeTab, activeComposerProfile?.toolApprovalMode);
49 }, [activeComposerProfile?.toolApprovalMode, activeTab, meta]);
50 const composerProfile = activeTabId
51 ? activeComposerProfile ?? backendActiveComposerProfile
52 : defaultComposerProfile;
53 const goal = composerProfile.goal;
54 const collaborationMode = displayedComposerProfileCollaborationMode(composerProfile);
55 const toolApprovalMode = composerProfile.toolApprovalMode;
56 const remoteSessionRoute = activeTab?.remote
57 ? (activeTab.sessionId ? `session-id:${activeTab.sessionId}` : activeTab.sessionPath ?? "")
58 : "";
59 const remoteComposerProfileReady = useRemoteComposerProfileSync({ activeTabId, sessionRoute: remoteSessionRoute, remote,
60 remoteProfile: remoteSession.composerProfile, collaborationMode, toolApprovalMode, goal,
61 qualityFloor: composerProfile.qualityFloor, pending: composerProfile.pending, setProfiles: setProfilesByTab });
62
63 const patchActiveComposerProfile = useCommittedCommand((patch: Partial<Omit<ComposerProfile, "pending">>, pendingFields: ComposerProfileField[]) => {
64 if (!activeTabId) return;
65 setProfilesByTab((current) => patchComposerProfile(current, activeTabId, composerProfile, patch, pendingFields));
66 });
67 const patchComposerProfileForTab = useCommittedCommand((tabId: string, patch: Partial<Omit<ComposerProfile, "pending">>, pendingFields: ComposerProfileField[]) => {
68 if (!tabId) return;
69 setProfilesByTab((current) => {
70 const base = current[tabId] ?? composerProfileFromTab(tabMetas.find((tab) => tab.id === tabId));
71 return patchComposerProfile(current, tabId, base, patch, pendingFields);
72 });
73 });
74
75 const patchActivatedGoalForTab = useCommittedCommand((tabId: string, nextGoal: string): void => {
76 const trimmed = nextGoal.trim();
77 patchComposerProfileForTab(tabId, {
78 collaborationMode: trimmed ? "goal" : "normal",
79 goalDraftMode: false,
80 goal: trimmed,
81 }, ["collaborationMode", "goal"]);
82 input.planIntentsRef.current = updateUserPlanModeIntent(input.planIntentsRef.current, tabId, false);
83 });
84
85 return {
86 composerProfile,
87 goal,
88 collaborationMode,
89 toolApprovalMode,
90 remoteComposerProfileReady,
91 patchActiveComposerProfile,
92 patchComposerProfileForTab,
93 patchActivatedGoalForTab,
94 };
95 }
96
96 lines TYPESCRIPT