@swarmclawai/swarmclaw 0.6.4 → 0.6.6
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/README.md +5 -3
- package/package.json +5 -1
- package/src/app/api/chatrooms/[id]/chat/route.ts +41 -2
- package/src/app/api/chatrooms/[id]/route.ts +15 -1
- package/src/app/api/chatrooms/route.ts +15 -2
- package/src/app/api/schedules/[id]/run/route.ts +3 -0
- package/src/app/api/tasks/route.ts +24 -0
- package/src/app/api/wallets/[id]/approve/route.ts +62 -0
- package/src/app/api/wallets/[id]/balance-history/route.ts +18 -0
- package/src/app/api/wallets/[id]/route.ts +118 -0
- package/src/app/api/wallets/[id]/send/route.ts +118 -0
- package/src/app/api/wallets/[id]/transactions/route.ts +18 -0
- package/src/app/api/wallets/route.ts +74 -0
- package/src/app/globals.css +8 -0
- package/src/cli/index.js +15 -0
- package/src/cli/spec.js +14 -0
- package/src/components/agents/agent-avatar.tsx +15 -1
- package/src/components/agents/agent-card.tsx +1 -0
- package/src/components/agents/agent-chat-list.tsx +1 -1
- package/src/components/agents/agent-sheet.tsx +112 -26
- package/src/components/chat/chat-area.tsx +2 -2
- package/src/components/chat/chat-header.tsx +48 -19
- package/src/components/chat/chat-tool-toggles.tsx +1 -1
- package/src/components/chat/delegation-banner.test.ts +27 -0
- package/src/components/chat/delegation-banner.tsx +109 -23
- package/src/components/chat/message-bubble.tsx +3 -2
- package/src/components/chat/message-list.tsx +5 -4
- package/src/components/chat/streaming-bubble.tsx +3 -2
- package/src/components/chat/thinking-indicator.tsx +3 -2
- package/src/components/chat/transfer-agent-picker.tsx +1 -1
- package/src/components/chatrooms/agent-hover-card.tsx +1 -1
- package/src/components/chatrooms/chatroom-input.tsx +1 -1
- package/src/components/chatrooms/chatroom-message.tsx +1 -1
- package/src/components/chatrooms/chatroom-sheet.tsx +1 -1
- package/src/components/chatrooms/chatroom-typing-bar.tsx +1 -1
- package/src/components/chatrooms/chatroom-view.tsx +1 -1
- package/src/components/connectors/connector-list.tsx +1 -1
- package/src/components/home/home-view.tsx +2 -1
- package/src/components/knowledge/knowledge-list.tsx +1 -1
- package/src/components/knowledge/knowledge-sheet.tsx +1 -1
- package/src/components/layout/app-layout.tsx +18 -3
- package/src/components/memory/memory-agent-list.tsx +1 -1
- package/src/components/memory/memory-browser.tsx +1 -0
- package/src/components/memory/memory-card.tsx +3 -2
- package/src/components/memory/memory-detail.tsx +3 -3
- package/src/components/memory/memory-sheet.tsx +2 -2
- package/src/components/projects/project-detail.tsx +4 -4
- package/src/components/secrets/secret-sheet.tsx +1 -1
- package/src/components/secrets/secrets-list.tsx +1 -1
- package/src/components/sessions/session-card.tsx +1 -1
- package/src/components/shared/agent-picker-list.tsx +1 -1
- package/src/components/shared/agent-switch-dialog.tsx +1 -1
- package/src/components/shared/settings/section-user-preferences.tsx +4 -4
- package/src/components/skills/skill-list.tsx +1 -1
- package/src/components/skills/skill-sheet.tsx +1 -1
- package/src/components/tasks/task-board.tsx +3 -3
- package/src/components/tasks/task-sheet.tsx +21 -1
- package/src/components/wallets/wallet-approval-dialog.tsx +99 -0
- package/src/components/wallets/wallet-panel.tsx +616 -0
- package/src/components/wallets/wallet-section.tsx +100 -0
- package/src/lib/server/agent-registry.ts +2 -2
- package/src/lib/server/chat-execution.ts +35 -3
- package/src/lib/server/chatroom-health.ts +60 -0
- package/src/lib/server/chatroom-helpers.test.ts +94 -0
- package/src/lib/server/chatroom-helpers.ts +64 -11
- package/src/lib/server/connectors/inbound-audio-transcription.test.ts +191 -0
- package/src/lib/server/connectors/inbound-audio-transcription.ts +261 -0
- package/src/lib/server/connectors/manager.ts +80 -2
- package/src/lib/server/connectors/whatsapp-text.test.ts +29 -0
- package/src/lib/server/connectors/whatsapp-text.ts +26 -0
- package/src/lib/server/connectors/whatsapp.ts +8 -5
- package/src/lib/server/orchestrator-lg.ts +12 -2
- package/src/lib/server/orchestrator.ts +6 -1
- package/src/lib/server/queue-followups.test.ts +224 -0
- package/src/lib/server/queue.ts +226 -24
- package/src/lib/server/scheduler.ts +3 -0
- package/src/lib/server/session-tools/chatroom.ts +11 -2
- package/src/lib/server/session-tools/context-mgmt.ts +2 -2
- package/src/lib/server/session-tools/index.ts +6 -2
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/shell.ts +1 -1
- package/src/lib/server/session-tools/wallet.ts +124 -0
- package/src/lib/server/session-tools/web.ts +2 -2
- package/src/lib/server/solana.ts +122 -0
- package/src/lib/server/storage.ts +38 -0
- package/src/lib/server/stream-agent-chat.ts +126 -63
- package/src/lib/server/task-mention.test.ts +41 -0
- package/src/lib/server/task-mention.ts +3 -2
- package/src/lib/tool-definitions.ts +1 -0
- package/src/lib/view-routes.ts +1 -0
- package/src/stores/use-app-store.ts +8 -0
- package/src/types/index.ts +60 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import ReactMarkdown from 'react-markdown'
|
|
4
4
|
import { useAppStore } from '@/stores/use-app-store'
|
|
5
5
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
6
6
|
import { api } from '@/lib/api-client'
|
|
@@ -10,6 +10,7 @@ type DelegationStatus = 'delegating' | 'checking' | 'completed' | 'failed'
|
|
|
10
10
|
interface DelegationBannerProps {
|
|
11
11
|
agentName: string
|
|
12
12
|
agentAvatarSeed: string | null
|
|
13
|
+
agentAvatarUrl?: string | null
|
|
13
14
|
taskPreview: string
|
|
14
15
|
taskId: string | null
|
|
15
16
|
status: DelegationStatus
|
|
@@ -60,7 +61,7 @@ function statusText(status: DelegationStatus, name: string): string {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
export function DelegationBanner({ agentName, agentAvatarSeed, taskPreview, taskId, status }: DelegationBannerProps) {
|
|
64
|
+
export function DelegationBanner({ agentName, agentAvatarSeed, agentAvatarUrl, taskPreview, taskId, status }: DelegationBannerProps) {
|
|
64
65
|
const cfg = STATUS_CONFIG[status]
|
|
65
66
|
|
|
66
67
|
const handleTaskClick = () => {
|
|
@@ -83,7 +84,7 @@ export function DelegationBanner({ agentName, agentAvatarSeed, taskPreview, task
|
|
|
83
84
|
}}
|
|
84
85
|
>
|
|
85
86
|
<div className="shrink-0" style={{ animation: 'delegation-handoff-in 0.45s cubic-bezier(0.16, 1, 0.3, 1) 0.05s both' }}>
|
|
86
|
-
<AgentAvatar seed={agentAvatarSeed} name={agentName} size={24} />
|
|
87
|
+
<AgentAvatar seed={agentAvatarSeed} avatarUrl={agentAvatarUrl} name={agentName} size={24} />
|
|
87
88
|
</div>
|
|
88
89
|
<StatusIcon status={status} color={cfg.color} />
|
|
89
90
|
<div className="flex flex-col gap-0.5 min-w-0 flex-1">
|
|
@@ -120,6 +121,8 @@ export interface TaskCompletionInfo {
|
|
|
120
121
|
/** The agent that executed the task (present on delegated results) */
|
|
121
122
|
executorName: string | null
|
|
122
123
|
workingDir: string | null
|
|
124
|
+
reportPath: string | null
|
|
125
|
+
outputFiles: string[]
|
|
123
126
|
resumeInfo: string | null
|
|
124
127
|
resultBody: string
|
|
125
128
|
imageUrl?: string
|
|
@@ -140,12 +143,32 @@ export function parseTaskCompletion(text: string): TaskCompletionInfo | null {
|
|
|
140
143
|
const sections = bodyStart === -1 ? [] : text.slice(bodyStart + 2).split('\n\n')
|
|
141
144
|
|
|
142
145
|
let workingDir: string | null = null
|
|
146
|
+
let reportPath: string | null = null
|
|
147
|
+
const outputFiles: string[] = []
|
|
143
148
|
let resumeInfo: string | null = null
|
|
144
149
|
const resultParts: string[] = []
|
|
145
150
|
|
|
146
151
|
for (const section of sections) {
|
|
147
152
|
if (section.startsWith('Working directory: ')) {
|
|
148
153
|
workingDir = section.replace('Working directory: ', '').replace(/^`|`$/g, '')
|
|
154
|
+
} else if (section.startsWith('Output files:')) {
|
|
155
|
+
const fromBackticks = [...section.matchAll(/`([^`\n]+)`/g)].map((m) => (m[1] || '').trim()).filter(Boolean)
|
|
156
|
+
if (fromBackticks.length > 0) {
|
|
157
|
+
for (const fileRef of fromBackticks) {
|
|
158
|
+
if (!outputFiles.includes(fileRef)) outputFiles.push(fileRef)
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
const fromBullets = section
|
|
162
|
+
.split('\n')
|
|
163
|
+
.slice(1)
|
|
164
|
+
.map((line) => line.replace(/^\s*-\s*/, '').trim())
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
for (const fileRef of fromBullets) {
|
|
167
|
+
if (!outputFiles.includes(fileRef)) outputFiles.push(fileRef)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} else if (section.startsWith('Task report: ')) {
|
|
171
|
+
reportPath = section.replace('Task report: ', '').replace(/^`|`$/g, '')
|
|
149
172
|
} else if (/^(Claude session|Codex thread|OpenCode session|CLI session):/.test(section)) {
|
|
150
173
|
resumeInfo = section
|
|
151
174
|
} else if (section.trim()) {
|
|
@@ -153,12 +176,21 @@ export function parseTaskCompletion(text: string): TaskCompletionInfo | null {
|
|
|
153
176
|
}
|
|
154
177
|
}
|
|
155
178
|
|
|
156
|
-
return {
|
|
179
|
+
return {
|
|
180
|
+
status,
|
|
181
|
+
taskTitle,
|
|
182
|
+
taskId,
|
|
183
|
+
executorName,
|
|
184
|
+
workingDir,
|
|
185
|
+
reportPath,
|
|
186
|
+
outputFiles,
|
|
187
|
+
resumeInfo,
|
|
188
|
+
resultBody: resultParts.join('\n\n'),
|
|
189
|
+
}
|
|
157
190
|
}
|
|
158
191
|
|
|
159
192
|
export function TaskCompletionCard({ info }: { info: TaskCompletionInfo }) {
|
|
160
193
|
const isSuccess = info.status === 'completed'
|
|
161
|
-
const [expanded, setExpanded] = useState(false)
|
|
162
194
|
|
|
163
195
|
const handleTaskClick = () => {
|
|
164
196
|
if (!info.taskId) return
|
|
@@ -170,10 +202,6 @@ export function TaskCompletionCard({ info }: { info: TaskCompletionInfo }) {
|
|
|
170
202
|
})
|
|
171
203
|
}
|
|
172
204
|
|
|
173
|
-
// Truncate result for preview
|
|
174
|
-
const resultPreview = info.resultBody.length > 200 ? info.resultBody.slice(0, 200) + '...' : info.resultBody
|
|
175
|
-
const hasLongResult = info.resultBody.length > 200
|
|
176
|
-
|
|
177
205
|
return (
|
|
178
206
|
<div
|
|
179
207
|
className="rounded-[14px] overflow-hidden"
|
|
@@ -278,6 +306,47 @@ export function TaskCompletionCard({ info }: { info: TaskCompletionInfo }) {
|
|
|
278
306
|
</div>
|
|
279
307
|
)}
|
|
280
308
|
|
|
309
|
+
{info.outputFiles.length > 0 && (
|
|
310
|
+
<div className="flex flex-col gap-1">
|
|
311
|
+
<span className="text-[11px] text-text-3/55">Output files</span>
|
|
312
|
+
<div className="flex flex-wrap gap-1.5">
|
|
313
|
+
{info.outputFiles.map((fileRef) => {
|
|
314
|
+
const openPath = info.workingDir && !fileRef.startsWith('/') && !fileRef.startsWith('~/')
|
|
315
|
+
? `${info.workingDir.replace(/\/$/, '')}/${fileRef}`
|
|
316
|
+
: fileRef
|
|
317
|
+
return (
|
|
318
|
+
<button
|
|
319
|
+
key={fileRef}
|
|
320
|
+
type="button"
|
|
321
|
+
onClick={() => { api('POST', '/files/open', { path: openPath }).catch(() => {}) }}
|
|
322
|
+
className="px-2 py-1 rounded-[7px] text-[10px] font-mono bg-white/[0.03] border border-white/[0.08] text-text-3/70 hover:text-text-3 cursor-pointer max-w-full truncate"
|
|
323
|
+
title={`Open ${openPath}`}
|
|
324
|
+
>
|
|
325
|
+
{fileRef}
|
|
326
|
+
</button>
|
|
327
|
+
)
|
|
328
|
+
})}
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
)}
|
|
332
|
+
|
|
333
|
+
{info.reportPath && (
|
|
334
|
+
<div className="flex items-center gap-2">
|
|
335
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="shrink-0 text-text-3/40">
|
|
336
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
337
|
+
<polyline points="14 2 14 8 20 8" />
|
|
338
|
+
</svg>
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
onClick={() => { api('POST', '/files/open', { path: info.reportPath }).catch(() => {}) }}
|
|
342
|
+
className="text-[11px] text-text-3/60 hover:text-text-3 font-mono truncate bg-transparent border-none p-0 cursor-pointer transition-colors"
|
|
343
|
+
title="Open task report"
|
|
344
|
+
>
|
|
345
|
+
{info.reportPath}
|
|
346
|
+
</button>
|
|
347
|
+
</div>
|
|
348
|
+
)}
|
|
349
|
+
|
|
281
350
|
{/* Image artifact */}
|
|
282
351
|
{info.imageUrl && (
|
|
283
352
|
<div className="mt-0.5">
|
|
@@ -295,19 +364,35 @@ export function TaskCompletionCard({ info }: { info: TaskCompletionInfo }) {
|
|
|
295
364
|
{/* Result body */}
|
|
296
365
|
{info.resultBody && (
|
|
297
366
|
<div className="mt-0.5">
|
|
298
|
-
<div className="rounded-[10px] bg-white/[0.02] border border-white/[0.04] px-3 py-2.5">
|
|
299
|
-
<
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
367
|
+
<div className="rounded-[10px] bg-white/[0.02] border border-white/[0.04] px-3 py-2.5 max-h-[260px] overflow-y-auto">
|
|
368
|
+
<div className="text-[12px] leading-[1.6] text-text-3/80 break-words">
|
|
369
|
+
<ReactMarkdown
|
|
370
|
+
components={{
|
|
371
|
+
a: ({ href, children }) => (
|
|
372
|
+
<a
|
|
373
|
+
href={href}
|
|
374
|
+
target="_blank"
|
|
375
|
+
rel="noreferrer"
|
|
376
|
+
className="text-emerald-300 hover:text-emerald-200 underline decoration-emerald-300/40"
|
|
377
|
+
>
|
|
378
|
+
{children}
|
|
379
|
+
</a>
|
|
380
|
+
),
|
|
381
|
+
img: ({ src, alt }) => (
|
|
382
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
383
|
+
<img
|
|
384
|
+
src={src || ''}
|
|
385
|
+
alt={alt || 'Task artifact'}
|
|
386
|
+
loading="lazy"
|
|
387
|
+
className="max-w-full rounded-[8px] border border-white/[0.08] my-2"
|
|
388
|
+
/>
|
|
389
|
+
),
|
|
390
|
+
p: ({ children }) => <p className="m-0 mb-2">{children}</p>,
|
|
391
|
+
}}
|
|
307
392
|
>
|
|
308
|
-
{
|
|
309
|
-
</
|
|
310
|
-
|
|
393
|
+
{info.resultBody}
|
|
394
|
+
</ReactMarkdown>
|
|
395
|
+
</div>
|
|
311
396
|
</div>
|
|
312
397
|
</div>
|
|
313
398
|
)}
|
|
@@ -321,12 +406,13 @@ export function TaskCompletionCard({ info }: { info: TaskCompletionInfo }) {
|
|
|
321
406
|
interface DelegationSourceBannerProps {
|
|
322
407
|
delegatorName: string
|
|
323
408
|
delegatorAvatarSeed: string | null
|
|
409
|
+
delegatorAvatarUrl?: string | null
|
|
324
410
|
taskTitle: string
|
|
325
411
|
taskId: string | null
|
|
326
412
|
description: string
|
|
327
413
|
}
|
|
328
414
|
|
|
329
|
-
export function DelegationSourceBanner({ delegatorName, delegatorAvatarSeed, taskTitle, taskId, description }: DelegationSourceBannerProps) {
|
|
415
|
+
export function DelegationSourceBanner({ delegatorName, delegatorAvatarSeed, delegatorAvatarUrl, taskTitle, taskId, description }: DelegationSourceBannerProps) {
|
|
330
416
|
const handleTaskClick = () => {
|
|
331
417
|
if (!taskId) return
|
|
332
418
|
const store = useAppStore.getState()
|
|
@@ -343,7 +429,7 @@ export function DelegationSourceBanner({ delegatorName, delegatorAvatarSeed, tas
|
|
|
343
429
|
style={{ animation: 'delegation-handoff-in 0.45s cubic-bezier(0.16, 1, 0.3, 1)' }}
|
|
344
430
|
>
|
|
345
431
|
<div className="shrink-0 mt-0.5" style={{ animation: 'delegation-handoff-in 0.45s cubic-bezier(0.16, 1, 0.3, 1) 0.05s both' }}>
|
|
346
|
-
<AgentAvatar seed={delegatorAvatarSeed} name={delegatorName} size={24} />
|
|
432
|
+
<AgentAvatar seed={delegatorAvatarSeed} avatarUrl={delegatorAvatarUrl} name={delegatorName} size={24} />
|
|
347
433
|
</div>
|
|
348
434
|
<div className="flex flex-col gap-1 min-w-0 flex-1">
|
|
349
435
|
<span className="text-[12px] font-600 text-indigo-400">
|
|
@@ -136,6 +136,7 @@ interface Props {
|
|
|
136
136
|
message: Message
|
|
137
137
|
assistantName?: string
|
|
138
138
|
agentAvatarSeed?: string
|
|
139
|
+
agentAvatarUrl?: string | null
|
|
139
140
|
agentName?: string
|
|
140
141
|
isLast?: boolean
|
|
141
142
|
onRetry?: () => void
|
|
@@ -147,7 +148,7 @@ interface Props {
|
|
|
147
148
|
momentOverlay?: React.ReactNode
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
export const MessageBubble = memo(function MessageBubble({ message, assistantName, agentAvatarSeed, agentName, isLast, onRetry, messageIndex, onToggleBookmark, onEditResend, onFork, onTransferToAgent, momentOverlay }: Props) {
|
|
151
|
+
export const MessageBubble = memo(function MessageBubble({ message, assistantName, agentAvatarSeed, agentAvatarUrl, agentName, isLast, onRetry, messageIndex, onToggleBookmark, onEditResend, onFork, onTransferToAgent, momentOverlay }: Props) {
|
|
151
152
|
const isUser = message.role === 'user'
|
|
152
153
|
const isHeartbeat = !isUser && (message.kind === 'heartbeat' || /^\s*HEARTBEAT_OK\b/i.test(message.text || ''))
|
|
153
154
|
const currentUser = useAppStore((s) => s.currentUser)
|
|
@@ -231,7 +232,7 @@ export const MessageBubble = memo(function MessageBubble({ message, assistantNam
|
|
|
231
232
|
{!isUser && (
|
|
232
233
|
<div className="absolute left-[4px] top-0">
|
|
233
234
|
<div style={momentOverlay ? { animation: 'avatar-moment-pulse 0.6s ease' } : undefined}>
|
|
234
|
-
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} name={agentName} size={28} /> : <AiAvatar size="sm" />}
|
|
235
|
+
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} avatarUrl={agentAvatarUrl} name={agentName} size={28} /> : <AiAvatar size="sm" />}
|
|
235
236
|
</div>
|
|
236
237
|
{momentOverlay}
|
|
237
238
|
</div>
|
|
@@ -439,7 +439,7 @@ export function MessageList({ messages, streaming, connectorFilter = null }: Pro
|
|
|
439
439
|
)}
|
|
440
440
|
{filteredMessages.length === 0 && !streaming && (
|
|
441
441
|
<div className="flex flex-col items-center justify-center gap-3 py-20 text-center" style={{ animation: 'fadeUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) both' }}>
|
|
442
|
-
<AgentAvatar seed={agent?.avatarSeed || null} name={agent?.name || 'Agent'} size={48} />
|
|
442
|
+
<AgentAvatar seed={agent?.avatarSeed || null} avatarUrl={agent?.avatarUrl} name={agent?.name || 'Agent'} size={48} />
|
|
443
443
|
<span className="font-display text-[16px] font-600 text-text-2">{agent?.name || 'Assistant'}</span>
|
|
444
444
|
<span className="text-[14px] text-text-3/60">
|
|
445
445
|
{INTRO_GREETINGS[stableHash(agent?.id || session?.id || '') % INTRO_GREETINGS.length]}
|
|
@@ -526,6 +526,7 @@ export function MessageList({ messages, streaming, connectorFilter = null }: Pro
|
|
|
526
526
|
message={msg}
|
|
527
527
|
assistantName={assistantName}
|
|
528
528
|
agentAvatarSeed={agent?.avatarSeed}
|
|
529
|
+
agentAvatarUrl={agent?.avatarUrl}
|
|
529
530
|
agentName={agent?.name}
|
|
530
531
|
isLast={isLastAssistant}
|
|
531
532
|
onRetry={isLastAssistant ? retryLastMessage : undefined}
|
|
@@ -540,9 +541,9 @@ export function MessageList({ messages, streaming, connectorFilter = null }: Pro
|
|
|
540
541
|
)
|
|
541
542
|
})}
|
|
542
543
|
<ApprovalCards agentId={agent?.id} />
|
|
543
|
-
{streaming && !displayText && <ThinkingIndicator assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentName={agent?.name} />}
|
|
544
|
-
{streaming && displayText && <StreamingBubble text={displayText} assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentName={agent?.name} />}
|
|
545
|
-
{appSettings.suggestionsEnabled
|
|
544
|
+
{streaming && !displayText && <ThinkingIndicator assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentAvatarUrl={agent?.avatarUrl} agentName={agent?.name} />}
|
|
545
|
+
{streaming && displayText && <StreamingBubble text={displayText} assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentAvatarUrl={agent?.avatarUrl} agentName={agent?.name} />}
|
|
546
|
+
{appSettings.suggestionsEnabled === true && !streaming && filteredMessages.length > 0 && filteredMessages[filteredMessages.length - 1]?.role === 'assistant' && (
|
|
546
547
|
<SuggestionsBar lastMessage={filteredMessages[filteredMessages.length - 1]} onSend={sendMessage} />
|
|
547
548
|
)}
|
|
548
549
|
</div>
|
|
@@ -104,10 +104,11 @@ interface Props {
|
|
|
104
104
|
text: string
|
|
105
105
|
assistantName?: string
|
|
106
106
|
agentAvatarSeed?: string
|
|
107
|
+
agentAvatarUrl?: string | null
|
|
107
108
|
agentName?: string
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
export function StreamingBubble({ text, assistantName, agentAvatarSeed, agentName }: Props) {
|
|
111
|
+
export function StreamingBubble({ text, assistantName, agentAvatarSeed, agentAvatarUrl, agentName }: Props) {
|
|
111
112
|
const toolEvents = useChatStore((s) => s.toolEvents)
|
|
112
113
|
const streamPhase = useChatStore((s) => s.streamPhase)
|
|
113
114
|
const streamToolName = useChatStore((s) => s.streamToolName)
|
|
@@ -137,7 +138,7 @@ export function StreamingBubble({ text, assistantName, agentAvatarSeed, agentNam
|
|
|
137
138
|
style={{ animation: 'msg-in-left 0.35s cubic-bezier(0.16, 1, 0.3, 1)' }}
|
|
138
139
|
>
|
|
139
140
|
<div className="absolute left-[4px] top-0 relative">
|
|
140
|
-
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} name={agentName} size={28} /> : <AiAvatar size="sm" mood={streamPhase === 'tool' ? 'tool' : 'thinking'} />}
|
|
141
|
+
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} avatarUrl={agentAvatarUrl} name={agentName} size={28} /> : <AiAvatar size="sm" mood={streamPhase === 'tool' ? 'tool' : 'thinking'} />}
|
|
141
142
|
{currentMoment && (
|
|
142
143
|
<ActivityMoment
|
|
143
144
|
key={currentMoment.id}
|
|
@@ -10,6 +10,7 @@ import { useChatStore } from '@/stores/use-chat-store'
|
|
|
10
10
|
interface Props {
|
|
11
11
|
assistantName?: string
|
|
12
12
|
agentAvatarSeed?: string
|
|
13
|
+
agentAvatarUrl?: string | null
|
|
13
14
|
agentName?: string
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -34,7 +35,7 @@ function ElapsedTimer({ startTime }: { startTime: number }) {
|
|
|
34
35
|
)
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
export function ThinkingIndicator({ assistantName, agentAvatarSeed, agentName }: Props) {
|
|
38
|
+
export function ThinkingIndicator({ assistantName, agentAvatarSeed, agentAvatarUrl, agentName }: Props) {
|
|
38
39
|
const streamPhase = useChatStore((s) => s.streamPhase)
|
|
39
40
|
const streamToolName = useChatStore((s) => s.streamToolName)
|
|
40
41
|
const thinkingText = useChatStore((s) => s.thinkingText)
|
|
@@ -50,7 +51,7 @@ export function ThinkingIndicator({ assistantName, agentAvatarSeed, agentName }:
|
|
|
50
51
|
<div className="flex flex-col items-start relative pl-[44px]"
|
|
51
52
|
style={{ animation: 'msg-in-left 0.35s cubic-bezier(0.16, 1, 0.3, 1)' }}>
|
|
52
53
|
<div className="absolute left-[4px] top-0">
|
|
53
|
-
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} name={agentName} size={28} /> : <AiAvatar size="sm" mood={streamPhase === 'tool' ? 'tool' : 'thinking'} />}
|
|
54
|
+
{agentName ? <AgentAvatar seed={agentAvatarSeed || null} avatarUrl={agentAvatarUrl} name={agentName} size={28} /> : <AiAvatar size="sm" mood={streamPhase === 'tool' ? 'tool' : 'thinking'} />}
|
|
54
55
|
</div>
|
|
55
56
|
<div className="flex items-center gap-2.5 mb-2 px-1">
|
|
56
57
|
<span className="text-[12px] font-600 text-text-3">{assistantName || 'Claude'}</span>
|
|
@@ -52,7 +52,7 @@ export function TransferAgentPicker({ excludeIds, filterIds, onSelect, onClose }
|
|
|
52
52
|
className="w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-white/[0.06] transition-colors cursor-pointer bg-transparent border-none"
|
|
53
53
|
style={{ fontFamily: 'inherit' }}
|
|
54
54
|
>
|
|
55
|
-
<AgentAvatar seed={a.avatarSeed} name={a.name} size={20} />
|
|
55
|
+
<AgentAvatar seed={a.avatarSeed} avatarUrl={a.avatarUrl} name={a.name} size={20} />
|
|
56
56
|
<span className="text-[12px] text-text truncate">{a.name}</span>
|
|
57
57
|
</button>
|
|
58
58
|
))}
|
|
@@ -46,7 +46,7 @@ export function AgentHoverCard({ agent, children, status }: Props) {
|
|
|
46
46
|
<HoverCardContent align="start" className="w-[280px]">
|
|
47
47
|
{/* Header: avatar + name + model */}
|
|
48
48
|
<div className="flex items-center gap-2">
|
|
49
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={28} status={status} />
|
|
49
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={28} status={status} />
|
|
50
50
|
<div className="min-w-0 flex-1">
|
|
51
51
|
<div className="text-[13px] font-600 text-text truncate">{agent.name}</div>
|
|
52
52
|
<div className="label-mono truncate">{agent.model}</div>
|
|
@@ -203,7 +203,7 @@ export function ChatroomInput({ agents, onSend, disabled }: Props) {
|
|
|
203
203
|
selectedIndex === i + 1 ? 'bg-white/[0.08]' : 'hover:bg-white/[0.06]'
|
|
204
204
|
}`}
|
|
205
205
|
>
|
|
206
|
-
<AgentAvatar seed={agent.avatarSeed} name={agent.name} size={20} />
|
|
206
|
+
<AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={20} />
|
|
207
207
|
<span className="text-[13px] text-text">{agent.name}</span>
|
|
208
208
|
</button>
|
|
209
209
|
))}
|
|
@@ -172,7 +172,7 @@ export function ChatroomMessageBubble({ message, agents, onToggleReaction, onRep
|
|
|
172
172
|
className="bg-transparent border-none p-0 cursor-pointer transition-all duration-150 hover:scale-110 hover:-translate-y-0.5"
|
|
173
173
|
style={momentOverlay ? { animation: 'avatar-moment-pulse 0.6s ease' } : undefined}
|
|
174
174
|
>
|
|
175
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={message.senderName} size={28} status={streamingAgentIds?.has(message.senderId) ? 'busy' : 'online'} />
|
|
175
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={message.senderName} size={28} status={streamingAgentIds?.has(message.senderId) ? 'busy' : 'online'} />
|
|
176
176
|
</button>
|
|
177
177
|
) : (
|
|
178
178
|
<div style={momentOverlay ? { animation: 'avatar-moment-pulse 0.6s ease' } : undefined}>
|
|
@@ -178,7 +178,7 @@ export function ChatroomSheet() {
|
|
|
178
178
|
selected ? 'bg-accent-soft/40' : 'hover:bg-white/[0.04]'
|
|
179
179
|
}`}
|
|
180
180
|
>
|
|
181
|
-
<AgentAvatar seed={agent.avatarSeed} name={agent.name} size={24} />
|
|
181
|
+
<AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={24} />
|
|
182
182
|
<span className="text-[13px] text-text flex-1 truncate">{agent.name}</span>
|
|
183
183
|
{selected && (
|
|
184
184
|
<CheckIcon size={14} className="text-accent-bright shrink-0" />
|
|
@@ -63,7 +63,7 @@ export function ChatroomTypingBar({ streamingAgents }: Props) {
|
|
|
63
63
|
return (
|
|
64
64
|
<div key={agentId} className="flex gap-2.5 px-4 py-1.5" style={{ animation: 'msg-in 0.2s ease-out both' }}>
|
|
65
65
|
<div className="shrink-0 mt-0.5 w-7">
|
|
66
|
-
<AgentAvatar seed={agent?.avatarSeed || null} name={a.name} size={28} />
|
|
66
|
+
<AgentAvatar seed={agent?.avatarSeed || null} avatarUrl={agent?.avatarUrl} name={a.name} size={28} />
|
|
67
67
|
</div>
|
|
68
68
|
<div className="flex-1 min-w-0">
|
|
69
69
|
<div className="flex items-baseline gap-2 mb-0.5">
|
|
@@ -192,7 +192,7 @@ export function ChatroomView() {
|
|
|
192
192
|
onClick={() => navigateToAgent(agent.id)}
|
|
193
193
|
className="relative transition-all duration-200 hover:scale-110 hover:z-10 hover:-translate-y-0.5 cursor-pointer bg-transparent border-none p-0"
|
|
194
194
|
>
|
|
195
|
-
<AgentAvatar seed={agent.avatarSeed} name={agent.name} size={22} status={streamingAgents.has(agent.id) ? 'busy' : 'online'} />
|
|
195
|
+
<AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={22} status={streamingAgents.has(agent.id) ? 'busy' : 'online'} />
|
|
196
196
|
</button>
|
|
197
197
|
</TooltipTrigger>
|
|
198
198
|
<TooltipContent side="bottom" sideOffset={6}>
|
|
@@ -206,7 +206,7 @@ export function ConnectorList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
206
206
|
</>
|
|
207
207
|
) : agent ? (
|
|
208
208
|
<>
|
|
209
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={24} />
|
|
209
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={24} />
|
|
210
210
|
<div className="flex-1 min-w-0">
|
|
211
211
|
<span className="text-[12px] font-600 text-text-2 block truncate">{agent.name}</span>
|
|
212
212
|
<span className="text-[10px] text-text-3/60 block">{agent.provider}/{agent.model}</span>
|
|
@@ -353,7 +353,7 @@ export function HomeView() {
|
|
|
353
353
|
style={{ fontFamily: 'inherit' }}
|
|
354
354
|
>
|
|
355
355
|
<div className="relative">
|
|
356
|
-
<AgentAvatar seed={agent.avatarSeed} name={agent.name} size={36} />
|
|
356
|
+
<AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={36} />
|
|
357
357
|
<div className={`absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full border-2 border-surface ${
|
|
358
358
|
isTyping ? 'bg-accent-bright animate-pulse'
|
|
359
359
|
: isOnline ? 'bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.4)]'
|
|
@@ -414,6 +414,7 @@ export function HomeView() {
|
|
|
414
414
|
>
|
|
415
415
|
<AgentAvatar
|
|
416
416
|
seed={agent?.avatarSeed}
|
|
417
|
+
avatarUrl={agent?.avatarUrl}
|
|
417
418
|
name={displayName}
|
|
418
419
|
size={28}
|
|
419
420
|
/>
|
|
@@ -183,7 +183,7 @@ export function KnowledgeList() {
|
|
|
183
183
|
<div className="flex items-center gap-1.5">
|
|
184
184
|
<div className="flex items-center -space-x-1.5">
|
|
185
185
|
{scopedAgents.slice(0, 5).map((agent) => (
|
|
186
|
-
<AgentAvatar key={agent.id} seed={agent.avatarSeed} name={agent.name} size={16} className="ring-1 ring-surface" />
|
|
186
|
+
<AgentAvatar key={agent.id} seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={16} className="ring-1 ring-surface" />
|
|
187
187
|
))}
|
|
188
188
|
</div>
|
|
189
189
|
{scopedAgents.length > 5 && (
|
|
@@ -360,7 +360,7 @@ export function KnowledgeSheet() {
|
|
|
360
360
|
}`}
|
|
361
361
|
style={{ fontFamily: 'inherit' }}
|
|
362
362
|
>
|
|
363
|
-
<AgentAvatar seed={agent.avatarSeed} name={agent.name} size={24} />
|
|
363
|
+
<AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={24} />
|
|
364
364
|
<span className="text-[13px] text-text flex-1 truncate">{agent.name}</span>
|
|
365
365
|
{selected && (
|
|
366
366
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="text-accent-bright shrink-0">
|
|
@@ -41,6 +41,7 @@ import { PluginSheet } from '@/components/plugins/plugin-sheet'
|
|
|
41
41
|
import { RunList } from '@/components/runs/run-list'
|
|
42
42
|
import { ActivityFeed } from '@/components/activity/activity-feed'
|
|
43
43
|
import { MetricsDashboard } from '@/components/usage/metrics-dashboard'
|
|
44
|
+
import { WalletPanel } from '@/components/wallets/wallet-panel'
|
|
44
45
|
import { ProjectList } from '@/components/projects/project-list'
|
|
45
46
|
import { ProjectDetail } from '@/components/projects/project-detail'
|
|
46
47
|
import { ProjectSheet } from '@/components/projects/project-sheet'
|
|
@@ -398,6 +399,11 @@ export function AppLayout() {
|
|
|
398
399
|
<line x1="18" y1="20" x2="18" y2="10" /><line x1="12" y1="20" x2="12" y2="4" /><line x1="6" y1="20" x2="6" y2="14" />
|
|
399
400
|
</svg>
|
|
400
401
|
</NavItem>
|
|
402
|
+
<NavItem view="wallets" label="Wallets" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('wallets')}>
|
|
403
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
404
|
+
<rect x="2" y="6" width="20" height="14" rx="2" /><path d="M22 10H18a2 2 0 0 0 0 4h4" /><path d="M6 6V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2" />
|
|
405
|
+
</svg>
|
|
406
|
+
</NavItem>
|
|
401
407
|
<NavItem view="runs" label="Runs" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('runs')}>
|
|
402
408
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
403
409
|
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
|
|
@@ -519,8 +525,8 @@ export function AppLayout() {
|
|
|
519
525
|
</div>
|
|
520
526
|
)}
|
|
521
527
|
|
|
522
|
-
{/* Desktop: Side panel */}
|
|
523
|
-
{isDesktop && sidebarOpen && (
|
|
528
|
+
{/* Desktop: Side panel (wallets has its own built-in sidebar) */}
|
|
529
|
+
{isDesktop && sidebarOpen && activeView !== 'wallets' && (
|
|
524
530
|
<div
|
|
525
531
|
className="w-[280px] shrink-0 bg-raised border-r border-white/[0.04] flex flex-col h-full"
|
|
526
532
|
style={{ animation: 'panel-in 0.2s cubic-bezier(0.16, 1, 0.3, 1)' }}
|
|
@@ -727,6 +733,8 @@ export function AppLayout() {
|
|
|
727
733
|
<ActivityFeed />
|
|
728
734
|
) : activeView === 'usage' ? (
|
|
729
735
|
<MetricsDashboard />
|
|
736
|
+
) : activeView === 'wallets' ? (
|
|
737
|
+
<WalletPanel />
|
|
730
738
|
) : activeView === 'chatrooms' ? (
|
|
731
739
|
<div className="flex-1 flex h-full min-w-0">
|
|
732
740
|
<div className="w-[280px] shrink-0 border-r border-white/[0.06] flex flex-col">
|
|
@@ -886,6 +894,7 @@ const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
886
894
|
logs: 'Application logs & error tracking',
|
|
887
895
|
plugins: 'Extend agent capabilities with custom plugins',
|
|
888
896
|
usage: 'Usage metrics, cost tracking & agent performance',
|
|
897
|
+
wallets: 'Agent crypto wallets — hold funds, send SOL, manage spending',
|
|
889
898
|
runs: 'Live run monitoring & history',
|
|
890
899
|
settings: 'Manage providers, API keys & orchestrator engine',
|
|
891
900
|
projects: 'Group agents, tasks & schedules into projects',
|
|
@@ -895,7 +904,7 @@ const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
895
904
|
const FULL_WIDTH_VIEWS = new Set<AppView>([
|
|
896
905
|
'home', 'chatrooms', 'schedules', 'secrets', 'providers', 'skills',
|
|
897
906
|
'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins',
|
|
898
|
-
'usage', 'runs', 'logs', 'settings', 'activity', 'projects',
|
|
907
|
+
'usage', 'wallets', 'runs', 'logs', 'settings', 'activity', 'projects',
|
|
899
908
|
])
|
|
900
909
|
|
|
901
910
|
const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { icon: string; title: string; description: string; features: string[] }> = {
|
|
@@ -1007,6 +1016,12 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { icon: str
|
|
|
1007
1016
|
description: 'Audit trail of all entity mutations across the system.',
|
|
1008
1017
|
features: ['Track agent, task, and connector changes', 'Filter by entity type and action', 'Real-time updates via WebSocket', 'Relative timestamps'],
|
|
1009
1018
|
},
|
|
1019
|
+
wallets: {
|
|
1020
|
+
icon: 'wallet',
|
|
1021
|
+
title: 'Wallets',
|
|
1022
|
+
description: 'Agent crypto wallets for autonomous financial operations on Solana.',
|
|
1023
|
+
features: ['Create Solana wallets for agents', 'Per-transaction and daily spending limits', 'User approval for transactions', 'Balance tracking and transaction history'],
|
|
1024
|
+
},
|
|
1010
1025
|
}
|
|
1011
1026
|
|
|
1012
1027
|
function ViewEmptyState({ view }: { view: AppView }) {
|
|
@@ -120,7 +120,7 @@ export function MemoryAgentList() {
|
|
|
120
120
|
{isActive && (
|
|
121
121
|
<div className="absolute left-0 top-2 bottom-2 w-[2.5px] rounded-full bg-accent-bright" />
|
|
122
122
|
)}
|
|
123
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={28} />
|
|
123
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={28} />
|
|
124
124
|
<span className={`text-[13px] font-600 flex-1 truncate ${isActive ? 'text-accent-bright' : 'text-text-2'}`}>
|
|
125
125
|
{agent.name}
|
|
126
126
|
</span>
|
|
@@ -163,6 +163,7 @@ export function MemoryBrowser() {
|
|
|
163
163
|
active={e.id === selectedMemoryId}
|
|
164
164
|
agentName={showAgent ? (agent?.name || null) : undefined}
|
|
165
165
|
agentAvatarSeed={showAgent ? (agent?.avatarSeed || null) : undefined}
|
|
166
|
+
agentAvatarUrl={showAgent ? (agent?.avatarUrl || null) : undefined}
|
|
166
167
|
onClick={() => setSelectedMemoryId(e.id)}
|
|
167
168
|
/>
|
|
168
169
|
)
|
|
@@ -17,10 +17,11 @@ interface Props {
|
|
|
17
17
|
active?: boolean
|
|
18
18
|
agentName?: string | null
|
|
19
19
|
agentAvatarSeed?: string | null
|
|
20
|
+
agentAvatarUrl?: string | null
|
|
20
21
|
onClick: () => void
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export function MemoryCard({ entry, active, agentName, agentAvatarSeed, onClick }: Props) {
|
|
24
|
+
export function MemoryCard({ entry, active, agentName, agentAvatarSeed, agentAvatarUrl, onClick }: Props) {
|
|
24
25
|
return (
|
|
25
26
|
<div
|
|
26
27
|
onClick={onClick}
|
|
@@ -73,7 +74,7 @@ export function MemoryCard({ entry, active, agentName, agentAvatarSeed, onClick
|
|
|
73
74
|
)}
|
|
74
75
|
{agentName ? (
|
|
75
76
|
<div className="flex items-center gap-1.5 mt-1.5">
|
|
76
|
-
<AgentAvatar seed={agentAvatarSeed || null} name={agentName} size={16} />
|
|
77
|
+
<AgentAvatar seed={agentAvatarSeed || null} avatarUrl={agentAvatarUrl} name={agentName} size={16} />
|
|
77
78
|
<span className="text-[10px] text-text-3/60 truncate">{agentName}</span>
|
|
78
79
|
</div>
|
|
79
80
|
) : !entry.agentId ? (
|
|
@@ -329,7 +329,7 @@ export function MemoryDetail() {
|
|
|
329
329
|
: 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
|
|
330
330
|
style={{ fontFamily: 'inherit' }}
|
|
331
331
|
>
|
|
332
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={16} />
|
|
332
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={16} />
|
|
333
333
|
<span className="truncate max-w-[100px]">{agent.name}</span>
|
|
334
334
|
</button>
|
|
335
335
|
))}
|
|
@@ -360,7 +360,7 @@ export function MemoryDetail() {
|
|
|
360
360
|
: 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
|
|
361
361
|
style={{ fontFamily: 'inherit' }}
|
|
362
362
|
>
|
|
363
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={16} />
|
|
363
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={16} />
|
|
364
364
|
<span className="truncate max-w-[100px]">{agent.name}</span>
|
|
365
365
|
</button>
|
|
366
366
|
)
|
|
@@ -406,7 +406,7 @@ export function MemoryDetail() {
|
|
|
406
406
|
const a = agents[aid]
|
|
407
407
|
return (
|
|
408
408
|
<span key={aid} className="flex items-center gap-1.5 px-2.5 py-1 rounded-[8px] bg-white/[0.03] text-[11px] text-text-3">
|
|
409
|
-
<AgentAvatar seed={a?.avatarSeed || null} name={a?.name || aid} size={16} />
|
|
409
|
+
<AgentAvatar seed={a?.avatarSeed || null} avatarUrl={a?.avatarUrl} name={a?.name || aid} size={16} />
|
|
410
410
|
{a?.name || aid}
|
|
411
411
|
</span>
|
|
412
412
|
)
|
|
@@ -104,7 +104,7 @@ export function MemorySheet() {
|
|
|
104
104
|
: 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
|
|
105
105
|
style={{ fontFamily: 'inherit' }}
|
|
106
106
|
>
|
|
107
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={20} />
|
|
107
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={20} />
|
|
108
108
|
<span className="truncate max-w-[120px]">{agent.name}</span>
|
|
109
109
|
</button>
|
|
110
110
|
))}
|
|
@@ -140,7 +140,7 @@ export function MemorySheet() {
|
|
|
140
140
|
: 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
|
|
141
141
|
style={{ fontFamily: 'inherit' }}
|
|
142
142
|
>
|
|
143
|
-
<AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={20} />
|
|
143
|
+
<AgentAvatar seed={agent.avatarSeed || null} avatarUrl={agent.avatarUrl} name={agent.name} size={20} />
|
|
144
144
|
<span className="truncate max-w-[120px]">{agent.name}</span>
|
|
145
145
|
</button>
|
|
146
146
|
)
|