@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,168 @@
1
+ import { AVATAR_IMAGE_MAX_SIZE } from '@/constants';
2
+ import type { UUID } from '@elizaos/core';
3
+ import { type ClassValue, clsx } from 'clsx';
4
+ import dayjs from 'dayjs';
5
+ import localizedFormat from 'dayjs/plugin/localizedFormat';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import type { Agent, UUID as CoreUUID } from '@elizaos/core';
8
+ import type { MessageChannel as ClientMessageChannel } from '@/types';
9
+
10
+ /**
11
+ * Combines multiple class names into a single string.
12
+ * * @param {...ClassValue} inputs - Array of class names to be combined.
13
+ * @returns { string } - Combined class names as a single string.
14
+ */
15
+ export function cn(...inputs: ClassValue[]) {
16
+ return twMerge(clsx(inputs));
17
+ }
18
+
19
+ dayjs.extend(localizedFormat);
20
+
21
+ export const moment = dayjs;
22
+
23
+ export const formatAgentName = (name: string) => {
24
+ return name.substring(0, 2);
25
+ };
26
+
27
+ /**
28
+ * Converts a character name to a URL-friendly format by replacing spaces with hyphens
29
+ */
30
+ /**
31
+ * Converts a character name to a URL-friendly format by replacing spaces with hyphens.
32
+ *
33
+ * @param {string} name - The name of the character to convert.
34
+ * @returns {string} The URL-friendly version of the character name.
35
+ */
36
+ export function characterNameToUrl(name: string): string {
37
+ return name.replace(/\s+/g, '-');
38
+ }
39
+
40
+ /**
41
+ * Converts a URL-friendly character name back to its original format by replacing hyphens with spaces
42
+ */
43
+ export function urlToCharacterName(urlName: string): string {
44
+ return urlName.replace(/-+/g, ' ');
45
+ }
46
+
47
+ // crypto.randomUUID only works in https context in firefox
48
+ export function randomUUID(): UUID {
49
+ return URL.createObjectURL(new Blob()).split('/').pop() as UUID;
50
+ }
51
+
52
+ export function getEntityId(): UUID {
53
+ const USER_ID_KEY = 'elizaos-client-user-id';
54
+ const existingUserId = localStorage.getItem(USER_ID_KEY);
55
+
56
+ if (existingUserId) {
57
+ return existingUserId as UUID;
58
+ }
59
+
60
+ const newUserId = randomUUID() as UUID;
61
+ localStorage.setItem(USER_ID_KEY, newUserId);
62
+
63
+ return newUserId;
64
+ }
65
+
66
+ export const compressImage = (
67
+ file: File,
68
+ maxSize = AVATAR_IMAGE_MAX_SIZE,
69
+ quality = 0.8
70
+ ): Promise<string> => {
71
+ return new Promise((resolve, reject) => {
72
+ const reader = new FileReader();
73
+ reader.onload = (e) => {
74
+ if (e.target?.result) {
75
+ const img = new Image();
76
+ img.src = e.target.result as string;
77
+ img.onload = () => {
78
+ const canvas = document.createElement('canvas');
79
+ let width = img.width;
80
+ let height = img.height;
81
+
82
+ if (width > height) {
83
+ if (width > maxSize) {
84
+ height *= maxSize / width;
85
+ width = maxSize;
86
+ }
87
+ } else {
88
+ if (height > maxSize) {
89
+ width *= maxSize / height;
90
+ height = maxSize;
91
+ }
92
+ }
93
+
94
+ canvas.width = width;
95
+ canvas.height = height;
96
+ const ctx = canvas.getContext('2d');
97
+ ctx?.drawImage(img, 0, 0, width, height);
98
+ const resizedBase64 = canvas.toDataURL('image/jpeg', quality);
99
+
100
+ resolve(resizedBase64);
101
+ };
102
+ img.onerror = reject;
103
+ }
104
+ };
105
+ reader.onerror = reject;
106
+ reader.readAsDataURL(file);
107
+ });
108
+ };
109
+
110
+ const AGENT_AVATAR_PLACEHOLDERS = [
111
+ '/images/agents/agent1.png', // Assuming these exist
112
+ '/images/agents/agent2.png',
113
+ '/images/agents/agent3.png',
114
+ '/images/agents/agent4.png',
115
+ '/images/agents/agent5.png',
116
+ ];
117
+
118
+ export const getAgentAvatar = (
119
+ agent: { id?: UUID; settings?: { avatar?: string | null } } | undefined
120
+ ): string => {
121
+ if (agent?.settings?.avatar) {
122
+ return agent.settings.avatar;
123
+ }
124
+ if (agent?.id) {
125
+ // Simple deterministic assignment based on agent ID
126
+ let hash = 0;
127
+ for (let i = 0; i < agent.id.length; i++) {
128
+ const char = agent.id.charCodeAt(i);
129
+ hash = (hash << 5) - hash + char;
130
+ hash |= 0; // Convert to 32bit integer
131
+ }
132
+ const index = Math.abs(hash) % AGENT_AVATAR_PLACEHOLDERS.length;
133
+ return AGENT_AVATAR_PLACEHOLDERS[index];
134
+ }
135
+ // Fallback if no ID or other issue, or if AGENT_AVATAR_PLACEHOLDERS is empty
136
+ return '/elizaos-icon.png';
137
+ };
138
+
139
+ export const generateGroupName = (
140
+ channel: Partial<ClientMessageChannel> | undefined,
141
+ participants: Partial<Agent>[] | undefined,
142
+ currentUserId: CoreUUID | string | undefined
143
+ ): string => {
144
+ if (channel?.name && channel.name.trim() !== '') {
145
+ return channel.name;
146
+ }
147
+ if (participants && participants.length > 0) {
148
+ const otherParticipants = participants.filter((p) => p.id !== currentUserId && p.name); // Ensure name exists
149
+ if (
150
+ otherParticipants.length === 0 &&
151
+ participants.some((p) => p.id === currentUserId && p.name)
152
+ ) {
153
+ // If only current user is a participant (and has a name), or no other named participants
154
+ const currentUserParticipant = participants.find((p) => p.id === currentUserId);
155
+ if (currentUserParticipant) return currentUserParticipant.name || 'Unnamed Group';
156
+ return 'Unnamed Group'; // Fallback if current user somehow has no name
157
+ }
158
+ if (otherParticipants.length > 0) {
159
+ return (
160
+ otherParticipants
161
+ .map((p) => p.name)
162
+ .slice(0, 3)
163
+ .join(', ') + (otherParticipants.length > 3 ? '...' : '')
164
+ );
165
+ }
166
+ }
167
+ return 'Unnamed Group';
168
+ };
package/src/main.tsx ADDED
@@ -0,0 +1,16 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import './index.css';
4
+ import App from './App.tsx';
5
+
6
+ const rootElement = document.getElementById('root');
7
+
8
+ if (!rootElement) {
9
+ throw new Error('Root element not found');
10
+ }
11
+
12
+ createRoot(rootElement).render(
13
+ <StrictMode>
14
+ <App />
15
+ </StrictMode>
16
+ );
@@ -0,0 +1,12 @@
1
+ // Browser stub for Node-only modules (e.g., @sentry/node, @sentry/node-core)
2
+ // Provides explicit no-op implementations to avoid runtime errors during bundling.
3
+
4
+ export function init(_opts?: any): void {}
5
+ export function captureException(_err?: any): void {}
6
+ export async function flush(_timeout?: number): Promise<boolean> {
7
+ return true;
8
+ }
9
+
10
+ // Some consumers might import a namespace object. Provide a default export too.
11
+ const defaultExport = { init, captureException, flush };
12
+ export default defaultExport;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Mock for Node.js module API for browser compatibility
3
+ * This provides stub implementations for Node.js module functions
4
+ * that don't exist in the browser environment
5
+ */
6
+
7
+ // Track warned modules to avoid spamming console
8
+ const warnedModules = new Set<string>();
9
+
10
+ // Mock createRequire function that returns appropriate polyfills
11
+ export const createRequire = (_url?: string) => {
12
+ // Return a mock require function that provides polyfills
13
+ return (id: string) => {
14
+ // Only warn once per module
15
+ if (!warnedModules.has(id)) {
16
+ warnedModules.add(id);
17
+ console.debug(`Browser polyfill: Redirecting require('${id}') to browser-compatible version`);
18
+ }
19
+
20
+ // Return appropriate polyfills for known modules
21
+ if (id === 'crypto' || id === 'node:crypto') {
22
+ // Return the crypto-browserify polyfill if available
23
+ if (typeof window !== 'undefined' && (window as any).crypto) {
24
+ return (window as any).crypto;
25
+ }
26
+ return {};
27
+ }
28
+
29
+ if (id === 'buffer' || id === 'node:buffer') {
30
+ // Return the buffer polyfill if available
31
+ if (typeof window !== 'undefined' && (window as any).Buffer) {
32
+ return { Buffer: (window as any).Buffer };
33
+ }
34
+ return {};
35
+ }
36
+
37
+ return {};
38
+ };
39
+ };
40
+
41
+ // Mock module object
42
+ export const Module = {
43
+ createRequire,
44
+ _extensions: {},
45
+ _cache: {},
46
+ _pathCache: {},
47
+ _nodeModulePaths: () => [],
48
+ globalPaths: [],
49
+ syncBuiltinESMExports: () => {},
50
+ isBuiltin: (_module: string) => false,
51
+ };
52
+
53
+ // Export as default for compatibility
54
+ export default {
55
+ createRequire,
56
+ Module,
57
+ };
@@ -0,0 +1,37 @@
1
+ // Minimal, robust browser shims for Node globals that some deps expect
2
+ import { Buffer } from 'buffer';
3
+
4
+ // Ensure globalThis is used as the single global
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const g: any =
7
+ typeof globalThis !== 'undefined'
8
+ ? globalThis
9
+ : typeof window !== 'undefined'
10
+ ? window
11
+ : // @ts-ignore
12
+ typeof global !== 'undefined'
13
+ ? global
14
+ : {};
15
+
16
+ if (!g.Buffer) {
17
+ g.Buffer = Buffer;
18
+ }
19
+
20
+ if (!g.global) {
21
+ g.global = g;
22
+ }
23
+
24
+ if (!g.process) {
25
+ g.process = {
26
+ env: {},
27
+ browser: true,
28
+ version: '',
29
+ versions: {},
30
+ nextTick: (cb: (...args: any[]) => void) =>
31
+ Promise.resolve()
32
+ .then(cb)
33
+ .catch(() => setTimeout(cb, 0)),
34
+ };
35
+ }
36
+
37
+ export {};
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { useParams } from 'react-router-dom';
3
+ import { useAgent } from '@/hooks/use-query-hooks';
4
+ import { UUID } from '@elizaos/core';
5
+
6
+ const AgentDetail: React.FC = () => {
7
+ const { id } = useParams<{ id: string }>();
8
+ const { data, isLoading, error } = useAgent((id as UUID) || null);
9
+
10
+ if (isLoading) return <div>Loading agent details...</div>;
11
+ if (error) return <div>Error loading agent: {(error as Error).message}</div>;
12
+ if (!data?.data) return <div>Agent not found</div>;
13
+
14
+ const agent = data.data;
15
+
16
+ return (
17
+ <div className="p-4">
18
+ <h1 className="text-2xl font-bold mb-4">{agent.name}</h1>
19
+ <div className="grid gap-4">
20
+ <div className="border rounded-lg p-4 shadow-sm">
21
+ <h2 className="text-xl font-semibold">Agent Details</h2>
22
+ <p className="text-sm text-gray-500">ID: {agent.id}</p>
23
+ {/* Add more agent details here */}
24
+ </div>
25
+ </div>
26
+ </div>
27
+ );
28
+ };
29
+
30
+ export default AgentDetail;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { useAgents } from '@/hooks/use-query-hooks';
3
+ import type { AgentWithStatus } from '@/types';
4
+
5
+ const AgentList: React.FC = () => {
6
+ const { data, isLoading, error } = useAgents();
7
+ const agents = data?.data?.agents || [];
8
+
9
+ if (isLoading) return <div>Loading agents...</div>;
10
+ if (error) return <div>Error loading agents: {(error as Error).message}</div>;
11
+
12
+ return (
13
+ <div className="p-4">
14
+ <h1 className="text-2xl font-bold mb-4">Agents</h1>
15
+ <div className="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
16
+ {agents.map((agent) => (
17
+ <div key={agent.id} className="border rounded-lg p-4 shadow-sm">
18
+ <h2 className="text-xl font-semibold">{agent.name}</h2>
19
+ <p className="text-sm text-gray-500">{agent.id}</p>
20
+ </div>
21
+ ))}
22
+ </div>
23
+ </div>
24
+ );
25
+ };
26
+
27
+ export default AgentList;
@@ -0,0 +1,48 @@
1
+ import { useNavigate, useParams } from 'react-router-dom';
2
+ import { Button } from '@/components/ui/button';
3
+ import AgentSettings from '@/components/agent-settings';
4
+ import { useAgent } from '@/hooks/use-query-hooks';
5
+ import { ArrowLeft } from 'lucide-react';
6
+ import { Loader2 } from 'lucide-react';
7
+ import type { UUID, Agent } from '@elizaos/core';
8
+
9
+ export default function AgentSettingsRoute() {
10
+ const { agentId } = useParams<{ agentId: string }>();
11
+ const navigate = useNavigate();
12
+ const { data: agentData, isLoading } = useAgent(agentId as UUID);
13
+
14
+ if (isLoading) {
15
+ return (
16
+ <div className="flex items-center justify-center h-full">
17
+ <Loader2 className="h-8 w-8 animate-spin" />
18
+ </div>
19
+ );
20
+ }
21
+
22
+ if (!agentData?.data) {
23
+ return (
24
+ <div className="flex flex-col items-center justify-center h-full gap-4">
25
+ <p className="text-muted-foreground">Agent not found</p>
26
+ <Button onClick={() => navigate('/')}>Back to Home</Button>
27
+ </div>
28
+ );
29
+ }
30
+
31
+ const agent: Agent = {
32
+ ...agentData.data,
33
+ createdAt: agentData.data.createdAt ?? Date.now(),
34
+ bio: agentData.data.bio ?? [],
35
+ topics: agentData.data.topics ?? [],
36
+ adjectives: agentData.data.adjectives ?? [],
37
+ style: agentData.data.style ?? { all: [], chat: [], post: [] },
38
+ settings: agentData.data.settings ?? { secrets: {} },
39
+ } as Agent;
40
+
41
+ return (
42
+ <div className="flex w-full justify-center px-4 sm:px-6 overflow-y-auto">
43
+ <div className="w-full md:max-w-4xl py-6">
44
+ <AgentSettings agent={agent} agentId={agentId as UUID} onSaveComplete={() => {}} />
45
+ </div>
46
+ </div>
47
+ );
48
+ }
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import { useParams, Link } from 'react-router-dom';
3
+
4
+ const CharacterDetail: React.FC = () => {
5
+ const { id } = useParams<{ id: string }>();
6
+
7
+ // This is a placeholder component - in a real implementation,
8
+ // you would fetch character data from an API based on the ID
9
+ const character = {
10
+ id,
11
+ name: `Character ${id}`,
12
+ description: 'This is a character description.',
13
+ traits: ['Friendly', 'Intelligent', 'Curious'],
14
+ };
15
+
16
+ return (
17
+ <div className="p-4">
18
+ <h1 className="text-2xl font-bold mb-4">{character.name}</h1>
19
+ <div className="grid gap-4">
20
+ <div className="border rounded-lg p-4 shadow-sm">
21
+ <h2 className="text-xl font-semibold">Character Details</h2>
22
+ <p className="text-sm text-gray-500">ID: {character.id}</p>
23
+ <p className="mt-2">{character.description}</p>
24
+
25
+ <h3 className="text-lg font-semibold mt-4">Traits</h3>
26
+ <ul className="list-disc pl-5">
27
+ {character.traits.map((trait, index) => (
28
+ <li key={index}>{trait}</li>
29
+ ))}
30
+ </ul>
31
+ </div>
32
+ </div>
33
+
34
+ <div className="mt-4 flex gap-2">
35
+ <Link
36
+ to={`/characters/${id}/edit`}
37
+ className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
38
+ >
39
+ Edit Character
40
+ </Link>
41
+ <Link
42
+ to="/characters"
43
+ className="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600"
44
+ >
45
+ Back to List
46
+ </Link>
47
+ </div>
48
+ </div>
49
+ );
50
+ };
51
+
52
+ export default CharacterDetail;
@@ -0,0 +1,79 @@
1
+ import React, { useState } from 'react';
2
+ import { useParams, useNavigate } from 'react-router-dom';
3
+ import { Button } from '@/components/ui/button';
4
+ import { Input } from '@/components/ui/input';
5
+ import { Label } from '@/components/ui/label';
6
+ import { Textarea } from '@/components/ui/textarea';
7
+
8
+ const CharacterForm: React.FC = () => {
9
+ const { id } = useParams<{ id: string }>();
10
+ const navigate = useNavigate();
11
+ const isEditing = id !== 'new';
12
+
13
+ // Initial state - in a real app, you would fetch this data for editing
14
+ const [formData, setFormData] = useState({
15
+ name: isEditing ? `Character ${id}` : '',
16
+ description: isEditing ? 'This is a character description.' : '',
17
+ traits: isEditing ? 'Friendly, Intelligent, Curious' : '',
18
+ });
19
+
20
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
21
+ const { name, value } = e.target;
22
+ setFormData((prev) => ({ ...prev, [name]: value }));
23
+ };
24
+
25
+ const handleSubmit = (e: React.FormEvent) => {
26
+ e.preventDefault();
27
+ // In a real app, you would save the data to an API here
28
+ console.log('Form submitted:', formData);
29
+
30
+ // Navigate back to the character list
31
+ navigate('/characters');
32
+ };
33
+
34
+ return (
35
+ <div className="p-4">
36
+ <h1 className="text-2xl font-bold mb-4">
37
+ {isEditing ? `Edit Character: ${formData.name}` : 'Create New Character'}
38
+ </h1>
39
+
40
+ <form onSubmit={handleSubmit} className="space-y-4">
41
+ <div className="space-y-2">
42
+ <Label htmlFor="name">Name</Label>
43
+ <Input id="name" name="name" value={formData.name} onChange={handleChange} required />
44
+ </div>
45
+
46
+ <div className="space-y-2">
47
+ <Label htmlFor="description">Description</Label>
48
+ <Textarea
49
+ id="description"
50
+ name="description"
51
+ value={formData.description}
52
+ onChange={handleChange}
53
+ rows={4}
54
+ />
55
+ </div>
56
+
57
+ <div className="space-y-2">
58
+ <Label htmlFor="traits">Traits (comma separated)</Label>
59
+ <Input
60
+ id="traits"
61
+ name="traits"
62
+ value={formData.traits}
63
+ onChange={handleChange}
64
+ placeholder="Friendly, Intelligent, Curious"
65
+ />
66
+ </div>
67
+
68
+ <div className="flex gap-2">
69
+ <Button type="submit">{isEditing ? 'Update Character' : 'Create Character'}</Button>
70
+ <Button type="button" variant="outline" onClick={() => navigate('/characters')}>
71
+ Cancel
72
+ </Button>
73
+ </div>
74
+ </form>
75
+ </div>
76
+ );
77
+ };
78
+
79
+ export default CharacterForm;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { Link } from 'react-router-dom';
3
+
4
+ const CharacterList: React.FC = () => {
5
+ // This is a placeholder component - in a real implementation,
6
+ // you would fetch character data from an API
7
+ const characters = [
8
+ { id: '1', name: 'Character 1' },
9
+ { id: '2', name: 'Character 2' },
10
+ { id: '3', name: 'Character 3' },
11
+ ];
12
+
13
+ return (
14
+ <div className="p-4">
15
+ <h1 className="text-2xl font-bold mb-4">Characters</h1>
16
+ <div className="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
17
+ {characters.map((character) => (
18
+ <div key={character.id} className="border rounded-lg p-4 shadow-sm">
19
+ <h2 className="text-xl font-semibold">{character.name}</h2>
20
+ <Link to={`/characters/${character.id}`} className="text-blue-500 hover:underline">
21
+ View Details
22
+ </Link>
23
+ </div>
24
+ ))}
25
+ </div>
26
+ <div className="mt-4">
27
+ <Link
28
+ to="/characters/new"
29
+ className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
30
+ >
31
+ Create New Character
32
+ </Link>
33
+ </div>
34
+ </div>
35
+ );
36
+ };
37
+
38
+ export default CharacterList;