@swarmclawai/swarmclaw 0.6.0 → 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.
Files changed (109) hide show
  1. package/README.md +15 -2
  2. package/bin/server-cmd.js +1 -0
  3. package/package.json +2 -1
  4. package/src/app/api/canvas/[sessionId]/route.ts +31 -0
  5. package/src/app/api/chatrooms/[id]/chat/route.ts +10 -136
  6. package/src/app/api/connectors/[id]/route.ts +1 -0
  7. package/src/app/api/connectors/route.ts +2 -1
  8. package/src/app/api/files/open/route.ts +43 -0
  9. package/src/app/api/search/route.ts +9 -7
  10. package/src/app/api/sessions/[id]/messages/route.ts +70 -2
  11. package/src/app/api/sessions/[id]/route.ts +4 -0
  12. package/src/app/api/tasks/metrics/route.ts +101 -0
  13. package/src/app/api/tasks/route.ts +17 -2
  14. package/src/app/api/tts/route.ts +3 -2
  15. package/src/app/api/tts/stream/route.ts +3 -2
  16. package/src/app/api/uploads/[filename]/route.ts +19 -34
  17. package/src/app/api/uploads/route.ts +94 -0
  18. package/src/app/globals.css +5 -0
  19. package/src/cli/index.js +16 -1
  20. package/src/cli/spec.js +26 -0
  21. package/src/components/agents/agent-card.tsx +3 -3
  22. package/src/components/agents/agent-chat-list.tsx +29 -6
  23. package/src/components/agents/agent-sheet.tsx +66 -4
  24. package/src/components/agents/inspector-panel.tsx +81 -6
  25. package/src/components/agents/openclaw-skills-panel.tsx +32 -3
  26. package/src/components/agents/personality-builder.tsx +42 -14
  27. package/src/components/agents/soul-library-picker.tsx +89 -0
  28. package/src/components/canvas/canvas-panel.tsx +96 -0
  29. package/src/components/chat/activity-moment.tsx +8 -4
  30. package/src/components/chat/chat-area.tsx +46 -22
  31. package/src/components/chat/chat-header.tsx +455 -286
  32. package/src/components/chat/chat-preview-panel.tsx +1 -2
  33. package/src/components/chat/delegation-banner.tsx +371 -0
  34. package/src/components/chat/file-path-chip.tsx +23 -2
  35. package/src/components/chat/heartbeat-history-panel.tsx +269 -0
  36. package/src/components/chat/message-bubble.tsx +315 -25
  37. package/src/components/chat/message-list.tsx +180 -7
  38. package/src/components/chat/streaming-bubble.tsx +68 -1
  39. package/src/components/chat/tool-call-bubble.tsx +45 -3
  40. package/src/components/chat/transfer-agent-picker.tsx +1 -1
  41. package/src/components/chatrooms/chatroom-list.tsx +8 -1
  42. package/src/components/chatrooms/chatroom-message.tsx +8 -3
  43. package/src/components/chatrooms/chatroom-view.tsx +3 -3
  44. package/src/components/connectors/connector-list.tsx +168 -90
  45. package/src/components/connectors/connector-sheet.tsx +68 -16
  46. package/src/components/home/home-view.tsx +1 -1
  47. package/src/components/input/chat-input.tsx +28 -2
  48. package/src/components/layout/app-layout.tsx +19 -2
  49. package/src/components/projects/project-detail.tsx +1 -1
  50. package/src/components/schedules/schedule-sheet.tsx +260 -127
  51. package/src/components/settings/gateway-disconnect-overlay.tsx +80 -0
  52. package/src/components/shared/agent-switch-dialog.tsx +1 -1
  53. package/src/components/shared/chatroom-picker-list.tsx +61 -0
  54. package/src/components/shared/connector-platform-icon.tsx +51 -4
  55. package/src/components/shared/icon-button.tsx +16 -2
  56. package/src/components/shared/keyboard-shortcuts-dialog.tsx +1 -1
  57. package/src/components/shared/search-dialog.tsx +17 -10
  58. package/src/components/shared/settings/section-embedding.tsx +48 -13
  59. package/src/components/shared/settings/section-orchestrator.tsx +46 -15
  60. package/src/components/shared/settings/section-storage.tsx +206 -0
  61. package/src/components/shared/settings/section-user-preferences.tsx +18 -0
  62. package/src/components/shared/settings/section-voice.tsx +42 -21
  63. package/src/components/shared/settings/section-web-search.tsx +30 -6
  64. package/src/components/shared/settings/settings-page.tsx +3 -1
  65. package/src/components/shared/settings/storage-browser.tsx +259 -0
  66. package/src/components/tasks/task-card.tsx +14 -1
  67. package/src/components/tasks/task-sheet.tsx +328 -3
  68. package/src/components/usage/metrics-dashboard.tsx +90 -6
  69. package/src/hooks/use-continuous-speech.ts +10 -4
  70. package/src/hooks/use-voice-conversation.ts +53 -10
  71. package/src/hooks/use-ws.ts +4 -2
  72. package/src/lib/providers/anthropic.ts +13 -7
  73. package/src/lib/providers/index.ts +1 -0
  74. package/src/lib/providers/openai.ts +13 -7
  75. package/src/lib/server/chat-execution.ts +51 -11
  76. package/src/lib/server/chatroom-helpers.ts +146 -0
  77. package/src/lib/server/connectors/manager.ts +218 -7
  78. package/src/lib/server/heartbeat-service.ts +8 -1
  79. package/src/lib/server/main-agent-loop.ts +1 -1
  80. package/src/lib/server/memory-consolidation.ts +15 -2
  81. package/src/lib/server/memory-db.ts +134 -6
  82. package/src/lib/server/mime.ts +51 -0
  83. package/src/lib/server/openclaw-gateway.ts +2 -2
  84. package/src/lib/server/orchestrator-lg.ts +2 -0
  85. package/src/lib/server/orchestrator.ts +5 -2
  86. package/src/lib/server/playwright-proxy.mjs +2 -3
  87. package/src/lib/server/prompt-runtime-context.ts +53 -0
  88. package/src/lib/server/queue.ts +52 -7
  89. package/src/lib/server/session-tools/canvas.ts +67 -0
  90. package/src/lib/server/session-tools/connector.ts +83 -9
  91. package/src/lib/server/session-tools/crud.ts +21 -0
  92. package/src/lib/server/session-tools/delegate.ts +68 -4
  93. package/src/lib/server/session-tools/git.ts +71 -0
  94. package/src/lib/server/session-tools/http.ts +57 -0
  95. package/src/lib/server/session-tools/index.ts +8 -0
  96. package/src/lib/server/session-tools/memory.ts +1 -0
  97. package/src/lib/server/session-tools/search-providers.ts +16 -8
  98. package/src/lib/server/session-tools/subagent.ts +106 -0
  99. package/src/lib/server/session-tools/web.ts +115 -4
  100. package/src/lib/server/stream-agent-chat.ts +32 -10
  101. package/src/lib/server/task-mention.ts +41 -0
  102. package/src/lib/sessions.ts +10 -0
  103. package/src/lib/soul-library.ts +103 -0
  104. package/src/lib/task-dedupe.ts +26 -0
  105. package/src/lib/tool-definitions.ts +2 -0
  106. package/src/lib/tts.ts +2 -2
  107. package/src/stores/use-app-store.ts +5 -1
  108. package/src/stores/use-chat-store.ts +65 -2
  109. package/src/types/index.ts +32 -2
@@ -4,7 +4,7 @@ import { useEffect, useCallback, useState, useRef } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
5
  import { useWs } from '@/hooks/use-ws'
6
6
  import { useChatStore } from '@/stores/use-chat-store'
7
- import { fetchMessages, clearMessages, deleteSession, devServer, checkBrowser, stopBrowser } from '@/lib/sessions'
7
+ import { fetchMessages, fetchMessagesPaginated, clearMessages, deleteSession, devServer, checkBrowser, stopBrowser } from '@/lib/sessions'
8
8
  import { uploadImage } from '@/lib/upload'
9
9
  import { deleteAgent } from '@/lib/agents'
10
10
  import { useMediaQuery } from '@/hooks/use-media-query'
@@ -17,6 +17,7 @@ import { useVoiceConversation } from '@/hooks/use-voice-conversation'
17
17
  import { ChatInput } from '@/components/input/chat-input'
18
18
  import { ChatPreviewPanel } from './chat-preview-panel'
19
19
  import { InspectorPanel } from '@/components/agents/inspector-panel'
20
+ import { HeartbeatHistoryPanel } from './heartbeat-history-panel'
20
21
  import { Dropdown, DropdownItem } from '@/components/shared/dropdown'
21
22
  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
22
23
  import { speak } from '@/lib/tts'
@@ -47,6 +48,8 @@ export function ChatArea() {
47
48
  const setEditingAgentId = useAppStore((s) => s.setEditingAgentId)
48
49
  const setAgentSheetOpen = useAppStore((s) => s.setAgentSheetOpen)
49
50
  const inspectorOpen = useAppStore((s) => s.inspectorOpen)
51
+ const sidebarOpen = useAppStore((s) => s.sidebarOpen)
52
+ const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
50
53
  const currentAgent = session?.agentId ? agents[session.agentId] ?? null : null
51
54
 
52
55
  const voice = useVoiceConversation()
@@ -60,6 +63,8 @@ export function ChatArea() {
60
63
  const [confirmClear, setConfirmClear] = useState(false)
61
64
  const [confirmDeleteAgent, setConfirmDeleteAgent] = useState(false)
62
65
  const [browserActive, setBrowserActive] = useState(false)
66
+ const [heartbeatHistoryOpen, setHeartbeatHistoryOpen] = useState(false)
67
+ const [messagesLoading, setMessagesLoading] = useState(true)
63
68
  const [isDragging, setIsDragging] = useState(false)
64
69
  const dragCounter = useRef(0)
65
70
  const setPendingImage = useChatStore((s) => s.setPendingImage)
@@ -69,13 +74,19 @@ export function ChatArea() {
69
74
  const chatState = useChatStore.getState()
70
75
  const preserveLocalStream = chatState.streaming && chatState.streamingSessionId === sessionId
71
76
  // Clear stale state from the previous session, but keep active local stream state for this session.
77
+ setMessagesLoading(true)
72
78
  setMessages([])
73
79
  if (!preserveLocalStream) {
74
80
  useChatStore.setState({ streaming: false, streamingSessionId: null, streamText: '', toolEvents: [] })
75
81
  }
76
- fetchMessages(sessionId).then(setMessages).catch((err) => {
82
+ fetchMessagesPaginated(sessionId, 100).then((data) => {
83
+ setMessages(data.messages)
84
+ useChatStore.setState({ hasMoreMessages: data.hasMore, totalMessages: data.total })
85
+ }).catch((err) => {
77
86
  console.error('Failed to load messages:', err)
78
87
  setMessages(session?.messages || [])
88
+ }).finally(() => {
89
+ setMessagesLoading(false)
79
90
  })
80
91
  // If server reports session is still active, show streaming state
81
92
  if (session?.active) {
@@ -125,12 +136,13 @@ export function ChatArea() {
125
136
  return !isHeartbeat && !!m.text?.trim()
126
137
  })
127
138
  if (latestAssistant?.text) {
128
- void speak(latestAssistant.text)
139
+ void speak(latestAssistant.text, currentAgent?.elevenLabsVoiceId)
129
140
  }
130
141
  }
131
142
  }
132
143
  if (isServerActiveRef.current) await loadSessions()
133
144
  } catch (err) { console.error('Failed to refresh messages:', err) }
145
+ // eslint-disable-next-line react-hooks/exhaustive-deps
134
146
  }, [sessionId])
135
147
 
136
148
  // Subscribe to WS messages for this session — always subscribe when session exists,
@@ -198,10 +210,6 @@ export function ChatArea() {
198
210
  setCurrentSession(null)
199
211
  }, [sessionId])
200
212
 
201
- const handleBack = useCallback(() => {
202
- setCurrentSession(null)
203
- }, [])
204
-
205
213
  const handlePrompt = useCallback((text: string) => {
206
214
  sendMessage(text)
207
215
  }, [sendMessage])
@@ -244,7 +252,7 @@ export function ChatArea() {
244
252
 
245
253
  const streamingForThisSession = streaming && (!streamingSessionId || streamingSessionId === session.id)
246
254
  const isMainChat = session.name === '__main__'
247
- const isEmpty = !messages.length && !streamingForThisSession
255
+ const isEmpty = !messages.length && !streamingForThisSession && !messagesLoading
248
256
 
249
257
  return (
250
258
  <div className="flex-1 flex h-full min-h-0 min-w-0">
@@ -261,12 +269,14 @@ export function ChatArea() {
261
269
  streaming={streamingForThisSession}
262
270
  onStop={stopStreaming}
263
271
  onMenuToggle={() => setMenuOpen(!menuOpen)}
264
- onBack={handleBack}
272
+ onBack={sidebarOpen ? () => setSidebarOpen(false) : undefined}
265
273
  browserActive={browserActive}
266
274
  onStopBrowser={handleStopBrowser}
267
275
  voiceActive={voice.active}
268
276
  voiceSupported={voice.supported}
269
277
  onVoiceToggle={handleVoiceToggle}
278
+ heartbeatHistoryOpen={heartbeatHistoryOpen}
279
+ onToggleHeartbeatHistory={() => setHeartbeatHistoryOpen((v) => !v)}
270
280
  />
271
281
  )}
272
282
  {!isDesktop && (
@@ -285,7 +295,17 @@ export function ChatArea() {
285
295
  )}
286
296
  <DevServerBar status={devServerStatus} onStop={handleStopDevServer} />
287
297
 
288
- {isEmpty ? (
298
+ {messagesLoading && !messages.length ? (
299
+ <div className="flex-1 flex items-center justify-center">
300
+ <div className="flex flex-col items-center gap-3" style={{ animation: 'fade-in 0.2s ease' }}>
301
+ <div className="relative w-10 h-10">
302
+ <div className="absolute inset-0 rounded-full border-2 border-white/[0.06]" />
303
+ <div className="absolute inset-0 rounded-full border-2 border-transparent border-t-accent-bright animate-spin" />
304
+ </div>
305
+ <span className="text-[13px] text-text-3/50 font-500">Loading messages...</span>
306
+ </div>
307
+ </div>
308
+ ) : isEmpty ? (
289
309
  <div className="flex-1 flex flex-col items-center justify-center px-6 pb-4 relative">
290
310
  {/* Atmospheric background glow */}
291
311
  <div className="absolute inset-0 pointer-events-none overflow-hidden">
@@ -361,19 +381,9 @@ export function ChatArea() {
361
381
  />
362
382
 
363
383
  <Dropdown open={menuOpen} onClose={() => setMenuOpen(false)}>
364
- {session.agentId && agents[session.agentId] && (
365
- <DropdownItem onClick={() => { setMenuOpen(false); setEditingAgentId(session.agentId!); setAgentSheetOpen(true) }}>
366
- Edit Agent
367
- </DropdownItem>
368
- )}
369
384
  <DropdownItem onClick={() => { setMenuOpen(false); setConfirmClear(true) }}>
370
385
  Clear History
371
386
  </DropdownItem>
372
- {session.agentId && agents[session.agentId] && !isMainChat && (
373
- <DropdownItem danger onClick={() => { setMenuOpen(false); setConfirmDeleteAgent(true) }}>
374
- Delete Agent
375
- </DropdownItem>
376
- )}
377
387
  {!isMainChat && (
378
388
  <DropdownItem danger onClick={() => { setMenuOpen(false); setConfirmDelete(true) }}>
379
389
  Delete Chat
@@ -432,7 +442,21 @@ export function ChatArea() {
432
442
  <ChatPreviewPanel content={previewContent} onClose={() => setPreviewContent(null)} />
433
443
  )}
434
444
  {isDesktop && inspectorOpen && currentAgent && (
435
- <InspectorPanel agent={currentAgent} />
445
+ <InspectorPanel
446
+ agent={currentAgent}
447
+ onEditAgent={() => { setEditingAgentId(session.agentId!); setAgentSheetOpen(true) }}
448
+ onClearHistory={() => setConfirmClear(true)}
449
+ onDeleteAgent={!isMainChat ? () => setConfirmDeleteAgent(true) : undefined}
450
+ onDeleteChat={!isMainChat ? () => setConfirmDelete(true) : undefined}
451
+ isMainChat={isMainChat}
452
+ />
453
+ )}
454
+ {isDesktop && heartbeatHistoryOpen && currentAgent?.heartbeatEnabled && (
455
+ <HeartbeatHistoryPanel
456
+ messages={messages}
457
+ agentHeartbeatGoal={currentAgent.heartbeatGoal ?? undefined}
458
+ onClose={() => setHeartbeatHistoryOpen(false)}
459
+ />
436
460
  )}
437
461
  </div>
438
462
  )
@@ -442,7 +466,7 @@ function PromptIcon({ type }: { type: string }) {
442
466
  const cls = "w-5 h-5"
443
467
  switch (type) {
444
468
  case 'book':
445
- return <svg className={cls} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" style={{ color: '#818CF8' }}><rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" /><rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" /></svg>
469
+ return <svg className={cls} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" style={{ color: 'var(--color-accent-bright)' }}><rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" /><rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" /></svg>
446
470
  case 'link':
447
471
  return <svg className={cls} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" style={{ color: '#F472B6' }}><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" /></svg>
448
472
  case 'bot':