@swarmclawai/swarmclaw 0.6.4 → 0.6.7

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 (143) hide show
  1. package/README.md +62 -30
  2. package/package.json +10 -1
  3. package/src/app/api/agents/[id]/clone/route.ts +40 -0
  4. package/src/app/api/agents/route.ts +39 -14
  5. package/src/app/api/chatrooms/[id]/chat/route.ts +58 -3
  6. package/src/app/api/chatrooms/[id]/moderate/route.ts +150 -0
  7. package/src/app/api/chatrooms/[id]/route.ts +34 -2
  8. package/src/app/api/chatrooms/route.ts +26 -3
  9. package/src/app/api/connectors/[id]/health/route.ts +64 -0
  10. package/src/app/api/connectors/route.ts +17 -2
  11. package/src/app/api/knowledge/route.ts +6 -1
  12. package/src/app/api/openclaw/doctor/route.ts +17 -0
  13. package/src/app/api/schedules/[id]/run/route.ts +3 -0
  14. package/src/app/api/sessions/[id]/chat/route.ts +5 -1
  15. package/src/app/api/sessions/route.ts +11 -2
  16. package/src/app/api/tasks/[id]/route.ts +18 -13
  17. package/src/app/api/tasks/route.ts +44 -1
  18. package/src/app/api/usage/route.ts +16 -7
  19. package/src/app/api/wallets/[id]/approve/route.ts +62 -0
  20. package/src/app/api/wallets/[id]/balance-history/route.ts +18 -0
  21. package/src/app/api/wallets/[id]/route.ts +118 -0
  22. package/src/app/api/wallets/[id]/send/route.ts +118 -0
  23. package/src/app/api/wallets/[id]/transactions/route.ts +18 -0
  24. package/src/app/api/wallets/route.ts +74 -0
  25. package/src/app/globals.css +8 -0
  26. package/src/cli/index.js +20 -0
  27. package/src/cli/index.ts +223 -39
  28. package/src/cli/spec.js +14 -0
  29. package/src/components/agents/agent-avatar.tsx +15 -1
  30. package/src/components/agents/agent-card.tsx +38 -6
  31. package/src/components/agents/agent-chat-list.tsx +79 -3
  32. package/src/components/agents/agent-sheet.tsx +191 -26
  33. package/src/components/auth/setup-wizard.tsx +268 -353
  34. package/src/components/chat/chat-area.tsx +24 -9
  35. package/src/components/chat/chat-header.tsx +48 -19
  36. package/src/components/chat/chat-tool-toggles.tsx +1 -1
  37. package/src/components/chat/delegation-banner.test.ts +27 -0
  38. package/src/components/chat/delegation-banner.tsx +109 -23
  39. package/src/components/chat/message-bubble.tsx +17 -16
  40. package/src/components/chat/message-list.tsx +6 -5
  41. package/src/components/chat/streaming-bubble.tsx +3 -2
  42. package/src/components/chat/thinking-indicator.tsx +3 -2
  43. package/src/components/chat/transfer-agent-picker.tsx +1 -1
  44. package/src/components/chatrooms/agent-hover-card.tsx +1 -1
  45. package/src/components/chatrooms/chatroom-input.tsx +1 -1
  46. package/src/components/chatrooms/chatroom-message.tsx +165 -23
  47. package/src/components/chatrooms/chatroom-sheet.tsx +289 -4
  48. package/src/components/chatrooms/chatroom-typing-bar.tsx +1 -1
  49. package/src/components/chatrooms/chatroom-view.tsx +62 -17
  50. package/src/components/connectors/connector-health.tsx +120 -0
  51. package/src/components/connectors/connector-list.tsx +1 -1
  52. package/src/components/connectors/connector-sheet.tsx +9 -0
  53. package/src/components/home/home-view.tsx +25 -3
  54. package/src/components/input/chat-input.tsx +8 -1
  55. package/src/components/knowledge/knowledge-list.tsx +1 -1
  56. package/src/components/knowledge/knowledge-sheet.tsx +1 -1
  57. package/src/components/layout/app-layout.tsx +35 -4
  58. package/src/components/memory/memory-agent-list.tsx +1 -1
  59. package/src/components/memory/memory-browser.tsx +1 -0
  60. package/src/components/memory/memory-card.tsx +3 -2
  61. package/src/components/memory/memory-detail.tsx +3 -3
  62. package/src/components/memory/memory-sheet.tsx +2 -2
  63. package/src/components/projects/project-detail.tsx +4 -4
  64. package/src/components/schedules/schedule-list.tsx +55 -9
  65. package/src/components/schedules/schedule-sheet.tsx +134 -23
  66. package/src/components/secrets/secret-sheet.tsx +1 -1
  67. package/src/components/secrets/secrets-list.tsx +1 -1
  68. package/src/components/sessions/session-card.tsx +1 -1
  69. package/src/components/shared/agent-picker-list.tsx +1 -1
  70. package/src/components/shared/agent-switch-dialog.tsx +1 -1
  71. package/src/components/shared/command-palette.tsx +237 -0
  72. package/src/components/shared/connector-platform-icon.tsx +1 -0
  73. package/src/components/shared/settings/section-user-preferences.tsx +4 -4
  74. package/src/components/skills/skill-list.tsx +1 -1
  75. package/src/components/skills/skill-sheet.tsx +1 -1
  76. package/src/components/tasks/task-board.tsx +3 -3
  77. package/src/components/tasks/task-card.tsx +22 -2
  78. package/src/components/tasks/task-sheet.tsx +112 -17
  79. package/src/components/usage/metrics-dashboard.tsx +13 -25
  80. package/src/components/wallets/wallet-approval-dialog.tsx +99 -0
  81. package/src/components/wallets/wallet-panel.tsx +616 -0
  82. package/src/components/wallets/wallet-section.tsx +100 -0
  83. package/src/hooks/use-swipe.ts +49 -0
  84. package/src/lib/providers/anthropic.ts +16 -2
  85. package/src/lib/providers/claude-cli.ts +7 -1
  86. package/src/lib/providers/index.ts +7 -0
  87. package/src/lib/providers/ollama.ts +16 -2
  88. package/src/lib/providers/openai.ts +7 -2
  89. package/src/lib/providers/openclaw.ts +6 -1
  90. package/src/lib/providers/provider-defaults.ts +7 -0
  91. package/src/lib/schedule-templates.ts +115 -0
  92. package/src/lib/server/agent-registry.ts +2 -2
  93. package/src/lib/server/alert-dispatch.ts +64 -0
  94. package/src/lib/server/chat-execution.ts +76 -4
  95. package/src/lib/server/chatroom-health.ts +60 -0
  96. package/src/lib/server/chatroom-helpers.test.ts +94 -0
  97. package/src/lib/server/chatroom-helpers.ts +86 -12
  98. package/src/lib/server/chatroom-routing.ts +65 -0
  99. package/src/lib/server/connectors/discord.ts +3 -0
  100. package/src/lib/server/connectors/email.ts +267 -0
  101. package/src/lib/server/connectors/inbound-audio-transcription.test.ts +191 -0
  102. package/src/lib/server/connectors/inbound-audio-transcription.ts +261 -0
  103. package/src/lib/server/connectors/manager.ts +239 -5
  104. package/src/lib/server/connectors/openclaw.ts +3 -0
  105. package/src/lib/server/connectors/slack.ts +6 -0
  106. package/src/lib/server/connectors/telegram.ts +18 -0
  107. package/src/lib/server/connectors/types.ts +2 -0
  108. package/src/lib/server/connectors/whatsapp-text.test.ts +29 -0
  109. package/src/lib/server/connectors/whatsapp-text.ts +26 -0
  110. package/src/lib/server/connectors/whatsapp.ts +17 -5
  111. package/src/lib/server/cost.ts +70 -0
  112. package/src/lib/server/create-notification.ts +2 -0
  113. package/src/lib/server/daemon-state.ts +124 -0
  114. package/src/lib/server/dag-validation.ts +115 -0
  115. package/src/lib/server/memory-db.ts +12 -7
  116. package/src/lib/server/openclaw-doctor.ts +48 -0
  117. package/src/lib/server/orchestrator-lg.ts +12 -2
  118. package/src/lib/server/orchestrator.ts +6 -1
  119. package/src/lib/server/queue-followups.test.ts +224 -0
  120. package/src/lib/server/queue.ts +238 -24
  121. package/src/lib/server/scheduler.ts +3 -0
  122. package/src/lib/server/session-run-manager.ts +22 -1
  123. package/src/lib/server/session-tools/chatroom.ts +11 -2
  124. package/src/lib/server/session-tools/context-mgmt.ts +2 -2
  125. package/src/lib/server/session-tools/index.ts +8 -2
  126. package/src/lib/server/session-tools/memory.ts +23 -4
  127. package/src/lib/server/session-tools/openclaw-workspace.ts +132 -0
  128. package/src/lib/server/session-tools/shell.ts +1 -1
  129. package/src/lib/server/session-tools/wallet.ts +124 -0
  130. package/src/lib/server/session-tools/web.ts +2 -2
  131. package/src/lib/server/solana.ts +122 -0
  132. package/src/lib/server/storage.ts +158 -6
  133. package/src/lib/server/stream-agent-chat.ts +126 -63
  134. package/src/lib/server/task-mention.test.ts +41 -0
  135. package/src/lib/server/task-mention.ts +3 -2
  136. package/src/lib/setup-defaults.ts +277 -0
  137. package/src/lib/tool-definitions.ts +1 -0
  138. package/src/lib/validation/schemas.ts +69 -0
  139. package/src/lib/view-routes.ts +1 -0
  140. package/src/stores/use-app-store.ts +15 -3
  141. package/src/stores/use-chatroom-store.ts +52 -2
  142. package/src/types/index.ts +98 -2
  143. package/tsconfig.json +2 -1
@@ -7,7 +7,8 @@ import { api } from '@/lib/api-client'
7
7
  import { BottomSheet } from '@/components/shared/bottom-sheet'
8
8
  import { toast } from 'sonner'
9
9
  import { ModelCombobox } from '@/components/shared/model-combobox'
10
- import type { ProviderType, ClaudeSkill } from '@/types'
10
+ import type { ProviderType, ClaudeSkill, AgentWallet } from '@/types'
11
+ import { WalletSection } from '@/components/wallets/wallet-section'
11
12
  import { AVAILABLE_TOOLS, PLATFORM_TOOLS } from '@/lib/tool-definitions'
12
13
  import { NATIVE_CAPABILITY_PROVIDER_IDS, NON_LANGGRAPH_PROVIDER_IDS } from '@/lib/provider-sets'
13
14
  import { AgentAvatar } from './agent-avatar'
@@ -105,12 +106,18 @@ export function AgentSheet() {
105
106
  const [openclawEnabled, setOpenclawEnabled] = useState(false)
106
107
  const [projectId, setProjectId] = useState<string | undefined>(undefined)
107
108
  const [avatarSeed, setAvatarSeed] = useState('')
109
+ const [avatarUrl, setAvatarUrl] = useState<string | null>(null)
110
+ const [uploading, setUploading] = useState(false)
108
111
  const [thinkingLevel, setThinkingLevel] = useState<'' | 'minimal' | 'low' | 'medium' | 'high'>('')
109
112
  const [voiceId, setVoiceId] = useState('')
110
113
  const [heartbeatEnabled, setHeartbeatEnabled] = useState(false)
111
114
  const [heartbeatIntervalSec, setHeartbeatIntervalSec] = useState('') // '' = default (30m)
112
115
  const [heartbeatModel, setHeartbeatModel] = useState('')
113
116
  const [heartbeatPrompt, setHeartbeatPrompt] = useState('')
117
+ const [budgetEnabled, setBudgetEnabled] = useState(false)
118
+ const [monthlyBudget, setMonthlyBudget] = useState('')
119
+ const [budgetAction, setBudgetAction] = useState<'warn' | 'block'>('warn')
120
+ const [agentWallet, setAgentWallet] = useState<(Omit<AgentWallet, 'encryptedPrivateKey'> & { balanceLamports?: number; balanceSol?: number }) | null>(null)
114
121
  const [addingKey, setAddingKey] = useState(false)
115
122
  const [newKeyName, setNewKeyName] = useState('')
116
123
  const [newKeyValue, setNewKeyValue] = useState('')
@@ -178,18 +185,30 @@ export function AgentSheet() {
178
185
  setMcpDisabledTools(editing.mcpDisabledTools || [])
179
186
  setFallbackCredentialIds(editing.fallbackCredentialIds || [])
180
187
  // platformAssignScope derived from isOrchestrator — no separate state
181
- setCapabilities(editing.capabilities || [])
188
+ setCapabilities(Array.isArray(editing.capabilities) ? editing.capabilities : [])
182
189
  setCapInput('')
183
190
  setOllamaMode(editing.credentialId && editing.provider === 'ollama' ? 'cloud' : 'local')
184
191
  setOpenclawEnabled(editing.provider === 'openclaw')
185
192
  setProjectId(editing.projectId)
186
193
  setAvatarSeed(editing.avatarSeed || crypto.randomUUID().slice(0, 8))
194
+ setAvatarUrl(editing.avatarUrl || null)
187
195
  setThinkingLevel(editing.thinkingLevel || '')
188
196
  setVoiceId(editing.elevenLabsVoiceId || '')
189
197
  setHeartbeatEnabled(editing.heartbeatEnabled || false)
190
198
  setHeartbeatIntervalSec(parseDurationToSec(editing.heartbeatInterval, editing.heartbeatIntervalSec))
191
199
  setHeartbeatModel(editing.heartbeatModel || '')
192
200
  setHeartbeatPrompt(editing.heartbeatPrompt || '')
201
+ setBudgetEnabled(typeof editing.monthlyBudget === 'number' && editing.monthlyBudget > 0)
202
+ setMonthlyBudget(typeof editing.monthlyBudget === 'number' && editing.monthlyBudget > 0 ? String(editing.monthlyBudget) : '')
203
+ setBudgetAction(editing.budgetAction || 'warn')
204
+ // Load wallet if agent has one
205
+ if (editing.walletId) {
206
+ api<Omit<AgentWallet, 'encryptedPrivateKey'> & { balanceLamports?: number; balanceSol?: number }>('GET', `/wallets/${editing.walletId}`)
207
+ .then(setAgentWallet)
208
+ .catch(() => setAgentWallet(null))
209
+ } else {
210
+ setAgentWallet(null)
211
+ }
193
212
  } else {
194
213
  setName('')
195
214
  setDescription('')
@@ -221,6 +240,9 @@ export function AgentSheet() {
221
240
  setHeartbeatIntervalSec('')
222
241
  setHeartbeatModel('')
223
242
  setHeartbeatPrompt('')
243
+ setBudgetEnabled(false)
244
+ setMonthlyBudget('')
245
+ setBudgetAction('warn')
224
246
  }
225
247
  }
226
248
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -310,6 +332,7 @@ export function AgentSheet() {
310
332
  capabilities,
311
333
  projectId: projectId || undefined,
312
334
  avatarSeed: avatarSeed.trim() || undefined,
335
+ avatarUrl: avatarUrl || null,
313
336
  thinkingLevel: thinkingLevel || undefined,
314
337
  elevenLabsVoiceId: voiceId.trim() || null,
315
338
  heartbeatEnabled,
@@ -317,6 +340,8 @@ export function AgentSheet() {
317
340
  heartbeatIntervalSec: heartbeatIntervalSec ? Number(heartbeatIntervalSec) : null,
318
341
  heartbeatModel: heartbeatModel.trim() || null,
319
342
  heartbeatPrompt: heartbeatPrompt.trim() || null,
343
+ monthlyBudget: budgetEnabled && monthlyBudget ? Number(monthlyBudget) : null,
344
+ budgetAction: budgetEnabled ? budgetAction : undefined,
320
345
  }
321
346
  if (editing) {
322
347
  await updateAgent(editing.id, data)
@@ -480,30 +505,82 @@ export function AgentSheet() {
480
505
 
481
506
  <div className="mb-8">
482
507
  <SectionLabel>Avatar</SectionLabel>
483
- <div className="flex items-center gap-3">
484
- <AgentAvatar seed={avatarSeed || null} name={name || 'A'} size={40} />
485
- <input
486
- type="text"
487
- value={avatarSeed}
488
- onChange={(e) => setAvatarSeed(e.target.value)}
489
- placeholder="Avatar seed (any text)"
490
- className={inputClass}
491
- style={{ fontFamily: 'inherit', flex: 1 }}
492
- />
493
- <button
494
- type="button"
495
- onClick={() => setAvatarSeed(crypto.randomUUID().slice(0, 8))}
496
- className="inline-flex items-center gap-1.5 px-3 py-2 rounded-[10px] border border-white/[0.08] bg-transparent text-text-3 text-[12px] font-600 cursor-pointer transition-all hover:bg-white/[0.04] hover:text-text-2 active:scale-95 shrink-0"
497
- style={{ fontFamily: 'inherit' }}
498
- title="Shuffle avatar"
499
- >
500
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
501
- <rect x="4" y="4" width="16" height="16" rx="2" />
502
- <circle cx="9" cy="9" r="1" fill="currentColor" />
503
- <circle cx="15" cy="15" r="1" fill="currentColor" />
504
- </svg>
505
- Shuffle
506
- </button>
508
+ <div className="flex flex-col gap-3">
509
+ <div className="flex items-center gap-4">
510
+ <div className="relative group shrink-0">
511
+ <AgentAvatar seed={avatarUrl ? null : (avatarSeed || null)} avatarUrl={avatarUrl} name={name || 'A'} size={64} />
512
+ <label className="absolute inset-0 rounded-full flex items-center justify-center bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer">
513
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
514
+ <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
515
+ <circle cx="12" cy="13" r="4" />
516
+ </svg>
517
+ <input
518
+ type="file"
519
+ accept="image/*"
520
+ className="hidden"
521
+ onChange={async (e) => {
522
+ const file = e.target.files?.[0]
523
+ if (!file) return
524
+ setUploading(true)
525
+ try {
526
+ const res = await fetch('/api/upload', {
527
+ method: 'POST',
528
+ headers: { 'x-filename': file.name },
529
+ body: await file.arrayBuffer(),
530
+ })
531
+ const data = await res.json()
532
+ if (data.url) {
533
+ setAvatarUrl(data.url)
534
+ setAvatarSeed('')
535
+ }
536
+ } finally {
537
+ setUploading(false)
538
+ e.target.value = ''
539
+ }
540
+ }}
541
+ />
542
+ </label>
543
+ </div>
544
+ <div className="flex flex-col gap-1.5 flex-1 min-w-0">
545
+ {avatarUrl && (
546
+ <button
547
+ type="button"
548
+ onClick={() => {
549
+ setAvatarUrl(null)
550
+ if (!avatarSeed) setAvatarSeed(crypto.randomUUID().slice(0, 8))
551
+ }}
552
+ className="text-[11px] text-text-3 hover:text-red-400 transition-colors self-start cursor-pointer"
553
+ >
554
+ Remove custom image
555
+ </button>
556
+ )}
557
+ {uploading && <span className="text-[11px] text-text-3">Uploading...</span>}
558
+ </div>
559
+ </div>
560
+ <div className="flex items-center gap-3">
561
+ <input
562
+ type="text"
563
+ value={avatarSeed}
564
+ onChange={(e) => { setAvatarSeed(e.target.value); setAvatarUrl(null) }}
565
+ placeholder="Avatar seed (any text)"
566
+ className={inputClass}
567
+ style={{ fontFamily: 'inherit', flex: 1 }}
568
+ />
569
+ <button
570
+ type="button"
571
+ onClick={() => { setAvatarSeed(crypto.randomUUID().slice(0, 8)); setAvatarUrl(null) }}
572
+ className="inline-flex items-center gap-1.5 px-3 py-2 rounded-[10px] border border-white/[0.08] bg-transparent text-text-3 text-[12px] font-600 cursor-pointer transition-all hover:bg-white/[0.04] hover:text-text-2 active:scale-95 shrink-0"
573
+ style={{ fontFamily: 'inherit' }}
574
+ title="Shuffle avatar"
575
+ >
576
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
577
+ <rect x="4" y="4" width="16" height="16" rx="2" />
578
+ <circle cx="9" cy="9" r="1" fill="currentColor" />
579
+ <circle cx="15" cy="15" r="1" fill="currentColor" />
580
+ </svg>
581
+ Shuffle
582
+ </button>
583
+ </div>
507
584
  </div>
508
585
  </div>
509
586
 
@@ -666,6 +743,94 @@ export function AgentSheet() {
666
743
  <p className="text-[11px] text-text-3/70 mt-1.5">Periodic check-in runs on idle sessions using this agent. Processes pending events and monitors status.</p>
667
744
  </div>
668
745
 
746
+ {/* Monthly Budget */}
747
+ <div className="mb-8">
748
+ <div className="flex items-center justify-between mb-3">
749
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em]">Monthly Budget</label>
750
+ <button
751
+ type="button"
752
+ onClick={() => setBudgetEnabled(!budgetEnabled)}
753
+ className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${budgetEnabled ? 'bg-accent' : 'bg-white/[0.12]'}`}
754
+ >
755
+ <span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${budgetEnabled ? 'translate-x-[18px]' : ''}`} />
756
+ </button>
757
+ </div>
758
+ {budgetEnabled && (
759
+ <div className="space-y-4 mt-3">
760
+ <div>
761
+ <label className="block text-[12px] text-text-3/70 mb-1.5">Budget cap (USD)</label>
762
+ <div className="relative">
763
+ <span className="absolute left-3.5 top-1/2 -translate-y-1/2 text-text-3/50 text-[14px]">$</span>
764
+ <input
765
+ type="number"
766
+ min="0.01"
767
+ step="0.01"
768
+ value={monthlyBudget}
769
+ onChange={(e) => setMonthlyBudget(e.target.value)}
770
+ placeholder="10.00"
771
+ className={`${inputClass} pl-7`}
772
+ style={{ fontFamily: 'inherit' }}
773
+ />
774
+ </div>
775
+ </div>
776
+ <div>
777
+ <label className="block text-[12px] text-text-3/70 mb-1.5">When exceeded</label>
778
+ <div className="flex gap-2">
779
+ <button
780
+ type="button"
781
+ onClick={() => setBudgetAction('warn')}
782
+ className={`flex-1 px-3 py-2.5 rounded-[10px] border text-[13px] font-600 cursor-pointer transition-all ${
783
+ budgetAction === 'warn'
784
+ ? 'border-amber-400/40 bg-amber-400/[0.08] text-amber-400'
785
+ : 'border-white/[0.08] bg-transparent text-text-3 hover:bg-white/[0.04]'
786
+ }`}
787
+ style={{ fontFamily: 'inherit' }}
788
+ >
789
+ Warn
790
+ </button>
791
+ <button
792
+ type="button"
793
+ onClick={() => setBudgetAction('block')}
794
+ className={`flex-1 px-3 py-2.5 rounded-[10px] border text-[13px] font-600 cursor-pointer transition-all ${
795
+ budgetAction === 'block'
796
+ ? 'border-red-400/40 bg-red-400/[0.08] text-red-400'
797
+ : 'border-white/[0.08] bg-transparent text-text-3 hover:bg-white/[0.04]'
798
+ }`}
799
+ style={{ fontFamily: 'inherit' }}
800
+ >
801
+ Block
802
+ </button>
803
+ </div>
804
+ </div>
805
+ </div>
806
+ )}
807
+ <p className="text-[11px] text-text-3/70 mt-1.5">
808
+ {budgetAction === 'block'
809
+ ? 'Cap monthly spend for this agent. When exceeded, chat runs are blocked until the next month.'
810
+ : 'Cap monthly spend for this agent. When exceeded, a warning is shown but runs continue.'}
811
+ </p>
812
+ </div>
813
+
814
+ {/* Wallet Section */}
815
+ {editingId && (
816
+ <WalletSection
817
+ agentId={editingId}
818
+ wallet={agentWallet}
819
+ onWalletCreated={async () => {
820
+ await loadAgents()
821
+ // Fetch the wallet for this agent
822
+ try {
823
+ const wallets = await api<Record<string, Omit<AgentWallet, 'encryptedPrivateKey'>>>('GET', '/wallets')
824
+ const match = Object.values(wallets).find((w) => w.agentId === editingId)
825
+ if (match) {
826
+ const detail = await api<Omit<AgentWallet, 'encryptedPrivateKey'> & { balanceLamports?: number; balanceSol?: number }>('GET', `/wallets/${match.id}`)
827
+ setAgentWallet(detail)
828
+ }
829
+ } catch { /* ignore */ }
830
+ }}
831
+ />
832
+ )}
833
+
669
834
  {provider !== 'openclaw' && (
670
835
  <div className="mb-8">
671
836
  <label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">