@swarmclawai/swarmclaw 0.3.1 → 0.4.5
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 +33 -13
- package/bin/server-cmd.js +14 -7
- package/bin/swarmclaw.js +3 -1
- package/bin/update-cmd.js +120 -0
- package/next.config.ts +10 -0
- package/package.json +4 -1
- package/src/app/api/agents/[id]/route.ts +20 -18
- package/src/app/api/agents/[id]/thread/route.ts +4 -3
- package/src/app/api/agents/route.ts +8 -3
- package/src/app/api/auth/route.ts +3 -1
- package/src/app/api/claude-skills/route.ts +3 -1
- package/src/app/api/clawhub/install/route.ts +2 -2
- package/src/app/api/connectors/[id]/route.ts +14 -3
- package/src/app/api/connectors/[id]/webhook/route.ts +99 -0
- package/src/app/api/connectors/route.ts +12 -4
- package/src/app/api/credentials/[id]/route.ts +2 -1
- package/src/app/api/credentials/route.ts +5 -3
- package/src/app/api/daemon/route.ts +6 -1
- package/src/app/api/documents/route.ts +2 -2
- package/src/app/api/files/serve/route.ts +8 -0
- package/src/app/api/ip/route.ts +3 -1
- package/src/app/api/knowledge/[id]/route.ts +5 -4
- package/src/app/api/knowledge/upload/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/route.ts +11 -14
- package/src/app/api/mcp-servers/[id]/test/route.ts +2 -1
- package/src/app/api/mcp-servers/[id]/tools/route.ts +2 -1
- package/src/app/api/mcp-servers/route.ts +5 -3
- package/src/app/api/memory/[id]/route.ts +9 -8
- package/src/app/api/memory/route.ts +2 -2
- package/src/app/api/memory-images/[filename]/route.ts +2 -1
- package/src/app/api/openclaw/directory/route.ts +26 -0
- package/src/app/api/openclaw/discover/route.ts +61 -0
- package/src/app/api/openclaw/sync/route.ts +30 -0
- package/src/app/api/orchestrator/graph/route.ts +25 -0
- package/src/app/api/orchestrator/run/route.ts +2 -2
- package/src/app/api/plugins/marketplace/route.ts +3 -1
- package/src/app/api/plugins/route.ts +3 -1
- package/src/app/api/projects/[id]/route.ts +55 -0
- package/src/app/api/projects/route.ts +27 -0
- package/src/app/api/providers/[id]/models/route.ts +2 -1
- package/src/app/api/providers/[id]/route.ts +13 -12
- package/src/app/api/providers/configs/route.ts +3 -1
- package/src/app/api/providers/route.ts +7 -3
- package/src/app/api/schedules/[id]/route.ts +16 -15
- package/src/app/api/schedules/[id]/run/route.ts +4 -3
- package/src/app/api/schedules/route.ts +8 -3
- package/src/app/api/secrets/[id]/route.ts +16 -17
- package/src/app/api/secrets/route.ts +5 -3
- package/src/app/api/sessions/[id]/chat/route.ts +5 -2
- package/src/app/api/sessions/[id]/clear/route.ts +2 -1
- package/src/app/api/sessions/[id]/deploy/route.ts +2 -1
- package/src/app/api/sessions/[id]/devserver/route.ts +2 -1
- package/src/app/api/sessions/[id]/messages/route.ts +2 -1
- package/src/app/api/sessions/[id]/retry/route.ts +2 -1
- package/src/app/api/sessions/[id]/route.ts +2 -1
- package/src/app/api/sessions/route.ts +11 -4
- package/src/app/api/settings/route.ts +3 -1
- package/src/app/api/setup/doctor/route.ts +1 -0
- package/src/app/api/setup/openclaw-device/route.ts +3 -1
- package/src/app/api/skills/[id]/route.ts +23 -21
- package/src/app/api/skills/import/route.ts +2 -2
- package/src/app/api/skills/route.ts +5 -3
- package/src/app/api/tasks/[id]/approve/route.ts +74 -0
- package/src/app/api/tasks/[id]/route.ts +9 -5
- package/src/app/api/tasks/route.ts +5 -2
- package/src/app/api/tts/stream/route.ts +48 -0
- package/src/app/api/upload/route.ts +2 -2
- package/src/app/api/uploads/[filename]/route.ts +4 -1
- package/src/app/api/usage/route.ts +3 -1
- package/src/app/api/version/route.ts +3 -1
- package/src/app/api/webhooks/[id]/route.ts +31 -32
- package/src/app/api/webhooks/route.ts +5 -3
- package/src/app/icon.svg +58 -0
- package/src/app/page.tsx +11 -26
- package/src/cli/index.js +28 -9
- package/src/cli/index.ts +45 -2
- package/src/cli/spec.js +2 -8
- package/src/components/agents/agent-card.tsx +1 -1
- package/src/components/agents/agent-list.tsx +3 -1
- package/src/components/agents/agent-sheet.tsx +166 -81
- package/src/components/chat/chat-area.tsx +71 -34
- package/src/components/chat/chat-header.tsx +141 -29
- package/src/components/chat/chat-tool-toggles.tsx +12 -53
- package/src/components/chat/message-bubble.tsx +110 -42
- package/src/components/chat/tool-call-bubble.tsx +50 -6
- package/src/components/chat/tool-request-banner.tsx +1 -9
- package/src/components/chat/voice-overlay.tsx +80 -0
- package/src/components/connectors/connector-list.tsx +9 -10
- package/src/components/connectors/connector-sheet.tsx +55 -36
- package/src/components/input/chat-input.tsx +72 -56
- package/src/components/knowledge/knowledge-list.tsx +27 -31
- package/src/components/layout/app-layout.tsx +133 -90
- package/src/components/layout/daemon-indicator.tsx +3 -5
- package/src/components/logs/log-list.tsx +5 -9
- package/src/components/mcp-servers/mcp-server-list.tsx +24 -2
- package/src/components/memory/memory-detail.tsx +1 -1
- package/src/components/plugins/plugin-list.tsx +227 -27
- package/src/components/projects/project-list.tsx +122 -0
- package/src/components/projects/project-sheet.tsx +135 -0
- package/src/components/providers/provider-list.tsx +46 -13
- package/src/components/providers/provider-sheet.tsx +0 -45
- package/src/components/runs/run-list.tsx +6 -15
- package/src/components/schedules/schedule-card.tsx +54 -4
- package/src/components/schedules/schedule-list.tsx +9 -4
- package/src/components/schedules/schedule-sheet.tsx +0 -47
- package/src/components/secrets/secrets-list.tsx +20 -2
- package/src/components/sessions/new-session-sheet.tsx +14 -15
- package/src/components/sessions/session-card.tsx +1 -1
- package/src/components/sessions/session-list.tsx +7 -7
- package/src/components/shared/connector-platform-icon.tsx +26 -20
- package/src/components/shared/model-combobox.tsx +148 -0
- package/src/components/shared/settings/section-heartbeat.tsx +8 -40
- package/src/components/shared/settings/section-orchestrator.tsx +9 -11
- package/src/components/shared/settings/section-web-search.tsx +56 -0
- package/src/components/shared/settings/settings-page.tsx +73 -0
- package/src/components/skills/skill-list.tsx +262 -35
- package/src/components/skills/skill-sheet.tsx +0 -45
- package/src/components/tasks/task-board.tsx +3 -6
- package/src/components/tasks/task-card.tsx +43 -1
- package/src/components/tasks/task-list.tsx +8 -7
- package/src/components/tasks/task-sheet.tsx +0 -44
- package/src/components/usage/usage-list.tsx +12 -4
- package/src/hooks/use-continuous-speech.ts +144 -0
- package/src/hooks/use-view-router.ts +52 -0
- package/src/hooks/use-voice-conversation.ts +80 -0
- package/src/hooks/use-ws.ts +66 -0
- package/src/instrumentation.ts +2 -0
- package/src/lib/chat.ts +14 -2
- package/src/lib/id.ts +6 -0
- package/src/lib/projects.ts +13 -0
- package/src/lib/provider-sets.ts +5 -0
- package/src/lib/providers/anthropic.ts +15 -2
- package/src/lib/providers/index.ts +8 -0
- package/src/lib/providers/ollama.ts +10 -2
- package/src/lib/providers/openai.ts +42 -13
- package/src/lib/providers/openclaw.ts +11 -0
- package/src/lib/server/api-routes.test.ts +5 -6
- package/src/lib/server/build-llm.ts +17 -4
- package/src/lib/server/chat-execution.ts +57 -8
- package/src/lib/server/collection-helpers.ts +54 -0
- package/src/lib/server/connectors/bluebubbles.test.ts +208 -0
- package/src/lib/server/connectors/bluebubbles.ts +357 -0
- package/src/lib/server/connectors/connector-routing.test.ts +1 -1
- package/src/lib/server/connectors/googlechat.ts +46 -7
- package/src/lib/server/connectors/manager.ts +401 -6
- package/src/lib/server/connectors/media.ts +2 -2
- package/src/lib/server/connectors/openclaw.ts +64 -0
- package/src/lib/server/connectors/pairing.test.ts +99 -0
- package/src/lib/server/connectors/pairing.ts +256 -0
- package/src/lib/server/connectors/signal.ts +1 -0
- package/src/lib/server/connectors/teams.ts +5 -5
- package/src/lib/server/connectors/types.ts +10 -0
- package/src/lib/server/context-manager.ts +1 -1
- package/src/lib/server/daemon-state.ts +3 -0
- package/src/lib/server/data-dir.ts +1 -0
- package/src/lib/server/execution-log.ts +3 -3
- package/src/lib/server/heartbeat-service.ts +67 -3
- package/src/lib/server/knowledge-db.test.ts +2 -33
- package/src/lib/server/langgraph-checkpoint.ts +274 -0
- package/src/lib/server/main-agent-loop.ts +67 -8
- package/src/lib/server/memory-db.ts +6 -6
- package/src/lib/server/openclaw-approvals.ts +105 -0
- package/src/lib/server/openclaw-sync.ts +496 -0
- package/src/lib/server/orchestrator-lg.ts +422 -20
- package/src/lib/server/orchestrator.ts +29 -9
- package/src/lib/server/process-manager.ts +2 -2
- package/src/lib/server/queue.ts +39 -13
- package/src/lib/server/scheduler.ts +2 -2
- package/src/lib/server/session-mailbox.ts +2 -2
- package/src/lib/server/session-run-manager.ts +8 -3
- package/src/lib/server/session-tools/connector.ts +51 -4
- package/src/lib/server/session-tools/crud.ts +3 -3
- package/src/lib/server/session-tools/delegate.ts +5 -5
- package/src/lib/server/session-tools/file.ts +176 -3
- package/src/lib/server/session-tools/index.ts +4 -0
- package/src/lib/server/session-tools/memory.ts +2 -2
- package/src/lib/server/session-tools/openclaw-nodes.ts +112 -0
- package/src/lib/server/session-tools/sandbox.ts +197 -0
- package/src/lib/server/session-tools/search-providers.ts +270 -0
- package/src/lib/server/session-tools/session-info.ts +2 -2
- package/src/lib/server/session-tools/web.ts +47 -66
- package/src/lib/server/storage-mcp.test.ts +25 -2
- package/src/lib/server/storage.ts +36 -7
- package/src/lib/server/stream-agent-chat.ts +106 -22
- package/src/lib/server/task-result.test.ts +44 -0
- package/src/lib/server/task-result.ts +14 -0
- package/src/lib/server/task-validation.test.ts +23 -0
- package/src/lib/server/task-validation.ts +5 -3
- package/src/lib/server/ws-hub.ts +85 -0
- package/src/lib/tool-definitions.ts +44 -0
- package/src/lib/tts-stream.ts +130 -0
- package/src/lib/upload.ts +7 -1
- package/src/lib/view-routes.ts +28 -0
- package/src/lib/ws-client.ts +124 -0
- package/src/proxy.ts +3 -0
- package/src/stores/use-app-store.ts +28 -1
- package/src/stores/use-chat-store.ts +42 -14
- package/src/types/index.ts +34 -2
- package/src/app/api/agents/generate/route.ts +0 -42
- package/src/app/api/generate/info/route.ts +0 -12
- package/src/app/api/generate/route.ts +0 -106
- package/src/app/favicon.ico +0 -0
- package/src/components/shared/ai-gen-block.tsx +0 -77
|
@@ -6,9 +6,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u
|
|
|
6
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
7
7
|
import { useMediaQuery } from '@/hooks/use-media-query'
|
|
8
8
|
import { Avatar } from '@/components/shared/avatar'
|
|
9
|
-
import {
|
|
10
|
-
import { NewSessionSheet } from '@/components/sessions/new-session-sheet'
|
|
11
|
-
import { SettingsSheet } from '@/components/shared/settings-sheet'
|
|
9
|
+
import { SettingsPage } from '@/components/shared/settings/settings-page'
|
|
12
10
|
import { AgentList } from '@/components/agents/agent-list'
|
|
13
11
|
import { AgentChatList } from '@/components/agents/agent-chat-list'
|
|
14
12
|
import { AgentSheet } from '@/components/agents/agent-sheet'
|
|
@@ -39,6 +37,8 @@ import { PluginList } from '@/components/plugins/plugin-list'
|
|
|
39
37
|
import { PluginSheet } from '@/components/plugins/plugin-sheet'
|
|
40
38
|
import { UsageList } from '@/components/usage/usage-list'
|
|
41
39
|
import { RunList } from '@/components/runs/run-list'
|
|
40
|
+
import { ProjectList } from '@/components/projects/project-list'
|
|
41
|
+
import { ProjectSheet } from '@/components/projects/project-sheet'
|
|
42
42
|
import { NetworkBanner } from './network-banner'
|
|
43
43
|
import { UpdateBanner } from './update-banner'
|
|
44
44
|
import { MobileHeader } from './mobile-header'
|
|
@@ -55,8 +55,6 @@ export function AppLayout() {
|
|
|
55
55
|
const currentSessionId = useAppStore((s) => s.currentSessionId)
|
|
56
56
|
const sidebarOpen = useAppStore((s) => s.sidebarOpen)
|
|
57
57
|
const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
|
|
58
|
-
const setSettingsOpen = useAppStore((s) => s.setSettingsOpen)
|
|
59
|
-
const setNewSessionOpen = useAppStore((s) => s.setNewSessionOpen)
|
|
60
58
|
const setUser = useAppStore((s) => s.setUser)
|
|
61
59
|
const setCurrentSession = useAppStore((s) => s.setCurrentSession)
|
|
62
60
|
const activeView = useAppStore((s) => s.activeView)
|
|
@@ -72,8 +70,11 @@ export function AppLayout() {
|
|
|
72
70
|
const setMcpServerSheetOpen = useAppStore((s) => s.setMcpServerSheetOpen)
|
|
73
71
|
const setKnowledgeSheetOpen = useAppStore((s) => s.setKnowledgeSheetOpen)
|
|
74
72
|
const setPluginSheetOpen = useAppStore((s) => s.setPluginSheetOpen)
|
|
73
|
+
const setProjectSheetOpen = useAppStore((s) => s.setProjectSheetOpen)
|
|
74
|
+
const tasks = useAppStore((s) => s.tasks)
|
|
75
75
|
const isDesktop = useMediaQuery('(min-width: 768px)')
|
|
76
76
|
const hasSelectedSession = !!(currentSessionId && sessions[currentSessionId])
|
|
77
|
+
const pendingApprovalCount = Object.values(tasks).filter((t) => t.pendingApproval).length
|
|
77
78
|
|
|
78
79
|
const [agentViewMode, setAgentViewMode] = useState<'chat' | 'config'>('chat')
|
|
79
80
|
const [shortcutsOpen, setShortcutsOpen] = useState(false)
|
|
@@ -118,8 +119,7 @@ export function AppLayout() {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
const openNewSheet = () => {
|
|
121
|
-
if (activeView === '
|
|
122
|
-
else if (activeView === 'agents') setAgentSheetOpen(true)
|
|
122
|
+
if (activeView === 'agents') setAgentSheetOpen(true)
|
|
123
123
|
else if (activeView === 'schedules') setScheduleSheetOpen(true)
|
|
124
124
|
else if (activeView === 'tasks') setTaskSheetOpen(true)
|
|
125
125
|
else if (activeView === 'secrets') setSecretSheetOpen(true)
|
|
@@ -130,20 +130,29 @@ export function AppLayout() {
|
|
|
130
130
|
else if (activeView === 'mcp_servers') setMcpServerSheetOpen(true)
|
|
131
131
|
else if (activeView === 'knowledge') setKnowledgeSheetOpen(true)
|
|
132
132
|
else if (activeView === 'plugins') setPluginSheetOpen(true)
|
|
133
|
+
else if (activeView === 'projects') setProjectSheetOpen(true)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const handleNavClick = (view: AppView) => {
|
|
137
|
+
if (FULL_WIDTH_VIEWS.has(view)) {
|
|
138
|
+
setActiveView(view)
|
|
139
|
+
setSidebarOpen(false)
|
|
140
|
+
} else if (activeView === view && sidebarOpen) {
|
|
141
|
+
setSidebarOpen(false)
|
|
142
|
+
} else {
|
|
143
|
+
setActiveView(view)
|
|
144
|
+
setSidebarOpen(true)
|
|
145
|
+
}
|
|
133
146
|
}
|
|
134
147
|
|
|
135
148
|
const agents = useAppStore((s) => s.agents)
|
|
136
149
|
const currentAgentId = useAppStore((s) => s.currentAgentId)
|
|
137
150
|
const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
|
|
138
|
-
const mainSession = Object.values(sessions).find((s) => s.name === '__main__' && s.user === currentUser)
|
|
139
|
-
|
|
140
151
|
const goToMainChat = async () => {
|
|
141
152
|
// Navigate to default agent's chat thread
|
|
142
153
|
const defaultAgent = agents['default'] || Object.values(agents)[0]
|
|
143
154
|
if (defaultAgent) {
|
|
144
155
|
await setCurrentAgent(defaultAgent.id)
|
|
145
|
-
} else if (mainSession) {
|
|
146
|
-
setCurrentSession(mainSession.id)
|
|
147
156
|
}
|
|
148
157
|
setActiveView('agents')
|
|
149
158
|
setSidebarOpen(false)
|
|
@@ -230,82 +239,82 @@ export function AppLayout() {
|
|
|
230
239
|
|
|
231
240
|
{/* Nav items */}
|
|
232
241
|
<div className={`flex flex-col gap-0.5 ${railExpanded ? 'px-3' : 'items-center'}`}>
|
|
233
|
-
<NavItem view="agents" label="Agents" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
242
|
+
<NavItem view="agents" label="Agents" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('agents')}>
|
|
234
243
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
235
244
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" />
|
|
236
245
|
</svg>
|
|
237
246
|
</NavItem>
|
|
238
|
-
<NavItem view="
|
|
247
|
+
<NavItem view="projects" label="Projects" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('projects')}>
|
|
239
248
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
240
|
-
<
|
|
249
|
+
<path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7-7H4a2 2 0 0 0-2 2v17Z" /><path d="M14 2v7h7" />
|
|
241
250
|
</svg>
|
|
242
251
|
</NavItem>
|
|
243
|
-
<NavItem view="schedules" label="Schedules" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
252
|
+
<NavItem view="schedules" label="Schedules" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('schedules')}>
|
|
244
253
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
245
254
|
<circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" />
|
|
246
255
|
</svg>
|
|
247
256
|
</NavItem>
|
|
248
|
-
<NavItem view="memory" label="Memory" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
257
|
+
<NavItem view="memory" label="Memory" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('memory')}>
|
|
249
258
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
250
259
|
<ellipse cx="12" cy="5" rx="9" ry="3" /><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" /><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
|
|
251
260
|
</svg>
|
|
252
261
|
</NavItem>
|
|
253
|
-
<NavItem view="tasks" label="Tasks" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
262
|
+
<NavItem view="tasks" label="Tasks" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('tasks')} badge={pendingApprovalCount}>
|
|
254
263
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
255
264
|
<path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2" /><rect x="9" y="3" width="6" height="4" rx="1" /><path d="M9 14l2 2 4-4" />
|
|
256
265
|
</svg>
|
|
257
266
|
</NavItem>
|
|
258
|
-
<NavItem view="secrets" label="Secrets" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
267
|
+
<NavItem view="secrets" label="Secrets" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('secrets')}>
|
|
259
268
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
260
269
|
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
261
270
|
</svg>
|
|
262
271
|
</NavItem>
|
|
263
|
-
<NavItem view="providers" label="Providers" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
272
|
+
<NavItem view="providers" label="Providers" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('providers')}>
|
|
264
273
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
265
274
|
<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" />
|
|
266
275
|
</svg>
|
|
267
276
|
</NavItem>
|
|
268
|
-
<NavItem view="skills" label="Skills" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
277
|
+
<NavItem view="skills" label="Skills" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('skills')}>
|
|
269
278
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
270
279
|
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" /><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
|
|
271
280
|
</svg>
|
|
272
281
|
</NavItem>
|
|
273
|
-
<NavItem view="connectors" label="Connectors" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
282
|
+
<NavItem view="connectors" label="Connectors" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('connectors')}>
|
|
274
283
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
275
284
|
<path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3" /><line x1="8" y1="12" x2="16" y2="12" />
|
|
276
285
|
</svg>
|
|
277
286
|
</NavItem>
|
|
278
|
-
<NavItem view="webhooks" label="Webhooks" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
287
|
+
<NavItem view="webhooks" label="Webhooks" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('webhooks')}>
|
|
279
288
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
280
289
|
<path d="M22 12h-4l-3 7L9 5l-3 7H2" />
|
|
281
290
|
</svg>
|
|
282
291
|
</NavItem>
|
|
283
|
-
<NavItem view="mcp_servers" label="MCP" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
292
|
+
<NavItem view="mcp_servers" label="MCP" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('mcp_servers')}>
|
|
284
293
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
285
294
|
<rect x="2" y="2" width="20" height="8" rx="2" /><rect x="2" y="14" width="20" height="8" rx="2" /><line x1="6" y1="6" x2="6.01" y2="6" /><line x1="6" y1="18" x2="6.01" y2="18" />
|
|
286
295
|
</svg>
|
|
287
296
|
</NavItem>
|
|
288
|
-
<NavItem view="knowledge" label="Knowledge" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
297
|
+
<NavItem view="knowledge" label="Knowledge" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('knowledge')}>
|
|
289
298
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
290
299
|
<circle cx="12" cy="12" r="10" /><line x1="2" y1="12" x2="22" y2="12" /><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
|
291
300
|
</svg>
|
|
292
301
|
</NavItem>
|
|
293
|
-
<NavItem view="plugins" label="Plugins" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
302
|
+
<NavItem view="plugins" label="Plugins" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('plugins')}>
|
|
294
303
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
295
304
|
<path d="M12 2v4m0 12v4M2 12h4m12 0h4" /><circle cx="12" cy="12" r="4" /><path d="M8 8L5.5 5.5M16 8l2.5-2.5M8 16l-2.5 2.5M16 16l2.5 2.5" />
|
|
296
305
|
</svg>
|
|
297
306
|
</NavItem>
|
|
298
|
-
<NavItem view="usage" label="Usage" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
307
|
+
<NavItem view="usage" label="Usage" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('usage')}>
|
|
299
308
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
300
309
|
<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" />
|
|
301
310
|
</svg>
|
|
302
311
|
</NavItem>
|
|
303
|
-
<NavItem view="runs" label="Runs" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
312
|
+
<NavItem view="runs" label="Runs" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('runs')}>
|
|
304
313
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
305
314
|
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
|
|
306
315
|
</svg>
|
|
307
316
|
</NavItem>
|
|
308
|
-
<NavItem view="logs" label="Logs" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() =>
|
|
317
|
+
<NavItem view="logs" label="Logs" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('logs')}>
|
|
309
318
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
310
319
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
|
|
311
320
|
</svg>
|
|
@@ -350,7 +359,7 @@ export function AppLayout() {
|
|
|
350
359
|
{railExpanded && <DaemonIndicator />}
|
|
351
360
|
{railExpanded ? (
|
|
352
361
|
<button
|
|
353
|
-
onClick={() =>
|
|
362
|
+
onClick={() => handleNavClick('settings')}
|
|
354
363
|
className="w-full flex items-center gap-2.5 px-3 py-2 rounded-[10px] text-[13px] font-500 cursor-pointer transition-all
|
|
355
364
|
bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04] border-none"
|
|
356
365
|
style={{ fontFamily: 'inherit' }}
|
|
@@ -363,7 +372,7 @@ export function AppLayout() {
|
|
|
363
372
|
</button>
|
|
364
373
|
) : (
|
|
365
374
|
<RailTooltip label="Settings" description="API keys, providers & app config">
|
|
366
|
-
<button onClick={() =>
|
|
375
|
+
<button onClick={() => handleNavClick('settings')} className="rail-btn">
|
|
367
376
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
368
377
|
<circle cx="12" cy="12" r="3" />
|
|
369
378
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
@@ -400,7 +409,7 @@ export function AppLayout() {
|
|
|
400
409
|
style={{ animation: 'panel-in 0.2s cubic-bezier(0.16, 1, 0.3, 1)' }}
|
|
401
410
|
>
|
|
402
411
|
<div className="flex items-center px-5 pt-5 pb-3 shrink-0">
|
|
403
|
-
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] capitalize flex-1">{activeView
|
|
412
|
+
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] capitalize flex-1">{activeView}</h2>
|
|
404
413
|
{activeView === 'logs' || activeView === 'usage' || activeView === 'runs' ? null : activeView === 'memory' ? (
|
|
405
414
|
<button
|
|
406
415
|
onClick={() => useAppStore.getState().setMemorySheetOpen(true)}
|
|
@@ -422,17 +431,10 @@ export function AppLayout() {
|
|
|
422
431
|
<line x1="12" y1="5" x2="12" y2="19" />
|
|
423
432
|
<line x1="5" y1="12" x2="19" y2="12" />
|
|
424
433
|
</svg>
|
|
425
|
-
{activeView === '
|
|
434
|
+
{activeView === 'agents' ? 'Agent' : activeView === 'schedules' ? 'Schedule' : activeView === 'tasks' ? 'Task' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : 'New'}
|
|
426
435
|
</button>
|
|
427
436
|
)}
|
|
428
437
|
</div>
|
|
429
|
-
{activeView === 'sessions' && (
|
|
430
|
-
<>
|
|
431
|
-
<UpdateBanner />
|
|
432
|
-
<NetworkBanner />
|
|
433
|
-
<SessionList inSidebar onSelect={() => {}} />
|
|
434
|
-
</>
|
|
435
|
-
)}
|
|
436
438
|
{activeView === 'agents' && (
|
|
437
439
|
<>
|
|
438
440
|
<div className="flex gap-1 px-4 pb-2">
|
|
@@ -488,7 +490,7 @@ export function AppLayout() {
|
|
|
488
490
|
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" /><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
|
|
489
491
|
</svg>
|
|
490
492
|
</a>
|
|
491
|
-
<button onClick={() =>
|
|
493
|
+
<button onClick={() => handleNavClick('settings')} className="rail-btn">
|
|
492
494
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
493
495
|
<circle cx="12" cy="12" r="3" />
|
|
494
496
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
@@ -500,7 +502,7 @@ export function AppLayout() {
|
|
|
500
502
|
</div>
|
|
501
503
|
{/* View selector tabs */}
|
|
502
504
|
<div className="flex px-4 py-2 gap-1 shrink-0 flex-wrap">
|
|
503
|
-
{(['agents', '
|
|
505
|
+
{(['agents', 'schedules', 'memory', 'tasks', 'secrets', 'providers', 'skills', 'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins', 'usage', 'runs', 'logs'] as AppView[]).map((v) => (
|
|
504
506
|
<button
|
|
505
507
|
key={v}
|
|
506
508
|
onClick={() => setActiveView(v)}
|
|
@@ -514,7 +516,7 @@ export function AppLayout() {
|
|
|
514
516
|
</button>
|
|
515
517
|
))}
|
|
516
518
|
</div>
|
|
517
|
-
{activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && (
|
|
519
|
+
{activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && activeView !== 'settings' && (
|
|
518
520
|
<div className="px-4 py-2.5 shrink-0">
|
|
519
521
|
<button
|
|
520
522
|
onClick={() => {
|
|
@@ -526,17 +528,10 @@ export function AppLayout() {
|
|
|
526
528
|
shadow-[0_2px_12px_rgba(99,102,241,0.15)]"
|
|
527
529
|
style={{ fontFamily: 'inherit' }}
|
|
528
530
|
>
|
|
529
|
-
+ New {activeView === '
|
|
531
|
+
+ New {activeView === 'agents' ? 'Agent' : activeView === 'schedules' ? 'Schedule' : activeView === 'tasks' ? 'Task' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : activeView === 'projects' ? 'Project' : 'Entry'}
|
|
530
532
|
</button>
|
|
531
533
|
</div>
|
|
532
534
|
)}
|
|
533
|
-
{activeView === 'sessions' && (
|
|
534
|
-
<>
|
|
535
|
-
<UpdateBanner />
|
|
536
|
-
<NetworkBanner />
|
|
537
|
-
<SessionList inSidebar onSelect={() => setSidebarOpen(false)} />
|
|
538
|
-
</>
|
|
539
|
-
)}
|
|
540
535
|
{activeView === 'agents' && (
|
|
541
536
|
<>
|
|
542
537
|
<div className="flex gap-1 px-4 pb-2">
|
|
@@ -566,6 +561,7 @@ export function AppLayout() {
|
|
|
566
561
|
{activeView === 'mcp_servers' && <McpServerList />}
|
|
567
562
|
{activeView === 'knowledge' && <KnowledgeList />}
|
|
568
563
|
{activeView === 'plugins' && <PluginList inSidebar />}
|
|
564
|
+
{activeView === 'projects' && <ProjectList />}
|
|
569
565
|
{activeView === 'usage' && <UsageList />}
|
|
570
566
|
{activeView === 'runs' && <RunList />}
|
|
571
567
|
{activeView === 'logs' && <LogList />}
|
|
@@ -596,37 +592,51 @@ export function AppLayout() {
|
|
|
596
592
|
</div>
|
|
597
593
|
)}
|
|
598
594
|
</div>
|
|
599
|
-
) : activeView === 'sessions' && hasSelectedSession ? (
|
|
600
|
-
<ChatArea />
|
|
601
|
-
) : activeView === 'sessions' ? (
|
|
602
|
-
<div className="flex-1 flex flex-col">
|
|
603
|
-
{!isDesktop ? (
|
|
604
|
-
<SessionList />
|
|
605
|
-
) : (
|
|
606
|
-
<div className="flex-1 flex items-center justify-center px-8">
|
|
607
|
-
<div className="text-center max-w-[420px]">
|
|
608
|
-
<h2 className="font-display text-[24px] font-700 text-text mb-2 tracking-[-0.02em]">
|
|
609
|
-
No Chat Selected
|
|
610
|
-
</h2>
|
|
611
|
-
<p className="text-[14px] text-text-3">
|
|
612
|
-
Choose a session from the sidebar or switch to Agents view.
|
|
613
|
-
</p>
|
|
614
|
-
</div>
|
|
615
|
-
</div>
|
|
616
|
-
)}
|
|
617
|
-
</div>
|
|
618
595
|
) : activeView === 'tasks' && isDesktop ? (
|
|
619
596
|
<TaskBoard />
|
|
620
597
|
) : activeView === 'memory' ? (
|
|
621
598
|
<MemoryDetail />
|
|
599
|
+
) : activeView === 'settings' ? (
|
|
600
|
+
<SettingsPage />
|
|
601
|
+
) : !sidebarOpen && FULL_WIDTH_VIEWS.has(activeView) ? (
|
|
602
|
+
<div className="flex-1 flex flex-col h-full">
|
|
603
|
+
<div className="flex items-center px-6 pt-5 pb-3 shrink-0">
|
|
604
|
+
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] capitalize flex-1">
|
|
605
|
+
{activeView === 'mcp_servers' ? 'MCP Servers' : activeView.replace('_', ' ')}
|
|
606
|
+
</h2>
|
|
607
|
+
{activeView !== 'usage' && activeView !== 'runs' && activeView !== 'logs' && (
|
|
608
|
+
<button
|
|
609
|
+
onClick={openNewSheet}
|
|
610
|
+
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-[#6366F1]/15 transition-all cursor-pointer"
|
|
611
|
+
style={{ fontFamily: 'inherit' }}
|
|
612
|
+
>
|
|
613
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
614
|
+
<line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" />
|
|
615
|
+
</svg>
|
|
616
|
+
{activeView === 'schedules' ? 'Schedule' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : activeView === 'projects' ? 'Project' : 'New'}
|
|
617
|
+
</button>
|
|
618
|
+
)}
|
|
619
|
+
</div>
|
|
620
|
+
{activeView === 'schedules' && <ScheduleList />}
|
|
621
|
+
{activeView === 'secrets' && <SecretsList />}
|
|
622
|
+
{activeView === 'providers' && <ProviderList />}
|
|
623
|
+
{activeView === 'skills' && <SkillList />}
|
|
624
|
+
{activeView === 'connectors' && <ConnectorList />}
|
|
625
|
+
{activeView === 'webhooks' && <WebhookList />}
|
|
626
|
+
{activeView === 'mcp_servers' && <McpServerList />}
|
|
627
|
+
{activeView === 'knowledge' && <KnowledgeList />}
|
|
628
|
+
{activeView === 'plugins' && <PluginList />}
|
|
629
|
+
{activeView === 'projects' && <ProjectList />}
|
|
630
|
+
{activeView === 'usage' && <UsageList />}
|
|
631
|
+
{activeView === 'runs' && <RunList />}
|
|
632
|
+
{activeView === 'logs' && <LogList />}
|
|
633
|
+
</div>
|
|
622
634
|
) : (
|
|
623
635
|
<ViewEmptyState view={activeView} />
|
|
624
636
|
)}
|
|
625
637
|
</div>
|
|
626
638
|
</ErrorBoundary>
|
|
627
639
|
|
|
628
|
-
<NewSessionSheet />
|
|
629
|
-
<SettingsSheet />
|
|
630
640
|
<AgentSheet />
|
|
631
641
|
<ScheduleSheet />
|
|
632
642
|
<MemorySheet />
|
|
@@ -639,6 +649,7 @@ export function AppLayout() {
|
|
|
639
649
|
<McpServerSheet />
|
|
640
650
|
<KnowledgeSheet />
|
|
641
651
|
<PluginSheet />
|
|
652
|
+
<ProjectSheet />
|
|
642
653
|
|
|
643
654
|
<Dialog open={shortcutsOpen} onOpenChange={setShortcutsOpen}>
|
|
644
655
|
<DialogContent className="sm:max-w-[380px] bg-raised border-white/[0.08]">
|
|
@@ -718,7 +729,6 @@ class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boole
|
|
|
718
729
|
}
|
|
719
730
|
|
|
720
731
|
const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
721
|
-
sessions: 'Session history & debug view',
|
|
722
732
|
agents: 'Chat with & configure your AI agents',
|
|
723
733
|
schedules: 'Automated task schedules',
|
|
724
734
|
memory: 'Long-term agent memory store',
|
|
@@ -733,10 +743,18 @@ const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
733
743
|
logs: 'Application logs & error tracking',
|
|
734
744
|
plugins: 'Extend agent capabilities with custom plugins',
|
|
735
745
|
usage: 'Token usage analytics & cost tracking',
|
|
736
|
-
runs: 'Live
|
|
746
|
+
runs: 'Live run monitoring & history',
|
|
747
|
+
settings: 'Manage providers, API keys & orchestrator engine',
|
|
748
|
+
projects: 'Group agents, tasks & schedules into projects',
|
|
737
749
|
}
|
|
738
750
|
|
|
739
|
-
const
|
|
751
|
+
const FULL_WIDTH_VIEWS = new Set<AppView>([
|
|
752
|
+
'schedules', 'secrets', 'providers', 'skills',
|
|
753
|
+
'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins',
|
|
754
|
+
'usage', 'runs', 'logs', 'settings', 'projects',
|
|
755
|
+
])
|
|
756
|
+
|
|
757
|
+
const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; title: string; description: string; features: string[] }> = {
|
|
740
758
|
schedules: {
|
|
741
759
|
icon: 'clock',
|
|
742
760
|
title: 'Schedules',
|
|
@@ -746,14 +764,14 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'sessions' | 'agents'>, { icon:
|
|
|
746
764
|
memory: {
|
|
747
765
|
icon: 'database',
|
|
748
766
|
title: 'Memory',
|
|
749
|
-
description: 'Long-term memory store for AI agents. Orchestrators can store and retrieve knowledge across
|
|
750
|
-
features: ['Agents store findings and learnings automatically', 'Full-text search across all stored memories', 'Organized by categories and agents', 'Persists across
|
|
767
|
+
description: 'Long-term memory store for AI agents. Orchestrators can store and retrieve knowledge across conversations.',
|
|
768
|
+
features: ['Agents store findings and learnings automatically', 'Full-text search across all stored memories', 'Organized by categories and agents', 'Persists across conversations for continuity'],
|
|
751
769
|
},
|
|
752
770
|
tasks: {
|
|
753
771
|
icon: 'clipboard',
|
|
754
772
|
title: 'Task Board',
|
|
755
773
|
description: 'A Trello-style board for managing orchestrator jobs. Create tasks, assign them to orchestrators, and track progress.',
|
|
756
|
-
features: ['Kanban columns: Backlog, Queued, Running, Completed, Failed', 'Assign tasks to specific orchestrator agents', 'Sequential queue ensures orchestrators don\'t conflict', 'View results and
|
|
774
|
+
features: ['Kanban columns: Backlog, Queued, Running, Completed, Failed', 'Assign tasks to specific orchestrator agents', 'Sequential queue ensures orchestrators don\'t conflict', 'View results and logs for completed tasks'],
|
|
757
775
|
},
|
|
758
776
|
secrets: {
|
|
759
777
|
icon: 'lock',
|
|
@@ -777,7 +795,7 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'sessions' | 'agents'>, { icon:
|
|
|
777
795
|
icon: 'link',
|
|
778
796
|
title: 'Connectors',
|
|
779
797
|
description: 'Bridge chat platforms to your AI agents. Receive messages from Discord, Telegram, Slack, or WhatsApp and route them to agents.',
|
|
780
|
-
features: ['Connect Discord, Telegram, Slack, or WhatsApp bots', 'Route incoming messages to any agent', 'Each platform channel gets its own
|
|
798
|
+
features: ['Connect Discord, Telegram, Slack, or WhatsApp bots', 'Route incoming messages to any agent', 'Each platform channel gets its own chat thread', 'Start and stop connectors from the UI'],
|
|
781
799
|
},
|
|
782
800
|
webhooks: {
|
|
783
801
|
icon: 'webhook',
|
|
@@ -788,7 +806,7 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'sessions' | 'agents'>, { icon:
|
|
|
788
806
|
mcp_servers: {
|
|
789
807
|
icon: 'server',
|
|
790
808
|
title: 'MCP Servers',
|
|
791
|
-
description: 'Connect agents to external MCP (Model Context Protocol) servers, injecting their tools into
|
|
809
|
+
description: 'Connect agents to external MCP (Model Context Protocol) servers, injecting their tools into agent chats.',
|
|
792
810
|
features: ['Configure stdio, SSE, or streamable HTTP transports', 'Test connections and discover available tools', 'Assign MCP servers to specific agents', 'Tools appear alongside built-in tools in chat'],
|
|
793
811
|
},
|
|
794
812
|
knowledge: {
|
|
@@ -812,20 +830,32 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'sessions' | 'agents'>, { icon:
|
|
|
812
830
|
usage: {
|
|
813
831
|
icon: 'bar-chart',
|
|
814
832
|
title: 'Usage',
|
|
815
|
-
description: 'Track token usage and costs across all providers and
|
|
816
|
-
features: ['Per-provider cost breakdown', 'Token usage over time', '
|
|
833
|
+
description: 'Track token usage and costs across all providers and agents.',
|
|
834
|
+
features: ['Per-provider cost breakdown', 'Token usage over time', 'Per-agent cost tracking', 'Export usage data'],
|
|
817
835
|
},
|
|
818
836
|
runs: {
|
|
819
837
|
icon: 'activity',
|
|
820
838
|
title: 'Runs',
|
|
821
|
-
description: 'View the
|
|
839
|
+
description: 'View the run queue and execution history.',
|
|
822
840
|
features: ['Monitor queued and running tasks', 'View run results and errors', 'Cancel pending runs', 'Automatic retry tracking'],
|
|
823
841
|
},
|
|
842
|
+
settings: {
|
|
843
|
+
icon: 'settings',
|
|
844
|
+
title: 'Settings',
|
|
845
|
+
description: 'Manage providers, API keys & orchestrator engine.',
|
|
846
|
+
features: ['Configure LLM providers', 'Manage API credentials', 'Tune orchestrator settings', 'Set up voice & embedding'],
|
|
847
|
+
},
|
|
848
|
+
projects: {
|
|
849
|
+
icon: 'folder',
|
|
850
|
+
title: 'Projects',
|
|
851
|
+
description: 'Organize your work into projects. Group agents, tasks, and schedules under a common scope.',
|
|
852
|
+
features: ['Create named projects with color badges', 'Assign agents and tasks to projects', 'Filter sidebar views by project', 'Global view when no filter is active'],
|
|
853
|
+
},
|
|
824
854
|
}
|
|
825
855
|
|
|
826
856
|
function ViewEmptyState({ view }: { view: AppView }) {
|
|
827
|
-
if (view === '
|
|
828
|
-
const config = VIEW_EMPTY_STATES[view as Exclude<AppView, '
|
|
857
|
+
if (view === 'agents') return null
|
|
858
|
+
const config = VIEW_EMPTY_STATES[view as Exclude<AppView, 'agents'>]
|
|
829
859
|
if (!config) return null
|
|
830
860
|
|
|
831
861
|
return (
|
|
@@ -907,16 +937,17 @@ function ViewEmptyIcon({ type }: { type: string }) {
|
|
|
907
937
|
}
|
|
908
938
|
}
|
|
909
939
|
|
|
910
|
-
function NavItem({ view, label, expanded, active, sidebarOpen, onClick, children }: {
|
|
940
|
+
function NavItem({ view, label, expanded, active, sidebarOpen, onClick, badge, children }: {
|
|
911
941
|
view: AppView
|
|
912
942
|
label: string
|
|
913
943
|
expanded: boolean
|
|
914
944
|
active: AppView
|
|
915
945
|
sidebarOpen: boolean
|
|
916
946
|
onClick: () => void
|
|
947
|
+
badge?: number
|
|
917
948
|
children: React.ReactNode
|
|
918
949
|
}) {
|
|
919
|
-
const isActive = active === view && sidebarOpen
|
|
950
|
+
const isActive = active === view && (sidebarOpen || FULL_WIDTH_VIEWS.has(view))
|
|
920
951
|
|
|
921
952
|
if (expanded) {
|
|
922
953
|
return (
|
|
@@ -928,7 +959,14 @@ function NavItem({ view, label, expanded, active, sidebarOpen, onClick, children
|
|
|
928
959
|
: 'bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04]'}`}
|
|
929
960
|
style={{ fontFamily: 'inherit' }}
|
|
930
961
|
>
|
|
931
|
-
<span className="shrink-0">
|
|
962
|
+
<span className="shrink-0 relative">
|
|
963
|
+
{children}
|
|
964
|
+
{!!badge && (
|
|
965
|
+
<span className="absolute -top-1.5 -right-1.5 min-w-[14px] h-[14px] rounded-full bg-amber-500 text-black text-[9px] font-700 flex items-center justify-center px-0.5">
|
|
966
|
+
{badge}
|
|
967
|
+
</span>
|
|
968
|
+
)}
|
|
969
|
+
</span>
|
|
932
970
|
<span className="truncate">{label}</span>
|
|
933
971
|
</button>
|
|
934
972
|
)
|
|
@@ -937,8 +975,13 @@ function NavItem({ view, label, expanded, active, sidebarOpen, onClick, children
|
|
|
937
975
|
return (
|
|
938
976
|
<Tooltip>
|
|
939
977
|
<TooltipTrigger asChild>
|
|
940
|
-
<button onClick={onClick} className={`rail-btn ${isActive ? 'active' : ''}`}>
|
|
978
|
+
<button onClick={onClick} className={`rail-btn ${isActive ? 'active' : ''} relative`}>
|
|
941
979
|
{children}
|
|
980
|
+
{!!badge && (
|
|
981
|
+
<span className="absolute -top-0.5 -right-0.5 min-w-[14px] h-[14px] rounded-full bg-amber-500 text-black text-[9px] font-700 flex items-center justify-center px-0.5">
|
|
982
|
+
{badge}
|
|
983
|
+
</span>
|
|
984
|
+
)}
|
|
942
985
|
</button>
|
|
943
986
|
</TooltipTrigger>
|
|
944
987
|
<TooltipContent side="right" sideOffset={8}
|
|
@@ -995,7 +1038,7 @@ function DesktopEmptyState({ userName }: { userName: string | null }) {
|
|
|
995
1038
|
<span className="text-text-2">What would you like to do?</span>
|
|
996
1039
|
</h1>
|
|
997
1040
|
<p className="text-[15px] text-text-3 mb-12">
|
|
998
|
-
Create a new
|
|
1041
|
+
Create a new chat to start chatting
|
|
999
1042
|
</p>
|
|
1000
1043
|
<button
|
|
1001
1044
|
onClick={() => setNewSessionOpen(true)}
|
|
@@ -1008,7 +1051,7 @@ function DesktopEmptyState({ userName }: { userName: string | null }) {
|
|
|
1008
1051
|
<line x1="12" y1="5" x2="12" y2="19" />
|
|
1009
1052
|
<line x1="5" y1="12" x2="19" y2="12" />
|
|
1010
1053
|
</svg>
|
|
1011
|
-
New
|
|
1054
|
+
New Chat
|
|
1012
1055
|
</button>
|
|
1013
1056
|
</div>
|
|
1014
1057
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from 'react'
|
|
4
4
|
import { api } from '@/lib/api-client'
|
|
5
|
+
import { useWs } from '@/hooks/use-ws'
|
|
5
6
|
|
|
6
7
|
interface DaemonStatus {
|
|
7
8
|
running: boolean
|
|
@@ -21,11 +22,8 @@ export function DaemonIndicator() {
|
|
|
21
22
|
} catch { /* ignore */ }
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
|
|
26
|
-
const interval = setInterval(fetchStatus, 30_000)
|
|
27
|
-
return () => clearInterval(interval)
|
|
28
|
-
}, [])
|
|
25
|
+
useEffect(() => { fetchStatus() }, [])
|
|
26
|
+
useWs('daemon', fetchStatus, 30_000)
|
|
29
27
|
|
|
30
28
|
const toggle = async () => {
|
|
31
29
|
try {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState, useRef, useCallback } from 'react'
|
|
4
4
|
import { api } from '@/lib/api-client'
|
|
5
|
+
import { useWs } from '@/hooks/use-ws'
|
|
5
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
7
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
7
8
|
|
|
@@ -67,12 +68,7 @@ export function LogList() {
|
|
|
67
68
|
loadAgents()
|
|
68
69
|
}, [fetchLogs])
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
if (!autoRefresh) return
|
|
73
|
-
const id = setInterval(fetchLogs, 3000)
|
|
74
|
-
return () => clearInterval(id)
|
|
75
|
-
}, [autoRefresh, fetchLogs])
|
|
71
|
+
useWs('logs', fetchLogs, autoRefresh ? 3000 : undefined)
|
|
76
72
|
|
|
77
73
|
const clearLogs = async () => {
|
|
78
74
|
try {
|
|
@@ -151,7 +147,7 @@ export function LogList() {
|
|
|
151
147
|
return (
|
|
152
148
|
<div className="flex-1 flex flex-col overflow-hidden">
|
|
153
149
|
{/* Controls */}
|
|
154
|
-
<div className="px-
|
|
150
|
+
<div className="px-5 py-2 space-y-2 shrink-0">
|
|
155
151
|
{/* Search */}
|
|
156
152
|
<input
|
|
157
153
|
value={search}
|
|
@@ -250,12 +246,12 @@ export function LogList() {
|
|
|
250
246
|
</div>
|
|
251
247
|
|
|
252
248
|
{/* Total count */}
|
|
253
|
-
<div className="px-
|
|
249
|
+
<div className="px-5 py-1 text-[10px] text-text-3/60">
|
|
254
250
|
{entries.length} of {total} entries
|
|
255
251
|
</div>
|
|
256
252
|
|
|
257
253
|
{/* Log entries */}
|
|
258
|
-
<div ref={scrollRef} className="flex-1 overflow-y-auto px-
|
|
254
|
+
<div ref={scrollRef} className="flex-1 overflow-y-auto px-4 pb-8">
|
|
259
255
|
{entries.length === 0 ? (
|
|
260
256
|
<div className="flex items-center justify-center h-32 text-text-3 text-[12px]">
|
|
261
257
|
No log entries
|