@elizaos/client 1.5.5-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/assets/empty-module-CLMscLYw.js +1 -0
- package/dist/assets/main-BBZ_3lkn.css +5999 -0
- package/dist/assets/main-C5zNUkXH.js +7 -0
- package/dist/assets/main-Dz64ENQg.js +614 -0
- package/dist/assets/react-vendor-DM5m98rr.js +545 -0
- package/dist/assets/ui-vendor-BQCqNqg0.js +1 -0
- package/dist/elizaos-avatar.png +0 -0
- package/dist/elizaos-icon.png +0 -0
- package/dist/elizaos-logo-light.png +0 -0
- package/dist/elizaos.webp +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/images/agents/agent1.png +0 -0
- package/dist/images/agents/agent2.png +0 -0
- package/dist/images/agents/agent3.png +0 -0
- package/dist/images/agents/agent4.png +0 -0
- package/dist/images/agents/agent5.png +0 -0
- package/dist/index.html +14 -0
- package/index.html +24 -0
- package/package.json +159 -0
- package/postcss.config.js +3 -0
- package/public/elizaos-avatar.png +0 -0
- package/public/elizaos-icon.png +0 -0
- package/public/elizaos-logo-light.png +0 -0
- package/public/elizaos.webp +0 -0
- package/public/favicon.ico +0 -0
- package/public/images/agents/agent1.png +0 -0
- package/public/images/agents/agent2.png +0 -0
- package/public/images/agents/agent3.png +0 -0
- package/public/images/agents/agent4.png +0 -0
- package/public/images/agents/agent5.png +0 -0
- package/src/App.tsx +222 -0
- package/src/components/AgentDetailsPanel.tsx +147 -0
- package/src/components/ChatInputArea.tsx +196 -0
- package/src/components/ChatMessageListComponent.tsx +139 -0
- package/src/components/actionTool.tsx +186 -0
- package/src/components/add-agent-card.tsx +77 -0
- package/src/components/agent-action-viewer.tsx +816 -0
- package/src/components/agent-avatar-stack.tsx +121 -0
- package/src/components/agent-card.cy.tsx +259 -0
- package/src/components/agent-card.tsx +177 -0
- package/src/components/agent-creator.tsx +142 -0
- package/src/components/agent-log-viewer.tsx +645 -0
- package/src/components/agent-memory-edit-overlay.tsx +461 -0
- package/src/components/agent-memory-viewer.tsx +504 -0
- package/src/components/agent-settings.tsx +270 -0
- package/src/components/agent-sidebar.tsx +178 -0
- package/src/components/api-key-dialog.tsx +113 -0
- package/src/components/app-sidebar.tsx +685 -0
- package/src/components/array-input.tsx +116 -0
- package/src/components/audio-recorder.tsx +292 -0
- package/src/components/avatar-panel.tsx +141 -0
- package/src/components/character-form.tsx +1138 -0
- package/src/components/chat.tsx +1813 -0
- package/src/components/combobox.tsx +187 -0
- package/src/components/confirmation-dialog.tsx +59 -0
- package/src/components/connection-error-banner.tsx +101 -0
- package/src/components/connection-status.cy.tsx +73 -0
- package/src/components/connection-status.tsx +155 -0
- package/src/components/copy-button.tsx +35 -0
- package/src/components/delete-button.tsx +24 -0
- package/src/components/env-settings.tsx +261 -0
- package/src/components/group-card.tsx +160 -0
- package/src/components/group-panel.tsx +543 -0
- package/src/components/input-copy.tsx +21 -0
- package/src/components/logs-page.tsx +41 -0
- package/src/components/media-content.tsx +385 -0
- package/src/components/memory-graph.tsx +170 -0
- package/src/components/missing-secrets-dialog.tsx +72 -0
- package/src/components/onboarding-tour.tsx +247 -0
- package/src/components/page-title.tsx +8 -0
- package/src/components/plugins-panel.tsx +383 -0
- package/src/components/profile-card.tsx +66 -0
- package/src/components/profile-overlay.tsx +283 -0
- package/src/components/retry-button.tsx +28 -0
- package/src/components/secret-panel.tsx +1505 -0
- package/src/components/server-management.tsx +264 -0
- package/src/components/split-button.tsx +148 -0
- package/src/components/stop-agent-button.tsx +99 -0
- package/src/components/ui/alert-dialog.cy.tsx +333 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +49 -0
- package/src/components/ui/avatar.cy.tsx +180 -0
- package/src/components/ui/avatar.tsx +57 -0
- package/src/components/ui/badge.cy.tsx +146 -0
- package/src/components/ui/badge.tsx +43 -0
- package/src/components/ui/button.cy.tsx +177 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.cy.tsx +160 -0
- package/src/components/ui/card.tsx +73 -0
- package/src/components/ui/chat/animated-markdown.tsx +59 -0
- package/src/components/ui/chat/chat-bubble.tsx +178 -0
- package/src/components/ui/chat/chat-container.tsx +51 -0
- package/src/components/ui/chat/chat-input.cy.tsx +169 -0
- package/src/components/ui/chat/chat-input.tsx +47 -0
- package/src/components/ui/chat/chat-message-list.tsx +61 -0
- package/src/components/ui/chat/chat-tts-button.tsx +199 -0
- package/src/components/ui/chat/code-block.tsx +79 -0
- package/src/components/ui/chat/expandable-chat.tsx +131 -0
- package/src/components/ui/chat/hooks/useAutoScroll.ts +86 -0
- package/src/components/ui/chat/markdown.tsx +209 -0
- package/src/components/ui/chat/message-loading.tsx +48 -0
- package/src/components/ui/checkbox.cy.tsx +170 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.cy.tsx +283 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.cy.tsx +313 -0
- package/src/components/ui/command.tsx +143 -0
- package/src/components/ui/dialog.cy.tsx +279 -0
- package/src/components/ui/dialog.tsx +104 -0
- package/src/components/ui/dropdown-menu.cy.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +281 -0
- package/src/components/ui/input.cy.tsx +82 -0
- package/src/components/ui/input.tsx +27 -0
- package/src/components/ui/label.cy.tsx +157 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/resizable.tsx +42 -0
- package/src/components/ui/scroll-area.cy.tsx +242 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.cy.tsx +277 -0
- package/src/components/ui/select.tsx +155 -0
- package/src/components/ui/separator.cy.tsx +145 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.cy.tsx +324 -0
- package/src/components/ui/sheet.tsx +119 -0
- package/src/components/ui/sidebar.tsx +734 -0
- package/src/components/ui/skeleton.cy.tsx +149 -0
- package/src/components/ui/skeleton.tsx +17 -0
- package/src/components/ui/split-button.cy.tsx +274 -0
- package/src/components/ui/split-button.tsx +112 -0
- package/src/components/ui/switch.tsx +28 -0
- package/src/components/ui/tabs.cy.tsx +271 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.cy.tsx +136 -0
- package/src/components/ui/textarea.tsx +26 -0
- package/src/components/ui/toast.cy.tsx +209 -0
- package/src/components/ui/toast.tsx +126 -0
- package/src/components/ui/toaster.tsx +29 -0
- package/src/components/ui/tooltip.cy.tsx +244 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/config/agent-templates.ts +349 -0
- package/src/config/voice-models.ts +181 -0
- package/src/constants.ts +23 -0
- package/src/context/AuthContext.tsx +44 -0
- package/src/context/ConnectionContext.tsx +194 -0
- package/src/entry.tsx +9 -0
- package/src/hooks/__tests__/use-agent-tab-state.test.ts +137 -0
- package/src/hooks/__tests__/use-agent-update.test.tsx +250 -0
- package/src/hooks/__tests__/use-character-convert.test.ts +102 -0
- package/src/hooks/__tests__/use-panel-width-state.test.ts +243 -0
- package/src/hooks/__tests__/use-sidebar-state.test.ts +117 -0
- package/src/hooks/use-agent-management.ts +130 -0
- package/src/hooks/use-agent-tab-state.ts +74 -0
- package/src/hooks/use-agent-update.ts +469 -0
- package/src/hooks/use-character-convert.ts +138 -0
- package/src/hooks/use-confirmation.ts +55 -0
- package/src/hooks/use-delete-agent.ts +123 -0
- package/src/hooks/use-dm-channels.ts +198 -0
- package/src/hooks/use-elevenlabs-voices.ts +83 -0
- package/src/hooks/use-file-upload.ts +224 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-onboarding.tsx +49 -0
- package/src/hooks/use-panel-width-state.ts +147 -0
- package/src/hooks/use-partial-update.ts +288 -0
- package/src/hooks/use-plugin-details.ts +462 -0
- package/src/hooks/use-plugins.ts +119 -0
- package/src/hooks/use-query-hooks.ts +1263 -0
- package/src/hooks/use-server-agents.ts +62 -0
- package/src/hooks/use-server-version.tsx +47 -0
- package/src/hooks/use-sidebar-state.ts +50 -0
- package/src/hooks/use-socket-chat.ts +264 -0
- package/src/hooks/use-toast.ts +260 -0
- package/src/hooks/use-version.tsx +64 -0
- package/src/index.css +146 -0
- package/src/lib/api-client-config.ts +53 -0
- package/src/lib/api-type-mappers.ts +196 -0
- package/src/lib/export-utils.ts +123 -0
- package/src/lib/logger.ts +19 -0
- package/src/lib/media-utils.ts +170 -0
- package/src/lib/pca.test.ts +17 -0
- package/src/lib/pca.ts +52 -0
- package/src/lib/socketio-manager.ts +664 -0
- package/src/lib/utils.ts +168 -0
- package/src/main.tsx +16 -0
- package/src/mocks/empty-module.ts +12 -0
- package/src/mocks/node-module.ts +57 -0
- package/src/polyfills.ts +37 -0
- package/src/routes/agent-detail.tsx +30 -0
- package/src/routes/agent-list.tsx +27 -0
- package/src/routes/agent-settings.tsx +48 -0
- package/src/routes/character-detail.tsx +52 -0
- package/src/routes/character-form.tsx +79 -0
- package/src/routes/character-list.tsx +38 -0
- package/src/routes/chat.tsx +128 -0
- package/src/routes/createAgent.tsx +13 -0
- package/src/routes/group-new.tsx +50 -0
- package/src/routes/group.tsx +29 -0
- package/src/routes/home.tsx +218 -0
- package/src/routes/not-found.tsx +71 -0
- package/src/test/setup.ts +154 -0
- package/src/types/crypto-browserify.d.ts +4 -0
- package/src/types/index.ts +13 -0
- package/src/types/rooms.ts +8 -0
- package/src/types.ts +84 -0
- package/src/vite-env.d.ts +40 -0
- package/tailwind.config.ts +90 -0
- package/tsconfig.json +10 -0
- package/vite.config.ts +102 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import CharacterForm from '@/components/character-form';
|
|
2
|
+
import { useAgentUpdate } from '@/hooks/use-agent-update';
|
|
3
|
+
import { useAgentManagement } from '@/hooks/use-agent-management';
|
|
4
|
+
import ConfirmationDialog from '@/components/confirmation-dialog';
|
|
5
|
+
import { useConfirmation } from '@/hooks/use-confirmation';
|
|
6
|
+
import { useToast } from '@/hooks/use-toast';
|
|
7
|
+
import { createElizaClient } from '@/lib/api-client-config';
|
|
8
|
+
import type { Agent, UUID } from '@elizaos/core';
|
|
9
|
+
import { AgentStatus } from '@elizaos/core';
|
|
10
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
11
|
+
import { useState, useRef } from 'react';
|
|
12
|
+
import { useNavigate } from 'react-router-dom';
|
|
13
|
+
import AvatarPanel from './avatar-panel';
|
|
14
|
+
import PluginsPanel from './plugins-panel';
|
|
15
|
+
import { SecretPanel, type SecretPanelRef } from './secret-panel';
|
|
16
|
+
import { useDeleteAgent } from '@/hooks/use-delete-agent';
|
|
17
|
+
|
|
18
|
+
export default function AgentSettings({
|
|
19
|
+
agent,
|
|
20
|
+
agentId,
|
|
21
|
+
onSaveComplete,
|
|
22
|
+
}: {
|
|
23
|
+
agent: Agent;
|
|
24
|
+
agentId: UUID;
|
|
25
|
+
onSaveComplete?: () => void;
|
|
26
|
+
}) {
|
|
27
|
+
const { toast } = useToast();
|
|
28
|
+
const navigate = useNavigate();
|
|
29
|
+
const queryClient = useQueryClient();
|
|
30
|
+
const { confirm, isOpen, onOpenChange, onConfirm, options } = useConfirmation();
|
|
31
|
+
const isActive = agent?.status === AgentStatus.ACTIVE;
|
|
32
|
+
const secretPanelRef = useRef<SecretPanelRef>(null);
|
|
33
|
+
const [currentSecrets, setCurrentSecrets] = useState<Record<string, string | null>>({});
|
|
34
|
+
|
|
35
|
+
const { handleDelete: handleDeleteAgent, isDeleting: isDeletingAgent } = useDeleteAgent(agent);
|
|
36
|
+
|
|
37
|
+
// Use our enhanced agent update hook for more intelligent handling of JSONb fields
|
|
38
|
+
const agentState = useAgentUpdate(agent);
|
|
39
|
+
|
|
40
|
+
// Use agent management hook for stop functionality
|
|
41
|
+
const { stopAgent, isAgentStopping } = useAgentManagement();
|
|
42
|
+
|
|
43
|
+
const handleStopAgent = async () => {
|
|
44
|
+
try {
|
|
45
|
+
await stopAgent(agent);
|
|
46
|
+
toast({
|
|
47
|
+
title: 'Success',
|
|
48
|
+
description: 'Agent stopped successfully',
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
toast({
|
|
52
|
+
title: 'Error',
|
|
53
|
+
description: error instanceof Error ? error.message : 'Failed to stop agent',
|
|
54
|
+
variant: 'destructive',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleSubmit = async () => {
|
|
60
|
+
if (!agentId) {
|
|
61
|
+
toast({
|
|
62
|
+
title: 'Error',
|
|
63
|
+
description: 'Agent ID is missing',
|
|
64
|
+
variant: 'destructive',
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Define the actual save logic
|
|
70
|
+
const performSave = async () => {
|
|
71
|
+
try {
|
|
72
|
+
const elizaClient = createElizaClient();
|
|
73
|
+
// Get secrets from state (or ref as fallback)
|
|
74
|
+
const secrets =
|
|
75
|
+
Object.keys(currentSecrets).length > 0
|
|
76
|
+
? currentSecrets
|
|
77
|
+
: secretPanelRef.current?.getSecrets() || {};
|
|
78
|
+
|
|
79
|
+
// Get only the fields that have changed
|
|
80
|
+
const changedFields = agentState.getChangedFields();
|
|
81
|
+
|
|
82
|
+
// Manually add secrets to changedFields if they exist
|
|
83
|
+
if (secrets && Object.keys(secrets).length > 0) {
|
|
84
|
+
// Ensure settings object exists in changedFields
|
|
85
|
+
if (!changedFields.settings) {
|
|
86
|
+
changedFields.settings = {};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const activeSecrets = Object.entries(secrets)
|
|
90
|
+
.filter(([_, value]) => value !== null)
|
|
91
|
+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
|
|
92
|
+
|
|
93
|
+
// Add only active secrets to the settings (exclude deleted ones)
|
|
94
|
+
changedFields.settings.secrets = activeSecrets;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// No need to send update if nothing changed
|
|
98
|
+
if (Object.keys(changedFields).length === 0) {
|
|
99
|
+
const secrets = agentState.agent?.settings?.secrets;
|
|
100
|
+
// Force include secrets if they exist even if no other changes detected
|
|
101
|
+
if (secrets && Object.keys(secrets).length > 0) {
|
|
102
|
+
const forceUpdate = {
|
|
103
|
+
id: agentId,
|
|
104
|
+
settings: { secrets },
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
await elizaClient.agents.updateAgent(agentId, forceUpdate as Partial<Agent>);
|
|
108
|
+
|
|
109
|
+
queryClient.invalidateQueries({ queryKey: ['agent', agentId] });
|
|
110
|
+
queryClient.invalidateQueries({ queryKey: ['agents'] });
|
|
111
|
+
|
|
112
|
+
toast({
|
|
113
|
+
title: 'Success',
|
|
114
|
+
description: 'Agent secrets updated successfully',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (onSaveComplete) {
|
|
118
|
+
onSaveComplete();
|
|
119
|
+
} else {
|
|
120
|
+
navigate('/');
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
toast({
|
|
126
|
+
title: 'No Changes',
|
|
127
|
+
description: 'No changes were made to the agent',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (onSaveComplete) {
|
|
131
|
+
onSaveComplete();
|
|
132
|
+
} else {
|
|
133
|
+
navigate('/');
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Always include the ID
|
|
139
|
+
const partialUpdate = {
|
|
140
|
+
id: agentId,
|
|
141
|
+
...changedFields,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Send the partial update
|
|
145
|
+
await elizaClient.agents.updateAgent(agentId, partialUpdate as Agent);
|
|
146
|
+
|
|
147
|
+
// Invalidate both the agent query and the agents list
|
|
148
|
+
queryClient.invalidateQueries({ queryKey: ['agent', agentId] });
|
|
149
|
+
queryClient.invalidateQueries({ queryKey: ['agents'] });
|
|
150
|
+
|
|
151
|
+
toast({
|
|
152
|
+
title: 'Success',
|
|
153
|
+
description: 'Agent updated successfully',
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Call the onSaveComplete callback if provided, otherwise navigate
|
|
157
|
+
if (onSaveComplete) {
|
|
158
|
+
onSaveComplete();
|
|
159
|
+
} else {
|
|
160
|
+
navigate('/');
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
toast({
|
|
164
|
+
title: 'Error',
|
|
165
|
+
description: error instanceof Error ? error.message : 'Failed to update agent',
|
|
166
|
+
variant: 'destructive',
|
|
167
|
+
});
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Validate required secrets if we have a secret panel ref
|
|
173
|
+
if (secretPanelRef?.current) {
|
|
174
|
+
const secretValidation = secretPanelRef.current.validateSecrets();
|
|
175
|
+
if (!secretValidation.isValid) {
|
|
176
|
+
// Show confirmation dialog for missing secrets
|
|
177
|
+
confirm(
|
|
178
|
+
{
|
|
179
|
+
title: 'Missing Required Secrets',
|
|
180
|
+
description: `The following required secrets are missing: ${secretValidation.missingSecrets.join(', ')}. Do you want to save anyway?`,
|
|
181
|
+
confirmText: 'Save Anyway',
|
|
182
|
+
cancelText: 'Cancel',
|
|
183
|
+
variant: 'destructive',
|
|
184
|
+
},
|
|
185
|
+
performSave
|
|
186
|
+
);
|
|
187
|
+
return; // Exit early - performSave will be called if user confirms
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// If validation passes or no secret panel, proceed with save
|
|
192
|
+
await performSave();
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const handleDelete = () => {
|
|
196
|
+
if (isDeletingAgent) return; // Prevent multiple clicks
|
|
197
|
+
|
|
198
|
+
confirm(
|
|
199
|
+
{
|
|
200
|
+
title: 'Delete Agent',
|
|
201
|
+
description: `Are you sure you want to delete the agent "${agent.name}"? This action cannot be undone.`,
|
|
202
|
+
confirmText: 'Delete',
|
|
203
|
+
variant: 'destructive',
|
|
204
|
+
},
|
|
205
|
+
handleDeleteAgent
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<>
|
|
211
|
+
<CharacterForm
|
|
212
|
+
characterValue={agentState.agent}
|
|
213
|
+
setCharacterValue={agentState}
|
|
214
|
+
title="Agent Settings"
|
|
215
|
+
description="Configure your AI agent's behaviour and capabilities."
|
|
216
|
+
onSubmit={handleSubmit}
|
|
217
|
+
onReset={agentState.reset}
|
|
218
|
+
onDelete={handleDelete}
|
|
219
|
+
onStopAgent={isActive ? handleStopAgent : undefined}
|
|
220
|
+
isAgent={true}
|
|
221
|
+
isDeleting={isDeletingAgent}
|
|
222
|
+
isStopping={isAgentStopping(agentId)}
|
|
223
|
+
customComponents={[
|
|
224
|
+
{
|
|
225
|
+
name: 'Plugins',
|
|
226
|
+
component: (
|
|
227
|
+
<PluginsPanel
|
|
228
|
+
characterValue={agentState.agent}
|
|
229
|
+
setCharacterValue={agentState}
|
|
230
|
+
initialPlugins={agent.plugins}
|
|
231
|
+
/>
|
|
232
|
+
),
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: 'Secret',
|
|
236
|
+
component: (
|
|
237
|
+
<SecretPanel
|
|
238
|
+
characterValue={agentState.agent}
|
|
239
|
+
ref={secretPanelRef}
|
|
240
|
+
onChange={(secrets) => {
|
|
241
|
+
setCurrentSecrets(secrets);
|
|
242
|
+
// Also update the agent state so changes persist across tab switches
|
|
243
|
+
agentState.updateSettings({ secrets });
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
),
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: 'Avatar',
|
|
250
|
+
component: (
|
|
251
|
+
<AvatarPanel characterValue={agentState.agent} setCharacterValue={agentState} />
|
|
252
|
+
),
|
|
253
|
+
},
|
|
254
|
+
]}
|
|
255
|
+
/>
|
|
256
|
+
|
|
257
|
+
{/* Confirmation Dialog */}
|
|
258
|
+
<ConfirmationDialog
|
|
259
|
+
open={isOpen}
|
|
260
|
+
onOpenChange={onOpenChange}
|
|
261
|
+
title={options?.title || ''}
|
|
262
|
+
description={options?.description || ''}
|
|
263
|
+
confirmText={options?.confirmText}
|
|
264
|
+
cancelText={options?.cancelText}
|
|
265
|
+
variant={options?.variant}
|
|
266
|
+
onConfirm={onConfirm}
|
|
267
|
+
/>
|
|
268
|
+
</>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
2
|
+
import { useAgentPanels, useAgent, type AgentPanel } from '@/hooks/use-query-hooks';
|
|
3
|
+
import type { UUID, Agent } from '@elizaos/core';
|
|
4
|
+
import { Columns3, Database, Eye, Code, InfoIcon, Loader2 } from 'lucide-react';
|
|
5
|
+
import { JSX, useMemo } from 'react';
|
|
6
|
+
import { AgentActionViewer } from './agent-action-viewer';
|
|
7
|
+
import { AgentLogViewer } from './agent-log-viewer';
|
|
8
|
+
import { AgentMemoryViewer } from './agent-memory-viewer';
|
|
9
|
+
import { Skeleton } from './ui/skeleton';
|
|
10
|
+
import AgentSettings from '@/components/agent-settings';
|
|
11
|
+
import { useAgentTabState } from '@/hooks/use-agent-tab-state';
|
|
12
|
+
|
|
13
|
+
type AgentSidebarProps = {
|
|
14
|
+
agentId: UUID | undefined;
|
|
15
|
+
agentName: string;
|
|
16
|
+
channelId?: UUID;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type FixedTabValue = 'details' | 'actions' | 'logs' | 'memories';
|
|
20
|
+
type TabValue = FixedTabValue | string;
|
|
21
|
+
|
|
22
|
+
export function AgentSidebar({ agentId, agentName, channelId }: AgentSidebarProps) {
|
|
23
|
+
const { currentTab: detailsTab, setTab: setDetailsTab } = useAgentTabState(agentId);
|
|
24
|
+
const { data: panelsResponse, isLoading: isLoadingPanels } = useAgentPanels(agentId!, {
|
|
25
|
+
enabled: !!agentId,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
data: agentDataResponse,
|
|
30
|
+
isLoading: isLoadingAgent,
|
|
31
|
+
error: agentError,
|
|
32
|
+
} = useAgent(agentId, { enabled: !!agentId && detailsTab === 'details' });
|
|
33
|
+
|
|
34
|
+
const agent = agentDataResponse?.data as Agent | undefined;
|
|
35
|
+
|
|
36
|
+
const agentPanels = useMemo(() => {
|
|
37
|
+
return panelsResponse?.data || [];
|
|
38
|
+
}, [panelsResponse]);
|
|
39
|
+
|
|
40
|
+
const allTabs: { value: TabValue; label: string; icon: JSX.Element }[] = useMemo(() => {
|
|
41
|
+
const fixedTabs: { value: FixedTabValue; label: string; icon: JSX.Element }[] = [
|
|
42
|
+
{ value: 'details', label: 'Details', icon: <InfoIcon className="h-4 w-4" /> },
|
|
43
|
+
{ value: 'actions', label: 'Model Calls', icon: <Eye className="h-4 w-4" /> },
|
|
44
|
+
{ value: 'memories', label: 'Memories', icon: <Database className="h-4 w-4" /> },
|
|
45
|
+
{ value: 'logs', label: 'Logs', icon: <Code className="h-4 w-4" /> },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const dynamicTabs = agentPanels.map((panel: AgentPanel) => ({
|
|
49
|
+
value: panel.name,
|
|
50
|
+
label: panel.name,
|
|
51
|
+
icon: <Columns3 className="h-4 w-4" />,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
return [...fixedTabs, ...dynamicTabs];
|
|
55
|
+
}, [agentPanels]);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Tabs
|
|
59
|
+
defaultValue="details"
|
|
60
|
+
value={detailsTab}
|
|
61
|
+
onValueChange={setDetailsTab}
|
|
62
|
+
className="flex flex-col h-screen w-full max-w-full"
|
|
63
|
+
>
|
|
64
|
+
<TabsList className="flex w-full max-w-full overflow-x-auto flex-shrink-0">
|
|
65
|
+
{allTabs.map((tab) => (
|
|
66
|
+
<TabsTrigger
|
|
67
|
+
key={tab.value}
|
|
68
|
+
value={tab.value}
|
|
69
|
+
className="flex items-center gap-1.5 flex-shrink-0"
|
|
70
|
+
>
|
|
71
|
+
{tab.icon}
|
|
72
|
+
<span className="truncate">{tab.label}</span>
|
|
73
|
+
</TabsTrigger>
|
|
74
|
+
))}
|
|
75
|
+
{isLoadingPanels && (
|
|
76
|
+
<>
|
|
77
|
+
{[...Array(2)].map((_, i) => (
|
|
78
|
+
<Skeleton key={`skel-tab-${i}`} className="h-9 w-full rounded-md flex-shrink-0" />
|
|
79
|
+
))}
|
|
80
|
+
</>
|
|
81
|
+
)}
|
|
82
|
+
</TabsList>
|
|
83
|
+
|
|
84
|
+
<TabsContent
|
|
85
|
+
value="details"
|
|
86
|
+
className="overflow-y-auto overflow-x-hidden flex-1 p-4 w-full max-w-full min-h-0"
|
|
87
|
+
>
|
|
88
|
+
{detailsTab === 'details' && agentId && (
|
|
89
|
+
<>
|
|
90
|
+
{isLoadingAgent && (
|
|
91
|
+
<div className="flex items-center justify-center h-full">
|
|
92
|
+
<Loader2 className="h-6 w-6 animate-spin text-primary" />
|
|
93
|
+
</div>
|
|
94
|
+
)}
|
|
95
|
+
{agentError && (
|
|
96
|
+
<div className="text-red-500 break-words">
|
|
97
|
+
Error loading agent details: {agentError.message}
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
{!isLoadingAgent && !agentError && agent && (
|
|
101
|
+
<div className="w-full max-w-full">
|
|
102
|
+
<AgentSettings
|
|
103
|
+
agent={agent}
|
|
104
|
+
agentId={agentId}
|
|
105
|
+
onSaveComplete={() => {
|
|
106
|
+
// Stay on the same page after save in sidebar context
|
|
107
|
+
// Agent settings saved from sidebar
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
{!isLoadingAgent && !agentError && !agent && !isLoadingPanels && (
|
|
113
|
+
<div className="text-muted-foreground">Agent details not found.</div>
|
|
114
|
+
)}
|
|
115
|
+
</>
|
|
116
|
+
)}
|
|
117
|
+
{detailsTab === 'details' && !agentId && (
|
|
118
|
+
<div className="p-4 text-muted-foreground">Select an agent to see their details.</div>
|
|
119
|
+
)}
|
|
120
|
+
</TabsContent>
|
|
121
|
+
|
|
122
|
+
<TabsContent
|
|
123
|
+
value="actions"
|
|
124
|
+
className="overflow-y-auto overflow-x-hidden flex-1 w-full max-w-full min-h-0"
|
|
125
|
+
>
|
|
126
|
+
{detailsTab === 'actions' && agentId && (
|
|
127
|
+
<div className="w-full max-w-full">
|
|
128
|
+
<AgentActionViewer agentId={agentId} />
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
{detailsTab === 'actions' && !agentId && (
|
|
132
|
+
<div className="p-4 text-muted-foreground">Select an agent to see their actions.</div>
|
|
133
|
+
)}
|
|
134
|
+
</TabsContent>
|
|
135
|
+
<TabsContent
|
|
136
|
+
value="logs"
|
|
137
|
+
className="overflow-y-auto overflow-x-hidden flex-1 w-full max-w-full min-h-0"
|
|
138
|
+
>
|
|
139
|
+
{detailsTab === 'logs' && agentId && (
|
|
140
|
+
<div className="w-full max-w-full">
|
|
141
|
+
<AgentLogViewer agentName={agentName} level="all" />
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
{detailsTab === 'logs' && !agentId && (
|
|
145
|
+
<div className="p-4 text-muted-foreground">Select an agent to see their logs.</div>
|
|
146
|
+
)}
|
|
147
|
+
</TabsContent>
|
|
148
|
+
<TabsContent
|
|
149
|
+
value="memories"
|
|
150
|
+
className="overflow-y-auto overflow-x-hidden flex-1 w-full max-w-full min-h-0"
|
|
151
|
+
>
|
|
152
|
+
{detailsTab === 'memories' && agentId && (
|
|
153
|
+
<div className="w-full max-w-full">
|
|
154
|
+
<AgentMemoryViewer agentId={agentId} agentName={agentName} channelId={channelId} />
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
{detailsTab === 'memories' && !agentId && (
|
|
158
|
+
<div className="p-4 text-muted-foreground">Select an agent to see their memories.</div>
|
|
159
|
+
)}
|
|
160
|
+
</TabsContent>
|
|
161
|
+
{agentPanels.map((panel: AgentPanel) => (
|
|
162
|
+
<TabsContent
|
|
163
|
+
key={panel.name}
|
|
164
|
+
value={panel.name}
|
|
165
|
+
className="overflow-y-auto overflow-x-hidden flex-1 w-full max-w-full min-h-0"
|
|
166
|
+
>
|
|
167
|
+
{detailsTab === panel.name && agentId && (
|
|
168
|
+
<iframe
|
|
169
|
+
src={panel.url}
|
|
170
|
+
title={panel.name}
|
|
171
|
+
className="w-full h-full border-0 flex-1 max-w-full"
|
|
172
|
+
/>
|
|
173
|
+
)}
|
|
174
|
+
</TabsContent>
|
|
175
|
+
))}
|
|
176
|
+
</Tabs>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { Button } from '@/components/ui/button';
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogDescription,
|
|
7
|
+
DialogFooter,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
} from '@/components/ui/dialog';
|
|
11
|
+
import { Input } from '@/components/ui/input';
|
|
12
|
+
import { Label } from '@/components/ui/label';
|
|
13
|
+
import { Eye, EyeOff } from 'lucide-react';
|
|
14
|
+
import { useToast } from '@/hooks/use-toast';
|
|
15
|
+
|
|
16
|
+
const getLocalStorageApiKey = () =>
|
|
17
|
+
typeof window === 'undefined' ? 'eliza-api-key' : `eliza-api-key-${window.location.origin}`;
|
|
18
|
+
interface ApiKeyDialogProps {
|
|
19
|
+
open: boolean;
|
|
20
|
+
onOpenChange: (open: boolean) => void;
|
|
21
|
+
onApiKeySaved: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function ApiKeyDialog({ open, onOpenChange, onApiKeySaved }: ApiKeyDialogProps) {
|
|
25
|
+
const [apiKey, setApiKey] = useState('');
|
|
26
|
+
const [showKey, setShowKey] = useState(false);
|
|
27
|
+
const { toast } = useToast();
|
|
28
|
+
|
|
29
|
+
const storageKey = getLocalStorageApiKey();
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (open) {
|
|
33
|
+
try {
|
|
34
|
+
const storedKey = localStorage.getItem(storageKey);
|
|
35
|
+
if (storedKey) setApiKey(storedKey);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error('Unable to access localStorage', err);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, [open, storageKey]);
|
|
41
|
+
|
|
42
|
+
const handleSave = () => {
|
|
43
|
+
if (!apiKey.trim()) {
|
|
44
|
+
toast({
|
|
45
|
+
title: 'API Key Required',
|
|
46
|
+
description: 'Please enter a valid API key.',
|
|
47
|
+
variant: 'destructive',
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
localStorage.setItem(storageKey, apiKey);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
toast({
|
|
55
|
+
title: 'Storage Error',
|
|
56
|
+
description: 'Unable to save the API key (browser storage blocked).',
|
|
57
|
+
variant: 'destructive',
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
onApiKeySaved();
|
|
62
|
+
toast({
|
|
63
|
+
title: 'API Key Saved',
|
|
64
|
+
description: 'The API key has been stored locally.',
|
|
65
|
+
});
|
|
66
|
+
onOpenChange(false);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
71
|
+
<DialogContent className="sm:max-w-[425px]">
|
|
72
|
+
<DialogHeader>
|
|
73
|
+
<DialogTitle>API Key Required</DialogTitle>
|
|
74
|
+
<DialogDescription>
|
|
75
|
+
Please enter the API key required to connect to the Eliza server. This key will be
|
|
76
|
+
stored locally in your browser.
|
|
77
|
+
</DialogDescription>
|
|
78
|
+
</DialogHeader>
|
|
79
|
+
<div className="grid gap-4 py-4">
|
|
80
|
+
<div className="grid grid-cols-4 items-center gap-4">
|
|
81
|
+
<Label htmlFor="api-key" className="text-right">
|
|
82
|
+
API Key
|
|
83
|
+
</Label>
|
|
84
|
+
<div className="col-span-3 relative">
|
|
85
|
+
<Input
|
|
86
|
+
id="api-key"
|
|
87
|
+
type={showKey ? 'text' : 'password'}
|
|
88
|
+
value={apiKey}
|
|
89
|
+
onChange={(e) => setApiKey(e.target.value)}
|
|
90
|
+
className="pr-10"
|
|
91
|
+
/>
|
|
92
|
+
<Button
|
|
93
|
+
type="button"
|
|
94
|
+
variant="ghost"
|
|
95
|
+
size="icon"
|
|
96
|
+
className="absolute right-1 top-1/2 h-7 w-7 -translate-y-1/2 text-muted-foreground"
|
|
97
|
+
onClick={() => setShowKey(!showKey)}
|
|
98
|
+
aria-label={showKey ? 'Hide API key' : 'Show API key'}
|
|
99
|
+
>
|
|
100
|
+
{showKey ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
|
101
|
+
</Button>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<DialogFooter>
|
|
106
|
+
<Button type="button" onClick={handleSave}>
|
|
107
|
+
Save Key
|
|
108
|
+
</Button>
|
|
109
|
+
</DialogFooter>
|
|
110
|
+
</DialogContent>
|
|
111
|
+
</Dialog>
|
|
112
|
+
);
|
|
113
|
+
}
|