@swarmclawai/swarmclaw 0.5.3 → 0.6.2
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 +53 -9
- package/bin/server-cmd.js +1 -0
- package/bin/swarmclaw.js +76 -16
- package/next.config.ts +11 -1
- package/package.json +5 -2
- package/scripts/postinstall.mjs +18 -0
- package/src/app/api/canvas/[sessionId]/route.ts +31 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +284 -0
- package/src/app/api/chatrooms/[id]/members/route.ts +82 -0
- package/src/app/api/chatrooms/[id]/pins/route.ts +39 -0
- package/src/app/api/chatrooms/[id]/reactions/route.ts +42 -0
- package/src/app/api/chatrooms/[id]/route.ts +84 -0
- package/src/app/api/chatrooms/route.ts +50 -0
- package/src/app/api/connectors/[id]/route.ts +1 -0
- package/src/app/api/connectors/route.ts +2 -1
- package/src/app/api/credentials/route.ts +2 -3
- package/src/app/api/files/open/route.ts +43 -0
- package/src/app/api/knowledge/[id]/route.ts +13 -2
- package/src/app/api/knowledge/route.ts +8 -1
- package/src/app/api/memory/route.ts +8 -0
- package/src/app/api/notifications/route.ts +4 -0
- package/src/app/api/orchestrator/run/route.ts +1 -1
- package/src/app/api/plugins/install/route.ts +2 -2
- package/src/app/api/search/route.ts +53 -1
- package/src/app/api/sessions/[id]/chat/route.ts +2 -0
- package/src/app/api/sessions/[id]/edit-resend/route.ts +1 -1
- package/src/app/api/sessions/[id]/fork/route.ts +1 -1
- package/src/app/api/sessions/[id]/messages/route.ts +70 -2
- package/src/app/api/sessions/[id]/route.ts +4 -0
- package/src/app/api/sessions/route.ts +3 -3
- package/src/app/api/settings/route.ts +9 -0
- package/src/app/api/setup/check-provider/route.ts +3 -16
- package/src/app/api/skills/[id]/route.ts +6 -0
- package/src/app/api/skills/route.ts +6 -0
- package/src/app/api/tasks/[id]/route.ts +12 -0
- package/src/app/api/tasks/bulk/route.ts +100 -0
- package/src/app/api/tasks/metrics/route.ts +101 -0
- package/src/app/api/tasks/route.ts +18 -2
- package/src/app/api/tts/route.ts +3 -2
- package/src/app/api/tts/stream/route.ts +3 -2
- package/src/app/api/uploads/[filename]/route.ts +19 -34
- package/src/app/api/uploads/route.ts +94 -0
- package/src/app/api/webhooks/[id]/route.ts +15 -1
- package/src/app/globals.css +63 -15
- package/src/app/page.tsx +142 -13
- package/src/cli/index.js +40 -1
- package/src/cli/index.test.js +30 -0
- package/src/cli/spec.js +42 -0
- package/src/components/agents/agent-avatar.tsx +57 -10
- package/src/components/agents/agent-card.tsx +50 -17
- package/src/components/agents/agent-chat-list.tsx +148 -12
- package/src/components/agents/agent-list.tsx +50 -19
- package/src/components/agents/agent-sheet.tsx +120 -65
- package/src/components/agents/inspector-panel.tsx +81 -6
- package/src/components/agents/openclaw-skills-panel.tsx +32 -3
- package/src/components/agents/personality-builder.tsx +42 -14
- package/src/components/agents/soul-library-picker.tsx +89 -0
- package/src/components/auth/access-key-gate.tsx +10 -3
- package/src/components/auth/setup-wizard.tsx +2 -2
- package/src/components/auth/user-picker.tsx +31 -3
- package/src/components/canvas/canvas-panel.tsx +96 -0
- package/src/components/chat/activity-moment.tsx +173 -0
- package/src/components/chat/chat-area.tsx +46 -22
- package/src/components/chat/chat-header.tsx +457 -286
- package/src/components/chat/chat-preview-panel.tsx +1 -2
- package/src/components/chat/chat-tool-toggles.tsx +1 -1
- package/src/components/chat/delegation-banner.tsx +371 -0
- package/src/components/chat/file-path-chip.tsx +146 -0
- package/src/components/chat/heartbeat-history-panel.tsx +269 -0
- package/src/components/chat/markdown-utils.ts +9 -0
- package/src/components/chat/message-bubble.tsx +356 -315
- package/src/components/chat/message-list.tsx +230 -8
- package/src/components/chat/streaming-bubble.tsx +104 -47
- package/src/components/chat/suggestions-bar.tsx +1 -1
- package/src/components/chat/thinking-indicator.tsx +72 -10
- package/src/components/chat/tool-call-bubble.tsx +111 -73
- package/src/components/chat/tool-request-banner.tsx +31 -7
- package/src/components/chat/transfer-agent-picker.tsx +63 -0
- package/src/components/chatrooms/agent-hover-card.tsx +124 -0
- package/src/components/chatrooms/chatroom-input.tsx +320 -0
- package/src/components/chatrooms/chatroom-list.tsx +130 -0
- package/src/components/chatrooms/chatroom-message.tsx +432 -0
- package/src/components/chatrooms/chatroom-sheet.tsx +215 -0
- package/src/components/chatrooms/chatroom-tool-request-banner.tsx +134 -0
- package/src/components/chatrooms/chatroom-typing-bar.tsx +88 -0
- package/src/components/chatrooms/chatroom-view.tsx +344 -0
- package/src/components/chatrooms/reaction-picker.tsx +273 -0
- package/src/components/connectors/connector-list.tsx +168 -90
- package/src/components/connectors/connector-sheet.tsx +95 -56
- package/src/components/home/home-view.tsx +501 -0
- package/src/components/input/chat-input.tsx +107 -43
- package/src/components/knowledge/knowledge-list.tsx +31 -1
- package/src/components/knowledge/knowledge-sheet.tsx +83 -2
- package/src/components/layout/app-layout.tsx +194 -97
- package/src/components/layout/update-banner.tsx +2 -2
- package/src/components/logs/log-list.tsx +2 -2
- package/src/components/mcp-servers/mcp-server-sheet.tsx +1 -1
- package/src/components/memory/memory-agent-list.tsx +143 -0
- package/src/components/memory/memory-browser.tsx +205 -0
- package/src/components/memory/memory-card.tsx +34 -7
- package/src/components/memory/memory-detail.tsx +359 -120
- package/src/components/memory/memory-sheet.tsx +157 -23
- package/src/components/plugins/plugin-list.tsx +1 -1
- package/src/components/plugins/plugin-sheet.tsx +1 -1
- package/src/components/projects/project-detail.tsx +509 -0
- package/src/components/projects/project-list.tsx +195 -59
- package/src/components/providers/provider-list.tsx +2 -2
- package/src/components/providers/provider-sheet.tsx +3 -3
- package/src/components/schedules/schedule-card.tsx +1 -1
- package/src/components/schedules/schedule-list.tsx +1 -1
- package/src/components/schedules/schedule-sheet.tsx +259 -126
- package/src/components/secrets/secret-sheet.tsx +47 -24
- package/src/components/secrets/secrets-list.tsx +18 -8
- package/src/components/sessions/new-session-sheet.tsx +33 -65
- package/src/components/sessions/session-card.tsx +45 -14
- package/src/components/sessions/session-list.tsx +35 -18
- package/src/components/settings/gateway-disconnect-overlay.tsx +80 -0
- package/src/components/shared/agent-picker-list.tsx +90 -0
- package/src/components/shared/agent-switch-dialog.tsx +156 -0
- package/src/components/shared/attachment-chip.tsx +165 -0
- package/src/components/shared/avatar.tsx +10 -1
- package/src/components/shared/chatroom-picker-list.tsx +61 -0
- package/src/components/shared/check-icon.tsx +12 -0
- package/src/components/shared/confirm-dialog.tsx +1 -1
- package/src/components/shared/connector-platform-icon.tsx +51 -4
- package/src/components/shared/empty-state.tsx +32 -0
- package/src/components/shared/file-preview.tsx +34 -0
- package/src/components/shared/form-styles.ts +2 -0
- package/src/components/shared/icon-button.tsx +16 -2
- package/src/components/shared/keyboard-shortcuts-dialog.tsx +116 -0
- package/src/components/shared/notification-center.tsx +44 -6
- package/src/components/shared/profile-sheet.tsx +115 -0
- package/src/components/shared/reply-quote.tsx +26 -0
- package/src/components/shared/search-dialog.tsx +31 -15
- package/src/components/shared/section-label.tsx +12 -0
- package/src/components/shared/settings/plugin-manager.tsx +1 -1
- package/src/components/shared/settings/section-embedding.tsx +48 -13
- package/src/components/shared/settings/section-orchestrator.tsx +46 -15
- package/src/components/shared/settings/section-providers.tsx +1 -1
- package/src/components/shared/settings/section-secrets.tsx +1 -1
- package/src/components/shared/settings/section-storage.tsx +206 -0
- package/src/components/shared/settings/section-theme.tsx +95 -0
- package/src/components/shared/settings/section-user-preferences.tsx +57 -0
- package/src/components/shared/settings/section-voice.tsx +42 -21
- package/src/components/shared/settings/section-web-search.tsx +30 -6
- package/src/components/shared/settings/settings-page.tsx +182 -27
- package/src/components/shared/settings/settings-sheet.tsx +9 -73
- package/src/components/shared/settings/storage-browser.tsx +259 -0
- package/src/components/shared/sheet-footer.tsx +33 -0
- package/src/components/skills/skill-list.tsx +61 -30
- package/src/components/skills/skill-sheet.tsx +81 -2
- package/src/components/tasks/task-board.tsx +448 -26
- package/src/components/tasks/task-card.tsx +59 -9
- package/src/components/tasks/task-column.tsx +62 -3
- package/src/components/tasks/task-list.tsx +12 -4
- package/src/components/tasks/task-sheet.tsx +416 -74
- package/src/components/ui/hover-card.tsx +52 -0
- package/src/components/usage/metrics-dashboard.tsx +90 -6
- package/src/components/usage/usage-list.tsx +1 -1
- package/src/components/webhooks/webhook-sheet.tsx +1 -1
- package/src/hooks/use-continuous-speech.ts +10 -4
- package/src/hooks/use-view-router.ts +69 -19
- package/src/hooks/use-voice-conversation.ts +53 -10
- package/src/hooks/use-ws.ts +4 -2
- package/src/instrumentation.ts +15 -1
- package/src/lib/chat.ts +2 -0
- package/src/lib/memory.ts +3 -0
- package/src/lib/providers/anthropic.ts +13 -7
- package/src/lib/providers/index.ts +1 -0
- package/src/lib/providers/openai.ts +13 -7
- package/src/lib/server/chat-execution.ts +75 -15
- package/src/lib/server/chatroom-helpers.ts +146 -0
- package/src/lib/server/connectors/manager.ts +229 -7
- package/src/lib/server/context-manager.ts +225 -13
- package/src/lib/server/create-notification.ts +14 -2
- package/src/lib/server/daemon-state.ts +157 -10
- package/src/lib/server/execution-log.ts +1 -0
- package/src/lib/server/heartbeat-service.ts +48 -6
- package/src/lib/server/heartbeat-wake.ts +110 -0
- package/src/lib/server/langgraph-checkpoint.ts +1 -0
- package/src/lib/server/main-agent-loop.ts +1 -1
- package/src/lib/server/memory-consolidation.ts +105 -0
- package/src/lib/server/memory-db.ts +183 -10
- package/src/lib/server/mime.ts +51 -0
- package/src/lib/server/openclaw-gateway.ts +9 -1
- package/src/lib/server/orchestrator-lg.ts +2 -0
- package/src/lib/server/orchestrator.ts +5 -2
- package/src/lib/server/playwright-proxy.mjs +2 -3
- package/src/lib/server/prompt-runtime-context.ts +53 -0
- package/src/lib/server/provider-health.ts +125 -0
- package/src/lib/server/queue.ts +56 -10
- package/src/lib/server/scheduler.ts +8 -0
- package/src/lib/server/session-run-manager.ts +4 -0
- package/src/lib/server/session-tools/canvas.ts +67 -0
- package/src/lib/server/session-tools/chatroom.ts +136 -0
- package/src/lib/server/session-tools/connector.ts +83 -9
- package/src/lib/server/session-tools/context-mgmt.ts +36 -18
- package/src/lib/server/session-tools/crud.ts +21 -0
- package/src/lib/server/session-tools/delegate.ts +68 -4
- package/src/lib/server/session-tools/git.ts +71 -0
- package/src/lib/server/session-tools/http.ts +57 -0
- package/src/lib/server/session-tools/index.ts +10 -0
- package/src/lib/server/session-tools/memory.ts +7 -1
- package/src/lib/server/session-tools/search-providers.ts +16 -8
- package/src/lib/server/session-tools/subagent.ts +106 -0
- package/src/lib/server/session-tools/web.ts +115 -4
- package/src/lib/server/storage.ts +53 -29
- package/src/lib/server/stream-agent-chat.ts +185 -57
- package/src/lib/server/system-events.ts +49 -0
- package/src/lib/server/task-mention.ts +41 -0
- package/src/lib/server/ws-hub.ts +11 -0
- package/src/lib/sessions.ts +10 -0
- package/src/lib/soul-library.ts +103 -0
- package/src/lib/soul-suggestions.ts +109 -0
- package/src/lib/task-dedupe.ts +26 -0
- package/src/lib/tasks.ts +4 -1
- package/src/lib/tool-definitions.ts +2 -0
- package/src/lib/tts.ts +2 -2
- package/src/lib/view-routes.ts +36 -1
- package/src/lib/ws-client.ts +14 -4
- package/src/stores/use-app-store.ts +41 -3
- package/src/stores/use-chat-store.ts +113 -5
- package/src/stores/use-chatroom-store.ts +276 -0
- package/src/types/index.ts +88 -4
|
@@ -11,8 +11,12 @@ import type { ProviderType, ClaudeSkill } from '@/types'
|
|
|
11
11
|
import { AVAILABLE_TOOLS, PLATFORM_TOOLS } from '@/lib/tool-definitions'
|
|
12
12
|
import { NATIVE_CAPABILITY_PROVIDER_IDS, NON_LANGGRAPH_PROVIDER_IDS } from '@/lib/provider-sets'
|
|
13
13
|
import { AgentAvatar } from './agent-avatar'
|
|
14
|
+
import { AgentPickerList } from '@/components/shared/agent-picker-list'
|
|
15
|
+
import { randomSoul } from '@/lib/soul-suggestions'
|
|
16
|
+
import { SectionLabel } from '@/components/shared/section-label'
|
|
17
|
+
import { SoulLibraryPicker } from './soul-library-picker'
|
|
14
18
|
|
|
15
|
-
const HB_PRESETS = [
|
|
19
|
+
const HB_PRESETS = [1800, 3600, 7200, 21600, 43200] as const
|
|
16
20
|
|
|
17
21
|
function formatHbDuration(sec: number): string {
|
|
18
22
|
if (sec >= 3600) {
|
|
@@ -60,6 +64,7 @@ export function AgentSheet() {
|
|
|
60
64
|
const loadProviders = useAppStore((s) => s.loadProviders)
|
|
61
65
|
const credentials = useAppStore((s) => s.credentials)
|
|
62
66
|
const loadCredentials = useAppStore((s) => s.loadCredentials)
|
|
67
|
+
const appSettings = useAppStore((s) => s.appSettings)
|
|
63
68
|
const dynamicSkills = useAppStore((s) => s.skills)
|
|
64
69
|
const mcpServers = useAppStore((s) => s.mcpServers)
|
|
65
70
|
const loadSkills = useAppStore((s) => s.loadSkills)
|
|
@@ -77,6 +82,8 @@ export function AgentSheet() {
|
|
|
77
82
|
const [name, setName] = useState('')
|
|
78
83
|
const [description, setDescription] = useState('')
|
|
79
84
|
const [soul, setSoul] = useState('')
|
|
85
|
+
const [soulInitial, setSoulInitial] = useState('')
|
|
86
|
+
const [soulSaveState, setSoulSaveState] = useState<'idle' | 'saved'>('idle')
|
|
80
87
|
const [systemPrompt, setSystemPrompt] = useState('')
|
|
81
88
|
const [provider, setProvider] = useState<ProviderType>('claude-cli')
|
|
82
89
|
const [model, setModel] = useState('')
|
|
@@ -92,7 +99,6 @@ export function AgentSheet() {
|
|
|
92
99
|
const [mcpTools, setMcpTools] = useState<Record<string, { name: string; description: string }[]>>({})
|
|
93
100
|
const [mcpToolsLoading, setMcpToolsLoading] = useState(false)
|
|
94
101
|
const [fallbackCredentialIds, setFallbackCredentialIds] = useState<string[]>([])
|
|
95
|
-
const [platformAssignScope, setPlatformAssignScope] = useState<'self' | 'all'>('self')
|
|
96
102
|
const [capabilities, setCapabilities] = useState<string[]>([])
|
|
97
103
|
const [capInput, setCapInput] = useState('')
|
|
98
104
|
const [ollamaMode, setOllamaMode] = useState<'local' | 'cloud'>('local')
|
|
@@ -100,6 +106,7 @@ export function AgentSheet() {
|
|
|
100
106
|
const [projectId, setProjectId] = useState<string | undefined>(undefined)
|
|
101
107
|
const [avatarSeed, setAvatarSeed] = useState('')
|
|
102
108
|
const [thinkingLevel, setThinkingLevel] = useState<'' | 'minimal' | 'low' | 'medium' | 'high'>('')
|
|
109
|
+
const [voiceId, setVoiceId] = useState('')
|
|
103
110
|
const [heartbeatEnabled, setHeartbeatEnabled] = useState(false)
|
|
104
111
|
const [heartbeatIntervalSec, setHeartbeatIntervalSec] = useState('') // '' = default (30m)
|
|
105
112
|
const [heartbeatModel, setHeartbeatModel] = useState('')
|
|
@@ -118,6 +125,7 @@ export function AgentSheet() {
|
|
|
118
125
|
const [configCopied, setConfigCopied] = useState(false)
|
|
119
126
|
|
|
120
127
|
const soulFileRef = useRef<HTMLInputElement>(null)
|
|
128
|
+
const [soulLibraryOpen, setSoulLibraryOpen] = useState(false)
|
|
121
129
|
const promptFileRef = useRef<HTMLInputElement>(null)
|
|
122
130
|
const importFileRef = useRef<HTMLInputElement>(null)
|
|
123
131
|
|
|
@@ -154,6 +162,8 @@ export function AgentSheet() {
|
|
|
154
162
|
setName(editing.name)
|
|
155
163
|
setDescription(editing.description)
|
|
156
164
|
setSoul(editing.soul || '')
|
|
165
|
+
setSoulInitial(editing.soul || '')
|
|
166
|
+
setSoulSaveState('idle')
|
|
157
167
|
setSystemPrompt(editing.systemPrompt)
|
|
158
168
|
setProvider(editing.provider)
|
|
159
169
|
setModel(editing.model)
|
|
@@ -167,14 +177,15 @@ export function AgentSheet() {
|
|
|
167
177
|
setMcpServerIds(editing.mcpServerIds || [])
|
|
168
178
|
setMcpDisabledTools(editing.mcpDisabledTools || [])
|
|
169
179
|
setFallbackCredentialIds(editing.fallbackCredentialIds || [])
|
|
170
|
-
|
|
180
|
+
// platformAssignScope derived from isOrchestrator — no separate state
|
|
171
181
|
setCapabilities(editing.capabilities || [])
|
|
172
182
|
setCapInput('')
|
|
173
183
|
setOllamaMode(editing.credentialId && editing.provider === 'ollama' ? 'cloud' : 'local')
|
|
174
184
|
setOpenclawEnabled(editing.provider === 'openclaw')
|
|
175
185
|
setProjectId(editing.projectId)
|
|
176
|
-
setAvatarSeed(editing.avatarSeed ||
|
|
186
|
+
setAvatarSeed(editing.avatarSeed || crypto.randomUUID().slice(0, 8))
|
|
177
187
|
setThinkingLevel(editing.thinkingLevel || '')
|
|
188
|
+
setVoiceId(editing.elevenLabsVoiceId || '')
|
|
178
189
|
setHeartbeatEnabled(editing.heartbeatEnabled || false)
|
|
179
190
|
setHeartbeatIntervalSec(parseDurationToSec(editing.heartbeatInterval, editing.heartbeatIntervalSec))
|
|
180
191
|
setHeartbeatModel(editing.heartbeatModel || '')
|
|
@@ -182,7 +193,10 @@ export function AgentSheet() {
|
|
|
182
193
|
} else {
|
|
183
194
|
setName('')
|
|
184
195
|
setDescription('')
|
|
185
|
-
|
|
196
|
+
const newSoul = randomSoul()
|
|
197
|
+
setSoul(newSoul)
|
|
198
|
+
setSoulInitial(newSoul)
|
|
199
|
+
setSoulSaveState('idle')
|
|
186
200
|
setSystemPrompt('')
|
|
187
201
|
setProvider('claude-cli')
|
|
188
202
|
setModel('')
|
|
@@ -195,7 +209,6 @@ export function AgentSheet() {
|
|
|
195
209
|
setSkillIds([])
|
|
196
210
|
setMcpDisabledTools([])
|
|
197
211
|
setFallbackCredentialIds([])
|
|
198
|
-
setPlatformAssignScope('self')
|
|
199
212
|
setCapabilities([])
|
|
200
213
|
setCapInput('')
|
|
201
214
|
setOllamaMode('local')
|
|
@@ -203,6 +216,7 @@ export function AgentSheet() {
|
|
|
203
216
|
setProjectId(undefined)
|
|
204
217
|
setAvatarSeed('')
|
|
205
218
|
setThinkingLevel('')
|
|
219
|
+
setVoiceId('')
|
|
206
220
|
setHeartbeatEnabled(false)
|
|
207
221
|
setHeartbeatIntervalSec('')
|
|
208
222
|
setHeartbeatModel('')
|
|
@@ -292,11 +306,12 @@ export function AgentSheet() {
|
|
|
292
306
|
mcpServerIds,
|
|
293
307
|
mcpDisabledTools: mcpDisabledTools.length ? mcpDisabledTools : undefined,
|
|
294
308
|
fallbackCredentialIds,
|
|
295
|
-
platformAssignScope,
|
|
309
|
+
platformAssignScope: (isOrchestrator ? 'all' : 'self') as 'all' | 'self',
|
|
296
310
|
capabilities,
|
|
297
311
|
projectId: projectId || undefined,
|
|
298
312
|
avatarSeed: avatarSeed.trim() || undefined,
|
|
299
313
|
thinkingLevel: thinkingLevel || undefined,
|
|
314
|
+
elevenLabsVoiceId: voiceId.trim() || null,
|
|
300
315
|
heartbeatEnabled,
|
|
301
316
|
heartbeatInterval: heartbeatIntervalSec ? formatHbDuration(Number(heartbeatIntervalSec)) : null,
|
|
302
317
|
heartbeatIntervalSec: heartbeatIntervalSec ? Number(heartbeatIntervalSec) : null,
|
|
@@ -305,16 +320,22 @@ export function AgentSheet() {
|
|
|
305
320
|
}
|
|
306
321
|
if (editing) {
|
|
307
322
|
await updateAgent(editing.id, data)
|
|
323
|
+
toast.success('Agent saved')
|
|
308
324
|
} else {
|
|
309
325
|
await createAgent(data)
|
|
326
|
+
toast.success('Agent created')
|
|
310
327
|
}
|
|
311
328
|
await loadAgents()
|
|
329
|
+
setSoulInitial(soul)
|
|
330
|
+
setSoulSaveState('saved')
|
|
331
|
+
setTimeout(() => setSoulSaveState('idle'), 1500)
|
|
312
332
|
onClose()
|
|
313
333
|
}
|
|
314
334
|
|
|
315
335
|
const handleDelete = async () => {
|
|
316
336
|
if (editing) {
|
|
317
337
|
await deleteAgent(editing.id)
|
|
338
|
+
toast.success('Agent moved to trash')
|
|
318
339
|
await loadAgents()
|
|
319
340
|
onClose()
|
|
320
341
|
}
|
|
@@ -414,6 +435,7 @@ export function AgentSheet() {
|
|
|
414
435
|
const inputClass = "w-full px-4 py-3.5 rounded-[14px] border border-white/[0.08] bg-surface text-text text-[15px] outline-none transition-all duration-200 placeholder:text-text-3/50 focus-glow"
|
|
415
436
|
|
|
416
437
|
return (
|
|
438
|
+
<>
|
|
417
439
|
<BottomSheet open={open} onClose={onClose} wide>
|
|
418
440
|
<div className="mb-10 flex items-start justify-between">
|
|
419
441
|
<div>
|
|
@@ -452,12 +474,12 @@ export function AgentSheet() {
|
|
|
452
474
|
</div>
|
|
453
475
|
|
|
454
476
|
<div className="mb-8">
|
|
455
|
-
<
|
|
477
|
+
<SectionLabel>Name</SectionLabel>
|
|
456
478
|
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. SEO Researcher" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
457
479
|
</div>
|
|
458
480
|
|
|
459
481
|
<div className="mb-8">
|
|
460
|
-
<
|
|
482
|
+
<SectionLabel>Avatar</SectionLabel>
|
|
461
483
|
<div className="flex items-center gap-3">
|
|
462
484
|
<AgentAvatar seed={avatarSeed || null} name={name || 'A'} size={40} />
|
|
463
485
|
<input
|
|
@@ -470,25 +492,29 @@ export function AgentSheet() {
|
|
|
470
492
|
/>
|
|
471
493
|
<button
|
|
472
494
|
type="button"
|
|
473
|
-
onClick={() => setAvatarSeed(
|
|
474
|
-
className="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] shrink-0"
|
|
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"
|
|
475
497
|
style={{ fontFamily: 'inherit' }}
|
|
498
|
+
title="Shuffle avatar"
|
|
476
499
|
>
|
|
477
|
-
|
|
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
|
|
478
506
|
</button>
|
|
479
507
|
</div>
|
|
480
508
|
</div>
|
|
481
509
|
|
|
482
510
|
<div className="mb-8">
|
|
483
|
-
<
|
|
511
|
+
<SectionLabel>Description</SectionLabel>
|
|
484
512
|
<input type="text" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="What does this agent do?" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
485
513
|
</div>
|
|
486
514
|
|
|
487
515
|
{/* Capabilities — hidden for OpenClaw (gateway manages its own capabilities) */}
|
|
488
516
|
{!openclawEnabled && <div className="mb-8">
|
|
489
|
-
<
|
|
490
|
-
Capabilities <span className="normal-case tracking-normal font-normal text-text-3">(for agent delegation)</span>
|
|
491
|
-
</label>
|
|
517
|
+
<SectionLabel>Capabilities <span className="normal-case tracking-normal font-normal text-text-3">(for agent delegation)</span></SectionLabel>
|
|
492
518
|
<div className="flex flex-wrap gap-1.5 mb-2">
|
|
493
519
|
{capabilities.map((cap) => (
|
|
494
520
|
<span
|
|
@@ -568,6 +594,24 @@ export function AgentSheet() {
|
|
|
568
594
|
<p className="text-[11px] text-text-3/70 mt-1.5">Controls reasoning depth. Anthropic models use extended thinking; OpenAI o-series uses reasoning_effort. Others get system prompt guidance.</p>
|
|
569
595
|
</div>
|
|
570
596
|
|
|
597
|
+
{/* ElevenLabs Voice ID */}
|
|
598
|
+
{appSettings.elevenLabsEnabled && (
|
|
599
|
+
<div className="mb-8">
|
|
600
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
601
|
+
ElevenLabs Voice ID <span className="normal-case tracking-normal font-normal text-text-3">(optional)</span>
|
|
602
|
+
</label>
|
|
603
|
+
<input
|
|
604
|
+
type="text"
|
|
605
|
+
value={voiceId}
|
|
606
|
+
onChange={(e) => setVoiceId(e.target.value)}
|
|
607
|
+
placeholder="Leave blank for global default"
|
|
608
|
+
className={inputClass}
|
|
609
|
+
style={{ fontFamily: 'inherit' }}
|
|
610
|
+
/>
|
|
611
|
+
<p className="text-[11px] text-text-3/70 mt-1.5">Override the default voice for this agent. Leave blank to use the global default.</p>
|
|
612
|
+
</div>
|
|
613
|
+
)}
|
|
614
|
+
|
|
571
615
|
{/* Heartbeat Configuration */}
|
|
572
616
|
<div className="mb-8">
|
|
573
617
|
<div className="flex items-center justify-between mb-3">
|
|
@@ -624,11 +668,45 @@ export function AgentSheet() {
|
|
|
624
668
|
|
|
625
669
|
{provider !== 'openclaw' && (
|
|
626
670
|
<div className="mb-8">
|
|
627
|
-
<label className="
|
|
671
|
+
<label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
628
672
|
Soul / Personality <span className="normal-case tracking-normal font-normal text-text-3">(optional)</span>
|
|
673
|
+
{soul !== soulInitial && soulSaveState === 'idle' && (
|
|
674
|
+
<span className="inline-flex items-center gap-1 normal-case tracking-normal text-[10px] text-amber-400 font-600">
|
|
675
|
+
<span className="w-1.5 h-1.5 rounded-full bg-amber-400" />
|
|
676
|
+
Unsaved
|
|
677
|
+
</span>
|
|
678
|
+
)}
|
|
679
|
+
{soulSaveState === 'saved' && (
|
|
680
|
+
<span className="inline-flex items-center gap-1 normal-case tracking-normal text-[10px] text-emerald-400 font-600">
|
|
681
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><polyline points="20 6 9 17 4 12" /></svg>
|
|
682
|
+
Saved
|
|
683
|
+
</span>
|
|
684
|
+
)}
|
|
629
685
|
</label>
|
|
630
686
|
<div className="flex items-center gap-2 mb-3">
|
|
631
687
|
<p className="text-[12px] text-text-3/60">Define the agent's voice, tone, and personality. Injected before the system prompt.</p>
|
|
688
|
+
<button
|
|
689
|
+
type="button"
|
|
690
|
+
onClick={() => setSoul(randomSoul())}
|
|
691
|
+
className="inline-flex items-center gap-1.5 shrink-0 px-2 py-1 rounded-[8px] border border-white/[0.08] bg-transparent text-[11px] text-text-3 hover:text-text-2 cursor-pointer transition-colors"
|
|
692
|
+
style={{ fontFamily: 'inherit' }}
|
|
693
|
+
title="Randomize personality"
|
|
694
|
+
>
|
|
695
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
696
|
+
<rect x="4" y="4" width="16" height="16" rx="2" />
|
|
697
|
+
<circle cx="9" cy="9" r="1" fill="currentColor" />
|
|
698
|
+
<circle cx="15" cy="15" r="1" fill="currentColor" />
|
|
699
|
+
</svg>
|
|
700
|
+
Shuffle
|
|
701
|
+
</button>
|
|
702
|
+
<button
|
|
703
|
+
type="button"
|
|
704
|
+
onClick={() => setSoulLibraryOpen(true)}
|
|
705
|
+
className="shrink-0 px-2 py-1 rounded-[8px] border border-accent-bright/20 bg-accent-soft text-[11px] text-accent-bright hover:brightness-110 cursor-pointer transition-colors"
|
|
706
|
+
style={{ fontFamily: 'inherit' }}
|
|
707
|
+
>
|
|
708
|
+
Browse Library
|
|
709
|
+
</button>
|
|
632
710
|
<button onClick={() => soulFileRef.current?.click()} className="shrink-0 px-2 py-1 rounded-[8px] border border-white/[0.08] bg-surface text-[11px] text-text-3 hover:text-text-2 cursor-pointer transition-colors" style={{ fontFamily: 'inherit' }}>Upload .md</button>
|
|
633
711
|
<input ref={soulFileRef} type="file" accept=".md,.txt,.markdown" onChange={handleFileUpload(setSoul)} className="hidden" />
|
|
634
712
|
</div>
|
|
@@ -854,7 +932,7 @@ export function AgentSheet() {
|
|
|
854
932
|
)}
|
|
855
933
|
|
|
856
934
|
{!openclawEnabled && <div className="mb-8">
|
|
857
|
-
<
|
|
935
|
+
<SectionLabel>Provider</SectionLabel>
|
|
858
936
|
<div className="grid grid-cols-3 gap-3">
|
|
859
937
|
{providers.filter((p) => !isOrchestrator || p.id !== 'claude-cli').map((p) => {
|
|
860
938
|
const isConnected = !p.requiresApiKey || Object.values(credentials).some((c) => c.provider === p.id)
|
|
@@ -883,7 +961,7 @@ export function AgentSheet() {
|
|
|
883
961
|
|
|
884
962
|
{!openclawEnabled && currentProvider && currentProvider.models.length > 0 && (
|
|
885
963
|
<div className="mb-8">
|
|
886
|
-
<
|
|
964
|
+
<SectionLabel>Model</SectionLabel>
|
|
887
965
|
<ModelCombobox
|
|
888
966
|
providerId={currentProvider.id}
|
|
889
967
|
value={model}
|
|
@@ -900,7 +978,7 @@ export function AgentSheet() {
|
|
|
900
978
|
{/* Ollama Mode Toggle */}
|
|
901
979
|
{!openclawEnabled && provider === 'ollama' && (
|
|
902
980
|
<div className="mb-8">
|
|
903
|
-
<
|
|
981
|
+
<SectionLabel>Mode</SectionLabel>
|
|
904
982
|
<div className="flex p-1 rounded-[14px] bg-surface border border-white/[0.06]">
|
|
905
983
|
{(['local', 'cloud'] as const).map((mode) => (
|
|
906
984
|
<button
|
|
@@ -931,9 +1009,7 @@ export function AgentSheet() {
|
|
|
931
1009
|
|
|
932
1010
|
{!openclawEnabled && (currentProvider?.requiresApiKey || currentProvider?.optionalApiKey || (provider === 'ollama' && ollamaMode === 'cloud')) && (
|
|
933
1011
|
<div className="mb-8">
|
|
934
|
-
<
|
|
935
|
-
API Key{currentProvider?.optionalApiKey && !currentProvider?.requiresApiKey && <span className="normal-case tracking-normal font-normal text-text-3"> (optional)</span>}
|
|
936
|
-
</label>
|
|
1012
|
+
<SectionLabel>API Key{currentProvider?.optionalApiKey && !currentProvider?.requiresApiKey && <span className="normal-case tracking-normal font-normal text-text-3"> (optional)</span>}</SectionLabel>
|
|
937
1013
|
{providerCredentials.length > 0 && !addingKey ? (
|
|
938
1014
|
<div className="flex gap-2">
|
|
939
1015
|
<select value={credentialId || ''} onChange={(e) => {
|
|
@@ -1037,9 +1113,7 @@ export function AgentSheet() {
|
|
|
1037
1113
|
|
|
1038
1114
|
{currentProvider?.requiresEndpoint && (provider === 'openclaw' || (provider === 'ollama' && ollamaMode === 'local')) && (
|
|
1039
1115
|
<div className="mb-8">
|
|
1040
|
-
<
|
|
1041
|
-
{provider === 'openclaw' ? 'OpenClaw Endpoint' : 'Endpoint'}
|
|
1042
|
-
</label>
|
|
1116
|
+
<SectionLabel>{provider === 'openclaw' ? 'OpenClaw Endpoint' : 'Endpoint'}</SectionLabel>
|
|
1043
1117
|
<input type="text" value={apiEndpoint || ''} onChange={(e) => setApiEndpoint(e.target.value || null)} placeholder={currentProvider.defaultEndpoint || 'http://localhost:11434'} className={`${inputClass} font-mono text-[14px]`} />
|
|
1044
1118
|
{provider === 'openclaw' && (
|
|
1045
1119
|
<p className="text-[13px] text-text-3/70 mt-2">The URL of your OpenClaw gateway</p>
|
|
@@ -1058,7 +1132,7 @@ export function AgentSheet() {
|
|
|
1058
1132
|
<div
|
|
1059
1133
|
onClick={() => setTools((prev) => prev.includes(t.id) ? prev.filter((x) => x !== t.id) : [...prev, t.id])}
|
|
1060
1134
|
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer shrink-0
|
|
1061
|
-
${tools.includes(t.id) ? 'bg-
|
|
1135
|
+
${tools.includes(t.id) ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
1062
1136
|
>
|
|
1063
1137
|
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1064
1138
|
${tools.includes(t.id) ? 'left-[22px]' : 'left-0.5'}`} />
|
|
@@ -1082,7 +1156,7 @@ export function AgentSheet() {
|
|
|
1082
1156
|
<div
|
|
1083
1157
|
onClick={() => setTools((prev) => prev.includes(t.id) ? prev.filter((x) => x !== t.id) : [...prev, t.id])}
|
|
1084
1158
|
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer shrink-0
|
|
1085
|
-
${tools.includes(t.id) ? 'bg-
|
|
1159
|
+
${tools.includes(t.id) ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
1086
1160
|
>
|
|
1087
1161
|
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1088
1162
|
${tools.includes(t.id) ? 'left-[22px]' : 'left-0.5'}`} />
|
|
@@ -1092,22 +1166,6 @@ export function AgentSheet() {
|
|
|
1092
1166
|
</label>
|
|
1093
1167
|
))}
|
|
1094
1168
|
</div>
|
|
1095
|
-
{(tools.includes('manage_tasks') || tools.includes('manage_schedules')) && (
|
|
1096
|
-
<div className="mt-4 ml-1 pt-3 border-t border-white/[0.04]">
|
|
1097
|
-
<label className="flex items-center gap-3 cursor-pointer">
|
|
1098
|
-
<div
|
|
1099
|
-
onClick={() => setPlatformAssignScope((prev) => prev === 'all' ? 'self' : 'all')}
|
|
1100
|
-
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer shrink-0
|
|
1101
|
-
${platformAssignScope === 'all' ? 'bg-[#6366F1]' : 'bg-white/[0.08]'}`}
|
|
1102
|
-
>
|
|
1103
|
-
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1104
|
-
${platformAssignScope === 'all' ? 'left-[22px]' : 'left-0.5'}`} />
|
|
1105
|
-
</div>
|
|
1106
|
-
<span className="font-display text-[14px] font-600 text-text-2">Assign to Other Agents</span>
|
|
1107
|
-
<span className="text-[12px] text-text-3">Allow this agent to assign tasks and schedules to other agents</span>
|
|
1108
|
-
</label>
|
|
1109
|
-
</div>
|
|
1110
|
-
)}
|
|
1111
1169
|
</div>
|
|
1112
1170
|
)}
|
|
1113
1171
|
|
|
@@ -1259,7 +1317,7 @@ export function AgentSheet() {
|
|
|
1259
1317
|
enabled ? [...prev, fullName] : prev.filter((x) => x !== fullName)
|
|
1260
1318
|
)}
|
|
1261
1319
|
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer shrink-0
|
|
1262
|
-
${enabled ? 'bg-
|
|
1320
|
+
${enabled ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
1263
1321
|
>
|
|
1264
1322
|
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1265
1323
|
${enabled ? 'left-[22px]' : 'left-0.5'}`} />
|
|
@@ -1287,35 +1345,25 @@ export function AgentSheet() {
|
|
|
1287
1345
|
if (next && provider === 'claude-cli') setProvider('anthropic')
|
|
1288
1346
|
}}
|
|
1289
1347
|
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer
|
|
1290
|
-
${isOrchestrator ? 'bg-
|
|
1348
|
+
${isOrchestrator ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
1291
1349
|
>
|
|
1292
1350
|
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1293
1351
|
${isOrchestrator ? 'left-[22px]' : 'left-0.5'}`} />
|
|
1294
1352
|
</div>
|
|
1295
|
-
<span className="font-display text-[14px] font-600 text-text-2">
|
|
1296
|
-
<span className="text-[12px] text-text-3">
|
|
1353
|
+
<span className="font-display text-[14px] font-600 text-text-2">Can Delegate to Other Agents</span>
|
|
1354
|
+
<span className="text-[12px] text-text-3">Route work to specialized agents and coordinate multi-agent tasks</span>
|
|
1297
1355
|
</label>
|
|
1298
1356
|
</div>
|
|
1299
1357
|
)}
|
|
1300
1358
|
|
|
1301
1359
|
{provider !== 'openclaw' && isOrchestrator && agentOptions.length > 0 && (
|
|
1302
1360
|
<div className="mb-8">
|
|
1303
|
-
<
|
|
1304
|
-
<
|
|
1305
|
-
{agentOptions
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
className={`px-3 py-2 rounded-[10px] text-[13px] font-600 cursor-pointer transition-all border
|
|
1310
|
-
${subAgentIds.includes(a.id)
|
|
1311
|
-
? 'bg-accent-soft border-accent-bright/25 text-accent-bright'
|
|
1312
|
-
: 'bg-surface border-white/[0.06] text-text-3 hover:text-text-2'}`}
|
|
1313
|
-
style={{ fontFamily: 'inherit' }}
|
|
1314
|
-
>
|
|
1315
|
-
{a.name}
|
|
1316
|
-
</button>
|
|
1317
|
-
))}
|
|
1318
|
-
</div>
|
|
1361
|
+
<SectionLabel>Available Agents</SectionLabel>
|
|
1362
|
+
<AgentPickerList
|
|
1363
|
+
agents={agentOptions}
|
|
1364
|
+
selected={subAgentIds}
|
|
1365
|
+
onSelect={(id) => toggleAgent(id)}
|
|
1366
|
+
/>
|
|
1319
1367
|
</div>
|
|
1320
1368
|
)}
|
|
1321
1369
|
|
|
@@ -1366,7 +1414,7 @@ export function AgentSheet() {
|
|
|
1366
1414
|
onClick={handleTestAndSave}
|
|
1367
1415
|
disabled={!name.trim() || providerNeedsKey || testStatus === 'testing' || saving || (!openclawEnabled && testStatus === 'pass')}
|
|
1368
1416
|
className={`flex-1 py-3.5 rounded-[14px] border-none text-white text-[15px] font-600 cursor-pointer active:scale-[0.97] disabled:opacity-60 transition-all hover:brightness-110
|
|
1369
|
-
${testStatus === 'pass' ? 'bg-emerald-600 shadow-[0_4px_20px_rgba(16,185,129,0.25)]' : 'bg-
|
|
1417
|
+
${testStatus === 'pass' ? 'bg-emerald-600 shadow-[0_4px_20px_rgba(16,185,129,0.25)]' : 'bg-accent-bright shadow-[0_4px_20px_rgba(99,102,241,0.25)]'}`}
|
|
1370
1418
|
style={{ fontFamily: 'inherit' }}
|
|
1371
1419
|
>
|
|
1372
1420
|
{openclawEnabled
|
|
@@ -1379,6 +1427,13 @@ export function AgentSheet() {
|
|
|
1379
1427
|
</button>
|
|
1380
1428
|
</div>
|
|
1381
1429
|
</BottomSheet>
|
|
1430
|
+
|
|
1431
|
+
<SoulLibraryPicker
|
|
1432
|
+
open={soulLibraryOpen}
|
|
1433
|
+
onClose={() => setSoulLibraryOpen(false)}
|
|
1434
|
+
onSelect={(s) => setSoul(s)}
|
|
1435
|
+
/>
|
|
1436
|
+
</>
|
|
1382
1437
|
)
|
|
1383
1438
|
}
|
|
1384
1439
|
|
|
@@ -12,6 +12,11 @@ import { CronJobForm } from './cron-job-form'
|
|
|
12
12
|
|
|
13
13
|
interface Props {
|
|
14
14
|
agent: Agent
|
|
15
|
+
onEditAgent?: () => void
|
|
16
|
+
onClearHistory?: () => void
|
|
17
|
+
onDeleteAgent?: () => void
|
|
18
|
+
onDeleteChat?: () => void
|
|
19
|
+
isMainChat?: boolean
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
type InspectorTab = 'overview' | 'files' | 'skills' | 'automations' | 'advanced'
|
|
@@ -24,7 +29,7 @@ const TABS: { id: InspectorTab; label: string; openclawOnly?: boolean }[] = [
|
|
|
24
29
|
{ id: 'advanced', label: 'Advanced' },
|
|
25
30
|
]
|
|
26
31
|
|
|
27
|
-
export function InspectorPanel({ agent }: Props) {
|
|
32
|
+
export function InspectorPanel({ agent, onEditAgent, onClearHistory, onDeleteAgent, onDeleteChat, isMainChat }: Props) {
|
|
28
33
|
const inspectorTab = useAppStore((s) => s.inspectorTab)
|
|
29
34
|
const setInspectorTab = useAppStore((s) => s.setInspectorTab)
|
|
30
35
|
const setInspectorOpen = useAppStore((s) => s.setInspectorOpen)
|
|
@@ -52,7 +57,7 @@ export function InspectorPanel({ agent }: Props) {
|
|
|
52
57
|
const agentSchedules = Object.values(schedules).filter((s) => s.agentId === agent.id)
|
|
53
58
|
|
|
54
59
|
return (
|
|
55
|
-
<div className="w-[400px] shrink-0 border-l border-white/[0.06] bg-
|
|
60
|
+
<div className="w-[400px] shrink-0 border-l border-white/[0.06] bg-bg flex flex-col h-full overflow-hidden fade-up-delay">
|
|
56
61
|
{/* Header */}
|
|
57
62
|
<div className="flex items-center justify-between px-4 py-3 border-b border-white/[0.06] shrink-0">
|
|
58
63
|
<h3 className="font-display text-[14px] font-600 text-text truncate">{agent.name}</h3>
|
|
@@ -69,12 +74,14 @@ export function InspectorPanel({ agent }: Props) {
|
|
|
69
74
|
</div>
|
|
70
75
|
|
|
71
76
|
{/* Tab bar */}
|
|
72
|
-
<div className="flex gap-0.5 px-3 pt-2 pb-1 overflow-x-auto shrink-0">
|
|
77
|
+
<div className="flex gap-0.5 px-3 pt-2 pb-1 overflow-x-auto shrink-0" role="tablist">
|
|
73
78
|
{visibleTabs.map((tab) => (
|
|
74
79
|
<button
|
|
75
80
|
key={tab.id}
|
|
81
|
+
role="tab"
|
|
76
82
|
onClick={() => setInspectorTab(tab.id)}
|
|
77
|
-
|
|
83
|
+
aria-selected={inspectorTab === tab.id}
|
|
84
|
+
className={`px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 cursor-pointer transition-all whitespace-nowrap focus-visible:ring-1 focus-visible:ring-accent-bright/50
|
|
78
85
|
${inspectorTab === tab.id
|
|
79
86
|
? 'bg-accent-soft text-accent-bright'
|
|
80
87
|
: 'bg-transparent text-text-3 hover:text-text-2'}`}
|
|
@@ -88,7 +95,14 @@ export function InspectorPanel({ agent }: Props) {
|
|
|
88
95
|
{/* Tab content */}
|
|
89
96
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
90
97
|
{inspectorTab === 'overview' && (
|
|
91
|
-
<OverviewTab
|
|
98
|
+
<OverviewTab
|
|
99
|
+
agent={agent}
|
|
100
|
+
onEditAgent={onEditAgent}
|
|
101
|
+
onClearHistory={onClearHistory}
|
|
102
|
+
onDeleteAgent={onDeleteAgent}
|
|
103
|
+
onDeleteChat={onDeleteChat}
|
|
104
|
+
isMainChat={isMainChat}
|
|
105
|
+
/>
|
|
92
106
|
)}
|
|
93
107
|
{inspectorTab === 'files' && isOpenClaw && (
|
|
94
108
|
<AgentFilesEditor agentId={agent.id} />
|
|
@@ -117,7 +131,16 @@ export function InspectorPanel({ agent }: Props) {
|
|
|
117
131
|
)
|
|
118
132
|
}
|
|
119
133
|
|
|
120
|
-
|
|
134
|
+
interface OverviewTabProps {
|
|
135
|
+
agent: Agent
|
|
136
|
+
onEditAgent?: () => void
|
|
137
|
+
onClearHistory?: () => void
|
|
138
|
+
onDeleteAgent?: () => void
|
|
139
|
+
onDeleteChat?: () => void
|
|
140
|
+
isMainChat?: boolean
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function OverviewTab({ agent, onEditAgent, onClearHistory, onDeleteAgent, onDeleteChat, isMainChat }: OverviewTabProps) {
|
|
121
144
|
return (
|
|
122
145
|
<div className="p-4 flex flex-col gap-4">
|
|
123
146
|
<div>
|
|
@@ -160,6 +183,58 @@ function OverviewTab({ agent }: { agent: Agent }) {
|
|
|
160
183
|
</div>
|
|
161
184
|
</div>
|
|
162
185
|
)}
|
|
186
|
+
|
|
187
|
+
{/* Actions */}
|
|
188
|
+
{(onEditAgent || onClearHistory || onDeleteAgent || onDeleteChat) && (
|
|
189
|
+
<>
|
|
190
|
+
<div className="border-t border-white/[0.06] mt-2" />
|
|
191
|
+
<div className="flex flex-col gap-2">
|
|
192
|
+
{onEditAgent && (
|
|
193
|
+
<button
|
|
194
|
+
onClick={onEditAgent}
|
|
195
|
+
className="w-full px-3 py-2 rounded-[8px] text-[12px] font-600 text-accent-bright bg-accent-soft/50 border border-accent-bright/10 cursor-pointer transition-all hover:bg-accent-soft"
|
|
196
|
+
style={{ fontFamily: 'inherit' }}
|
|
197
|
+
>
|
|
198
|
+
Edit Agent
|
|
199
|
+
</button>
|
|
200
|
+
)}
|
|
201
|
+
{(onClearHistory || onDeleteAgent || onDeleteChat) && (
|
|
202
|
+
<>
|
|
203
|
+
<label className="block text-[11px] font-600 uppercase tracking-wider text-red-400/50 mt-2">Danger Zone</label>
|
|
204
|
+
<div className="flex flex-col gap-1.5">
|
|
205
|
+
{onClearHistory && (
|
|
206
|
+
<button
|
|
207
|
+
onClick={onClearHistory}
|
|
208
|
+
className="w-full px-3 py-2 rounded-[8px] text-[12px] font-600 text-red-400/80 bg-red-400/[0.04] border border-red-400/[0.08] cursor-pointer transition-all hover:bg-red-400/[0.08] hover:text-red-400 text-left"
|
|
209
|
+
style={{ fontFamily: 'inherit' }}
|
|
210
|
+
>
|
|
211
|
+
Clear History
|
|
212
|
+
</button>
|
|
213
|
+
)}
|
|
214
|
+
{onDeleteAgent && !isMainChat && (
|
|
215
|
+
<button
|
|
216
|
+
onClick={onDeleteAgent}
|
|
217
|
+
className="w-full px-3 py-2 rounded-[8px] text-[12px] font-600 text-red-400/80 bg-red-400/[0.04] border border-red-400/[0.08] cursor-pointer transition-all hover:bg-red-400/[0.08] hover:text-red-400 text-left"
|
|
218
|
+
style={{ fontFamily: 'inherit' }}
|
|
219
|
+
>
|
|
220
|
+
Delete Agent
|
|
221
|
+
</button>
|
|
222
|
+
)}
|
|
223
|
+
{onDeleteChat && !isMainChat && (
|
|
224
|
+
<button
|
|
225
|
+
onClick={onDeleteChat}
|
|
226
|
+
className="w-full px-3 py-2 rounded-[8px] text-[12px] font-600 text-red-400/80 bg-red-400/[0.04] border border-red-400/[0.08] cursor-pointer transition-all hover:bg-red-400/[0.08] hover:text-red-400 text-left"
|
|
227
|
+
style={{ fontFamily: 'inherit' }}
|
|
228
|
+
>
|
|
229
|
+
Delete Chat
|
|
230
|
+
</button>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
</>
|
|
234
|
+
)}
|
|
235
|
+
</div>
|
|
236
|
+
</>
|
|
237
|
+
)}
|
|
163
238
|
</div>
|
|
164
239
|
)
|
|
165
240
|
}
|
|
@@ -23,6 +23,7 @@ export function OpenClawSkillsPanel({ agentId, initialMode = 'all', initialAllow
|
|
|
23
23
|
const [saving, setSaving] = useState(false)
|
|
24
24
|
const [installTarget, setInstallTarget] = useState<OpenClawSkillEntry | null>(null)
|
|
25
25
|
const [removeTarget, setRemoveTarget] = useState<OpenClawSkillEntry | null>(null)
|
|
26
|
+
const [readinessFilter, setReadinessFilter] = useState<'all' | 'ready' | 'needs-setup'>('all')
|
|
26
27
|
|
|
27
28
|
const loadSkills = useCallback(async () => {
|
|
28
29
|
setLoading(true)
|
|
@@ -67,15 +68,24 @@ export function OpenClawSkillsPanel({ agentId, initialMode = 'all', initialAllow
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
const readyCount = skills.filter((s) => s.eligible).length
|
|
72
|
+
const needsSetupCount = skills.filter((s) => !s.eligible).length
|
|
73
|
+
|
|
74
|
+
const filteredSkills = readinessFilter === 'all'
|
|
75
|
+
? skills
|
|
76
|
+
: readinessFilter === 'ready'
|
|
77
|
+
? skills.filter((s) => s.eligible)
|
|
78
|
+
: skills.filter((s) => !s.eligible)
|
|
79
|
+
|
|
70
80
|
const grouped = SOURCE_ORDER
|
|
71
81
|
.map((source) => ({
|
|
72
82
|
source,
|
|
73
|
-
items:
|
|
83
|
+
items: filteredSkills.filter((s) => s.source === source),
|
|
74
84
|
}))
|
|
75
85
|
.filter((g) => g.items.length > 0)
|
|
76
86
|
|
|
77
87
|
if (loading) {
|
|
78
|
-
return <div className="flex items-center justify-center h-32 text-[13px] text-text-3/50"
|
|
88
|
+
return <div className="flex items-center justify-center gap-2 h-32 text-[13px] text-text-3/50"><span className="w-3 h-3 rounded-full border-2 border-text-3/20 border-t-accent-bright animate-spin" />Loading skills...</div>
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
if (error) {
|
|
@@ -90,7 +100,7 @@ export function OpenClawSkillsPanel({ agentId, initialMode = 'all', initialAllow
|
|
|
90
100
|
<button
|
|
91
101
|
key={m}
|
|
92
102
|
onClick={() => handleModeChange(m)}
|
|
93
|
-
className={`px-3 py-1.5 rounded-[8px] text-[11px] font-600 capitalize cursor-pointer transition-all
|
|
103
|
+
className={`px-3 py-1.5 rounded-[8px] text-[11px] font-600 capitalize cursor-pointer transition-all focus-visible:ring-1 focus-visible:ring-accent-bright/50
|
|
94
104
|
${mode === m ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'}`}
|
|
95
105
|
style={{ fontFamily: 'inherit' }}
|
|
96
106
|
>
|
|
@@ -99,6 +109,25 @@ export function OpenClawSkillsPanel({ agentId, initialMode = 'all', initialAllow
|
|
|
99
109
|
))}
|
|
100
110
|
</div>
|
|
101
111
|
|
|
112
|
+
{/* Readiness filter */}
|
|
113
|
+
<div className="flex gap-1">
|
|
114
|
+
{([
|
|
115
|
+
{ key: 'all' as const, label: `All (${skills.length})` },
|
|
116
|
+
{ key: 'ready' as const, label: `Ready (${readyCount})` },
|
|
117
|
+
{ key: 'needs-setup' as const, label: `Needs Setup (${needsSetupCount})` },
|
|
118
|
+
]).map((f) => (
|
|
119
|
+
<button
|
|
120
|
+
key={f.key}
|
|
121
|
+
onClick={() => setReadinessFilter(f.key)}
|
|
122
|
+
className={`px-3 py-1.5 rounded-[8px] text-[11px] font-600 cursor-pointer transition-all focus-visible:ring-1 focus-visible:ring-accent-bright/50
|
|
123
|
+
${readinessFilter === f.key ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'}`}
|
|
124
|
+
style={{ fontFamily: 'inherit' }}
|
|
125
|
+
>
|
|
126
|
+
{f.label}
|
|
127
|
+
</button>
|
|
128
|
+
))}
|
|
129
|
+
</div>
|
|
130
|
+
|
|
102
131
|
{/* Skill groups */}
|
|
103
132
|
{grouped.map(({ source, items }) => (
|
|
104
133
|
<div key={source}>
|