@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.
Files changed (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +350 -0
  3. package/dist/assets/empty-module-CLMscLYw.js +1 -0
  4. package/dist/assets/main-BBZ_3lkn.css +5999 -0
  5. package/dist/assets/main-C5zNUkXH.js +7 -0
  6. package/dist/assets/main-Dz64ENQg.js +614 -0
  7. package/dist/assets/react-vendor-DM5m98rr.js +545 -0
  8. package/dist/assets/ui-vendor-BQCqNqg0.js +1 -0
  9. package/dist/elizaos-avatar.png +0 -0
  10. package/dist/elizaos-icon.png +0 -0
  11. package/dist/elizaos-logo-light.png +0 -0
  12. package/dist/elizaos.webp +0 -0
  13. package/dist/favicon.ico +0 -0
  14. package/dist/images/agents/agent1.png +0 -0
  15. package/dist/images/agents/agent2.png +0 -0
  16. package/dist/images/agents/agent3.png +0 -0
  17. package/dist/images/agents/agent4.png +0 -0
  18. package/dist/images/agents/agent5.png +0 -0
  19. package/dist/index.html +14 -0
  20. package/index.html +24 -0
  21. package/package.json +159 -0
  22. package/postcss.config.js +3 -0
  23. package/public/elizaos-avatar.png +0 -0
  24. package/public/elizaos-icon.png +0 -0
  25. package/public/elizaos-logo-light.png +0 -0
  26. package/public/elizaos.webp +0 -0
  27. package/public/favicon.ico +0 -0
  28. package/public/images/agents/agent1.png +0 -0
  29. package/public/images/agents/agent2.png +0 -0
  30. package/public/images/agents/agent3.png +0 -0
  31. package/public/images/agents/agent4.png +0 -0
  32. package/public/images/agents/agent5.png +0 -0
  33. package/src/App.tsx +222 -0
  34. package/src/components/AgentDetailsPanel.tsx +147 -0
  35. package/src/components/ChatInputArea.tsx +196 -0
  36. package/src/components/ChatMessageListComponent.tsx +139 -0
  37. package/src/components/actionTool.tsx +186 -0
  38. package/src/components/add-agent-card.tsx +77 -0
  39. package/src/components/agent-action-viewer.tsx +816 -0
  40. package/src/components/agent-avatar-stack.tsx +121 -0
  41. package/src/components/agent-card.cy.tsx +259 -0
  42. package/src/components/agent-card.tsx +177 -0
  43. package/src/components/agent-creator.tsx +142 -0
  44. package/src/components/agent-log-viewer.tsx +645 -0
  45. package/src/components/agent-memory-edit-overlay.tsx +461 -0
  46. package/src/components/agent-memory-viewer.tsx +504 -0
  47. package/src/components/agent-settings.tsx +270 -0
  48. package/src/components/agent-sidebar.tsx +178 -0
  49. package/src/components/api-key-dialog.tsx +113 -0
  50. package/src/components/app-sidebar.tsx +685 -0
  51. package/src/components/array-input.tsx +116 -0
  52. package/src/components/audio-recorder.tsx +292 -0
  53. package/src/components/avatar-panel.tsx +141 -0
  54. package/src/components/character-form.tsx +1138 -0
  55. package/src/components/chat.tsx +1813 -0
  56. package/src/components/combobox.tsx +187 -0
  57. package/src/components/confirmation-dialog.tsx +59 -0
  58. package/src/components/connection-error-banner.tsx +101 -0
  59. package/src/components/connection-status.cy.tsx +73 -0
  60. package/src/components/connection-status.tsx +155 -0
  61. package/src/components/copy-button.tsx +35 -0
  62. package/src/components/delete-button.tsx +24 -0
  63. package/src/components/env-settings.tsx +261 -0
  64. package/src/components/group-card.tsx +160 -0
  65. package/src/components/group-panel.tsx +543 -0
  66. package/src/components/input-copy.tsx +21 -0
  67. package/src/components/logs-page.tsx +41 -0
  68. package/src/components/media-content.tsx +385 -0
  69. package/src/components/memory-graph.tsx +170 -0
  70. package/src/components/missing-secrets-dialog.tsx +72 -0
  71. package/src/components/onboarding-tour.tsx +247 -0
  72. package/src/components/page-title.tsx +8 -0
  73. package/src/components/plugins-panel.tsx +383 -0
  74. package/src/components/profile-card.tsx +66 -0
  75. package/src/components/profile-overlay.tsx +283 -0
  76. package/src/components/retry-button.tsx +28 -0
  77. package/src/components/secret-panel.tsx +1505 -0
  78. package/src/components/server-management.tsx +264 -0
  79. package/src/components/split-button.tsx +148 -0
  80. package/src/components/stop-agent-button.tsx +99 -0
  81. package/src/components/ui/alert-dialog.cy.tsx +333 -0
  82. package/src/components/ui/alert-dialog.tsx +115 -0
  83. package/src/components/ui/alert.tsx +49 -0
  84. package/src/components/ui/avatar.cy.tsx +180 -0
  85. package/src/components/ui/avatar.tsx +57 -0
  86. package/src/components/ui/badge.cy.tsx +146 -0
  87. package/src/components/ui/badge.tsx +43 -0
  88. package/src/components/ui/button.cy.tsx +177 -0
  89. package/src/components/ui/button.tsx +56 -0
  90. package/src/components/ui/card.cy.tsx +160 -0
  91. package/src/components/ui/card.tsx +73 -0
  92. package/src/components/ui/chat/animated-markdown.tsx +59 -0
  93. package/src/components/ui/chat/chat-bubble.tsx +178 -0
  94. package/src/components/ui/chat/chat-container.tsx +51 -0
  95. package/src/components/ui/chat/chat-input.cy.tsx +169 -0
  96. package/src/components/ui/chat/chat-input.tsx +47 -0
  97. package/src/components/ui/chat/chat-message-list.tsx +61 -0
  98. package/src/components/ui/chat/chat-tts-button.tsx +199 -0
  99. package/src/components/ui/chat/code-block.tsx +79 -0
  100. package/src/components/ui/chat/expandable-chat.tsx +131 -0
  101. package/src/components/ui/chat/hooks/useAutoScroll.ts +86 -0
  102. package/src/components/ui/chat/markdown.tsx +209 -0
  103. package/src/components/ui/chat/message-loading.tsx +48 -0
  104. package/src/components/ui/checkbox.cy.tsx +170 -0
  105. package/src/components/ui/checkbox.tsx +30 -0
  106. package/src/components/ui/collapsible.cy.tsx +283 -0
  107. package/src/components/ui/collapsible.tsx +9 -0
  108. package/src/components/ui/command.cy.tsx +313 -0
  109. package/src/components/ui/command.tsx +143 -0
  110. package/src/components/ui/dialog.cy.tsx +279 -0
  111. package/src/components/ui/dialog.tsx +104 -0
  112. package/src/components/ui/dropdown-menu.cy.tsx +273 -0
  113. package/src/components/ui/dropdown-menu.tsx +281 -0
  114. package/src/components/ui/input.cy.tsx +82 -0
  115. package/src/components/ui/input.tsx +27 -0
  116. package/src/components/ui/label.cy.tsx +157 -0
  117. package/src/components/ui/label.tsx +19 -0
  118. package/src/components/ui/resizable.tsx +42 -0
  119. package/src/components/ui/scroll-area.cy.tsx +242 -0
  120. package/src/components/ui/scroll-area.tsx +46 -0
  121. package/src/components/ui/select.cy.tsx +277 -0
  122. package/src/components/ui/select.tsx +155 -0
  123. package/src/components/ui/separator.cy.tsx +145 -0
  124. package/src/components/ui/separator.tsx +29 -0
  125. package/src/components/ui/sheet.cy.tsx +324 -0
  126. package/src/components/ui/sheet.tsx +119 -0
  127. package/src/components/ui/sidebar.tsx +734 -0
  128. package/src/components/ui/skeleton.cy.tsx +149 -0
  129. package/src/components/ui/skeleton.tsx +17 -0
  130. package/src/components/ui/split-button.cy.tsx +274 -0
  131. package/src/components/ui/split-button.tsx +112 -0
  132. package/src/components/ui/switch.tsx +28 -0
  133. package/src/components/ui/tabs.cy.tsx +271 -0
  134. package/src/components/ui/tabs.tsx +53 -0
  135. package/src/components/ui/textarea.cy.tsx +136 -0
  136. package/src/components/ui/textarea.tsx +26 -0
  137. package/src/components/ui/toast.cy.tsx +209 -0
  138. package/src/components/ui/toast.tsx +126 -0
  139. package/src/components/ui/toaster.tsx +29 -0
  140. package/src/components/ui/tooltip.cy.tsx +244 -0
  141. package/src/components/ui/tooltip.tsx +30 -0
  142. package/src/config/agent-templates.ts +349 -0
  143. package/src/config/voice-models.ts +181 -0
  144. package/src/constants.ts +23 -0
  145. package/src/context/AuthContext.tsx +44 -0
  146. package/src/context/ConnectionContext.tsx +194 -0
  147. package/src/entry.tsx +9 -0
  148. package/src/hooks/__tests__/use-agent-tab-state.test.ts +137 -0
  149. package/src/hooks/__tests__/use-agent-update.test.tsx +250 -0
  150. package/src/hooks/__tests__/use-character-convert.test.ts +102 -0
  151. package/src/hooks/__tests__/use-panel-width-state.test.ts +243 -0
  152. package/src/hooks/__tests__/use-sidebar-state.test.ts +117 -0
  153. package/src/hooks/use-agent-management.ts +130 -0
  154. package/src/hooks/use-agent-tab-state.ts +74 -0
  155. package/src/hooks/use-agent-update.ts +469 -0
  156. package/src/hooks/use-character-convert.ts +138 -0
  157. package/src/hooks/use-confirmation.ts +55 -0
  158. package/src/hooks/use-delete-agent.ts +123 -0
  159. package/src/hooks/use-dm-channels.ts +198 -0
  160. package/src/hooks/use-elevenlabs-voices.ts +83 -0
  161. package/src/hooks/use-file-upload.ts +224 -0
  162. package/src/hooks/use-mobile.tsx +19 -0
  163. package/src/hooks/use-onboarding.tsx +49 -0
  164. package/src/hooks/use-panel-width-state.ts +147 -0
  165. package/src/hooks/use-partial-update.ts +288 -0
  166. package/src/hooks/use-plugin-details.ts +462 -0
  167. package/src/hooks/use-plugins.ts +119 -0
  168. package/src/hooks/use-query-hooks.ts +1263 -0
  169. package/src/hooks/use-server-agents.ts +62 -0
  170. package/src/hooks/use-server-version.tsx +47 -0
  171. package/src/hooks/use-sidebar-state.ts +50 -0
  172. package/src/hooks/use-socket-chat.ts +264 -0
  173. package/src/hooks/use-toast.ts +260 -0
  174. package/src/hooks/use-version.tsx +64 -0
  175. package/src/index.css +146 -0
  176. package/src/lib/api-client-config.ts +53 -0
  177. package/src/lib/api-type-mappers.ts +196 -0
  178. package/src/lib/export-utils.ts +123 -0
  179. package/src/lib/logger.ts +19 -0
  180. package/src/lib/media-utils.ts +170 -0
  181. package/src/lib/pca.test.ts +17 -0
  182. package/src/lib/pca.ts +52 -0
  183. package/src/lib/socketio-manager.ts +664 -0
  184. package/src/lib/utils.ts +168 -0
  185. package/src/main.tsx +16 -0
  186. package/src/mocks/empty-module.ts +12 -0
  187. package/src/mocks/node-module.ts +57 -0
  188. package/src/polyfills.ts +37 -0
  189. package/src/routes/agent-detail.tsx +30 -0
  190. package/src/routes/agent-list.tsx +27 -0
  191. package/src/routes/agent-settings.tsx +48 -0
  192. package/src/routes/character-detail.tsx +52 -0
  193. package/src/routes/character-form.tsx +79 -0
  194. package/src/routes/character-list.tsx +38 -0
  195. package/src/routes/chat.tsx +128 -0
  196. package/src/routes/createAgent.tsx +13 -0
  197. package/src/routes/group-new.tsx +50 -0
  198. package/src/routes/group.tsx +29 -0
  199. package/src/routes/home.tsx +218 -0
  200. package/src/routes/not-found.tsx +71 -0
  201. package/src/test/setup.ts +154 -0
  202. package/src/types/crypto-browserify.d.ts +4 -0
  203. package/src/types/index.ts +13 -0
  204. package/src/types/rooms.ts +8 -0
  205. package/src/types.ts +84 -0
  206. package/src/vite-env.d.ts +40 -0
  207. package/tailwind.config.ts +90 -0
  208. package/tsconfig.json +10 -0
  209. package/vite.config.ts +102 -0
@@ -0,0 +1,66 @@
1
+ import { Button } from './ui/button';
2
+ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from './ui/card';
3
+
4
+ interface ButtonConfig {
5
+ label?: string;
6
+ icon?: React.ReactNode;
7
+ action?: () => void;
8
+ className?: string;
9
+ variant?:
10
+ | 'link'
11
+ | 'default'
12
+ | 'destructive'
13
+ | 'outline'
14
+ | 'secondary'
15
+ | 'ghost'
16
+ | null
17
+ | undefined;
18
+ size?: 'default' | 'sm' | 'lg' | 'icon' | null | undefined;
19
+ disabled?: boolean;
20
+ }
21
+
22
+ interface ProfileCardProps {
23
+ title: React.ReactNode;
24
+ content: React.ReactNode;
25
+ buttons: ButtonConfig[];
26
+ className?: string;
27
+ }
28
+
29
+ export default function ProfileCard({ title, content, buttons, className }: ProfileCardProps) {
30
+ return (
31
+ <Card className={`h-full ${className || ''}`}>
32
+ <CardHeader className="pb-2 pt-3">
33
+ <CardTitle className="text-base truncate max-w-48">{title}</CardTitle>
34
+ </CardHeader>
35
+ <CardContent className="p-3">
36
+ <div
37
+ className="rounded-md bg-muted w-full mb-3 overflow-hidden"
38
+ style={{ aspectRatio: '1 / 1' }}
39
+ >
40
+ <div className="flex items-center justify-center h-full">
41
+ <div className="text-4xl font-bold uppercase h-full flex items-center justify-center w-full">
42
+ {content}
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </CardContent>
47
+ <CardFooter className="p-3 pb-4">
48
+ <div className="flex items-center gap-2 w-full justify-center">
49
+ {buttons.map(({ label, icon, action, className, variant, size, disabled }, index) => (
50
+ <Button
51
+ key={index}
52
+ variant={variant}
53
+ className={className}
54
+ onClick={action}
55
+ size={size}
56
+ disabled={disabled}
57
+ >
58
+ {icon}
59
+ {label && <span>{label}</span>}
60
+ </Button>
61
+ ))}
62
+ </div>
63
+ </CardFooter>
64
+ </Card>
65
+ );
66
+ }
@@ -0,0 +1,283 @@
1
+ import { useAgentManagement } from '@/hooks/use-agent-management';
2
+ import { useToast } from '@/hooks/use-toast';
3
+ import { exportCharacterAsJson } from '@/lib/export-utils';
4
+ import { formatAgentName, moment } from '@/lib/utils';
5
+ import type { Agent, UUID } from '@elizaos/core';
6
+ import { AgentStatus } from '@elizaos/core';
7
+ import { Brain, Cog, Loader2, Play, X, Download, Settings } from 'lucide-react';
8
+ import { useNavigate } from 'react-router';
9
+ import { useAgent } from '../hooks/use-query-hooks';
10
+ import StopAgentButton from './stop-agent-button';
11
+ import { Button } from './ui/button';
12
+ import { Card, CardContent, CardFooter, CardHeader } from './ui/card';
13
+ import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
14
+
15
+ interface ProfileOverlayProps {
16
+ isOpen: boolean;
17
+ onClose: () => void;
18
+ agentId: UUID;
19
+ }
20
+
21
+ /**
22
+ * Displays a modal overlay with detailed information and controls for a specific agent.
23
+ *
24
+ * Renders an interactive profile card for the agent identified by {@link agentId}, including avatar, status, metadata, capabilities, plugins, and action buttons for starting, stopping, messaging, and navigating to settings. The overlay is visible when {@link isOpen} is true and can be closed via the provided callback.
25
+ *
26
+ * @param isOpen - Whether the overlay is visible.
27
+ * @param onClose - Callback invoked to close the overlay.
28
+ * @param agentId - UUID of the agent whose profile is displayed.
29
+ *
30
+ * @returns The profile overlay component, or null if not open.
31
+ */
32
+ export default function ProfileOverlay({ isOpen, onClose, agentId }: ProfileOverlayProps) {
33
+ if (!isOpen) return null;
34
+
35
+ const { startAgent, isAgentStarting, isAgentStopping } = useAgentManagement();
36
+ const { toast } = useToast();
37
+ const navigate = useNavigate();
38
+
39
+ const { data: agentData } = useAgent(agentId);
40
+
41
+ const agent = agentData?.data as Agent | undefined;
42
+
43
+ const isActive = agent?.status === AgentStatus.ACTIVE;
44
+ const isStarting = isAgentStarting(agentId);
45
+ const isStopping = isAgentStopping(agentId);
46
+ const isProcessing = isStarting || isStopping;
47
+
48
+ // Start button configuration
49
+ const startButtonConfig = {
50
+ label: 'Start',
51
+ icon: <Play className="w-4 h-4" />,
52
+ };
53
+
54
+ if (isStarting) {
55
+ startButtonConfig.label = 'Starting...';
56
+ startButtonConfig.icon = <Loader2 className="animate-spin w-4 h-4" />;
57
+ }
58
+
59
+ // Handle agent start
60
+ const handleAgentStart = () => {
61
+ if (isProcessing) return;
62
+ startAgent(agent!);
63
+ };
64
+
65
+ // Handle character export
66
+ const handleExportCharacter = () => {
67
+ if (!agentData?.data) return;
68
+
69
+ // Ensure agent has required properties for export
70
+ const agent = {
71
+ ...agentData.data,
72
+ createdAt: agentData.data.createdAt || Date.now(),
73
+ updatedAt: agentData.data.updatedAt || Date.now(),
74
+ } as Agent;
75
+
76
+ exportCharacterAsJson(agent, toast);
77
+ };
78
+
79
+ return (
80
+ <div
81
+ className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4 backdrop-blur-sm"
82
+ onClick={onClose}
83
+ onKeyUp={(e) => {
84
+ if (e.key === 'Enter' || e.key === ' ') {
85
+ onClose();
86
+ }
87
+ }}
88
+ >
89
+ <Card
90
+ className="flex flex-col w-full max-w-md md:max-w-xl overflow-hidden relative"
91
+ onClick={(e) => e.stopPropagation()}
92
+ >
93
+ <CardHeader className="p-0 space-y-0">
94
+ <div className="absolute top-4 right-4 z-10">
95
+ <Button variant="ghost" size="icon" onClick={onClose}>
96
+ <X className="w-5 h-5" />
97
+ </Button>
98
+ </div>
99
+
100
+ <div className="p-6 w-full flex items-end bg-gradient-to-b from-primary/20 to-background">
101
+ <div className="flex w-full justify-between items-end">
102
+ <div className="flex flex-col gap-2">
103
+ <div className="w-24 h-24 flex justify-center items-center relative">
104
+ <div className="text-4xl bg-muted rounded-full h-full w-full flex justify-center items-center overflow-hidden border-4 border-background">
105
+ {typeof agent?.settings?.avatar === 'string' ? (
106
+ <img
107
+ src={agent.settings.avatar}
108
+ alt="Agent Avatar"
109
+ className="w-full h-full object-cover"
110
+ />
111
+ ) : (
112
+ formatAgentName(agent?.name ?? '')
113
+ )}
114
+ </div>
115
+ <div
116
+ className={`absolute bottom-1 right-1 w-4 h-4 rounded-full border-2 border-background ${
117
+ isActive ? 'bg-emerald-500' : 'bg-muted-foreground'
118
+ }`}
119
+ />
120
+ </div>
121
+ <div className="flex flex-col justify-center mr-4">
122
+ <div className="text-xl font-bold truncate max-w-48">{agent?.name}</div>
123
+ <div className="text-xs text-muted-foreground">
124
+ <Tooltip>
125
+ <TooltipTrigger asChild>
126
+ <span
127
+ className="cursor-pointer hover:underline"
128
+ onClick={(e) => {
129
+ e.stopPropagation();
130
+ if (agent?.id) {
131
+ navigator.clipboard.writeText(agent.id);
132
+ }
133
+ }}
134
+ onKeyUp={(e) => {
135
+ if (e.key === 'Enter' || e.key === ' ') {
136
+ e.stopPropagation();
137
+ if (agent?.id) {
138
+ navigator.clipboard.writeText(agent.id);
139
+ }
140
+ }
141
+ }}
142
+ >
143
+ ID: {agent?.id ?? 'N/A'}
144
+ </span>
145
+ </TooltipTrigger>
146
+ <TooltipContent side="bottom">
147
+ <p>Click to copy agent ID</p>
148
+ </TooltipContent>
149
+ </Tooltip>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </CardHeader>
156
+
157
+ <CardContent className="p-6 overflow-auto">
158
+ <div className="rounded-md bg-muted p-4 mb-6 max-h-60 overflow-y-auto">
159
+ <p className="font-medium text-sm mb-2">About Me</p>
160
+ <p className="font-light text-sm text-gray-500">{agentData?.data?.system}</p>
161
+ </div>
162
+
163
+ <div className="space-y-6">
164
+ <div>
165
+ <p className="font-medium text-sm mb-2">Status</p>
166
+ <div className="flex items-center">
167
+ <div
168
+ className={`w-3 h-3 rounded-full mr-2 ${isActive ? 'bg-green-500' : 'bg-gray-400'}`}
169
+ />
170
+ <span className="text-sm">{isActive ? 'Active' : 'Inactive'}</span>
171
+ </div>
172
+ </div>
173
+
174
+ <div>
175
+ <p className="font-medium text-sm mb-2">Model</p>
176
+ <div className="flex items-center gap-2">
177
+ <Brain className="w-4 h-4 text-muted-foreground" />
178
+ <span className="text-sm">
179
+ {typeof agent?.settings?.model === 'string'
180
+ ? agent.settings.model
181
+ : agent?.settings?.model !== undefined
182
+ ? String(agent.settings.model)
183
+ : 'Default'}
184
+ </span>
185
+ </div>
186
+ </div>
187
+
188
+ <div>
189
+ <p className="font-medium text-sm mb-2">Created</p>
190
+ <p className="text-sm text-gray-500">
191
+ {agent?.createdAt ? moment(agent.createdAt).format('LLL') : moment().format('LLL')}
192
+ </p>
193
+ </div>
194
+
195
+ <div>
196
+ <p className="font-medium text-sm mb-2">Plugins</p>
197
+ <div className="flex flex-wrap gap-2">
198
+ {agent?.plugins && agent.plugins.length > 0 ? (
199
+ agent.plugins.map((plugin, index) => {
200
+ // Extract plugin name by removing the prefix
201
+ const pluginName = plugin
202
+ .replace('@elizaos/plugin-', '')
203
+ .replace('@elizaos-plugins/plugin-', '');
204
+ return (
205
+ <span
206
+ key={index}
207
+ className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground border border-border"
208
+ >
209
+ {pluginName}
210
+ </span>
211
+ );
212
+ })
213
+ ) : (
214
+ <p className="text-sm text-gray-500">No plugins enabled</p>
215
+ )}
216
+ </div>
217
+ </div>
218
+ </div>
219
+ </CardContent>
220
+
221
+ <CardFooter className="flex justify-between items-center p-4 border-t">
222
+ <div className="flex items-center gap-2">
223
+ {isActive ? (
224
+ <StopAgentButton agent={agent} showIcon={true} size="default" className="h-9" />
225
+ ) : (
226
+ <Button
227
+ variant="default"
228
+ onClick={handleAgentStart}
229
+ disabled={isProcessing}
230
+ className="h-9"
231
+ >
232
+ {startButtonConfig.icon}
233
+ <span className="ml-2">{startButtonConfig.label}</span>
234
+ </Button>
235
+ )}
236
+
237
+ <Tooltip>
238
+ <TooltipTrigger asChild>
239
+ <Button
240
+ variant="outline"
241
+ onClick={handleExportCharacter}
242
+ disabled={!agent}
243
+ className="h-9"
244
+ size="sm"
245
+ >
246
+ Export
247
+ <Download size={16} />
248
+ </Button>
249
+ </TooltipTrigger>
250
+ <TooltipContent side="bottom">
251
+ <p>Export character as JSON</p>
252
+ </TooltipContent>
253
+ </Tooltip>
254
+
255
+ <Tooltip>
256
+ <TooltipTrigger asChild>
257
+ <Button
258
+ variant="outline"
259
+ onClick={() => navigate(`/settings/${agentId}`)}
260
+ disabled={!agent}
261
+ className="h-9"
262
+ size="sm"
263
+ >
264
+ <Settings size={16} className="mr-1" />
265
+ Settings
266
+ </Button>
267
+ </TooltipTrigger>
268
+ <TooltipContent side="bottom">
269
+ <p>Configure agent settings</p>
270
+ </TooltipContent>
271
+ </Tooltip>
272
+ </div>
273
+
274
+ {isActive && (
275
+ <Button variant="default" className="h-9" onClick={() => navigate(`/chat/${agent.id}`)}>
276
+ Message
277
+ </Button>
278
+ )}
279
+ </CardFooter>
280
+ </Card>
281
+ </div>
282
+ );
283
+ }
@@ -0,0 +1,28 @@
1
+ import { Button } from '@/components/ui/button';
2
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
3
+ import { RefreshCcw } from 'lucide-react';
4
+
5
+ interface RetryButtonProps {
6
+ onClick: () => void;
7
+ className?: string;
8
+ }
9
+
10
+ export default function RetryButton({ onClick, className }: RetryButtonProps) {
11
+ return (
12
+ <Tooltip>
13
+ <TooltipTrigger asChild>
14
+ <Button
15
+ variant="ghost"
16
+ size="icon"
17
+ className={`text-muted-foreground ${className}`}
18
+ onClick={onClick}
19
+ >
20
+ <RefreshCcw className="size-3" />
21
+ </Button>
22
+ </TooltipTrigger>
23
+ <TooltipContent side="bottom">
24
+ <p>Retry message</p>
25
+ </TooltipContent>
26
+ </Tooltip>
27
+ );
28
+ }