@swarmclawai/swarmclaw 0.7.8 → 0.8.0

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 (251) hide show
  1. package/README.md +12 -15
  2. package/next.config.ts +13 -2
  3. package/package.json +4 -2
  4. package/src/app/api/agents/[id]/thread/route.ts +9 -0
  5. package/src/app/api/agents/route.ts +4 -0
  6. package/src/app/api/agents/thread-route.test.ts +133 -0
  7. package/src/app/api/approvals/route.test.ts +148 -0
  8. package/src/app/api/canvas/[sessionId]/route.ts +3 -1
  9. package/src/app/api/chatrooms/[id]/chat/route.ts +4 -2
  10. package/src/app/api/chats/[id]/devserver/route.ts +48 -7
  11. package/src/app/api/chats/[id]/messages/route.ts +42 -18
  12. package/src/app/api/chats/[id]/route.ts +1 -1
  13. package/src/app/api/chats/[id]/stop/route.ts +5 -4
  14. package/src/app/api/chats/route.ts +22 -2
  15. package/src/app/api/clawhub/install/route.ts +28 -8
  16. package/src/app/api/connectors/[id]/route.ts +26 -1
  17. package/src/app/api/external-agents/route.test.ts +165 -0
  18. package/src/app/api/gateways/[id]/health/route.ts +27 -12
  19. package/src/app/api/gateways/[id]/route.ts +2 -0
  20. package/src/app/api/gateways/health-route.test.ts +135 -0
  21. package/src/app/api/gateways/route.ts +2 -0
  22. package/src/app/api/mcp-servers/route.test.ts +130 -0
  23. package/src/app/api/openclaw/deploy/route.ts +38 -5
  24. package/src/app/api/plugins/install/route.ts +46 -6
  25. package/src/app/api/plugins/marketplace/route.ts +48 -15
  26. package/src/app/api/preview-server/route.ts +26 -11
  27. package/src/app/api/schedules/[id]/run/route.ts +4 -0
  28. package/src/app/api/schedules/route.test.ts +86 -0
  29. package/src/app/api/schedules/route.ts +6 -1
  30. package/src/app/api/setup/check-provider/route.test.ts +19 -0
  31. package/src/app/api/setup/check-provider/route.ts +40 -10
  32. package/src/app/api/skills/[id]/route.ts +12 -0
  33. package/src/app/api/skills/import/route.ts +14 -12
  34. package/src/app/api/skills/route.ts +13 -1
  35. package/src/app/api/tasks/[id]/route.ts +10 -1
  36. package/src/app/api/tasks/import/github/route.test.ts +65 -0
  37. package/src/app/api/tasks/import/github/route.ts +337 -0
  38. package/src/app/api/wallets/[id]/approve/route.ts +17 -3
  39. package/src/app/api/wallets/[id]/route.ts +79 -33
  40. package/src/app/api/wallets/[id]/send/route.ts +19 -33
  41. package/src/app/api/wallets/route.ts +78 -61
  42. package/src/app/api/webhooks/[id]/route.ts +33 -6
  43. package/src/app/api/webhooks/route.test.ts +272 -0
  44. package/src/cli/index.js +1 -0
  45. package/src/cli/spec.js +1 -0
  46. package/src/components/agents/agent-card.tsx +9 -2
  47. package/src/components/agents/agent-chat-list.tsx +18 -2
  48. package/src/components/agents/agent-list.tsx +1 -0
  49. package/src/components/agents/agent-sheet.tsx +73 -24
  50. package/src/components/agents/inspector-panel.tsx +41 -0
  51. package/src/components/canvas/canvas-panel.tsx +236 -65
  52. package/src/components/chat/chat-card.tsx +36 -13
  53. package/src/components/chat/chat-header.tsx +44 -16
  54. package/src/components/chat/chat-list.tsx +28 -4
  55. package/src/components/chat/checkpoint-timeline.tsx +50 -34
  56. package/src/components/chat/message-bubble.tsx +208 -145
  57. package/src/components/chat/message-list.tsx +48 -19
  58. package/src/components/chatrooms/chatroom-message.tsx +2 -2
  59. package/src/components/chatrooms/chatroom-sheet.tsx +16 -2
  60. package/src/components/connectors/connector-health.tsx +1 -1
  61. package/src/components/connectors/connector-list.tsx +7 -2
  62. package/src/components/connectors/connector-sheet.tsx +337 -148
  63. package/src/components/gateways/gateway-sheet.tsx +2 -2
  64. package/src/components/mcp-servers/mcp-server-list.tsx +26 -5
  65. package/src/components/mcp-servers/mcp-server-sheet.tsx +19 -2
  66. package/src/components/openclaw/openclaw-deploy-panel.tsx +269 -21
  67. package/src/components/plugins/plugin-list.tsx +45 -9
  68. package/src/components/plugins/plugin-sheet.tsx +55 -7
  69. package/src/components/providers/provider-list.tsx +2 -1
  70. package/src/components/providers/provider-sheet.tsx +21 -2
  71. package/src/components/schedules/schedule-card.tsx +25 -1
  72. package/src/components/schedules/schedule-sheet.tsx +44 -2
  73. package/src/components/secrets/secret-sheet.tsx +21 -2
  74. package/src/components/shared/agent-switch-dialog.tsx +12 -1
  75. package/src/components/shared/bottom-sheet.tsx +13 -3
  76. package/src/components/shared/command-palette.tsx +8 -1
  77. package/src/components/shared/confirm-dialog.tsx +19 -4
  78. package/src/components/shared/connector-platform-icon.test.ts +28 -0
  79. package/src/components/shared/connector-platform-icon.tsx +39 -6
  80. package/src/components/shared/settings/plugin-manager.tsx +29 -6
  81. package/src/components/shared/settings/section-capability-policy.tsx +7 -3
  82. package/src/components/skills/skill-list.tsx +25 -0
  83. package/src/components/skills/skill-sheet.tsx +84 -12
  84. package/src/components/tasks/approvals-panel.tsx +191 -95
  85. package/src/components/tasks/task-board.tsx +273 -2
  86. package/src/components/tasks/task-card.tsx +38 -9
  87. package/src/components/ui/dialog.tsx +2 -2
  88. package/src/components/wallets/wallet-approval-dialog.tsx +4 -2
  89. package/src/components/wallets/wallet-panel.tsx +435 -90
  90. package/src/components/wallets/wallet-section.tsx +198 -48
  91. package/src/components/webhooks/webhook-sheet.tsx +22 -2
  92. package/src/lib/approval-display.ts +20 -0
  93. package/src/lib/canvas-content.ts +198 -0
  94. package/src/lib/chat-artifact-summary.ts +165 -0
  95. package/src/lib/chat-display.test.ts +91 -0
  96. package/src/lib/chat-display.ts +58 -0
  97. package/src/lib/chat-streaming-state.test.ts +47 -1
  98. package/src/lib/chat-streaming-state.ts +42 -0
  99. package/src/lib/ollama-model.ts +10 -0
  100. package/src/lib/openclaw-endpoint.test.ts +8 -0
  101. package/src/lib/openclaw-endpoint.ts +6 -1
  102. package/src/lib/plugin-install-cors.ts +46 -0
  103. package/src/lib/plugin-sources.test.ts +43 -0
  104. package/src/lib/plugin-sources.ts +77 -0
  105. package/src/lib/providers/ollama.ts +16 -6
  106. package/src/lib/providers/openclaw.test.ts +54 -0
  107. package/src/lib/providers/openclaw.ts +127 -11
  108. package/src/lib/schedule-dedupe-advanced.test.ts +1335 -0
  109. package/src/lib/schedule-dedupe.test.ts +66 -1
  110. package/src/lib/schedule-dedupe.ts +169 -12
  111. package/src/lib/schedule-origin.test.ts +20 -0
  112. package/src/lib/schedule-origin.ts +15 -0
  113. package/src/lib/server/__fixtures__/fake-mcp-stdio-server.mjs +27 -0
  114. package/src/lib/server/agent-availability.ts +16 -0
  115. package/src/lib/server/agent-runtime-config.ts +12 -4
  116. package/src/lib/server/agent-thread-session.test.ts +51 -0
  117. package/src/lib/server/agent-thread-session.ts +7 -0
  118. package/src/lib/server/approval-match.ts +205 -0
  119. package/src/lib/server/approvals-auto-approve.test.ts +538 -1
  120. package/src/lib/server/approvals.ts +214 -1
  121. package/src/lib/server/assistant-control.test.ts +29 -0
  122. package/src/lib/server/assistant-control.ts +23 -0
  123. package/src/lib/server/build-llm.test.ts +79 -0
  124. package/src/lib/server/build-llm.ts +14 -4
  125. package/src/lib/server/canvas-content.test.ts +32 -0
  126. package/src/lib/server/canvas-content.ts +6 -0
  127. package/src/lib/server/capability-router.test.ts +11 -0
  128. package/src/lib/server/capability-router.ts +26 -1
  129. package/src/lib/server/chat-execution-advanced.test.ts +651 -0
  130. package/src/lib/server/chat-execution-disabled.test.ts +94 -0
  131. package/src/lib/server/chat-execution-tool-events.test.ts +157 -0
  132. package/src/lib/server/chat-execution.ts +353 -72
  133. package/src/lib/server/clawhub-client.test.ts +14 -8
  134. package/src/lib/server/connectors/manager.test.ts +1147 -0
  135. package/src/lib/server/connectors/manager.ts +362 -63
  136. package/src/lib/server/connectors/pairing.ts +26 -5
  137. package/src/lib/server/connectors/types.ts +2 -0
  138. package/src/lib/server/connectors/whatsapp.test.ts +134 -0
  139. package/src/lib/server/connectors/whatsapp.ts +271 -47
  140. package/src/lib/server/context-manager.ts +6 -1
  141. package/src/lib/server/daemon-state.ts +1 -1
  142. package/src/lib/server/data-dir.test.ts +37 -0
  143. package/src/lib/server/data-dir.ts +20 -1
  144. package/src/lib/server/delegation-jobs-advanced.test.ts +513 -0
  145. package/src/lib/server/devserver-launch.test.ts +60 -0
  146. package/src/lib/server/devserver-launch.ts +85 -0
  147. package/src/lib/server/elevenlabs.test.ts +189 -1
  148. package/src/lib/server/elevenlabs.ts +147 -43
  149. package/src/lib/server/ethereum.ts +590 -0
  150. package/src/lib/server/eval/agent-regression-advanced.test.ts +302 -0
  151. package/src/lib/server/eval/agent-regression.test.ts +18 -1
  152. package/src/lib/server/eval/agent-regression.ts +383 -11
  153. package/src/lib/server/evm-swap.ts +475 -0
  154. package/src/lib/server/execution-log.ts +1 -0
  155. package/src/lib/server/heartbeat-service-timer.test.ts +173 -0
  156. package/src/lib/server/heartbeat-service.ts +15 -10
  157. package/src/lib/server/heartbeat-wake.test.ts +112 -0
  158. package/src/lib/server/heartbeat-wake.ts +338 -57
  159. package/src/lib/server/main-agent-loop-advanced.test.ts +538 -0
  160. package/src/lib/server/mcp-client.test.ts +16 -0
  161. package/src/lib/server/mcp-client.ts +25 -0
  162. package/src/lib/server/memory-integration.test.ts +719 -0
  163. package/src/lib/server/memory-policy.test.ts +43 -0
  164. package/src/lib/server/memory-policy.ts +132 -0
  165. package/src/lib/server/memory-tiers.test.ts +60 -0
  166. package/src/lib/server/memory-tiers.ts +16 -0
  167. package/src/lib/server/ollama-runtime.ts +58 -0
  168. package/src/lib/server/openclaw-deploy.test.ts +109 -1
  169. package/src/lib/server/openclaw-deploy.ts +557 -81
  170. package/src/lib/server/openclaw-gateway.test.ts +131 -0
  171. package/src/lib/server/openclaw-gateway.ts +10 -4
  172. package/src/lib/server/openclaw-health.test.ts +35 -0
  173. package/src/lib/server/openclaw-health.ts +215 -47
  174. package/src/lib/server/orchestrator-lg.ts +2 -2
  175. package/src/lib/server/plugins-advanced.test.ts +351 -0
  176. package/src/lib/server/plugins.ts +205 -5
  177. package/src/lib/server/queue-advanced.test.ts +528 -0
  178. package/src/lib/server/queue-followups.test.ts +262 -0
  179. package/src/lib/server/queue-reconcile.test.ts +128 -0
  180. package/src/lib/server/queue.ts +293 -61
  181. package/src/lib/server/scheduler.ts +29 -1
  182. package/src/lib/server/session-note.test.ts +36 -0
  183. package/src/lib/server/session-note.ts +42 -0
  184. package/src/lib/server/session-run-manager.ts +52 -4
  185. package/src/lib/server/session-tools/canvas.ts +14 -12
  186. package/src/lib/server/session-tools/connector.test.ts +138 -0
  187. package/src/lib/server/session-tools/connector.ts +348 -61
  188. package/src/lib/server/session-tools/context.ts +12 -3
  189. package/src/lib/server/session-tools/crud.ts +221 -10
  190. package/src/lib/server/session-tools/delegate-fallback.test.ts +103 -0
  191. package/src/lib/server/session-tools/delegate.ts +64 -8
  192. package/src/lib/server/session-tools/discovery-approvals.test.ts +142 -0
  193. package/src/lib/server/session-tools/discovery.ts +80 -12
  194. package/src/lib/server/session-tools/file-normalize.test.ts +36 -0
  195. package/src/lib/server/session-tools/file.ts +43 -4
  196. package/src/lib/server/session-tools/human-loop.ts +35 -5
  197. package/src/lib/server/session-tools/index.ts +44 -9
  198. package/src/lib/server/session-tools/manage-connectors.test.ts +139 -0
  199. package/src/lib/server/session-tools/manage-schedules-advanced.test.ts +564 -0
  200. package/src/lib/server/session-tools/manage-schedules.test.ts +283 -0
  201. package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +852 -0
  202. package/src/lib/server/session-tools/memory.test.ts +93 -0
  203. package/src/lib/server/session-tools/memory.ts +546 -79
  204. package/src/lib/server/session-tools/normalize-tool-args.ts +1 -1
  205. package/src/lib/server/session-tools/plugin-creator.ts +57 -1
  206. package/src/lib/server/session-tools/primitive-tools.test.ts +6 -0
  207. package/src/lib/server/session-tools/schedule.ts +6 -1
  208. package/src/lib/server/session-tools/shell-normalize.test.ts +25 -1
  209. package/src/lib/server/session-tools/shell.ts +22 -3
  210. package/src/lib/server/session-tools/wallet-tool.test.ts +254 -0
  211. package/src/lib/server/session-tools/wallet.ts +1374 -139
  212. package/src/lib/server/session-tools/web-inputs.test.ts +162 -1
  213. package/src/lib/server/session-tools/web.ts +468 -64
  214. package/src/lib/server/skill-discovery.ts +128 -0
  215. package/src/lib/server/skill-eligibility.test.ts +84 -0
  216. package/src/lib/server/skill-eligibility.ts +95 -0
  217. package/src/lib/server/skill-prompt-budget.test.ts +102 -0
  218. package/src/lib/server/skill-prompt-budget.ts +125 -0
  219. package/src/lib/server/skills-normalize.test.ts +54 -0
  220. package/src/lib/server/skills-normalize.ts +372 -26
  221. package/src/lib/server/solana.ts +214 -29
  222. package/src/lib/server/storage.ts +65 -36
  223. package/src/lib/server/stream-agent-chat.test.ts +419 -9
  224. package/src/lib/server/stream-agent-chat.ts +887 -83
  225. package/src/lib/server/system-events.ts +1 -1
  226. package/src/lib/server/tool-capability-policy-advanced.test.ts +502 -0
  227. package/src/lib/server/tool-loop-detection.test.ts +105 -0
  228. package/src/lib/server/tool-loop-detection.ts +260 -0
  229. package/src/lib/server/tool-planning.ts +4 -2
  230. package/src/lib/server/wallet-execution.test.ts +198 -0
  231. package/src/lib/server/wallet-portfolio.test.ts +98 -0
  232. package/src/lib/server/wallet-portfolio.ts +724 -0
  233. package/src/lib/server/wallet-service.test.ts +57 -0
  234. package/src/lib/server/wallet-service.ts +213 -0
  235. package/src/lib/server/watch-jobs-advanced.test.ts +594 -0
  236. package/src/lib/server/watch-jobs.ts +17 -2
  237. package/src/lib/server/workspace-context.ts +111 -0
  238. package/src/lib/skill-save-payload.test.ts +39 -0
  239. package/src/lib/skill-save-payload.ts +37 -0
  240. package/src/lib/tasks.ts +28 -0
  241. package/src/lib/tool-event-summary.test.ts +30 -0
  242. package/src/lib/tool-event-summary.ts +37 -0
  243. package/src/lib/validation/schemas.ts +1 -0
  244. package/src/lib/wallet-transactions.test.ts +75 -0
  245. package/src/lib/wallet-transactions.ts +43 -0
  246. package/src/lib/wallet.test.ts +17 -0
  247. package/src/lib/wallet.ts +183 -0
  248. package/src/proxy.test.ts +31 -0
  249. package/src/proxy.ts +34 -2
  250. package/src/stores/use-chat-store.ts +15 -1
  251. package/src/types/index.ts +210 -14
@@ -7,6 +7,7 @@ import { useChatStore } from '@/stores/use-chat-store'
7
7
  import { useAppStore } from '@/stores/use-app-store'
8
8
  import { api } from '@/lib/api-client'
9
9
  import { shouldHidePersistedStreamingAssistantMessage } from '@/lib/chat-streaming-state'
10
+ import { dedupeMessagesForDisplay } from '@/lib/chat-display'
10
11
  import { AgentAvatar } from '@/components/agents/agent-avatar'
11
12
  import { MessageBubble } from './message-bubble'
12
13
  import { StreamingBubble } from './streaming-bubble'
@@ -47,6 +48,22 @@ function dateSeparator(ts: number): string {
47
48
  return d.toLocaleDateString([], { month: 'short', day: 'numeric' })
48
49
  }
49
50
 
51
+ function getLatestAssistantToolMoment(messages: Message[]): { key: string; name: string; input: string } | null {
52
+ const last = messages[messages.length - 1]
53
+ if (!last || last.role !== 'assistant' || !last.toolEvents?.length) return null
54
+ const events = last.toolEvents
55
+ for (let i = events.length - 1; i >= 0; i--) {
56
+ if (isNotableTool(events[i].name)) {
57
+ return {
58
+ key: `${last.time}-${events[i].name}-${i}`,
59
+ name: events[i].name,
60
+ input: events[i].input || '',
61
+ }
62
+ }
63
+ }
64
+ return null
65
+ }
66
+
50
67
  interface Props {
51
68
  messages: Message[]
52
69
  streaming: boolean
@@ -90,7 +107,7 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
90
107
  const showGatewayOverlay = isOpenClaw && gatewayStatus === 'disconnected'
91
108
 
92
109
  // Moment overlay for last assistant message (heartbeat or tool events)
93
- type MomentType = { kind: 'heartbeat' } | { kind: 'tool'; name: string; input: string }
110
+ type MomentType = { kind: 'heartbeat' } | { kind: 'tool'; key: string; name: string; input: string }
94
111
  const [currentMoment, setCurrentMoment] = useState<MomentType | null>(null)
95
112
 
96
113
  const heartbeatTopic = agent?.id ? `heartbeat:agent:${agent.id}` : ''
@@ -98,23 +115,32 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
98
115
  setCurrentMoment({ kind: 'heartbeat' })
99
116
  })
100
117
 
101
- // Detect notable tool events on latest assistant message when messages change
102
118
  const prevToolKeyRef = useRef<string | null>(null)
119
+ const seededMomentSessionRef = useRef<string | null>(null)
120
+
103
121
  useEffect(() => {
104
- const last = messages[messages.length - 1]
105
- if (!last || last.role !== 'assistant' || !last.toolEvents?.length) return
106
- const events = last.toolEvents
107
- for (let i = events.length - 1; i >= 0; i--) {
108
- if (isNotableTool(events[i].name)) {
109
- const key = `${last.time}-${events[i].name}-${i}`
110
- if (key !== prevToolKeyRef.current) {
111
- prevToolKeyRef.current = key
112
- setCurrentMoment({ kind: 'tool', name: events[i].name, input: events[i].input || '' })
113
- }
114
- return
115
- }
122
+ if (!sessionId) {
123
+ seededMomentSessionRef.current = null
124
+ prevToolKeyRef.current = null
125
+ setCurrentMoment(null)
126
+ return
116
127
  }
117
- }, [messages])
128
+
129
+ if (seededMomentSessionRef.current === sessionId) return
130
+ seededMomentSessionRef.current = sessionId
131
+ prevToolKeyRef.current = getLatestAssistantToolMoment(messages)?.key || null
132
+ setCurrentMoment(null)
133
+ }, [messages, sessionId])
134
+
135
+ // Detect notable tool events on the latest assistant message after the session has been seeded.
136
+ useEffect(() => {
137
+ if (!sessionId || seededMomentSessionRef.current !== sessionId) return
138
+ const moment = getLatestAssistantToolMoment(messages)
139
+ if (!moment) return
140
+ if (moment.key === prevToolKeyRef.current) return
141
+ prevToolKeyRef.current = moment.key
142
+ setCurrentMoment({ kind: 'tool', key: moment.key, name: moment.name, input: moment.input })
143
+ }, [messages, sessionId])
118
144
 
119
145
  // Unread count tracking
120
146
  const unreadRef = useRef(0)
@@ -189,13 +215,16 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
189
215
  }
190
216
  }
191
217
 
218
+ const dedupedDisplayedMessages = dedupeMessagesForDisplay(displayedMessages)
219
+
192
220
  // Apply bookmark + connector filter
193
221
  let filteredMessages = bookmarkFilter
194
- ? displayedMessages.filter((msg) => msg.bookmarked)
195
- : displayedMessages
222
+ ? dedupedDisplayedMessages.filter((msg) => msg.bookmarked)
223
+ : dedupedDisplayedMessages
196
224
  if (connectorFilter) {
197
225
  filteredMessages = filteredMessages.filter((msg) => msg.source?.connectorId === connectorFilter)
198
226
  }
227
+ const hasVisiblePersistedStreamingMessage = filteredMessages.some((msg) => msg.role === 'assistant' && msg.streaming === true)
199
228
 
200
229
  // Search matches
201
230
  const searchMatches = useMemo(() => {
@@ -629,7 +658,7 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
629
658
  } else {
630
659
  momentOverlay = (
631
660
  <ActivityMoment
632
- key={`${currentMoment.name}-${Date.now()}`}
661
+ key={currentMoment.key}
633
662
  toolName={currentMoment.name}
634
663
  toolInput={currentMoment.input}
635
664
  onDismiss={() => setCurrentMoment(null)}
@@ -676,7 +705,7 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
676
705
  )
677
706
  })}
678
707
  <ApprovalCards agentId={agent?.id} />
679
- {streaming && !displayText && <ThinkingIndicator assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentAvatarUrl={agent?.avatarUrl} agentName={agent?.name} />}
708
+ {streaming && !displayText && !hasVisiblePersistedStreamingMessage && <ThinkingIndicator assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentAvatarUrl={agent?.avatarUrl} agentName={agent?.name} />}
680
709
  {streaming && displayText && <StreamingBubble text={displayText} assistantName={assistantName} agentAvatarSeed={agent?.avatarSeed} agentAvatarUrl={agent?.avatarUrl} agentName={agent?.name} />}
681
710
  {appSettings.suggestionsEnabled === true && !streaming && filteredMessages.length > 0 && filteredMessages[filteredMessages.length - 1]?.role === 'assistant' && (
682
711
  <SuggestionsBar lastMessage={filteredMessages[filteredMessages.length - 1]} onSend={sendMessage} />
@@ -14,7 +14,7 @@ import { AgentHoverCard } from './agent-hover-card'
14
14
  import { ChatroomToolRequestBanner } from './chatroom-tool-request-banner'
15
15
  import { isStructuredMarkdown } from '@/components/chat/markdown-utils'
16
16
  import { TransferAgentPicker } from '@/components/chat/transfer-agent-picker'
17
- import { ConnectorPlatformIcon, CONNECTOR_PLATFORM_META } from '@/components/shared/connector-platform-icon'
17
+ import { ConnectorPlatformIcon, getConnectorPlatformLabel } from '@/components/shared/connector-platform-icon'
18
18
  import type { ChatroomMessage, Chatroom, Agent } from '@/types'
19
19
 
20
20
  interface Props {
@@ -227,7 +227,7 @@ export function ChatroomMessageBubble({ message, agents, onToggleReaction, onRep
227
227
  <span className="text-[13px] font-600 text-text flex items-center gap-1.5">
228
228
  {message.source && <ConnectorPlatformIcon platform={message.source.platform} size={12} />}
229
229
  {isUser && message.source?.senderName
230
- ? `${message.source.senderName} via ${CONNECTOR_PLATFORM_META[message.source.platform]?.label || message.source.platform}`
230
+ ? `${message.source.senderName} via ${getConnectorPlatformLabel(message.source.platform)}`
231
231
  : message.senderName}
232
232
  </span>
233
233
  )}
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'
4
4
  import { useChatroomStore } from '@/stores/use-chatroom-store'
5
5
  import { useAppStore } from '@/stores/use-app-store'
6
6
  import { BottomSheet } from '@/components/shared/bottom-sheet'
7
+ import { ConfirmDialog } from '@/components/shared/confirm-dialog'
7
8
  import { toast } from 'sonner'
8
9
  import { AgentAvatar } from '@/components/agents/agent-avatar'
9
10
  import type { Agent, ChatroomRoutingRule } from '@/types'
@@ -165,6 +166,7 @@ export function ChatroomSheet() {
165
166
  const [saving, setSaving] = useState(false)
166
167
  const [addingRule, setAddingRule] = useState(false)
167
168
  const [editingRuleId, setEditingRuleId] = useState<string | null>(null)
169
+ const [confirmDelete, setConfirmDelete] = useState(false)
168
170
 
169
171
  const editing = editingId ? chatrooms[editingId] : null
170
172
 
@@ -186,6 +188,7 @@ export function ChatroomSheet() {
186
188
  }
187
189
  setAddingRule(false)
188
190
  setEditingRuleId(null)
191
+ setConfirmDelete(false)
189
192
  }, [editing, open])
190
193
 
191
194
  const handleSave = async () => {
@@ -222,11 +225,11 @@ export function ChatroomSheet() {
222
225
 
223
226
  const handleDelete = async () => {
224
227
  if (!editing || saving) return
225
- if (!confirm(`Delete chatroom "${editing.name}"?`)) return
226
228
  setSaving(true)
227
229
  try {
228
230
  await deleteChatroom(editing.id)
229
231
  toast.success('Chatroom deleted')
232
+ setConfirmDelete(false)
230
233
  setChatroomSheetOpen(false)
231
234
  } catch (err: unknown) {
232
235
  toast.error(err instanceof Error ? err.message : 'Failed to delete chatroom')
@@ -503,7 +506,7 @@ export function ChatroomSheet() {
503
506
  </button>
504
507
  {editing && (
505
508
  <button
506
- onClick={handleDelete}
509
+ onClick={() => setConfirmDelete(true)}
507
510
  disabled={saving}
508
511
  className="py-2.5 px-4 rounded-[8px] text-[13px] font-600 text-red-400 hover:bg-red-500/10 transition-all cursor-pointer"
509
512
  >
@@ -512,6 +515,17 @@ export function ChatroomSheet() {
512
515
  )}
513
516
  </div>
514
517
  </div>
518
+ <ConfirmDialog
519
+ open={confirmDelete}
520
+ title="Delete Chatroom?"
521
+ message={editing ? `Delete "${editing.name}"? This removes the chatroom and its configuration.` : 'Delete this chatroom?'}
522
+ confirmLabel={saving ? 'Deleting...' : 'Delete'}
523
+ confirmDisabled={saving}
524
+ cancelDisabled={saving}
525
+ danger
526
+ onConfirm={() => { void handleDelete() }}
527
+ onCancel={() => { if (!saving) setConfirmDelete(false) }}
528
+ />
515
529
  </BottomSheet>
516
530
  )
517
531
  }
@@ -93,7 +93,7 @@ export function ConnectorHealth({ connectorId }: { connectorId: string }) {
93
93
  {/* Vertical line */}
94
94
  <div className="absolute left-[7px] top-2 bottom-2 w-px bg-white/[0.08]" />
95
95
 
96
- <div className="space-y-3">
96
+ <div className="max-h-[320px] overflow-y-auto pr-2 space-y-3 sm:max-h-[38vh]">
97
97
  {recentEvents.map((ev) => {
98
98
  const cfg = EVENT_CONFIG[ev.event] ?? { color: 'bg-white/30', label: ev.event }
99
99
  return (
@@ -6,7 +6,12 @@ import { useChatroomStore } from '@/stores/use-chatroom-store'
6
6
  import { useWs } from '@/hooks/use-ws'
7
7
  import { api } from '@/lib/api-client'
8
8
  import type { Connector } from '@/types'
9
- import { ConnectorPlatformIcon, ConnectorPlatformBadge, CONNECTOR_PLATFORM_META, getConnectorPlatformLabel } from '@/components/shared/connector-platform-icon'
9
+ import {
10
+ ConnectorPlatformIcon,
11
+ ConnectorPlatformBadge,
12
+ getConnectorPlatformLabel,
13
+ resolveConnectorPlatformMeta,
14
+ } from '@/components/shared/connector-platform-icon'
10
15
  import { AgentAvatar } from '@/components/agents/agent-avatar'
11
16
 
12
17
  function relativeTime(ts: number): string {
@@ -181,7 +186,7 @@ export function ConnectorList({ inSidebar }: { inSidebar?: boolean }) {
181
186
  const agent = c.agentId ? agents[c.agentId] : null
182
187
  const chatroom = c.chatroomId ? chatrooms[c.chatroomId] : null
183
188
  const isRunning = c.status === 'running'
184
- const meta = CONNECTOR_PLATFORM_META[c.platform]
189
+ const meta = resolveConnectorPlatformMeta(c.platform)
185
190
  const group = getConnectorGroup(c)
186
191
  return (
187
192
  <button