@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,504 @@
|
|
|
1
|
+
import type { Memory, UUID } from '@elizaos/core';
|
|
2
|
+
import { Database, LoaderIcon, Pencil, Search, Brain, User, Bot, Clock, Copy } from 'lucide-react';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { useAgentMemories, useAgents } from '@/hooks/use-query-hooks';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { Input } from '@/components/ui/input';
|
|
7
|
+
import {
|
|
8
|
+
Select,
|
|
9
|
+
SelectContent,
|
|
10
|
+
SelectItem,
|
|
11
|
+
SelectTrigger,
|
|
12
|
+
SelectValue,
|
|
13
|
+
} from '@/components/ui/select';
|
|
14
|
+
import { Separator } from '@/components/ui/separator';
|
|
15
|
+
import MemoryEditOverlay from './agent-memory-edit-overlay';
|
|
16
|
+
|
|
17
|
+
// Number of items to load per batch
|
|
18
|
+
const ITEMS_PER_PAGE = 15;
|
|
19
|
+
|
|
20
|
+
interface MemoryContent {
|
|
21
|
+
thought?: boolean | string;
|
|
22
|
+
channelType?: string;
|
|
23
|
+
source?: string;
|
|
24
|
+
text?: string;
|
|
25
|
+
metadata?: {
|
|
26
|
+
fileType?: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
filename?: string;
|
|
29
|
+
path?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface ChatMemoryContent extends MemoryContent {
|
|
35
|
+
text?: string;
|
|
36
|
+
actions?: string[];
|
|
37
|
+
thought?: boolean | string;
|
|
38
|
+
inReplyTo?: string;
|
|
39
|
+
providers?: string[];
|
|
40
|
+
channelType?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
enum MemoryType {
|
|
44
|
+
all = 'all',
|
|
45
|
+
currentChat = 'currentChat',
|
|
46
|
+
messagesReceived = 'messagesReceived',
|
|
47
|
+
messagesSent = 'messagesSent',
|
|
48
|
+
facts = 'facts',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface AgentMemoryViewerProps {
|
|
52
|
+
agentId: UUID;
|
|
53
|
+
agentName: string;
|
|
54
|
+
channelId?: UUID; // Renamed from roomId to channelId for clarity
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function AgentMemoryViewer({ agentId, agentName, channelId }: AgentMemoryViewerProps) {
|
|
58
|
+
const [selectedType, setSelectedType] = useState<MemoryType>(MemoryType.all);
|
|
59
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
60
|
+
const [editingMemory, setEditingMemory] = useState<Memory | null>(null);
|
|
61
|
+
const [visibleItems, setVisibleItems] = useState(ITEMS_PER_PAGE);
|
|
62
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
63
|
+
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
64
|
+
|
|
65
|
+
// Get all agents to look up names by ID
|
|
66
|
+
const { data: agentsData } = useAgents();
|
|
67
|
+
|
|
68
|
+
// Fetch from appropriate table(s) based on selected type
|
|
69
|
+
const messagesTableName = selectedType === MemoryType.facts ? undefined : 'messages';
|
|
70
|
+
const factsTableName =
|
|
71
|
+
selectedType === MemoryType.facts || selectedType === MemoryType.all ? 'facts' : undefined;
|
|
72
|
+
|
|
73
|
+
// Only pass channelId when "Current Chat" is selected
|
|
74
|
+
const channelIdToUse =
|
|
75
|
+
selectedType === MemoryType.currentChat && channelId ? channelId : undefined;
|
|
76
|
+
|
|
77
|
+
const {
|
|
78
|
+
data: messagesData = [],
|
|
79
|
+
isLoading: isLoadingMessages,
|
|
80
|
+
error: messagesError,
|
|
81
|
+
} = useAgentMemories(agentId, messagesTableName, channelIdToUse);
|
|
82
|
+
const {
|
|
83
|
+
data: factsData = [],
|
|
84
|
+
isLoading: isLoadingFacts,
|
|
85
|
+
error: factsError,
|
|
86
|
+
} = useAgentMemories(agentId, factsTableName, channelIdToUse);
|
|
87
|
+
|
|
88
|
+
// Combine memories from both sources
|
|
89
|
+
const memories = [...messagesData, ...factsData];
|
|
90
|
+
const isLoading = isLoadingMessages || isLoadingFacts;
|
|
91
|
+
const error = messagesError || factsError;
|
|
92
|
+
|
|
93
|
+
// Filter and search memories
|
|
94
|
+
const filteredMemories = memories.filter((memory: Memory) => {
|
|
95
|
+
// Type filter
|
|
96
|
+
if (selectedType !== MemoryType.all && selectedType !== MemoryType.currentChat) {
|
|
97
|
+
// Facts are handled by table selection, so if we're on facts table, show all
|
|
98
|
+
if (selectedType === MemoryType.facts) {
|
|
99
|
+
return true; // Already filtered by table
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// For messages table, filter by type
|
|
103
|
+
if (selectedType === MemoryType.messagesSent && memory.entityId !== memory.agentId)
|
|
104
|
+
return false;
|
|
105
|
+
if (selectedType === MemoryType.messagesReceived && memory.entityId === memory.agentId)
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Search filter
|
|
110
|
+
if (searchQuery.trim()) {
|
|
111
|
+
const query = searchQuery.toLowerCase();
|
|
112
|
+
const content = memory.content as ChatMemoryContent;
|
|
113
|
+
const searchableText = [content?.text, content?.thought, memory.id, memory.metadata]
|
|
114
|
+
.filter(Boolean)
|
|
115
|
+
.join(' ')
|
|
116
|
+
.toLowerCase();
|
|
117
|
+
|
|
118
|
+
return searchableText.includes(query);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Handle scroll for infinite loading
|
|
125
|
+
const handleScroll = useCallback(() => {
|
|
126
|
+
if (!scrollContainerRef.current || loadingMore || visibleItems >= filteredMemories.length) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current;
|
|
131
|
+
const scrolledToBottom = scrollTop + clientHeight >= scrollHeight - 200;
|
|
132
|
+
|
|
133
|
+
if (scrolledToBottom) {
|
|
134
|
+
setLoadingMore(true);
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
setVisibleItems((prev) => Math.min(prev + ITEMS_PER_PAGE, filteredMemories.length));
|
|
137
|
+
setLoadingMore(false);
|
|
138
|
+
}, 500);
|
|
139
|
+
}
|
|
140
|
+
}, [loadingMore, visibleItems, filteredMemories.length]);
|
|
141
|
+
|
|
142
|
+
// Reset visible items when filter changes
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
setVisibleItems(ITEMS_PER_PAGE);
|
|
145
|
+
}, [selectedType, searchQuery]);
|
|
146
|
+
|
|
147
|
+
// Set up scroll listener
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
const scrollContainer = scrollContainerRef.current;
|
|
150
|
+
if (scrollContainer) {
|
|
151
|
+
scrollContainer.addEventListener('scroll', handleScroll);
|
|
152
|
+
return () => scrollContainer.removeEventListener('scroll', handleScroll);
|
|
153
|
+
}
|
|
154
|
+
}, [handleScroll]);
|
|
155
|
+
|
|
156
|
+
const formatDate = (timestamp: number) => {
|
|
157
|
+
const date = new Date(timestamp);
|
|
158
|
+
const now = new Date();
|
|
159
|
+
const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60);
|
|
160
|
+
|
|
161
|
+
if (diffInHours < 24) {
|
|
162
|
+
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
163
|
+
} else if (diffInHours < 168) {
|
|
164
|
+
// 7 days
|
|
165
|
+
return date.toLocaleDateString([], { weekday: 'short', hour: '2-digit', minute: '2-digit' });
|
|
166
|
+
} else {
|
|
167
|
+
return date.toLocaleDateString([], {
|
|
168
|
+
month: 'short',
|
|
169
|
+
day: 'numeric',
|
|
170
|
+
hour: '2-digit',
|
|
171
|
+
minute: '2-digit',
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const getMemoryIcon = (memory: Memory, content: ChatMemoryContent) => {
|
|
177
|
+
if (content?.thought) return Brain;
|
|
178
|
+
if (memory.entityId === memory.agentId) return Bot;
|
|
179
|
+
return User;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const copyToClipboard = async (text: string) => {
|
|
183
|
+
try {
|
|
184
|
+
await navigator.clipboard.writeText(text);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error('Failed to copy:', error);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Group messages by date
|
|
191
|
+
const groupMessagesByDate = (messages: Memory[]) => {
|
|
192
|
+
const groups: Record<string, Memory[]> = {};
|
|
193
|
+
|
|
194
|
+
for (const memory of messages) {
|
|
195
|
+
const date = new Date(memory.createdAt || 0);
|
|
196
|
+
const dateKey = date.toLocaleDateString();
|
|
197
|
+
|
|
198
|
+
if (!groups[dateKey]) {
|
|
199
|
+
groups[dateKey] = [];
|
|
200
|
+
}
|
|
201
|
+
groups[dateKey].push(memory);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return groups;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const visibleMemories = filteredMemories.slice(0, visibleItems);
|
|
208
|
+
const hasMoreToLoad = visibleItems < filteredMemories.length;
|
|
209
|
+
const messageGroups = groupMessagesByDate(visibleMemories);
|
|
210
|
+
|
|
211
|
+
// Loading state
|
|
212
|
+
if (isLoading && memories.length === 0) {
|
|
213
|
+
return (
|
|
214
|
+
<div className="flex flex-col h-[calc(100vh-100px)] min-h-[400px] w-full">
|
|
215
|
+
<div className="flex items-center justify-center flex-1">
|
|
216
|
+
<div className="flex flex-col items-center gap-4">
|
|
217
|
+
<LoaderIcon className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
218
|
+
<div className="text-center">
|
|
219
|
+
<h3 className="font-medium">Loading Memories</h3>
|
|
220
|
+
<p className="text-sm text-muted-foreground">
|
|
221
|
+
Fetching agent conversation history...
|
|
222
|
+
</p>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Error state
|
|
231
|
+
if (error) {
|
|
232
|
+
return (
|
|
233
|
+
<div className="flex flex-col h-[calc(100vh-100px)] min-h-[400px] w-full">
|
|
234
|
+
<div className="flex items-center justify-center flex-1">
|
|
235
|
+
<div className="text-center">
|
|
236
|
+
<Database className="h-12 w-12 text-destructive mx-auto mb-4" />
|
|
237
|
+
<h3 className="font-medium text-destructive">Failed to Load Memories</h3>
|
|
238
|
+
<p className="text-sm text-muted-foreground">
|
|
239
|
+
There was an error loading the agent memories.
|
|
240
|
+
</p>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Empty state
|
|
248
|
+
const EmptyState = () => (
|
|
249
|
+
<div className="flex flex-col items-center justify-center flex-1 text-center p-8">
|
|
250
|
+
<Database className="h-16 w-16 text-muted-foreground/30 mb-4" />
|
|
251
|
+
<h3 className="text-lg font-medium mb-2">No Memories Found</h3>
|
|
252
|
+
<p className="text-muted-foreground max-w-md mb-4">
|
|
253
|
+
{searchQuery
|
|
254
|
+
? `No memories match "${searchQuery}". Try adjusting your search or filter.`
|
|
255
|
+
: "This agent hasn't created any memories yet. Memories will appear here as the agent interacts."}
|
|
256
|
+
</p>
|
|
257
|
+
{searchQuery && (
|
|
258
|
+
<Button variant="outline" onClick={() => setSearchQuery('')}>
|
|
259
|
+
Clear Search
|
|
260
|
+
</Button>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// Memory card component
|
|
266
|
+
const MemoryCard = ({ memory }: { memory: Memory }) => {
|
|
267
|
+
const content = memory.content as ChatMemoryContent;
|
|
268
|
+
const IconComponent = getMemoryIcon(memory, content);
|
|
269
|
+
const isAgent = memory.entityId === memory.agentId;
|
|
270
|
+
|
|
271
|
+
// Look up entity name from agents data or fallback to metadata
|
|
272
|
+
const getEntityName = () => {
|
|
273
|
+
if (isAgent) {
|
|
274
|
+
// For agents, try to find the agent name by ID
|
|
275
|
+
const agent = agentsData?.data?.agents?.find((a) => a.id === memory.entityId);
|
|
276
|
+
return agent?.name || agentName;
|
|
277
|
+
} else {
|
|
278
|
+
// For users, use raw metadata or fallback
|
|
279
|
+
return (memory.metadata as any)?.raw?.senderName || memory.metadata?.source || 'User';
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const entityName = getEntityName();
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<div className="border rounded-lg p-4 bg-card hover:bg-accent/5 transition-colors group">
|
|
287
|
+
{/* Header */}
|
|
288
|
+
<div className="flex items-start justify-between mb-3">
|
|
289
|
+
<div className="flex items-center gap-3">
|
|
290
|
+
<div className="p-2 rounded-md bg-muted">
|
|
291
|
+
<IconComponent className="h-4 w-4" />
|
|
292
|
+
</div>
|
|
293
|
+
<div>
|
|
294
|
+
<div className="flex items-center gap-2">
|
|
295
|
+
<span className="font-medium text-sm">{entityName}</span>
|
|
296
|
+
<span className="text-xs px-2 py-0.5 rounded bg-muted text-muted-foreground">
|
|
297
|
+
{content?.thought ? 'Thought' : isAgent ? 'Agent' : 'User'}
|
|
298
|
+
</span>
|
|
299
|
+
</div>
|
|
300
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground mt-1">
|
|
301
|
+
<Clock className="h-3 w-3" />
|
|
302
|
+
<span>{formatDate(memory.createdAt || 0)}</span>
|
|
303
|
+
{memory.id && (
|
|
304
|
+
<>
|
|
305
|
+
<span>•</span>
|
|
306
|
+
<code className="text-[10px] bg-muted px-1 rounded">{memory.id.slice(-8)}</code>
|
|
307
|
+
</>
|
|
308
|
+
)}
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
{/* Action buttons */}
|
|
314
|
+
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
315
|
+
{content?.text && (
|
|
316
|
+
<Button
|
|
317
|
+
variant="ghost"
|
|
318
|
+
size="sm"
|
|
319
|
+
onClick={() => copyToClipboard(content.text || '')}
|
|
320
|
+
className="h-8 w-8 p-0"
|
|
321
|
+
title="Copy text"
|
|
322
|
+
>
|
|
323
|
+
<Copy className="h-3 w-3" />
|
|
324
|
+
</Button>
|
|
325
|
+
)}
|
|
326
|
+
{memory.id && (
|
|
327
|
+
<Button
|
|
328
|
+
variant="ghost"
|
|
329
|
+
size="sm"
|
|
330
|
+
onClick={() => setEditingMemory(memory)}
|
|
331
|
+
className="h-8 w-8 p-0"
|
|
332
|
+
title="Edit memory"
|
|
333
|
+
>
|
|
334
|
+
<Pencil className="h-3 w-3" />
|
|
335
|
+
</Button>
|
|
336
|
+
)}
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
{/* Content */}
|
|
341
|
+
<div className="space-y-3">
|
|
342
|
+
{/* Main text */}
|
|
343
|
+
{content?.text && (
|
|
344
|
+
<div className="bg-muted/50 rounded-md p-3">
|
|
345
|
+
<p className="text-sm leading-relaxed whitespace-pre-wrap">{content.text}</p>
|
|
346
|
+
</div>
|
|
347
|
+
)}
|
|
348
|
+
|
|
349
|
+
{/* Thought process */}
|
|
350
|
+
{content?.thought && (
|
|
351
|
+
<div className="border-l-2 border-muted pl-3">
|
|
352
|
+
<div className="flex items-center gap-2 mb-1">
|
|
353
|
+
<Brain className="h-3 w-3 text-muted-foreground" />
|
|
354
|
+
<span className="text-xs font-medium text-muted-foreground">Thought Process</span>
|
|
355
|
+
</div>
|
|
356
|
+
<p className="text-xs text-muted-foreground italic leading-relaxed">
|
|
357
|
+
{String(content.thought)}
|
|
358
|
+
</p>
|
|
359
|
+
</div>
|
|
360
|
+
)}
|
|
361
|
+
|
|
362
|
+
{/* Tags */}
|
|
363
|
+
{(content?.actions || content?.providers || content?.source) && (
|
|
364
|
+
<div className="flex flex-wrap gap-1">
|
|
365
|
+
{content.actions?.map((action) => (
|
|
366
|
+
<span
|
|
367
|
+
key={action}
|
|
368
|
+
className="text-xs px-2 py-1 bg-muted rounded text-muted-foreground"
|
|
369
|
+
title="Action"
|
|
370
|
+
>
|
|
371
|
+
{action}
|
|
372
|
+
</span>
|
|
373
|
+
))}
|
|
374
|
+
{content.providers?.map((provider) => (
|
|
375
|
+
<span
|
|
376
|
+
key={provider}
|
|
377
|
+
className="text-xs px-2 py-1 bg-muted rounded text-muted-foreground"
|
|
378
|
+
title="Provider"
|
|
379
|
+
>
|
|
380
|
+
{provider}
|
|
381
|
+
</span>
|
|
382
|
+
))}
|
|
383
|
+
{content.source && (
|
|
384
|
+
<span className="text-xs px-2 py-1 bg-muted rounded text-muted-foreground">
|
|
385
|
+
{content.source}
|
|
386
|
+
</span>
|
|
387
|
+
)}
|
|
388
|
+
</div>
|
|
389
|
+
)}
|
|
390
|
+
|
|
391
|
+
{/* Metadata (simplified) */}
|
|
392
|
+
{memory.metadata && Object.keys(memory.metadata).length > 0 && (
|
|
393
|
+
<details className="text-xs">
|
|
394
|
+
<summary className="cursor-pointer text-muted-foreground hover:text-foreground">
|
|
395
|
+
View metadata
|
|
396
|
+
</summary>
|
|
397
|
+
<div className="mt-2 p-2 bg-muted/30 rounded text-[10px] font-mono overflow-x-auto">
|
|
398
|
+
<pre>{JSON.stringify(memory.metadata, null, 2)}</pre>
|
|
399
|
+
</div>
|
|
400
|
+
</details>
|
|
401
|
+
)}
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<div className="flex flex-col h-[calc(100vh-100px)] min-h-[400px] w-full">
|
|
409
|
+
{/* Header */}
|
|
410
|
+
<div className="flex justify-between items-center mb-4 px-4 pt-4 flex-none border-b pb-3">
|
|
411
|
+
<div className="flex items-center gap-2">
|
|
412
|
+
<h3 className="text-lg font-medium">Memories</h3>
|
|
413
|
+
{!isLoading && (
|
|
414
|
+
<span className="ml-2 text-xs px-2 py-1 rounded bg-muted text-muted-foreground">
|
|
415
|
+
{filteredMemories.length}
|
|
416
|
+
</span>
|
|
417
|
+
)}
|
|
418
|
+
</div>
|
|
419
|
+
<div className="flex items-center gap-2">
|
|
420
|
+
{/* Search */}
|
|
421
|
+
<div className="relative">
|
|
422
|
+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
423
|
+
<Input
|
|
424
|
+
placeholder="Search memories..."
|
|
425
|
+
value={searchQuery}
|
|
426
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
427
|
+
className="pl-10 w-full min-w-0 max-w-64"
|
|
428
|
+
/>
|
|
429
|
+
</div>
|
|
430
|
+
{/* Type Filter */}
|
|
431
|
+
<Select
|
|
432
|
+
value={selectedType}
|
|
433
|
+
onValueChange={(value) => setSelectedType(value as MemoryType)}
|
|
434
|
+
>
|
|
435
|
+
<SelectTrigger className="w-40">
|
|
436
|
+
<SelectValue placeholder="Filter memories" />
|
|
437
|
+
</SelectTrigger>
|
|
438
|
+
<SelectContent>
|
|
439
|
+
<SelectItem value={MemoryType.all}>All Messages</SelectItem>
|
|
440
|
+
{channelId && <SelectItem value={MemoryType.currentChat}>Current Chat</SelectItem>}
|
|
441
|
+
<SelectItem value={MemoryType.messagesSent}>Agent Messages</SelectItem>
|
|
442
|
+
<SelectItem value={MemoryType.messagesReceived}>User Messages</SelectItem>
|
|
443
|
+
<SelectItem value={MemoryType.facts}>Facts</SelectItem>
|
|
444
|
+
</SelectContent>
|
|
445
|
+
</Select>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
{/* Content */}
|
|
450
|
+
<div ref={scrollContainerRef} className="flex-1 overflow-y-auto px-4">
|
|
451
|
+
{filteredMemories.length === 0 ? (
|
|
452
|
+
<EmptyState />
|
|
453
|
+
) : (
|
|
454
|
+
<div className="space-y-4">
|
|
455
|
+
{Object.entries(messageGroups).map(([date, messages]) => (
|
|
456
|
+
<div key={date} className="space-y-3">
|
|
457
|
+
<div className="flex items-center gap-3 py-2">
|
|
458
|
+
<Separator className="flex-1" />
|
|
459
|
+
<span className="text-sm font-medium text-muted-foreground px-2">{date}</span>
|
|
460
|
+
<Separator className="flex-1" />
|
|
461
|
+
</div>
|
|
462
|
+
<div className="space-y-3">
|
|
463
|
+
{messages.map((memory) => (
|
|
464
|
+
<MemoryCard key={memory.id || memory.createdAt} memory={memory} />
|
|
465
|
+
))}
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
))}
|
|
469
|
+
|
|
470
|
+
{/* Load more */}
|
|
471
|
+
{hasMoreToLoad && (
|
|
472
|
+
<div className="flex justify-center py-6">
|
|
473
|
+
{loadingMore ? (
|
|
474
|
+
<div className="flex items-center gap-2 text-muted-foreground">
|
|
475
|
+
<LoaderIcon className="h-4 w-4 animate-spin" />
|
|
476
|
+
<span className="text-sm">Loading more memories...</span>
|
|
477
|
+
</div>
|
|
478
|
+
) : (
|
|
479
|
+
<Button
|
|
480
|
+
variant="outline"
|
|
481
|
+
onClick={() => setVisibleItems((prev) => prev + ITEMS_PER_PAGE)}
|
|
482
|
+
className="px-8"
|
|
483
|
+
>
|
|
484
|
+
Load More
|
|
485
|
+
</Button>
|
|
486
|
+
)}
|
|
487
|
+
</div>
|
|
488
|
+
)}
|
|
489
|
+
</div>
|
|
490
|
+
)}
|
|
491
|
+
</div>
|
|
492
|
+
|
|
493
|
+
{/* Edit overlay */}
|
|
494
|
+
{editingMemory && (
|
|
495
|
+
<MemoryEditOverlay
|
|
496
|
+
isOpen={!!editingMemory}
|
|
497
|
+
onClose={() => setEditingMemory(null)}
|
|
498
|
+
memory={editingMemory}
|
|
499
|
+
agentId={agentId}
|
|
500
|
+
/>
|
|
501
|
+
)}
|
|
502
|
+
</div>
|
|
503
|
+
);
|
|
504
|
+
}
|