@swarmclawai/swarmclaw 0.5.2 → 0.6.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 (173) hide show
  1. package/README.md +42 -7
  2. package/bin/swarmclaw.js +76 -16
  3. package/next.config.ts +11 -1
  4. package/package.json +4 -2
  5. package/public/screenshots/agents.png +0 -0
  6. package/public/screenshots/dashboard.png +0 -0
  7. package/public/screenshots/providers.png +0 -0
  8. package/public/screenshots/tasks.png +0 -0
  9. package/scripts/postinstall.mjs +18 -0
  10. package/src/app/api/chatrooms/[id]/chat/route.ts +410 -0
  11. package/src/app/api/chatrooms/[id]/members/route.ts +82 -0
  12. package/src/app/api/chatrooms/[id]/pins/route.ts +39 -0
  13. package/src/app/api/chatrooms/[id]/reactions/route.ts +42 -0
  14. package/src/app/api/chatrooms/[id]/route.ts +84 -0
  15. package/src/app/api/chatrooms/route.ts +50 -0
  16. package/src/app/api/credentials/route.ts +2 -3
  17. package/src/app/api/knowledge/[id]/route.ts +13 -2
  18. package/src/app/api/knowledge/route.ts +8 -1
  19. package/src/app/api/memory/route.ts +8 -0
  20. package/src/app/api/notifications/[id]/route.ts +27 -0
  21. package/src/app/api/notifications/route.ts +68 -0
  22. package/src/app/api/orchestrator/run/route.ts +1 -1
  23. package/src/app/api/plugins/install/route.ts +2 -2
  24. package/src/app/api/search/route.ts +155 -0
  25. package/src/app/api/sessions/[id]/chat/route.ts +2 -0
  26. package/src/app/api/sessions/[id]/edit-resend/route.ts +1 -1
  27. package/src/app/api/sessions/[id]/fork/route.ts +1 -1
  28. package/src/app/api/sessions/route.ts +3 -3
  29. package/src/app/api/settings/route.ts +9 -0
  30. package/src/app/api/setup/check-provider/route.ts +3 -16
  31. package/src/app/api/skills/[id]/route.ts +6 -0
  32. package/src/app/api/skills/route.ts +6 -0
  33. package/src/app/api/tasks/[id]/route.ts +20 -0
  34. package/src/app/api/tasks/bulk/route.ts +100 -0
  35. package/src/app/api/tasks/route.ts +1 -0
  36. package/src/app/api/usage/route.ts +45 -0
  37. package/src/app/api/webhooks/[id]/route.ts +15 -1
  38. package/src/app/globals.css +58 -15
  39. package/src/app/page.tsx +142 -13
  40. package/src/cli/index.js +42 -0
  41. package/src/cli/index.test.js +30 -0
  42. package/src/cli/spec.js +32 -0
  43. package/src/components/agents/agent-avatar.tsx +57 -10
  44. package/src/components/agents/agent-card.tsx +48 -15
  45. package/src/components/agents/agent-chat-list.tsx +123 -10
  46. package/src/components/agents/agent-list.tsx +50 -19
  47. package/src/components/agents/agent-sheet.tsx +56 -63
  48. package/src/components/auth/access-key-gate.tsx +10 -3
  49. package/src/components/auth/setup-wizard.tsx +2 -2
  50. package/src/components/auth/user-picker.tsx +31 -3
  51. package/src/components/chat/activity-moment.tsx +169 -0
  52. package/src/components/chat/chat-header.tsx +2 -0
  53. package/src/components/chat/chat-tool-toggles.tsx +1 -1
  54. package/src/components/chat/file-path-chip.tsx +125 -0
  55. package/src/components/chat/markdown-utils.ts +9 -0
  56. package/src/components/chat/message-bubble.tsx +46 -295
  57. package/src/components/chat/message-list.tsx +50 -1
  58. package/src/components/chat/streaming-bubble.tsx +36 -46
  59. package/src/components/chat/suggestions-bar.tsx +1 -1
  60. package/src/components/chat/thinking-indicator.tsx +72 -10
  61. package/src/components/chat/tool-call-bubble.tsx +66 -70
  62. package/src/components/chat/tool-request-banner.tsx +31 -7
  63. package/src/components/chat/transfer-agent-picker.tsx +63 -0
  64. package/src/components/chatrooms/agent-hover-card.tsx +124 -0
  65. package/src/components/chatrooms/chatroom-input.tsx +320 -0
  66. package/src/components/chatrooms/chatroom-list.tsx +123 -0
  67. package/src/components/chatrooms/chatroom-message.tsx +427 -0
  68. package/src/components/chatrooms/chatroom-sheet.tsx +215 -0
  69. package/src/components/chatrooms/chatroom-tool-request-banner.tsx +134 -0
  70. package/src/components/chatrooms/chatroom-typing-bar.tsx +88 -0
  71. package/src/components/chatrooms/chatroom-view.tsx +344 -0
  72. package/src/components/chatrooms/reaction-picker.tsx +273 -0
  73. package/src/components/connectors/connector-sheet.tsx +34 -47
  74. package/src/components/home/home-view.tsx +501 -0
  75. package/src/components/input/chat-input.tsx +79 -41
  76. package/src/components/knowledge/knowledge-list.tsx +31 -1
  77. package/src/components/knowledge/knowledge-sheet.tsx +83 -2
  78. package/src/components/layout/app-layout.tsx +209 -83
  79. package/src/components/layout/mobile-header.tsx +2 -0
  80. package/src/components/layout/update-banner.tsx +2 -2
  81. package/src/components/logs/log-list.tsx +2 -2
  82. package/src/components/mcp-servers/mcp-server-sheet.tsx +1 -1
  83. package/src/components/memory/memory-agent-list.tsx +143 -0
  84. package/src/components/memory/memory-browser.tsx +205 -0
  85. package/src/components/memory/memory-card.tsx +34 -7
  86. package/src/components/memory/memory-detail.tsx +359 -120
  87. package/src/components/memory/memory-sheet.tsx +157 -23
  88. package/src/components/plugins/plugin-list.tsx +1 -1
  89. package/src/components/plugins/plugin-sheet.tsx +1 -1
  90. package/src/components/projects/project-detail.tsx +509 -0
  91. package/src/components/projects/project-list.tsx +195 -59
  92. package/src/components/providers/provider-list.tsx +2 -2
  93. package/src/components/providers/provider-sheet.tsx +3 -3
  94. package/src/components/schedules/schedule-card.tsx +3 -2
  95. package/src/components/schedules/schedule-list.tsx +1 -1
  96. package/src/components/schedules/schedule-sheet.tsx +25 -25
  97. package/src/components/secrets/secret-sheet.tsx +47 -24
  98. package/src/components/secrets/secrets-list.tsx +18 -8
  99. package/src/components/sessions/new-session-sheet.tsx +33 -65
  100. package/src/components/sessions/session-card.tsx +45 -14
  101. package/src/components/sessions/session-list.tsx +35 -18
  102. package/src/components/shared/agent-picker-list.tsx +90 -0
  103. package/src/components/shared/agent-switch-dialog.tsx +156 -0
  104. package/src/components/shared/attachment-chip.tsx +165 -0
  105. package/src/components/shared/avatar.tsx +10 -1
  106. package/src/components/shared/check-icon.tsx +12 -0
  107. package/src/components/shared/confirm-dialog.tsx +1 -1
  108. package/src/components/shared/empty-state.tsx +32 -0
  109. package/src/components/shared/file-preview.tsx +34 -0
  110. package/src/components/shared/form-styles.ts +2 -0
  111. package/src/components/shared/keyboard-shortcuts-dialog.tsx +116 -0
  112. package/src/components/shared/notification-center.tsx +223 -0
  113. package/src/components/shared/profile-sheet.tsx +115 -0
  114. package/src/components/shared/reply-quote.tsx +26 -0
  115. package/src/components/shared/search-dialog.tsx +296 -0
  116. package/src/components/shared/section-label.tsx +12 -0
  117. package/src/components/shared/settings/plugin-manager.tsx +1 -1
  118. package/src/components/shared/settings/section-providers.tsx +1 -1
  119. package/src/components/shared/settings/section-secrets.tsx +1 -1
  120. package/src/components/shared/settings/section-theme.tsx +95 -0
  121. package/src/components/shared/settings/section-user-preferences.tsx +39 -0
  122. package/src/components/shared/settings/settings-page.tsx +180 -27
  123. package/src/components/shared/settings/settings-sheet.tsx +9 -73
  124. package/src/components/shared/sheet-footer.tsx +33 -0
  125. package/src/components/skills/skill-list.tsx +61 -30
  126. package/src/components/skills/skill-sheet.tsx +81 -2
  127. package/src/components/tasks/task-board.tsx +448 -26
  128. package/src/components/tasks/task-card.tsx +46 -9
  129. package/src/components/tasks/task-column.tsx +62 -3
  130. package/src/components/tasks/task-list.tsx +12 -4
  131. package/src/components/tasks/task-sheet.tsx +89 -72
  132. package/src/components/ui/hover-card.tsx +52 -0
  133. package/src/components/usage/metrics-dashboard.tsx +78 -0
  134. package/src/components/usage/usage-list.tsx +1 -1
  135. package/src/components/webhooks/webhook-sheet.tsx +1 -1
  136. package/src/hooks/use-view-router.ts +69 -19
  137. package/src/instrumentation.ts +15 -1
  138. package/src/lib/chat.ts +2 -0
  139. package/src/lib/cron-human.ts +114 -0
  140. package/src/lib/memory.ts +3 -0
  141. package/src/lib/server/chat-execution.ts +24 -4
  142. package/src/lib/server/connectors/manager.ts +11 -0
  143. package/src/lib/server/context-manager.ts +225 -13
  144. package/src/lib/server/create-notification.ts +42 -0
  145. package/src/lib/server/daemon-state.ts +165 -10
  146. package/src/lib/server/execution-log.ts +1 -0
  147. package/src/lib/server/heartbeat-service.ts +40 -5
  148. package/src/lib/server/heartbeat-wake.ts +110 -0
  149. package/src/lib/server/langgraph-checkpoint.ts +1 -0
  150. package/src/lib/server/memory-consolidation.ts +92 -0
  151. package/src/lib/server/memory-db.ts +51 -6
  152. package/src/lib/server/openclaw-gateway.ts +9 -1
  153. package/src/lib/server/provider-health.ts +125 -0
  154. package/src/lib/server/queue.ts +5 -4
  155. package/src/lib/server/scheduler.ts +8 -0
  156. package/src/lib/server/session-run-manager.ts +4 -0
  157. package/src/lib/server/session-tools/chatroom.ts +136 -0
  158. package/src/lib/server/session-tools/context-mgmt.ts +36 -18
  159. package/src/lib/server/session-tools/index.ts +2 -0
  160. package/src/lib/server/session-tools/memory.ts +6 -1
  161. package/src/lib/server/storage.ts +80 -29
  162. package/src/lib/server/stream-agent-chat.ts +153 -47
  163. package/src/lib/server/system-events.ts +49 -0
  164. package/src/lib/server/ws-hub.ts +11 -0
  165. package/src/lib/soul-suggestions.ts +109 -0
  166. package/src/lib/tasks.ts +4 -1
  167. package/src/lib/view-routes.ts +36 -1
  168. package/src/lib/ws-client.ts +14 -4
  169. package/src/proxy.ts +79 -2
  170. package/src/stores/use-app-store.ts +94 -3
  171. package/src/stores/use-chat-store.ts +48 -3
  172. package/src/stores/use-chatroom-store.ts +276 -0
  173. package/src/types/index.ts +69 -2
@@ -0,0 +1,276 @@
1
+ 'use client'
2
+
3
+ import { create } from 'zustand'
4
+ import { api, getStoredAccessKey } from '@/lib/api-client'
5
+ import type { Chatroom, ChatroomMessage, SSEEvent } from '@/types'
6
+ import type { PendingFile } from '@/stores/use-chat-store'
7
+
8
+ interface ToolEvent {
9
+ name: string
10
+ input: string
11
+ output?: string
12
+ }
13
+
14
+ interface StreamingAgent {
15
+ text: string
16
+ name: string
17
+ error?: string
18
+ toolEvents: ToolEvent[]
19
+ }
20
+
21
+ interface ChatroomState {
22
+ chatrooms: Record<string, Chatroom>
23
+ currentChatroomId: string | null
24
+ streaming: boolean
25
+ streamingAgents: Map<string, StreamingAgent>
26
+ chatroomSheetOpen: boolean
27
+ editingChatroomId: string | null
28
+
29
+ // File uploads
30
+ pendingFiles: PendingFile[]
31
+ addPendingFile: (f: PendingFile) => void
32
+ removePendingFile: (index: number) => void
33
+ clearPendingFiles: () => void
34
+
35
+ // Reply-to
36
+ replyingTo: ChatroomMessage | null
37
+ setReplyingTo: (msg: ChatroomMessage | null) => void
38
+
39
+ loadChatrooms: () => Promise<void>
40
+ createChatroom: (data: { name: string; description?: string; agentIds?: string[]; chatMode?: 'sequential' | 'parallel'; autoAddress?: boolean }) => Promise<Chatroom>
41
+ updateChatroom: (id: string, data: Partial<Chatroom>) => Promise<void>
42
+ deleteChatroom: (id: string) => Promise<void>
43
+ setCurrentChatroom: (id: string | null) => void
44
+ sendMessage: (text: string) => Promise<void>
45
+ toggleReaction: (messageId: string, emoji: string) => Promise<void>
46
+ togglePin: (messageId: string) => Promise<void>
47
+ addMember: (agentId: string) => Promise<void>
48
+ removeMember: (agentId: string) => Promise<void>
49
+ setChatroomSheetOpen: (open: boolean) => void
50
+ setEditingChatroomId: (id: string | null) => void
51
+ }
52
+
53
+ export const useChatroomStore = create<ChatroomState>((set, get) => ({
54
+ chatrooms: {},
55
+ currentChatroomId: null,
56
+ streaming: false,
57
+ streamingAgents: new Map(),
58
+ chatroomSheetOpen: false,
59
+ editingChatroomId: null,
60
+
61
+ // File uploads
62
+ pendingFiles: [],
63
+ addPendingFile: (f) => set((s) => ({ pendingFiles: [...s.pendingFiles, f] })),
64
+ removePendingFile: (index) => set((s) => ({ pendingFiles: s.pendingFiles.filter((_, i) => i !== index) })),
65
+ clearPendingFiles: () => set({ pendingFiles: [] }),
66
+
67
+ // Reply-to
68
+ replyingTo: null,
69
+ setReplyingTo: (msg) => set({ replyingTo: msg }),
70
+
71
+ loadChatrooms: async () => {
72
+ const chatrooms = await api<Record<string, Chatroom>>('GET', '/chatrooms')
73
+ set({ chatrooms })
74
+ },
75
+
76
+ createChatroom: async (data) => {
77
+ const chatroom = await api<Chatroom>('POST', '/chatrooms', data)
78
+ set((s) => ({ chatrooms: { ...s.chatrooms, [chatroom.id]: chatroom } }))
79
+ return chatroom
80
+ },
81
+
82
+ updateChatroom: async (id, data) => {
83
+ const chatroom = await api<Chatroom>('PUT', `/chatrooms/${id}`, data)
84
+ set((s) => ({ chatrooms: { ...s.chatrooms, [id]: chatroom } }))
85
+ },
86
+
87
+ deleteChatroom: async (id) => {
88
+ await api('DELETE', `/chatrooms/${id}`)
89
+ set((s) => {
90
+ const chatrooms = { ...s.chatrooms }
91
+ delete chatrooms[id]
92
+ return {
93
+ chatrooms,
94
+ currentChatroomId: s.currentChatroomId === id ? null : s.currentChatroomId,
95
+ }
96
+ })
97
+ },
98
+
99
+ setCurrentChatroom: (id) => set({ currentChatroomId: id }),
100
+
101
+ sendMessage: async (text) => {
102
+ const { currentChatroomId, streaming, pendingFiles, replyingTo } = get()
103
+ if (!currentChatroomId || streaming || (!text.trim() && !pendingFiles.length)) return
104
+
105
+ set({ streaming: true, streamingAgents: new Map(), pendingFiles: [], replyingTo: null })
106
+
107
+ const imagePath = pendingFiles.length > 0 && pendingFiles[0].file.type.startsWith('image/')
108
+ ? pendingFiles[0].path
109
+ : undefined
110
+ const attachedFiles = pendingFiles.length > 0
111
+ ? pendingFiles.map((f) => f.path)
112
+ : undefined
113
+
114
+ const key = getStoredAccessKey()
115
+ try {
116
+ const res = await fetch(`/api/chatrooms/${currentChatroomId}/chat`, {
117
+ method: 'POST',
118
+ headers: {
119
+ 'Content-Type': 'application/json',
120
+ ...(key ? { 'X-Access-Key': key } : {}),
121
+ },
122
+ body: JSON.stringify({
123
+ text,
124
+ ...(imagePath ? { imagePath } : {}),
125
+ ...(attachedFiles ? { attachedFiles } : {}),
126
+ ...(replyingTo ? { replyToId: replyingTo.id } : {}),
127
+ }),
128
+ })
129
+
130
+ if (!res.ok || !res.body) {
131
+ set({ streaming: false })
132
+ return
133
+ }
134
+
135
+ const reader = res.body.getReader()
136
+ const decoder = new TextDecoder()
137
+ let buf = ''
138
+
139
+ while (true) {
140
+ const { done, value } = await reader.read()
141
+ if (done) break
142
+ buf += decoder.decode(value, { stream: true })
143
+ const lines = buf.split('\n')
144
+ buf = lines.pop() || ''
145
+ for (const line of lines) {
146
+ if (!line.startsWith('data: ')) continue
147
+ try {
148
+ const event = JSON.parse(line.slice(6)) as SSEEvent
149
+ const agentId = event.agentId
150
+ const agentName = event.agentName
151
+
152
+ if (event.t === 'cr_agent_start' && agentId && agentName) {
153
+ set((s) => {
154
+ const agents = new Map(s.streamingAgents)
155
+ agents.set(agentId, { text: '', name: agentName, toolEvents: [] })
156
+ return { streamingAgents: agents }
157
+ })
158
+ } else if (event.t === 'tool_call' && agentId && event.toolName) {
159
+ set((s) => {
160
+ const agents = new Map(s.streamingAgents)
161
+ const existing = agents.get(agentId)
162
+ if (existing) {
163
+ agents.set(agentId, {
164
+ ...existing,
165
+ toolEvents: [...existing.toolEvents, { name: event.toolName!, input: event.toolInput || '' }],
166
+ })
167
+ }
168
+ return { streamingAgents: agents }
169
+ })
170
+ } else if (event.t === 'tool_result' && agentId) {
171
+ set((s) => {
172
+ const agents = new Map(s.streamingAgents)
173
+ const existing = agents.get(agentId)
174
+ if (existing && existing.toolEvents.length > 0) {
175
+ const updatedEvents = [...existing.toolEvents]
176
+ const last = updatedEvents[updatedEvents.length - 1]
177
+ updatedEvents[updatedEvents.length - 1] = { ...last, output: event.toolOutput || event.text || '' }
178
+ agents.set(agentId, { ...existing, toolEvents: updatedEvents })
179
+ }
180
+ return { streamingAgents: agents }
181
+ })
182
+ } else if (event.t === 'd' && agentId && event.text) {
183
+ set((s) => {
184
+ const agents = new Map(s.streamingAgents)
185
+ const existing = agents.get(agentId)
186
+ if (existing) {
187
+ agents.set(agentId, { ...existing, text: existing.text + event.text })
188
+ }
189
+ return { streamingAgents: agents }
190
+ })
191
+ } else if (event.t === 'err' && agentId && event.text) {
192
+ set((s) => {
193
+ const agents = new Map(s.streamingAgents)
194
+ const existing = agents.get(agentId)
195
+ if (existing) {
196
+ agents.set(agentId, { ...existing, error: event.text })
197
+ }
198
+ return { streamingAgents: agents }
199
+ })
200
+ } else if (event.t === 'cr_agent_done' && agentId) {
201
+ const currentAgent = get().streamingAgents.get(agentId)
202
+ if (currentAgent?.error) {
203
+ setTimeout(() => {
204
+ set((s) => {
205
+ const agents = new Map(s.streamingAgents)
206
+ agents.delete(agentId)
207
+ return { streamingAgents: agents }
208
+ })
209
+ }, 4000)
210
+ } else {
211
+ set((s) => {
212
+ const agents = new Map(s.streamingAgents)
213
+ agents.delete(agentId)
214
+ return { streamingAgents: agents }
215
+ })
216
+ }
217
+ try {
218
+ const { currentChatroomId: cid } = get()
219
+ if (cid) {
220
+ const chatroom = await api<Chatroom>('GET', `/chatrooms/${cid}`)
221
+ set((s) => ({ chatrooms: { ...s.chatrooms, [cid]: chatroom } }))
222
+ }
223
+ } catch { /* will catch on next WS push */ }
224
+ } else if (event.t === 'done') {
225
+ break
226
+ }
227
+ } catch {
228
+ // skip malformed
229
+ }
230
+ }
231
+ }
232
+ } finally {
233
+ set({ streaming: false, streamingAgents: new Map() })
234
+ try {
235
+ const { currentChatroomId: cid } = get()
236
+ if (cid) {
237
+ const chatroom = await api<Chatroom>('GET', `/chatrooms/${cid}`)
238
+ set((s) => ({ chatrooms: { ...s.chatrooms, [cid]: chatroom } }))
239
+ }
240
+ } catch { /* ignore */ }
241
+ }
242
+ },
243
+
244
+ toggleReaction: async (messageId, emoji) => {
245
+ const { currentChatroomId } = get()
246
+ if (!currentChatroomId) return
247
+ await api('POST', `/chatrooms/${currentChatroomId}/reactions`, { messageId, emoji })
248
+ const chatroom = await api<Chatroom>('GET', `/chatrooms/${currentChatroomId}`)
249
+ set((s) => ({ chatrooms: { ...s.chatrooms, [currentChatroomId]: chatroom } }))
250
+ },
251
+
252
+ togglePin: async (messageId) => {
253
+ const { currentChatroomId } = get()
254
+ if (!currentChatroomId) return
255
+ await api('POST', `/chatrooms/${currentChatroomId}/pins`, { messageId })
256
+ const chatroom = await api<Chatroom>('GET', `/chatrooms/${currentChatroomId}`)
257
+ set((s) => ({ chatrooms: { ...s.chatrooms, [currentChatroomId]: chatroom } }))
258
+ },
259
+
260
+ addMember: async (agentId) => {
261
+ const { currentChatroomId } = get()
262
+ if (!currentChatroomId) return
263
+ const chatroom = await api<Chatroom>('POST', `/chatrooms/${currentChatroomId}/members`, { agentId })
264
+ set((s) => ({ chatrooms: { ...s.chatrooms, [currentChatroomId]: chatroom } }))
265
+ },
266
+
267
+ removeMember: async (agentId) => {
268
+ const { currentChatroomId } = get()
269
+ if (!currentChatroomId) return
270
+ const chatroom = await api<Chatroom>('DELETE', `/chatrooms/${currentChatroomId}/members`, { agentId })
271
+ set((s) => ({ chatrooms: { ...s.chatrooms, [currentChatroomId]: chatroom } }))
272
+ },
273
+
274
+ setChatroomSheetOpen: (open) => set({ chatroomSheetOpen: open }),
275
+ setEditingChatroomId: (id) => set({ editingChatroomId: id }),
276
+ }))
@@ -17,6 +17,7 @@ export interface Message {
17
17
  suppressed?: boolean
18
18
  bookmarked?: boolean
19
19
  suggestions?: string[]
20
+ replyToId?: string
20
21
  }
21
22
 
22
23
  export type ProviderType = 'claude-cli' | 'codex-cli' | 'opencode-cli' | 'openai' | 'ollama' | 'anthropic' | 'openclaw' | 'google' | 'deepseek' | 'groq' | 'together' | 'mistral' | 'xai' | 'fireworks'
@@ -182,11 +183,13 @@ export interface MarketplacePlugin {
182
183
  }
183
184
 
184
185
  export interface SSEEvent {
185
- t: 'd' | 'md' | 'r' | 'done' | 'err' | 'tool_call' | 'tool_result' | 'status'
186
+ t: 'd' | 'md' | 'r' | 'done' | 'err' | 'tool_call' | 'tool_result' | 'status' | 'thinking' | 'cr_agent_start' | 'cr_agent_done'
186
187
  text?: string
187
188
  toolName?: string
188
189
  toolInput?: string
189
190
  toolOutput?: string
191
+ agentId?: string
192
+ agentName?: string
190
193
  }
191
194
 
192
195
  export interface Directory {
@@ -253,6 +256,9 @@ export interface Agent {
253
256
  thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high'
254
257
  projectId?: string
255
258
  avatarSeed?: string
259
+ pinned?: boolean
260
+ lastUsedAt?: number
261
+ totalCost?: number
256
262
  trashedAt?: number
257
263
  openclawSkillMode?: SkillAllowlistMode
258
264
  openclawAllowedSkills?: string[]
@@ -331,12 +337,50 @@ export interface MemoryEntry {
331
337
  image?: MemoryImage | null
332
338
  imagePath?: string | null
333
339
  linkedMemoryIds?: string[]
340
+ pinned?: boolean
341
+ sharedWith?: string[]
334
342
  createdAt: number
335
343
  updatedAt: number
336
344
  }
337
345
 
338
346
  export type SessionType = 'human' | 'orchestrated'
339
- export type AppView = 'agents' | 'schedules' | 'memory' | 'tasks' | 'secrets' | 'providers' | 'skills' | 'connectors' | 'webhooks' | 'mcp_servers' | 'knowledge' | 'plugins' | 'usage' | 'runs' | 'logs' | 'settings' | 'projects' | 'activity'
347
+ export type AppView = 'home' | 'agents' | 'chatrooms' | 'schedules' | 'memory' | 'tasks' | 'secrets' | 'providers' | 'skills' | 'connectors' | 'webhooks' | 'mcp_servers' | 'knowledge' | 'plugins' | 'usage' | 'runs' | 'logs' | 'settings' | 'projects' | 'activity'
348
+
349
+ // --- Chatrooms ---
350
+
351
+ export interface ChatroomReaction {
352
+ emoji: string
353
+ reactorId: string // 'user' or agentId
354
+ time: number
355
+ }
356
+
357
+ export interface ChatroomMessage {
358
+ id: string
359
+ senderId: string // 'user' or agentId
360
+ senderName: string
361
+ role: 'user' | 'assistant'
362
+ text: string
363
+ mentions: string[] // parsed agentIds
364
+ reactions: ChatroomReaction[]
365
+ toolEvents?: MessageToolEvent[]
366
+ time: number
367
+ attachedFiles?: string[]
368
+ imagePath?: string
369
+ replyToId?: string
370
+ }
371
+
372
+ export interface Chatroom {
373
+ id: string
374
+ name: string
375
+ description?: string
376
+ agentIds: string[]
377
+ messages: ChatroomMessage[]
378
+ pinnedMessageIds?: string[]
379
+ chatMode?: 'sequential' | 'parallel'
380
+ autoAddress?: boolean
381
+ createdAt: number
382
+ updatedAt: number
383
+ }
340
384
 
341
385
  // --- Activity / Audit Trail ---
342
386
 
@@ -375,6 +419,22 @@ export interface Project {
375
419
  updatedAt: number
376
420
  }
377
421
 
422
+ // --- Notifications ---
423
+
424
+ export interface AppNotification {
425
+ id: string
426
+ type: 'info' | 'success' | 'warning' | 'error'
427
+ title: string
428
+ message?: string
429
+ actionLabel?: string
430
+ actionUrl?: string
431
+ entityType?: string
432
+ entityId?: string
433
+ dedupKey?: string
434
+ read: boolean
435
+ createdAt: number
436
+ }
437
+
378
438
  // --- Session Runs ---
379
439
 
380
440
  export type SessionRunStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'
@@ -442,6 +502,7 @@ export interface AppSettings {
442
502
  shellCommandTimeoutSec?: number
443
503
  claudeCodeTimeoutSec?: number
444
504
  cliProcessTimeoutSec?: number
505
+ userAvatarSeed?: string
445
506
  elevenLabsApiKey?: string | null
446
507
  elevenLabsVoiceId?: string | null
447
508
  speechRecognitionLang?: string | null
@@ -486,6 +547,10 @@ export interface AppSettings {
486
547
  memoryMaxPerLookup?: number
487
548
  // Voice conversation
488
549
  voiceAutoSendDelaySec?: number
550
+ // Default agent for main chat on startup
551
+ defaultAgentId?: string | null
552
+ // Theme
553
+ themeHue?: string
489
554
  // Web search provider
490
555
  webSearchProvider?: 'duckduckgo' | 'google' | 'bing' | 'searxng' | 'tavily' | 'brave'
491
556
  searxngUrl?: string
@@ -548,6 +613,8 @@ export interface Skill {
548
613
  description?: string
549
614
  sourceUrl?: string
550
615
  sourceFormat?: 'openclaw' | 'plain'
616
+ scope?: 'global' | 'agent'
617
+ agentIds?: string[]
551
618
  createdAt: number
552
619
  updatedAt: number
553
620
  }