Skip to content

Commit f2db5bb

Browse files
committed
Move agent management into profile sidebar
1 parent 5306735 commit f2db5bb

16 files changed

Lines changed: 2869 additions & 928 deletions

desktop/src/features/agents/ui/AgentGroupRows.tsx

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,30 @@ export type AgentGroupRowsProps = {
66
agents: ManagedAgent[];
77
channelIdToName: Record<string, string>;
88
channelsByPubkey: Record<string, { id: string; name: string }[]>;
9-
isActionPending: boolean;
109
logContent: string | null;
1110
logError: Error | null;
1211
logLoading: boolean;
1312
personaLabelsById: Record<string, string>;
1413
presenceLoaded: boolean;
1514
presenceLookup: PresenceLookup;
1615
selectedLogAgentPubkey: string | null;
17-
onAddToChannel: (agent: ManagedAgent) => void;
18-
onDelete: (pubkey: string) => void;
16+
onOpenProfile: (pubkey: string) => void;
1917
onSelectLogAgent: (pubkey: string | null) => void;
20-
onStart: (pubkey: string) => void;
21-
onStop: (pubkey: string) => void;
22-
onToggleStartOnAppLaunch: (pubkey: string, startOnAppLaunch: boolean) => void;
2318
};
2419

2520
export function AgentGroupRows({
2621
agents,
2722
channelIdToName,
2823
channelsByPubkey,
29-
isActionPending,
3024
logContent,
3125
logError,
3226
logLoading,
3327
personaLabelsById,
3428
presenceLoaded,
3529
presenceLookup,
3630
selectedLogAgentPubkey,
37-
onAddToChannel,
38-
onDelete,
31+
onOpenProfile,
3932
onSelectLogAgent,
40-
onStart,
41-
onStop,
42-
onToggleStartOnAppLaunch,
4333
}: AgentGroupRowsProps) {
4434
return (
4535
<div className="divide-y divide-border/50 border-t border-border/50">
@@ -48,7 +38,6 @@ export function AgentGroupRows({
4838
agent={agent}
4939
channelIdToName={channelIdToName}
5040
channelNames={channelsByPubkey[normalizePubkey(agent.pubkey)] ?? []}
51-
isActionPending={isActionPending}
5241
isLogSelected={selectedLogAgentPubkey === agent.pubkey}
5342
key={agent.pubkey}
5443
logContent={
@@ -59,12 +48,8 @@ export function AgentGroupRows({
5948
personaLabelsById={personaLabelsById}
6049
presenceLoaded={presenceLoaded}
6150
presenceLookup={presenceLookup}
62-
onAddToChannel={onAddToChannel}
63-
onDelete={onDelete}
51+
onOpenProfile={onOpenProfile}
6452
onSelectLogAgent={onSelectLogAgent}
65-
onStart={onStart}
66-
onStop={onStop}
67-
onToggleStartOnAppLaunch={onToggleStartOnAppLaunch}
6853
/>
6954
))}
7055
</div>
Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,76 @@
11
import * as React from "react";
22

3+
import { useAppNavigation } from "@/app/navigation/useAppNavigation";
4+
import { useOpenDmMutation } from "@/features/channels/hooks";
5+
import { UserProfilePanel } from "@/features/profile/ui/UserProfilePanel";
6+
import { useIdentityQuery } from "@/shared/api/hooks";
7+
import type { AgentPersona } from "@/shared/api/types";
8+
import { ProfilePanelProvider } from "@/shared/context/ProfilePanelContext";
9+
import { useThreadPanelWidth } from "@/shared/hooks/useThreadPanelWidth";
310
import { ViewLoadingFallback } from "@/shared/ui/ViewLoadingFallback";
411

512
const AgentsView = React.lazy(async () => {
613
const module = await import("@/features/agents/ui/AgentsView");
714
return { default: module.AgentsView };
815
});
916

17+
type ProfilePanelTarget =
18+
| { kind: "pubkey"; pubkey: string }
19+
| { kind: "persona"; persona: AgentPersona };
20+
1021
export function AgentsScreen() {
22+
const identityQuery = useIdentityQuery();
23+
const [profilePanelTarget, setProfilePanelTarget] =
24+
React.useState<ProfilePanelTarget | null>(null);
25+
const threadPanelWidth = useThreadPanelWidth();
26+
const openDmMutation = useOpenDmMutation();
27+
const { goChannel } = useAppNavigation();
28+
29+
const handleOpenDm = React.useCallback(
30+
async (pubkeys: string[]) => {
31+
const dm = await openDmMutation.mutateAsync({ pubkeys });
32+
await goChannel(dm.id);
33+
},
34+
[goChannel, openDmMutation],
35+
);
36+
1137
return (
12-
<div className="relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
13-
<React.Suspense fallback={<ViewLoadingFallback kind="agents" />}>
14-
<AgentsView />
15-
</React.Suspense>
16-
</div>
38+
<ProfilePanelProvider
39+
onOpenPersonaProfilePanel={(persona) =>
40+
setProfilePanelTarget({ kind: "persona", persona })
41+
}
42+
onOpenProfilePanel={(pubkey) =>
43+
setProfilePanelTarget({ kind: "pubkey", pubkey })
44+
}
45+
>
46+
<div className="relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
47+
<div className="flex min-h-0 min-w-0 flex-1 flex-row overflow-hidden">
48+
<React.Suspense fallback={<ViewLoadingFallback kind="agents" />}>
49+
<AgentsView />
50+
</React.Suspense>
51+
{profilePanelTarget ? (
52+
<UserProfilePanel
53+
canResetWidth={threadPanelWidth.canReset}
54+
currentPubkey={identityQuery.data?.pubkey}
55+
onClose={() => setProfilePanelTarget(null)}
56+
onOpenDm={handleOpenDm}
57+
onResetWidth={threadPanelWidth.onResetWidth}
58+
onResizeStart={threadPanelWidth.onResizeStart}
59+
persona={
60+
profilePanelTarget.kind === "persona"
61+
? profilePanelTarget.persona
62+
: undefined
63+
}
64+
pubkey={
65+
profilePanelTarget.kind === "pubkey"
66+
? profilePanelTarget.pubkey
67+
: undefined
68+
}
69+
widthPx={threadPanelWidth.widthPx}
70+
/>
71+
) : null}
72+
</div>
73+
</div>
74+
</ProfilePanelProvider>
1775
);
1876
}

desktop/src/features/agents/ui/AgentsView.tsx

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ import { UnifiedAgentsSection } from "./UnifiedAgentsSection";
2222
import { useManagedAgentActions } from "./useManagedAgentActions";
2323
import { usePersonaActions } from "./usePersonaActions";
2424
import { useTeamActions } from "./useTeamActions";
25+
import { useProfilePanel } from "@/shared/context/ProfilePanelContext";
2526

2627
export function AgentsView() {
28+
const { openPersonaProfilePanel, openProfilePanel } = useProfilePanel();
2729
const agents = useManagedAgentActions();
2830
const personas = usePersonaActions();
2931
const teamActions = useTeamActions(
@@ -83,11 +85,6 @@ export function AgentsView() {
8385
personaLabelsById={personas.personaLabelsById}
8486
presenceLoaded={agents.managedPresenceQuery.isSuccess}
8587
presenceLookup={agents.managedPresenceQuery.data ?? {}}
86-
onAddToChannel={(agent) => {
87-
agents.setActionNoticeMessage(null);
88-
agents.setActionErrorMessage(null);
89-
agents.setAgentToAddToChannel(agent);
90-
}}
9188
onBulkRemoveStopped={() => {
9289
void agents.handleBulkRemoveStopped();
9390
}}
@@ -97,22 +94,13 @@ export function AgentsView() {
9794
onCreateAgent={() => {
9895
agents.setIsCreateOpen(true);
9996
}}
100-
onDeleteAgent={(pubkey) => {
101-
void agents.handleDelete(pubkey);
102-
}}
103-
onSelectLogAgent={agents.setLogAgentPubkey}
104-
onStartAgent={(pubkey) => {
105-
void agents.handleStart(pubkey);
106-
}}
107-
onStopAgent={(pubkey) => {
108-
void agents.handleStop(pubkey);
97+
onOpenAgentProfile={(pubkey) => {
98+
openProfilePanel?.(pubkey);
10999
}}
110-
onToggleStartOnAppLaunch={(pubkey, startOnAppLaunch) => {
111-
void agents.handleToggleStartOnAppLaunch(
112-
pubkey,
113-
startOnAppLaunch,
114-
);
100+
onOpenPersonaProfile={(persona) => {
101+
openPersonaProfilePanel?.(persona);
115102
}}
103+
onSelectLogAgent={agents.setLogAgentPubkey}
116104
selectedLogAgentPubkey={agents.logAgentPubkey}
117105
// Persona props
118106
canChooseCatalog={personas.catalogPersonas.length > 0}
@@ -136,13 +124,6 @@ export function AgentsView() {
136124
isPersonasPending={personas.isPending}
137125
onCreatePersona={personas.openCreate}
138126
onChooseCatalog={personas.openCatalog}
139-
onDuplicatePersona={personas.openDuplicate}
140-
onEditPersona={personas.openEdit}
141-
onExportPersona={personas.handleExport}
142-
onDeactivatePersona={(persona) => {
143-
void personas.handleSetActive(persona, false, "library");
144-
}}
145-
onDeletePersona={personas.openDelete}
146127
onImportPersonaFile={(fileBytes, fileName) => {
147128
void personas.handleImportFile(fileBytes, fileName);
148129
}}

0 commit comments

Comments
 (0)