@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.
- package/README.md +62 -30
- package/package.json +10 -1
- package/src/app/api/agents/[id]/clone/route.ts +40 -0
- package/src/app/api/agents/route.ts +39 -14
- package/src/app/api/chatrooms/[id]/chat/route.ts +58 -3
- package/src/app/api/chatrooms/[id]/moderate/route.ts +150 -0
- package/src/app/api/chatrooms/[id]/route.ts +34 -2
- package/src/app/api/chatrooms/route.ts +26 -3
- package/src/app/api/connectors/[id]/health/route.ts +64 -0
- package/src/app/api/connectors/route.ts +17 -2
- package/src/app/api/knowledge/route.ts +6 -1
- package/src/app/api/openclaw/doctor/route.ts +17 -0
- package/src/app/api/schedules/[id]/run/route.ts +3 -0
- package/src/app/api/sessions/[id]/chat/route.ts +5 -1
- package/src/app/api/sessions/route.ts +11 -2
- package/src/app/api/tasks/[id]/route.ts +18 -13
- package/src/app/api/tasks/route.ts +44 -1
- package/src/app/api/usage/route.ts +16 -7
- 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 +20 -0
- package/src/cli/index.ts +223 -39
- package/src/cli/spec.js +14 -0
- package/src/components/agents/agent-avatar.tsx +15 -1
- package/src/components/agents/agent-card.tsx +38 -6
- package/src/components/agents/agent-chat-list.tsx +79 -3
- package/src/components/agents/agent-sheet.tsx +191 -26
- package/src/components/auth/setup-wizard.tsx +268 -353
- package/src/components/chat/chat-area.tsx +24 -9
- 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 +17 -16
- package/src/components/chat/message-list.tsx +6 -5
- 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 +165 -23
- package/src/components/chatrooms/chatroom-sheet.tsx +289 -4
- package/src/components/chatrooms/chatroom-typing-bar.tsx +1 -1
- package/src/components/chatrooms/chatroom-view.tsx +62 -17
- package/src/components/connectors/connector-health.tsx +120 -0
- package/src/components/connectors/connector-list.tsx +1 -1
- package/src/components/connectors/connector-sheet.tsx +9 -0
- package/src/components/home/home-view.tsx +25 -3
- package/src/components/input/chat-input.tsx +8 -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 +35 -4
- 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/schedules/schedule-list.tsx +55 -9
- package/src/components/schedules/schedule-sheet.tsx +134 -23
- 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/command-palette.tsx +237 -0
- package/src/components/shared/connector-platform-icon.tsx +1 -0
- 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-card.tsx +22 -2
- package/src/components/tasks/task-sheet.tsx +112 -17
- package/src/components/usage/metrics-dashboard.tsx +13 -25
- 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/hooks/use-swipe.ts +49 -0
- package/src/lib/providers/anthropic.ts +16 -2
- package/src/lib/providers/claude-cli.ts +7 -1
- package/src/lib/providers/index.ts +7 -0
- package/src/lib/providers/ollama.ts +16 -2
- package/src/lib/providers/openai.ts +7 -2
- package/src/lib/providers/openclaw.ts +6 -1
- package/src/lib/providers/provider-defaults.ts +7 -0
- package/src/lib/schedule-templates.ts +115 -0
- package/src/lib/server/agent-registry.ts +2 -2
- package/src/lib/server/alert-dispatch.ts +64 -0
- package/src/lib/server/chat-execution.ts +76 -4
- 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 +86 -12
- package/src/lib/server/chatroom-routing.ts +65 -0
- package/src/lib/server/connectors/discord.ts +3 -0
- package/src/lib/server/connectors/email.ts +267 -0
- 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 +239 -5
- package/src/lib/server/connectors/openclaw.ts +3 -0
- package/src/lib/server/connectors/slack.ts +6 -0
- package/src/lib/server/connectors/telegram.ts +18 -0
- package/src/lib/server/connectors/types.ts +2 -0
- 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 +17 -5
- package/src/lib/server/cost.ts +70 -0
- package/src/lib/server/create-notification.ts +2 -0
- package/src/lib/server/daemon-state.ts +124 -0
- package/src/lib/server/dag-validation.ts +115 -0
- package/src/lib/server/memory-db.ts +12 -7
- package/src/lib/server/openclaw-doctor.ts +48 -0
- 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 +238 -24
- package/src/lib/server/scheduler.ts +3 -0
- package/src/lib/server/session-run-manager.ts +22 -1
- 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 +8 -2
- package/src/lib/server/session-tools/memory.ts +23 -4
- package/src/lib/server/session-tools/openclaw-workspace.ts +132 -0
- 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 +158 -6
- 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/setup-defaults.ts +277 -0
- package/src/lib/tool-definitions.ts +1 -0
- package/src/lib/validation/schemas.ts +69 -0
- package/src/lib/view-routes.ts +1 -0
- package/src/stores/use-app-store.ts +15 -3
- package/src/stores/use-chatroom-store.ts +52 -2
- package/src/types/index.ts +98 -2
- 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
|
|
484
|
-
<
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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">
|