Skip to content

Commit 986b9bb

Browse files
committed
Add rename company agent, fix solana keys on agent settings page
1 parent 5094554 commit 986b9bb

File tree

2 files changed

+179
-33
lines changed

2 files changed

+179
-33
lines changed

app/settings/page.tsx

Lines changed: 171 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default function AgentSettings() {
7373
const [error, setError] = useState<ErrorState>(null);
7474

7575
// Wallet state
76-
const [walletData, setWalletData] = useState({} as WalletKeys);
76+
const [walletData, setWalletData] = useState<WalletKeys | null>(null);
7777
const [isWalletRevealed, setIsWalletRevealed] = useState(false);
7878
const [isLoadingWallet, setIsLoadingWallet] = useState(false);
7979
const [solanaWalletAddress, setSolanaWalletAddress] = useState<string | null>(null);
@@ -84,7 +84,7 @@ export default function AgentSettings() {
8484
// Memoized providers list - computed once when data changes
8585
const providers = useMemo(() => {
8686
// Return empty arrays if no data
87-
if (!agentData?.settings || !providerData?.length) {
87+
if (!agentData?.agent?.settings || !providerData?.length) {
8888
return {
8989
connected: [],
9090
available: [],
@@ -100,15 +100,15 @@ export default function AgentSettings() {
100100
const isSensitive = ['KEY', 'SECRET', 'PASSWORD'].some((keyword) => setting.name.includes(keyword));
101101

102102
// Only include if it exists in agent settings
103-
return isSensitive && agentData.settings.some((s) => s.name === setting.name);
103+
return isSensitive && agentData.agent?.settings.some((s) => s.name === setting.name);
104104
});
105105

106106
// If no relevant settings found, provider is not connected
107107
if (relevantSettings.length === 0) return false;
108108

109109
// Check if ALL relevant settings are HIDDEN
110110
return relevantSettings.every((setting) => {
111-
const agentSetting = agentData.settings.find((s) => s.name === setting.name);
111+
const agentSetting = agentData.agent?.settings.find((s) => s.name === setting.name);
112112
return agentSetting && agentSetting.value === 'HIDDEN';
113113
});
114114
});
@@ -121,8 +121,8 @@ export default function AgentSettings() {
121121

122122
// Find wallet address in agent settings
123123
useEffect(() => {
124-
if (agentData?.settings) {
125-
const setting = agentData.settings.find((s) => s.name === 'SOLANA_WALLET_ADDRESS');
124+
if (agentData?.agent?.settings) {
125+
const setting = agentData.agent.settings.find((s) => s.name === 'SOLANA_WALLET_ADDRESS');
126126
if (setting) {
127127
setSolanaWalletAddress(setting.value);
128128
}
@@ -166,6 +166,8 @@ export default function AgentSettings() {
166166
// Handler for disconnecting provider
167167
const handleDisconnect = async (name: string) => {
168168
const extension = providerData?.find((ext) => ext.name === name);
169+
if (!extension) return;
170+
169171
const emptySettings = extension.settings
170172
.filter((setting) => {
171173
return ['API_KEY', 'SECRET', 'PASSWORD', 'TOKEN'].some((keyword) =>
@@ -202,7 +204,7 @@ export default function AgentSettings() {
202204
// Agent deletion handler
203205
const handleDelete = async () => {
204206
try {
205-
await context.agixt.deleteAgent(agentData?.name || '');
207+
await context.agixt.deleteAgent(agentData?.agent?.name || '');
206208
mutateCompany();
207209
mutateAgent();
208210
router.push(pathname);
@@ -214,11 +216,11 @@ export default function AgentSettings() {
214216
// Agent export handler
215217
const handleExport = async () => {
216218
try {
217-
const agentConfig = await context.agixt.getAgentConfig(agentData?.name || '');
219+
const agentConfig = await context.agixt.getAgentConfig(agentData?.agent?.name || '');
218220
const element = document.createElement('a');
219221
const file = new Blob([JSON.stringify(agentConfig)], { type: 'application/json' });
220222
element.href = URL.createObjectURL(file);
221-
element.download = `${agentData?.name}.json`;
223+
element.download = `${agentData?.agent?.name}.json`;
222224
document.body.appendChild(element);
223225
element.click();
224226
document.body.removeChild(element);
@@ -230,7 +232,7 @@ export default function AgentSettings() {
230232
// Agent rename handler
231233
const handleSaveEdit = async () => {
232234
try {
233-
await context.agixt.renameAgent(agentData?.name || '', editName);
235+
await context.agixt.renameAgent(agentData?.agent?.name || '', editName);
234236
setCookie('agixt-agent', editName, {
235237
domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
236238
});
@@ -240,28 +242,90 @@ export default function AgentSettings() {
240242
}
241243
};
242244

245+
// Company agent rename handler
246+
const handleSaveCompanyEdit = async () => {
247+
try {
248+
const response = await axios.patch(
249+
`${process.env.NEXT_PUBLIC_AGIXT_SERVER}/api/agent/${agentData?.agent?.name}`,
250+
{
251+
new_name: editName,
252+
company_id: agentData?.agent?.companyId,
253+
},
254+
{
255+
headers: {
256+
'Content-Type': 'application/json',
257+
Authorization: getCookie('jwt'),
258+
},
259+
}
260+
);
261+
262+
if (response.status === 200) {
263+
setCookie('agixt-agent', editName, {
264+
domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
265+
});
266+
mutateAgent();
267+
mutateCompany();
268+
toast({
269+
title: 'Success',
270+
description: `Agent renamed to "${editName}" successfully`,
271+
});
272+
}
273+
} catch (error: any) {
274+
console.error('Failed to rename company agent:', error);
275+
console.error('Error response:', error.response?.data);
276+
toast({
277+
title: 'Error',
278+
description: error.response?.data?.detail || 'Failed to rename agent. Please try again.',
279+
variant: 'destructive',
280+
});
281+
}
282+
};
283+
243284
// Get agent wallet handler
244285
const getAgentWallet = async () => {
245286
try {
246-
const response = await axios.get(`${process.env.NEXT_PUBLIC_AGIXT_SERVER}/api/agent/${agentData?.name}/wallet`, {
287+
const serverUrl = process.env.NEXT_PUBLIC_AGIXT_SERVER;
288+
const agentName = agentData?.agent?.name;
289+
const jwt = getCookie('jwt');
290+
291+
console.log('Fetching wallet for agent:', agentName);
292+
console.log('Server URL:', serverUrl);
293+
console.log('JWT exists:', !!jwt);
294+
295+
const response = await axios.get(`${serverUrl}/api/agent/${agentName}/wallet`, {
247296
headers: {
248297
'Content-Type': 'application/json',
249-
Authorization: getCookie('jwt'),
298+
Authorization: jwt,
250299
},
251300
});
301+
console.log('Wallet response:', response.data);
252302
return response.data as WalletKeys;
253-
} catch (error) {
303+
} catch (error: any) {
254304
console.error('Failed to get agent wallet:', error);
305+
console.error('Error response:', error.response?.data);
306+
console.error('Error status:', error.response?.status);
307+
toast({
308+
title: 'Error',
309+
description: error.response?.data?.detail || 'Failed to retrieve wallet data. Please try again.',
310+
variant: 'destructive',
311+
});
312+
throw error;
255313
}
256314
};
257315

258316
// Reveal wallet handler
259317
const handleRevealWallet = async () => {
260-
if (walletData) {
261-
setIsWalletRevealed(!isWalletRevealed);
318+
if (walletData && isWalletRevealed) {
319+
setIsWalletRevealed(false);
262320
return;
263321
}
264322

323+
if (walletData && !isWalletRevealed) {
324+
setIsWalletRevealed(true);
325+
return;
326+
}
327+
328+
// Need to fetch wallet data
265329
setIsLoadingWallet(true);
266330
try {
267331
const data = await getAgentWallet();
@@ -281,21 +345,21 @@ export default function AgentSettings() {
281345
<Card className='w-full shadow-lg'>
282346
<CardHeader className='pb-2'>
283347
<div className='flex justify-between items-center'>
284-
<CardTitle className='text-xl font-bold'>{agentData?.name}</CardTitle>
348+
<CardTitle className='text-xl font-bold'>{agentData?.agent?.name}</CardTitle>
285349
</div>
286350
<p className='text-muted-foreground'>{companyData?.name}</p>
287351
</CardHeader>
288352

289353
<CardContent className='space-y-2 pb-2'>
290354
<div className='grid grid-cols-[auto_1fr] gap-x-2 text-sm'>
291355
<span className='font-medium text-muted-foreground'>Agent ID:</span>
292-
<span className='truncate' title={agentData?.id}>
293-
{agentData?.id}
356+
<span className='truncate' title={agentData?.agent?.id}>
357+
{agentData?.agent?.id}
294358
</span>
295359

296360
<span className='font-medium text-muted-foreground'>Company ID:</span>
297-
<span className='truncate' title={agentData?.companyId}>
298-
{agentData?.companyId}
361+
<span className='truncate' title={agentData?.agent?.companyId}>
362+
{agentData?.agent?.companyId}
299363
</span>
300364
{solanaWalletAddress && (
301365
<>
@@ -354,7 +418,7 @@ export default function AgentSettings() {
354418
</code>
355419
</div>
356420
</div>
357-
<Alert variant='warning' className='mt-2'>
421+
<Alert variant='default' className='mt-2'>
358422
<AlertDescription>
359423
Keep these details secure. Never share your private key or passphrase with anyone.
360424
</AlertDescription>
@@ -376,7 +440,12 @@ export default function AgentSettings() {
376440

377441
<Dialog>
378442
<DialogTrigger asChild>
379-
<Button variant='outline' size='sm' className='flex items-center'>
443+
<Button
444+
variant='outline'
445+
size='sm'
446+
className='flex items-center'
447+
onClick={() => setEditName(agentData?.agent?.name || '')}
448+
>
380449
<LuPencil className='h-4 w-4 mr-1' />
381450
Edit
382451
</Button>
@@ -447,7 +516,83 @@ export default function AgentSettings() {
447516
</Dialog>
448517
</div>
449518
) : (
450-
<></>
519+
<div className='flex items-center justify-center p-4'>
520+
<Card className='w-full shadow-lg'>
521+
<CardHeader className='pb-2'>
522+
<div className='flex justify-between items-center'>
523+
<CardTitle className='text-xl font-bold'>{agentData?.agent?.name}</CardTitle>
524+
</div>
525+
<p className='text-muted-foreground'>{companyData?.name} (Company Agent)</p>
526+
</CardHeader>
527+
528+
<CardContent className='space-y-2 pb-2'>
529+
<div className='grid grid-cols-[auto_1fr] gap-x-2 text-sm'>
530+
<span className='font-medium text-muted-foreground'>Agent ID:</span>
531+
<span className='truncate' title={agentData?.agent?.id}>
532+
{agentData?.agent?.id}
533+
</span>
534+
535+
<span className='font-medium text-muted-foreground'>Company ID:</span>
536+
<span className='truncate' title={agentData?.agent?.companyId}>
537+
{agentData?.agent?.companyId}
538+
</span>
539+
</div>
540+
</CardContent>
541+
542+
<CardFooter className={cn('pt-2', isMobile ? 'flex-wrap gap-2 justify-center' : 'flex justify-end gap-2')}>
543+
<Dialog>
544+
<DialogTrigger asChild>
545+
<Button
546+
variant='outline'
547+
size='sm'
548+
className='flex items-center'
549+
onClick={() => setEditName(agentData?.agent?.name || '')}
550+
>
551+
<LuPencil className='h-4 w-4 mr-1' />
552+
Rename
553+
</Button>
554+
</DialogTrigger>
555+
<DialogContent>
556+
<DialogHeader>
557+
<DialogTitle>Rename Company Agent</DialogTitle>
558+
</DialogHeader>
559+
<div className='py-4'>
560+
<Label htmlFor='company-agent-name'>Agent Name</Label>
561+
<Input
562+
id='company-agent-name'
563+
value={editName}
564+
onChange={(e) => setEditName(e.target.value)}
565+
className='mt-1'
566+
placeholder={agentData?.agent?.name || 'Enter new name'}
567+
/>
568+
</div>
569+
<DialogFooter>
570+
<DialogClose asChild>
571+
<Button variant='outline' className={isMobile ? 'w-full' : ''}>
572+
Cancel
573+
</Button>
574+
</DialogClose>
575+
<DialogClose asChild>
576+
<Button onClick={handleSaveCompanyEdit} className={isMobile ? 'w-full' : ''}>
577+
Save
578+
</Button>
579+
</DialogClose>
580+
</DialogFooter>
581+
</DialogContent>
582+
</Dialog>
583+
584+
<Button variant='outline' size='sm' className='flex items-center' onClick={handleExport}>
585+
<LuDownload className='h-4 w-4 mr-1' />
586+
Export
587+
</Button>
588+
589+
<Button variant='destructive' size='sm' className='flex items-center' onClick={handleDelete}>
590+
<LuTrash2 className='h-4 w-4 mr-1' />
591+
Delete
592+
</Button>
593+
</CardFooter>
594+
</Card>
595+
</div>
451596
)}
452597

453598
{/* Providers section */}
@@ -506,8 +651,8 @@ export default function AgentSettings() {
506651
onClick={() => {
507652
// Initialize settings with the default values from provider.settings
508653
setSettings(
509-
provider.settings.reduce((acc, setting) => {
510-
acc[setting.name] = setting.value;
654+
provider.settings.reduce((acc: Record<string, string>, setting) => {
655+
acc[setting.name] = setting.value as string;
511656
return acc;
512657
}, {}),
513658
);
@@ -536,7 +681,7 @@ export default function AgentSettings() {
536681
? 'password'
537682
: 'text'
538683
}
539-
defaultValue={prov.value}
684+
defaultValue={prov.value as string}
540685
value={settings[prov.name]}
541686
onChange={(e) =>
542687
setSettings((prev) => ({

components/interactive/useAgent.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,18 @@ export function useAgent(
6767
if (!searchName && companies?.length) {
6868
foundEarly = getDefaultAgent();
6969
}
70-
const swrHook = useSWR<{ agent: Agent | null; commands: string[]; extensions: any[] }>(
70+
const swrHook = useSWR<{ agent: Agent | null; commands: string[]; settings: any[] }>(
7171
[`/agent?name=${searchName}`, companies, withSettings],
72-
async (): Promise<{ agent: Agent | null; commands: string[]; extensions: any[] }> => {
72+
async (): Promise<{ agent: Agent | null; commands: string[]; settings: any[] }> => {
7373
try {
7474
if (withSettings) {
7575
const client = createGraphQLClient();
7676
const query = AgentSchema.toGQL('query', 'GetAgent', { name: searchName });
7777
const response = await client.request<{ agent: Agent }>(query, { name: searchName });
78-
return AgentSchema.parse(response.agent);
78+
const agent = AgentSchema.parse(response.agent);
79+
return { agent, commands: [], settings: [] };
7980
} else {
80-
const toReturn = { agent: foundEarly, commands: [], extensions: [] };
81+
const toReturn = { agent: foundEarly, commands: [], settings: [] };
8182
if (companies?.length && !toReturn.agent) {
8283
for (const company of companies) {
8384
const agent = company.agents.find((a) => a.name === searchName);
@@ -90,7 +91,7 @@ export function useAgent(
9091
toReturn.agent = getDefaultAgent();
9192
}
9293
if (toReturn.agent) {
93-
toReturn.extensions = (
94+
toReturn.settings = (
9495
await axios.get(`${process.env.NEXT_PUBLIC_AGIXT_SERVER}/api/agent/${toReturn.agent.name}/extensions`, {
9596
headers: {
9697
Authorization: getCookie('jwt'),
@@ -104,10 +105,10 @@ export function useAgent(
104105
}
105106
} catch (error) {
106107
console.error('Error fetching agent:', error);
107-
return { agent: null, commands: [], extensions: [] };
108+
return { agent: null, commands: [], settings: [] };
108109
}
109110
},
110-
{ fallbackData: { agent: null, commands: [], extensions: [] } },
111+
{ fallbackData: { agent: null, commands: [], settings: [] } },
111112
);
112113
const originalMutate = swrHook.mutate;
113114
swrHook.mutate = chainMutations(companiesHook, originalMutate);

0 commit comments

Comments
 (0)