@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,64 @@
1
+ import { ToastAction } from '@/components/ui/toast';
2
+ import { useEffect, useCallback } from 'react';
3
+ import { NavLink } from 'react-router';
4
+ import semver from 'semver';
5
+ import { useToast } from './use-toast';
6
+ import { useServerVersion } from './use-server-version';
7
+ import clientLogger from '../lib/logger';
8
+
9
+ export default function useVersion() {
10
+ const { toast } = useToast();
11
+ const { data: versionInfo } = useServerVersion();
12
+
13
+ async function getLatestRelease(repo: string) {
14
+ const apiUrl = `https://api.github.com/repos/${repo}/releases/latest`;
15
+
16
+ try {
17
+ const response = await fetch(apiUrl, {
18
+ headers: {
19
+ Accept: 'application/vnd.github.v3+json',
20
+ 'User-Agent': 'fetch-latest-release',
21
+ },
22
+ });
23
+
24
+ if (!response.ok) {
25
+ throw new Error(
26
+ `Failed to fetch latest release: ${response.status} ${response.statusText}`
27
+ );
28
+ }
29
+
30
+ const data = await response.json();
31
+ const latestVersion = data.tag_name;
32
+ return latestVersion;
33
+ } catch {}
34
+ }
35
+
36
+ const compareVersion = useCallback(async () => {
37
+ try {
38
+ const latestVersion = await getLatestRelease('elizaos/eliza');
39
+ const thisVersion = versionInfo?.version;
40
+ if (latestVersion && thisVersion) {
41
+ if (semver.gt(latestVersion.replace('v', ''), thisVersion.replace('v', ''))) {
42
+ toast({
43
+ variant: 'default',
44
+ title: `New version ${latestVersion} is available.`,
45
+ description: 'Visit GitHub for more information.',
46
+ action: (
47
+ <NavLink to="https://github.com/elizaos/eliza/releases" target="_blank">
48
+ <ToastAction altText="Update">Update</ToastAction>
49
+ </NavLink>
50
+ ),
51
+ });
52
+ }
53
+ }
54
+ } catch (e) {
55
+ clientLogger.error(`Unable to retrieve latest version from GitHub: ${e}`);
56
+ }
57
+ }, [toast, versionInfo?.version]);
58
+
59
+ useEffect(() => {
60
+ compareVersion();
61
+ }, [compareVersion]);
62
+
63
+ return null;
64
+ }
package/src/index.css ADDED
@@ -0,0 +1,146 @@
1
+ @import 'tailwindcss';
2
+ @config "../tailwind.config.ts";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ @layer base {
7
+ :root {
8
+ --background: 0 0% 100%;
9
+ --foreground: 240 10% 3.9%;
10
+ --card: 0 0% 93%;
11
+ --card-foreground: 240 10% 3.9%;
12
+ --popover: 0 0% 100%;
13
+ --popover-foreground: 240 10% 3.9%;
14
+ --primary: 240 5.9% 10%;
15
+ --primary-foreground: 0 0% 98%;
16
+ --secondary: 240 4.8% 95.9%;
17
+ --secondary-foreground: 240 5.9% 10%;
18
+ --muted: 240 4.8% 95.9%;
19
+ --muted-foreground: 240 3.8% 46.1%;
20
+ --accent: 240 4.8% 97%;
21
+ --accent-foreground: 240 5.9% 10%;
22
+ --destructive: 0 84% 60%;
23
+ --destructive-foreground: 0 0% 98%;
24
+ --border: 240 5.9% 90%;
25
+ --input: 240 5.9% 90%;
26
+ --ring: 240 5.9% 10%;
27
+ --radius: 1rem;
28
+ --sidebar-background: 0 0% 98%;
29
+ --sidebar-foreground: 240 5.3% 26.1%;
30
+ --sidebar-primary: 240 5.9% 10%;
31
+ --sidebar-primary-foreground: 0 0% 98%;
32
+ --sidebar-accent: 240 4.8% 95.9%;
33
+ --sidebar-accent-foreground: 240 5.9% 10%;
34
+ --sidebar-border: 220 13% 91%;
35
+ --sidebar-ring: 217.2 91.2% 59.8%;
36
+ }
37
+
38
+ .dark {
39
+ --background: 0 0% 9%;
40
+ --foreground: 0 0% 98%;
41
+ --card: 0 0% 12%;
42
+ --card-foreground: 0 0% 98%;
43
+ --popover: 0 0% 14%;
44
+ --popover-foreground: 0 0% 98%;
45
+ --primary: 0 0% 98%;
46
+ --primary-foreground: 0 0% 10%;
47
+ --secondary: 0 0% 16%;
48
+ --secondary-foreground: 0 0% 98%;
49
+ --muted: 0 0% 16%;
50
+ --muted-foreground: 0 0% 64%;
51
+ --accent: 0 0% 16%;
52
+ --accent-foreground: 0 0% 98%;
53
+ --destructive: 0 84% 60%;
54
+ --destructive-foreground: 0 0% 98%;
55
+ --border: 0 0% 20%;
56
+ --input: 0 0% 14%;
57
+ --ring: 0 0% 83.9%;
58
+ --sidebar-background: 0 0% 12%;
59
+ --sidebar-foreground: 0 0% 95%;
60
+ --sidebar-primary: 224.3 76.3% 48%;
61
+ --sidebar-primary-foreground: 0 0% 100%;
62
+ --sidebar-accent: 0 0% 16%;
63
+ --sidebar-accent-foreground: 0 0% 95%;
64
+ --sidebar-border: 0 0% 20%;
65
+ --sidebar-ring: 217.2 91.2% 59.8%;
66
+ }
67
+ }
68
+
69
+ @layer base {
70
+ * {
71
+ @apply border-border;
72
+ }
73
+
74
+ body {
75
+ @apply bg-background text-foreground;
76
+ }
77
+ }
78
+
79
+ .scrollbar-hide {
80
+ -ms-overflow-style: none;
81
+ /* IE and Edge */
82
+ scrollbar-width: none;
83
+ /* Firefox */
84
+ }
85
+
86
+ .scrollbar-hide::-webkit-scrollbar {
87
+ display: none;
88
+ /* Chrome, Safari, Opera */
89
+ }
90
+
91
+ /* Custom scrollbar styles for visible scrollbars (like Railway) */
92
+ .scrollbar-visible {
93
+ overflow-x: auto;
94
+ overflow-y: hidden;
95
+ scrollbar-width: thin;
96
+ scrollbar-color: rgb(156, 163, 175) rgb(243, 244, 246);
97
+ }
98
+
99
+ .scrollbar-visible::-webkit-scrollbar {
100
+ height: 8px;
101
+ display: block;
102
+ }
103
+
104
+ .scrollbar-visible::-webkit-scrollbar-track {
105
+ background-color: rgb(243, 244, 246);
106
+ border-radius: 9999px;
107
+ }
108
+
109
+ .scrollbar-visible::-webkit-scrollbar-thumb {
110
+ background-color: rgb(156, 163, 175);
111
+ border-radius: 9999px;
112
+ }
113
+
114
+ .scrollbar-visible::-webkit-scrollbar-thumb:hover {
115
+ background-color: rgb(107, 114, 128);
116
+ }
117
+
118
+ /* Dark mode styles */
119
+ .dark .scrollbar-visible {
120
+ scrollbar-color: rgb(75, 85, 99) rgb(31, 41, 55);
121
+ }
122
+
123
+ .dark .scrollbar-visible::-webkit-scrollbar-track {
124
+ background-color: rgb(31, 41, 55);
125
+ }
126
+
127
+ .dark .scrollbar-visible::-webkit-scrollbar-thumb {
128
+ background-color: rgb(75, 85, 99);
129
+ }
130
+
131
+ .dark .scrollbar-visible::-webkit-scrollbar-thumb:hover {
132
+ background-color: rgb(107, 114, 128);
133
+ }
134
+
135
+ @utility container {
136
+ margin-inline: auto;
137
+ }
138
+
139
+ @layer base {
140
+ * {
141
+ @apply border-border outline-ring/50;
142
+ }
143
+ body {
144
+ @apply bg-background text-foreground;
145
+ }
146
+ }
@@ -0,0 +1,53 @@
1
+ import { ElizaClient, type ApiClientConfig } from '@elizaos/api-client';
2
+
3
+ export function createApiClientConfig(): ApiClientConfig {
4
+ const getLocalStorageApiKey = () => `eliza-api-key-${window.location.origin}`;
5
+ const apiKey = localStorage.getItem(getLocalStorageApiKey());
6
+
7
+ const config: ApiClientConfig = {
8
+ baseUrl: window.location.origin,
9
+ timeout: 30000,
10
+ headers: {
11
+ Accept: 'application/json',
12
+ },
13
+ };
14
+
15
+ // Only include apiKey if it exists (don't pass undefined)
16
+ if (apiKey) {
17
+ config.apiKey = apiKey;
18
+ }
19
+
20
+ return config;
21
+ }
22
+
23
+ // Singleton instance
24
+ let elizaClientInstance: ElizaClient | null = null;
25
+
26
+ export function createElizaClient(): ElizaClient {
27
+ if (!elizaClientInstance) {
28
+ elizaClientInstance = ElizaClient.create(createApiClientConfig());
29
+ }
30
+ return elizaClientInstance;
31
+ }
32
+
33
+ export function getElizaClient(): ElizaClient {
34
+ return createElizaClient();
35
+ }
36
+
37
+ // Function to reset the singleton (useful for API key changes)
38
+ export function resetElizaClient(): void {
39
+ elizaClientInstance = null;
40
+ }
41
+
42
+ export function updateApiClientApiKey(newApiKey: string | null): void {
43
+ const getLocalStorageApiKey = () => `eliza-api-key-${window.location.origin}`;
44
+
45
+ if (newApiKey) {
46
+ localStorage.setItem(getLocalStorageApiKey(), newApiKey);
47
+ } else {
48
+ localStorage.removeItem(getLocalStorageApiKey());
49
+ }
50
+
51
+ // Reset the singleton so it uses the new API key
52
+ resetElizaClient();
53
+ }
@@ -0,0 +1,196 @@
1
+ import {
2
+ Agent as ApiAgent,
3
+ AgentLog as ApiAgentLog,
4
+ Message as ApiMessage,
5
+ MessageChannel as ApiMessageChannel,
6
+ MessageServer as ApiMessageServer,
7
+ Memory as ApiMemory,
8
+ } from '@elizaos/api-client';
9
+ import { Agent, AgentStatus, UUID, ChannelType, Memory } from '@elizaos/core';
10
+ import type {
11
+ AgentWithStatus,
12
+ MessageChannel as ClientMessageChannel,
13
+ MessageServer as ClientMessageServer,
14
+ ServerMessage,
15
+ } from '../types';
16
+ import type { UiMessage } from '../hooks/use-query-hooks';
17
+
18
+ // Map API Agent status strings to core AgentStatus enum
19
+ export function mapApiStatusToEnum(status: 'active' | 'inactive' | 'stopped'): AgentStatus {
20
+ switch (status) {
21
+ case 'active':
22
+ return AgentStatus.ACTIVE;
23
+ case 'inactive':
24
+ case 'stopped': // Map stopped to inactive since core doesn't have STOPPED
25
+ return AgentStatus.INACTIVE;
26
+ default:
27
+ return AgentStatus.INACTIVE;
28
+ }
29
+ }
30
+
31
+ // Map core AgentStatus enum to API status strings
32
+ export function mapEnumToApiStatus(status: AgentStatus): 'active' | 'inactive' | 'stopped' {
33
+ switch (status) {
34
+ case AgentStatus.ACTIVE:
35
+ return 'active';
36
+ case AgentStatus.INACTIVE:
37
+ return 'inactive';
38
+ default:
39
+ return 'inactive';
40
+ }
41
+ }
42
+
43
+ // Convert API Agent to client AgentWithStatus
44
+ export function mapApiAgentToClient(apiAgent: ApiAgent): AgentWithStatus {
45
+ return {
46
+ ...apiAgent,
47
+ id: apiAgent.id as UUID,
48
+ status: mapApiStatusToEnum(apiAgent.status),
49
+ createdAt:
50
+ apiAgent.createdAt instanceof Date
51
+ ? apiAgent.createdAt.getTime()
52
+ : new Date(apiAgent.createdAt).getTime(),
53
+ updatedAt:
54
+ apiAgent.updatedAt instanceof Date
55
+ ? apiAgent.updatedAt.getTime()
56
+ : new Date(apiAgent.updatedAt).getTime(),
57
+ } as AgentWithStatus;
58
+ }
59
+
60
+ // Convert Date to string for API
61
+ export function dateToApiString(date: Date | string | number): string {
62
+ if (date instanceof Date) {
63
+ return date.toISOString();
64
+ }
65
+ if (typeof date === 'number') {
66
+ return new Date(date).toISOString();
67
+ }
68
+ return date;
69
+ }
70
+
71
+ // Convert API date (Date object or string) to timestamp (ms)
72
+ export function apiDateToTimestamp(date: Date | string | number): number {
73
+ if (date instanceof Date) {
74
+ return date.getTime();
75
+ }
76
+ if (typeof date === 'string') {
77
+ return new Date(date).getTime();
78
+ }
79
+ return date;
80
+ }
81
+
82
+ // Convert API date to string
83
+ export function apiDateToString(date: Date | string): string {
84
+ if (date instanceof Date) {
85
+ return date.toISOString();
86
+ }
87
+ return date;
88
+ }
89
+
90
+ // Map API MessageChannel to client MessageChannel
91
+ export function mapApiChannelToClient(apiChannel: ApiMessageChannel): ClientMessageChannel {
92
+ return {
93
+ ...apiChannel,
94
+ id: apiChannel.id as UUID,
95
+ messageServerId: apiChannel.messageServerId as UUID,
96
+ type: apiChannel.type as ChannelType,
97
+ createdAt: apiDateToString(apiChannel.createdAt),
98
+ updatedAt: apiDateToString(apiChannel.updatedAt),
99
+ };
100
+ }
101
+
102
+ // Map API MessageServer to client MessageServer
103
+ export function mapApiServerToClient(apiServer: ApiMessageServer): ClientMessageServer {
104
+ return {
105
+ ...apiServer,
106
+ id: apiServer.id as UUID,
107
+ createdAt: apiDateToString(apiServer.createdAt),
108
+ updatedAt: apiDateToString(apiServer.updatedAt),
109
+ };
110
+ }
111
+
112
+ // Map array of API Servers to client MessageServers
113
+ export function mapApiServersToClient(apiServers: ApiMessageServer[]): ClientMessageServer[] {
114
+ return apiServers.map(mapApiServerToClient);
115
+ }
116
+
117
+ // Map array of API Channels to client MessageChannels
118
+ export function mapApiChannelsToClient(apiChannels: ApiMessageChannel[]): ClientMessageChannel[] {
119
+ return apiChannels.map(mapApiChannelToClient);
120
+ }
121
+
122
+ // Map API Message to UiMessage
123
+ export function mapApiMessageToUi(apiMessage: ApiMessage, serverId?: UUID): UiMessage {
124
+ // Ensure attachments are properly typed as Media[]
125
+ const attachments =
126
+ apiMessage.metadata?.attachments?.map((att: any) => ({
127
+ id: att.id || crypto.randomUUID(),
128
+ url: att.url,
129
+ title: att.title || att.name,
130
+ source: att.source,
131
+ description: att.description,
132
+ text: att.text,
133
+ contentType: att.contentType || att.type,
134
+ })) || undefined;
135
+
136
+ const messageType = apiMessage.sourceType;
137
+ const rawMessage = apiMessage.rawMessage;
138
+ return {
139
+ id: apiMessage.id as UUID,
140
+ text: apiMessage.content,
141
+ name: apiMessage.metadata?.authorDisplayName || apiMessage.metadata?.agentName || 'Unknown',
142
+ senderId: apiMessage.authorId as UUID,
143
+ isAgent: Boolean(apiMessage.metadata?.isAgent) || false,
144
+ createdAt: apiDateToTimestamp(apiMessage.createdAt),
145
+ channelId: apiMessage.channelId as UUID,
146
+ serverId: serverId || (apiMessage.metadata?.serverId as UUID),
147
+ prompt: apiMessage.metadata?.prompt,
148
+ attachments,
149
+ thought: apiMessage.metadata?.thought,
150
+ actions: apiMessage.metadata?.actions,
151
+ type: messageType,
152
+ rawMessage: rawMessage,
153
+ };
154
+ }
155
+
156
+ // Map API AgentLog to client format
157
+ export function mapApiLogToClient(apiLog: ApiAgentLog): AgentLog {
158
+ return {
159
+ id: apiLog.id,
160
+ type: apiLog?.type || apiLog.body?.modelType,
161
+ timestamp: apiLog.timestamp ? apiDateToTimestamp(apiLog.timestamp) : undefined,
162
+ message: apiLog.message,
163
+ details: apiLog.details,
164
+ roomId: apiLog.roomId,
165
+ body: apiLog.body,
166
+ createdAt: apiLog.createdAt ? apiDateToTimestamp(apiLog.createdAt) : undefined,
167
+ };
168
+ }
169
+
170
+ // Type for client-side AgentLog
171
+ export interface AgentLog {
172
+ id?: UUID;
173
+ type?: string;
174
+ timestamp?: number;
175
+ message?: string;
176
+ details?: string;
177
+ roomId?: UUID;
178
+ body?: any;
179
+ createdAt?: number;
180
+ }
181
+
182
+ // Map API Memory to client Memory
183
+ export function mapApiMemoryToClient(apiMemory: ApiMemory): Memory {
184
+ return {
185
+ id: apiMemory.id as UUID,
186
+ entityId: (apiMemory.metadata?.entityId ||
187
+ apiMemory.metadata?.userId ||
188
+ apiMemory.agentId) as UUID,
189
+ agentId: apiMemory.agentId as UUID,
190
+ content: apiMemory.content,
191
+ embedding: apiMemory.embedding,
192
+ roomId: apiMemory.roomId as UUID,
193
+ createdAt: apiDateToTimestamp(apiMemory.createdAt),
194
+ unique: apiMemory.metadata?.unique,
195
+ };
196
+ }
@@ -0,0 +1,123 @@
1
+ import type { Agent } from '@elizaos/core';
2
+
3
+ export interface ExportResult {
4
+ success: boolean;
5
+ filename?: string;
6
+ error?: string;
7
+ }
8
+
9
+ export interface ToastFunction {
10
+ (options: { title: string; description: string; variant?: 'default' | 'destructive' }): void;
11
+ }
12
+
13
+ /**
14
+ * Sanitizes a filename by replacing non-alphanumeric characters with dashes
15
+ * and cleaning up multiple consecutive dashes
16
+ */
17
+ export function sanitizeFilename(name: string): string {
18
+ return name
19
+ .replace(/[^a-zA-Z0-9]/g, '-') // Replace non-alphanumeric with dash
20
+ .replace(/-+/g, '-') // Replace multiple consecutive dashes with single dash
21
+ .replace(/^-|-$/g, '') // Remove leading/trailing dashes
22
+ .toLowerCase();
23
+ }
24
+
25
+ /**
26
+ * Converts an agent to character JSON data, excluding sensitive information
27
+ */
28
+ export function agentToCharacterData(agent: Agent): Record<string, any> {
29
+ const characterData = {
30
+ id: agent.id,
31
+ name: agent.name,
32
+ username: agent.username,
33
+ system: agent.system,
34
+ templates: agent.templates,
35
+ bio: agent.bio,
36
+ messageExamples: agent.messageExamples,
37
+ postExamples: agent.postExamples,
38
+ topics: agent.topics,
39
+ adjectives: agent.adjectives,
40
+ knowledge: agent.knowledge,
41
+ plugins: agent.plugins,
42
+ settings: agent.settings ? { ...agent.settings } : undefined,
43
+ style: agent.style,
44
+ };
45
+
46
+ // Remove secrets from settings if they exist
47
+ if (characterData.settings && 'secrets' in characterData.settings) {
48
+ const { secrets, ...settingsWithoutSecrets } = characterData.settings;
49
+ characterData.settings = settingsWithoutSecrets;
50
+ }
51
+
52
+ // Remove undefined/null fields to keep JSON clean
53
+ return Object.fromEntries(
54
+ Object.entries(characterData).filter(([_, value]) => value !== undefined && value !== null)
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Generates a filename for the exported character
60
+ */
61
+ export function generateExportFilename(agentName: string): string {
62
+ const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
63
+ const sanitizedName = sanitizeFilename(agentName || 'agent');
64
+ return `${sanitizedName}-${date}.json`;
65
+ }
66
+
67
+ /**
68
+ * Creates and triggers a download of a JSON file
69
+ */
70
+ export function downloadJsonFile(data: any, filename: string): void {
71
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
72
+ type: 'application/json',
73
+ });
74
+ const url = URL.createObjectURL(blob);
75
+ const link = document.createElement('a');
76
+ link.href = url;
77
+ link.download = filename;
78
+ document.body.appendChild(link);
79
+ link.click();
80
+ document.body.removeChild(link);
81
+ URL.revokeObjectURL(url);
82
+ }
83
+
84
+ /**
85
+ * Exports an agent's character data as a JSON file download
86
+ * @param agent - The agent containing the character data to export
87
+ * @param toast - Optional toast function for notifications
88
+ * @returns Export result with success status and filename or error
89
+ */
90
+ export function exportCharacterAsJson(agent: Agent, toast?: ToastFunction): ExportResult {
91
+ try {
92
+ const characterData = agentToCharacterData(agent);
93
+ const filename = generateExportFilename(agent.name);
94
+
95
+ downloadJsonFile(characterData, filename);
96
+
97
+ // Success notification
98
+ if (toast) {
99
+ toast({
100
+ title: 'Character Exported',
101
+ description: `${agent.name}'s character data has been downloaded as ${filename}`,
102
+ });
103
+ }
104
+
105
+ return { success: true, filename };
106
+ } catch (error) {
107
+ console.error('Failed to export character:', error);
108
+
109
+ // Error notification
110
+ if (toast) {
111
+ toast({
112
+ title: 'Export Failed',
113
+ description: 'Failed to export character data. Please try again.',
114
+ variant: 'destructive',
115
+ });
116
+ }
117
+
118
+ return {
119
+ success: false,
120
+ error: error instanceof Error ? error.message : 'Unknown error',
121
+ };
122
+ }
123
+ }
@@ -0,0 +1,19 @@
1
+ import { elizaLogger } from '@elizaos/core';
2
+
3
+ // Add client-specific context to logs
4
+ const clientLogger = {
5
+ info: (msg: string, ...args: any[]) => {
6
+ elizaLogger.info({ source: 'client' }, msg, ...args);
7
+ },
8
+ error: (msg: string, ...args: any[]) => {
9
+ elizaLogger.error({ source: 'client' }, msg, ...args);
10
+ },
11
+ warn: (msg: string, ...args: any[]) => {
12
+ elizaLogger.warn({ source: 'client' }, msg, ...args);
13
+ },
14
+ debug: (msg: string, ...args: any[]) => {
15
+ elizaLogger.debug({ source: 'client' }, msg, ...args);
16
+ },
17
+ };
18
+
19
+ export default clientLogger;