@swarmclawai/swarmclaw 0.6.7 → 0.7.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 (203) hide show
  1. package/README.md +82 -39
  2. package/next.config.ts +31 -6
  3. package/package.json +3 -2
  4. package/src/app/api/agents/[id]/thread/route.ts +1 -0
  5. package/src/app/api/agents/route.ts +19 -5
  6. package/src/app/api/approvals/route.ts +22 -0
  7. package/src/app/api/chatrooms/[id]/chat/route.ts +4 -0
  8. package/src/app/api/clawhub/install/route.ts +2 -2
  9. package/src/app/api/eval/run/route.ts +37 -0
  10. package/src/app/api/eval/scenarios/route.ts +24 -0
  11. package/src/app/api/eval/suite/route.ts +29 -0
  12. package/src/app/api/mcp-servers/[id]/conformance/route.ts +26 -0
  13. package/src/app/api/mcp-servers/[id]/invoke/route.ts +81 -0
  14. package/src/app/api/memory/graph/route.ts +46 -0
  15. package/src/app/api/memory/route.ts +36 -5
  16. package/src/app/api/notifications/route.ts +3 -0
  17. package/src/app/api/plugins/install/route.ts +57 -5
  18. package/src/app/api/plugins/marketplace/route.ts +73 -22
  19. package/src/app/api/plugins/route.ts +61 -1
  20. package/src/app/api/plugins/ui/route.ts +34 -0
  21. package/src/app/api/sessions/[id]/checkpoints/route.ts +31 -0
  22. package/src/app/api/sessions/[id]/restore/route.ts +36 -0
  23. package/src/app/api/settings/route.ts +62 -0
  24. package/src/app/api/setup/doctor/route.ts +22 -5
  25. package/src/app/api/souls/[id]/route.ts +65 -0
  26. package/src/app/api/souls/route.ts +70 -0
  27. package/src/app/api/tasks/[id]/approve/route.ts +4 -3
  28. package/src/app/api/tasks/[id]/route.ts +16 -3
  29. package/src/app/api/tasks/route.ts +10 -2
  30. package/src/app/api/usage/route.ts +9 -2
  31. package/src/app/globals.css +27 -0
  32. package/src/app/page.tsx +10 -5
  33. package/src/cli/index.js +37 -0
  34. package/src/components/activity/activity-feed.tsx +9 -2
  35. package/src/components/agents/agent-avatar.tsx +5 -1
  36. package/src/components/agents/agent-card.tsx +55 -9
  37. package/src/components/agents/agent-sheet.tsx +112 -34
  38. package/src/components/agents/inspector-panel.tsx +1 -1
  39. package/src/components/agents/soul-library-picker.tsx +84 -13
  40. package/src/components/auth/access-key-gate.tsx +63 -54
  41. package/src/components/auth/user-picker.tsx +37 -32
  42. package/src/components/chat/activity-moment.tsx +2 -0
  43. package/src/components/chat/chat-area.tsx +11 -0
  44. package/src/components/chat/chat-header.tsx +69 -25
  45. package/src/components/chat/chat-tool-toggles.tsx +2 -2
  46. package/src/components/chat/checkpoint-timeline.tsx +112 -0
  47. package/src/components/chat/code-block.tsx +3 -1
  48. package/src/components/chat/exec-approval-card.tsx +8 -1
  49. package/src/components/chat/message-bubble.tsx +164 -4
  50. package/src/components/chat/message-list.tsx +46 -4
  51. package/src/components/chat/session-approval-card.tsx +80 -0
  52. package/src/components/chat/session-debug-panel.tsx +106 -84
  53. package/src/components/chat/streaming-bubble.tsx +6 -5
  54. package/src/components/chat/task-approval-card.tsx +78 -0
  55. package/src/components/chat/thinking-indicator.tsx +48 -12
  56. package/src/components/chat/tool-call-bubble.tsx +3 -0
  57. package/src/components/chat/tool-request-banner.tsx +39 -20
  58. package/src/components/chatrooms/chatroom-list.tsx +11 -4
  59. package/src/components/chatrooms/chatroom-sheet.tsx +7 -2
  60. package/src/components/connectors/connector-list.tsx +33 -11
  61. package/src/components/connectors/connector-sheet.tsx +37 -7
  62. package/src/components/home/home-view.tsx +54 -24
  63. package/src/components/input/chat-input.tsx +22 -1
  64. package/src/components/knowledge/knowledge-list.tsx +17 -18
  65. package/src/components/knowledge/knowledge-sheet.tsx +9 -5
  66. package/src/components/layout/app-layout.tsx +87 -19
  67. package/src/components/mcp-servers/mcp-server-list.tsx +352 -50
  68. package/src/components/mcp-servers/mcp-server-sheet.tsx +25 -9
  69. package/src/components/memory/memory-browser.tsx +73 -45
  70. package/src/components/memory/memory-graph-view.tsx +203 -0
  71. package/src/components/memory/memory-list.tsx +20 -13
  72. package/src/components/plugins/plugin-list.tsx +214 -60
  73. package/src/components/plugins/plugin-sheet.tsx +119 -24
  74. package/src/components/projects/project-list.tsx +17 -9
  75. package/src/components/providers/provider-list.tsx +21 -6
  76. package/src/components/providers/provider-sheet.tsx +42 -25
  77. package/src/components/runs/run-list.tsx +17 -13
  78. package/src/components/schedules/schedule-card.tsx +10 -3
  79. package/src/components/schedules/schedule-list.tsx +2 -2
  80. package/src/components/schedules/schedule-sheet.tsx +28 -9
  81. package/src/components/secrets/secret-sheet.tsx +7 -2
  82. package/src/components/secrets/secrets-list.tsx +18 -5
  83. package/src/components/sessions/new-session-sheet.tsx +183 -376
  84. package/src/components/sessions/session-card.tsx +10 -2
  85. package/src/components/settings/gateway-connection-panel.tsx +9 -8
  86. package/src/components/shared/command-palette.tsx +13 -5
  87. package/src/components/shared/empty-state.tsx +20 -8
  88. package/src/components/shared/hint-tip.tsx +31 -0
  89. package/src/components/shared/notification-center.tsx +134 -86
  90. package/src/components/shared/profile-sheet.tsx +4 -0
  91. package/src/components/shared/settings/plugin-manager.tsx +360 -135
  92. package/src/components/shared/settings/section-capability-policy.tsx +3 -3
  93. package/src/components/shared/settings/section-runtime-loop.tsx +149 -4
  94. package/src/components/skills/clawhub-browser.tsx +1 -0
  95. package/src/components/skills/skill-list.tsx +31 -12
  96. package/src/components/skills/skill-sheet.tsx +20 -7
  97. package/src/components/tasks/approvals-panel.tsx +224 -0
  98. package/src/components/tasks/task-board.tsx +20 -12
  99. package/src/components/tasks/task-card.tsx +21 -7
  100. package/src/components/tasks/task-column.tsx +4 -3
  101. package/src/components/tasks/task-list.tsx +1 -1
  102. package/src/components/tasks/task-sheet.tsx +130 -1
  103. package/src/components/ui/dialog.tsx +1 -0
  104. package/src/components/ui/sheet.tsx +1 -0
  105. package/src/components/usage/metrics-dashboard.tsx +72 -48
  106. package/src/components/wallets/wallet-panel.tsx +65 -41
  107. package/src/components/wallets/wallet-section.tsx +9 -3
  108. package/src/components/webhooks/webhook-list.tsx +21 -12
  109. package/src/components/webhooks/webhook-sheet.tsx +13 -3
  110. package/src/lib/approval-display.test.ts +45 -0
  111. package/src/lib/approval-display.ts +62 -0
  112. package/src/lib/clipboard.ts +38 -0
  113. package/src/lib/memory.ts +8 -0
  114. package/src/lib/providers/claude-cli.ts +5 -3
  115. package/src/lib/providers/index.ts +67 -21
  116. package/src/lib/runtime-loop.ts +3 -2
  117. package/src/lib/server/approvals.ts +150 -0
  118. package/src/lib/server/chat-execution.ts +319 -74
  119. package/src/lib/server/chatroom-helpers.ts +63 -5
  120. package/src/lib/server/chatroom-orchestration.ts +74 -0
  121. package/src/lib/server/clawhub-client.ts +82 -6
  122. package/src/lib/server/connectors/manager.ts +27 -1
  123. package/src/lib/server/context-manager.ts +132 -50
  124. package/src/lib/server/cost.test.ts +73 -0
  125. package/src/lib/server/cost.ts +165 -34
  126. package/src/lib/server/daemon-state.ts +112 -1
  127. package/src/lib/server/data-dir.ts +18 -1
  128. package/src/lib/server/eval/runner.ts +126 -0
  129. package/src/lib/server/eval/scenarios.ts +218 -0
  130. package/src/lib/server/eval/scorer.ts +96 -0
  131. package/src/lib/server/eval/store.ts +37 -0
  132. package/src/lib/server/eval/types.ts +48 -0
  133. package/src/lib/server/execution-log.ts +12 -8
  134. package/src/lib/server/guardian.ts +34 -0
  135. package/src/lib/server/heartbeat-service.ts +53 -1
  136. package/src/lib/server/integrity-monitor.ts +208 -0
  137. package/src/lib/server/langgraph-checkpoint.ts +10 -0
  138. package/src/lib/server/link-understanding.ts +55 -0
  139. package/src/lib/server/llm-response-cache.test.ts +102 -0
  140. package/src/lib/server/llm-response-cache.ts +227 -0
  141. package/src/lib/server/main-agent-loop.ts +115 -16
  142. package/src/lib/server/main-session.ts +6 -3
  143. package/src/lib/server/mcp-conformance.test.ts +18 -0
  144. package/src/lib/server/mcp-conformance.ts +233 -0
  145. package/src/lib/server/memory-db.ts +193 -19
  146. package/src/lib/server/memory-retrieval.test.ts +56 -0
  147. package/src/lib/server/mmr.ts +73 -0
  148. package/src/lib/server/orchestrator-lg.ts +7 -1
  149. package/src/lib/server/orchestrator.ts +4 -3
  150. package/src/lib/server/plugins.ts +662 -132
  151. package/src/lib/server/process-manager.ts +18 -0
  152. package/src/lib/server/query-expansion.ts +57 -0
  153. package/src/lib/server/queue.ts +280 -11
  154. package/src/lib/server/runtime-settings.ts +9 -0
  155. package/src/lib/server/session-run-manager.test.ts +23 -0
  156. package/src/lib/server/session-run-manager.ts +32 -2
  157. package/src/lib/server/session-tools/canvas.ts +85 -50
  158. package/src/lib/server/session-tools/chatroom.ts +130 -127
  159. package/src/lib/server/session-tools/connector.ts +233 -454
  160. package/src/lib/server/session-tools/context-mgmt.ts +87 -105
  161. package/src/lib/server/session-tools/crud.ts +84 -7
  162. package/src/lib/server/session-tools/delegate.ts +351 -752
  163. package/src/lib/server/session-tools/discovery.ts +198 -0
  164. package/src/lib/server/session-tools/edit_file.ts +82 -0
  165. package/src/lib/server/session-tools/file-send.test.ts +39 -0
  166. package/src/lib/server/session-tools/file.ts +257 -425
  167. package/src/lib/server/session-tools/git.ts +87 -47
  168. package/src/lib/server/session-tools/http.ts +95 -33
  169. package/src/lib/server/session-tools/index.ts +217 -138
  170. package/src/lib/server/session-tools/memory.ts +154 -239
  171. package/src/lib/server/session-tools/monitor.ts +126 -0
  172. package/src/lib/server/session-tools/normalize-tool-args.test.ts +61 -0
  173. package/src/lib/server/session-tools/normalize-tool-args.ts +48 -0
  174. package/src/lib/server/session-tools/openclaw-nodes.ts +82 -99
  175. package/src/lib/server/session-tools/openclaw-workspace.ts +103 -93
  176. package/src/lib/server/session-tools/platform.ts +86 -0
  177. package/src/lib/server/session-tools/plugin-creator.ts +239 -0
  178. package/src/lib/server/session-tools/sample-ui.ts +97 -0
  179. package/src/lib/server/session-tools/sandbox.ts +175 -148
  180. package/src/lib/server/session-tools/schedule.ts +78 -0
  181. package/src/lib/server/session-tools/session-info.ts +104 -410
  182. package/src/lib/server/session-tools/shell-normalize.test.ts +43 -0
  183. package/src/lib/server/session-tools/shell.ts +171 -143
  184. package/src/lib/server/session-tools/subagent.ts +77 -77
  185. package/src/lib/server/session-tools/wallet.ts +182 -106
  186. package/src/lib/server/session-tools/web.ts +181 -327
  187. package/src/lib/server/storage.ts +36 -0
  188. package/src/lib/server/stream-agent-chat.ts +348 -242
  189. package/src/lib/server/task-quality-gate.test.ts +44 -0
  190. package/src/lib/server/task-quality-gate.ts +67 -0
  191. package/src/lib/server/task-validation.test.ts +78 -0
  192. package/src/lib/server/task-validation.ts +67 -2
  193. package/src/lib/server/tool-aliases.ts +68 -0
  194. package/src/lib/server/tool-capability-policy.ts +24 -5
  195. package/src/lib/server/tool-retry.ts +62 -0
  196. package/src/lib/server/transcript-repair.ts +72 -0
  197. package/src/lib/setup-defaults.ts +1 -0
  198. package/src/lib/tasks.ts +7 -1
  199. package/src/lib/tool-definitions.ts +24 -23
  200. package/src/lib/validation/schemas.ts +13 -0
  201. package/src/lib/view-routes.ts +2 -23
  202. package/src/stores/use-app-store.ts +23 -1
  203. package/src/types/index.ts +155 -10
@@ -3,65 +3,100 @@ import { tool, type StructuredToolInterface } from '@langchain/core/tools'
3
3
  import { loadSessions, saveSessions } from '../storage'
4
4
  import { notify } from '../ws-hub'
5
5
  import type { ToolBuildContext } from './context'
6
+ import type { Plugin, PluginHooks } from '@/types'
7
+ import { getPluginManager } from '../plugins'
8
+ import { normalizeToolInputArgs } from './normalize-tool-args'
6
9
 
7
- export function buildCanvasTools(bctx: ToolBuildContext): StructuredToolInterface[] {
8
- const { ctx, hasTool } = bctx
9
- if (!hasTool('canvas')) return []
10
+ /**
11
+ * Core Canvas Execution Logic
12
+ */
13
+ async function executeCanvasAction(args: Record<string, unknown>, context: { sessionId?: string }) {
14
+ const normalized = normalizeToolInputArgs(args)
15
+ const action = normalized.action as string
16
+ const content = normalized.content as string | undefined
17
+ try {
18
+ const sessionId = context.sessionId
19
+ if (!sessionId) return 'Error: no active session for canvas.'
10
20
 
11
- return [
12
- tool(
13
- async ({ action, content }) => {
14
- try {
15
- const sessionId = ctx?.sessionId
16
- if (!sessionId) return 'Error: no active session for canvas.'
21
+ const sessions = loadSessions()
22
+ const session = sessions[sessionId]
23
+ if (!session) return 'Error: session not found.'
17
24
 
18
- const sessions = loadSessions()
19
- const session = sessions[sessionId]
20
- if (!session) return 'Error: session not found.'
25
+ if (action === 'present') {
26
+ if (!content) return 'Error: content is required for present action.'
27
+ ;(session as Record<string, unknown>).canvasContent = content
28
+ session.lastActiveAt = Date.now()
29
+ sessions[sessionId] = session
30
+ saveSessions(sessions)
31
+ notify(`canvas:${sessionId}`)
32
+ return JSON.stringify({ ok: true, action: 'present', contentLength: content.length })
33
+ }
21
34
 
22
- if (action === 'present') {
23
- if (!content) return 'Error: content is required for present action.'
24
- ;(session as Record<string, unknown>).canvasContent = content
25
- session.lastActiveAt = Date.now()
26
- sessions[sessionId] = session
27
- saveSessions(sessions)
28
- notify(`canvas:${sessionId}`)
29
- return JSON.stringify({ ok: true, action: 'present', contentLength: content.length })
30
- }
35
+ if (action === 'hide') {
36
+ ;(session as Record<string, unknown>).canvasContent = null
37
+ session.lastActiveAt = Date.now()
38
+ sessions[sessionId] = session
39
+ saveSessions(sessions)
40
+ notify(`canvas:${sessionId}`)
41
+ return JSON.stringify({ ok: true, action: 'hide' })
42
+ }
31
43
 
32
- if (action === 'hide') {
33
- ;(session as Record<string, unknown>).canvasContent = null
34
- session.lastActiveAt = Date.now()
35
- sessions[sessionId] = session
36
- saveSessions(sessions)
37
- notify(`canvas:${sessionId}`)
38
- return JSON.stringify({ ok: true, action: 'hide' })
39
- }
44
+ if (action === 'snapshot') {
45
+ const current = (session as Record<string, unknown>).canvasContent
46
+ return JSON.stringify({
47
+ ok: true,
48
+ action: 'snapshot',
49
+ hasContent: !!current,
50
+ contentLength: typeof current === 'string' ? current.length : 0,
51
+ preview: typeof current === 'string' ? current.slice(0, 500) : null,
52
+ })
53
+ }
40
54
 
41
- if (action === 'snapshot') {
42
- const current = (session as Record<string, unknown>).canvasContent
43
- return JSON.stringify({
44
- ok: true,
45
- action: 'snapshot',
46
- hasContent: !!current,
47
- contentLength: typeof current === 'string' ? current.length : 0,
48
- preview: typeof current === 'string' ? current.slice(0, 500) : null,
49
- })
50
- }
55
+ return `Unknown canvas action "${action}".`
56
+ } catch (err: unknown) {
57
+ return `Error: ${err instanceof Error ? err.message : String(err)}`
58
+ }
59
+ }
51
60
 
52
- return `Unknown canvas action "${action}". Valid: present, hide, snapshot`
53
- } catch (err: unknown) {
54
- return `Error: ${err instanceof Error ? err.message : String(err)}`
55
- }
61
+ /**
62
+ * Register as a Built-in Plugin
63
+ */
64
+ const CanvasPlugin: Plugin = {
65
+ name: 'Core Canvas',
66
+ description: 'Present live HTML/CSS/JS content to the user in an interactive canvas panel.',
67
+ hooks: {} as PluginHooks,
68
+ tools: [
69
+ {
70
+ name: 'canvas',
71
+ description: 'Interact with the live canvas panel.',
72
+ parameters: {
73
+ type: 'object',
74
+ properties: {
75
+ action: { type: 'string', enum: ['present', 'hide', 'snapshot'] },
76
+ content: { type: 'string' }
77
+ },
78
+ required: ['action']
56
79
  },
80
+ execute: async (args, context) => executeCanvasAction(args, { sessionId: context.session.id })
81
+ }
82
+ ]
83
+ }
84
+
85
+ getPluginManager().registerBuiltin('canvas', CanvasPlugin)
86
+
87
+ /**
88
+ * Legacy Bridge
89
+ */
90
+ export function buildCanvasTools(bctx: ToolBuildContext): StructuredToolInterface[] {
91
+ if (!bctx.hasTool('canvas')) return []
92
+ return [
93
+ tool(
94
+ async (args) => executeCanvasAction(args, { sessionId: bctx.ctx?.sessionId || undefined }),
57
95
  {
58
96
  name: 'canvas',
59
- description: 'Present live HTML/CSS/JS content to the user in an interactive canvas panel. Use "present" to show content, "hide" to dismiss, "snapshot" to check current state. The canvas renders in a sandboxed iframe alongside the chat.',
60
- schema: z.object({
61
- action: z.enum(['present', 'hide', 'snapshot']).describe('Canvas action to perform'),
62
- content: z.string().optional().describe('HTML content to render (required for "present"). Can include inline CSS and JS.'),
63
- }),
64
- },
65
- ),
97
+ description: CanvasPlugin.tools![0].description,
98
+ schema: z.object({}).passthrough()
99
+ }
100
+ )
66
101
  ]
67
102
  }
@@ -4,142 +4,145 @@ import { loadChatrooms, saveChatrooms, loadAgents } from '../storage'
4
4
  import { genId } from '@/lib/id'
5
5
  import { notify } from '../ws-hub'
6
6
  import type { ToolBuildContext } from './context'
7
- import type { Chatroom } from '@/types'
7
+ import type { Chatroom, Plugin, PluginHooks } from '@/types'
8
+ import { getPluginManager } from '../plugins'
9
+ import { normalizeToolInputArgs } from './normalize-tool-args'
8
10
 
9
- export function buildChatroomTools(bctx: ToolBuildContext): StructuredToolInterface[] {
10
- const tools: StructuredToolInterface[] = []
11
- const { hasTool } = bctx
11
+ /**
12
+ * Core Chatroom Execution Logic
13
+ */
14
+ async function executeChatroomAction(args: Record<string, unknown>, context: { agentId?: string | null }) {
15
+ const normalized = normalizeToolInputArgs(args)
16
+ const action = normalized.action as string
17
+ const chatroomId = (normalized.chatroomId ?? normalized.chatroom_id) as string | undefined
18
+ const name = normalized.name as string | undefined
19
+ const description = normalized.description as string | undefined
20
+ const agentIds = (normalized.agentIds ?? normalized.agent_ids) as string[] | undefined
21
+ const agentId = (normalized.agentId ?? normalized.agent_id) as string | undefined
22
+ const message = (normalized.message ?? normalized.text) as string | undefined
23
+ const chatMode = (normalized.chatMode ?? normalized.chat_mode) as string | undefined
24
+ const autoAddress = (normalized.autoAddress ?? normalized.auto_address) as boolean | undefined
25
+ try {
26
+ const chatrooms = loadChatrooms() as Record<string, Chatroom>
12
27
 
13
- if (hasTool('manage_chatrooms')) {
14
- tools.push(
15
- tool(
16
- async ({ action, chatroomId, name, description, agentIds, agentId, message, chatMode, autoAddress }) => {
17
- try {
18
- const chatrooms = loadChatrooms() as Record<string, Chatroom>
28
+ if (action === 'list_chatrooms') {
29
+ const list = Object.values(chatrooms).map((cr) => ({
30
+ id: cr.id,
31
+ name: cr.name,
32
+ description: cr.description,
33
+ memberCount: cr.agentIds.length,
34
+ messageCount: cr.messages.length,
35
+ }))
36
+ return JSON.stringify(list)
37
+ }
19
38
 
20
- if (action === 'list_chatrooms') {
21
- const list = Object.values(chatrooms).map((cr) => ({
22
- id: cr.id,
23
- name: cr.name,
24
- description: cr.description,
25
- memberCount: cr.agentIds.length,
26
- messageCount: cr.messages.length,
27
- }))
28
- return JSON.stringify(list)
29
- }
39
+ if (action === 'create_chatroom') {
40
+ const id = genId()
41
+ const agents = loadAgents()
42
+ const requestedAgentIds = agentIds || []
43
+ const validAgentIds = requestedAgentIds.filter((aid: string) => !!agents[aid])
44
+
45
+ const chatroom: Chatroom = {
46
+ id,
47
+ name: name || 'New Chatroom',
48
+ description: description || '',
49
+ agentIds: validAgentIds,
50
+ messages: [],
51
+ chatMode: chatMode === 'parallel' ? 'parallel' : 'sequential',
52
+ autoAddress: Boolean(autoAddress),
53
+ createdAt: Date.now(),
54
+ updatedAt: Date.now(),
55
+ }
56
+ chatrooms[id] = chatroom
57
+ saveChatrooms(chatrooms)
58
+ notify('chatrooms')
59
+ return JSON.stringify({ ok: true, chatroom: { id, name: chatroom.name, agentIds: validAgentIds } })
60
+ }
30
61
 
31
- if (action === 'create_chatroom') {
32
- const id = genId()
33
- const agents = loadAgents()
34
- const requestedAgentIds = agentIds || []
35
- const invalidAgentIds = requestedAgentIds.filter((aid: string) => !agents[aid])
36
- if (invalidAgentIds.length > 0) {
37
- return `Error: unknown agent IDs: ${invalidAgentIds.join(', ')}`
38
- }
39
- const validAgentIds = requestedAgentIds
40
- const chatroom: Chatroom = {
41
- id,
42
- name: name || 'New Chatroom',
43
- description: description || '',
44
- agentIds: validAgentIds,
45
- messages: [],
46
- chatMode: chatMode === 'parallel' ? 'parallel' : 'sequential',
47
- autoAddress: Boolean(autoAddress),
48
- createdAt: Date.now(),
49
- updatedAt: Date.now(),
50
- }
51
- chatrooms[id] = chatroom
52
- saveChatrooms(chatrooms)
53
- notify('chatrooms')
54
- return JSON.stringify({ ok: true, chatroom: { id, name: chatroom.name, agentIds: validAgentIds } })
55
- }
62
+ if (!chatroomId) return 'Error: chatroomId is required.'
63
+ const chatroom = chatrooms[chatroomId]
64
+ if (!chatroom) return `Error: chatroom not found.`
56
65
 
57
- if (!chatroomId) return 'Error: chatroomId is required for this action.'
58
- const chatroom = chatrooms[chatroomId]
59
- if (!chatroom) return `Error: chatroom not found: ${chatroomId}`
66
+ if (action === 'add_agent') {
67
+ if (!agentId) return 'Error: agentId required.'
68
+ if (!chatroom.agentIds.includes(agentId)) {
69
+ chatroom.agentIds.push(agentId)
70
+ chatroom.updatedAt = Date.now()
71
+ saveChatrooms(chatrooms)
72
+ notify('chatrooms'); notify(`chatroom:${chatroomId}`)
73
+ }
74
+ return JSON.stringify({ ok: true, agentIds: chatroom.agentIds })
75
+ }
60
76
 
61
- if (action === 'add_agent') {
62
- if (!agentId) return 'Error: agentId is required.'
63
- const agents = loadAgents()
64
- if (!agents[agentId]) return `Error: agent not found: ${agentId}`
65
- if (!chatroom.agentIds.includes(agentId)) {
66
- chatroom.agentIds.push(agentId)
67
- chatroom.updatedAt = Date.now()
68
- chatrooms[chatroomId] = chatroom
69
- saveChatrooms(chatrooms)
70
- notify('chatrooms')
71
- notify(`chatroom:${chatroomId}`)
72
- }
73
- return JSON.stringify({ ok: true, agentIds: chatroom.agentIds })
74
- }
77
+ if (action === 'send_message') {
78
+ if (!message) return 'Error: message required.'
79
+ const msgId = genId()
80
+ const agents = loadAgents()
81
+ const senderName = context.agentId ? (agents[context.agentId]?.name || 'Agent') : 'Agent'
82
+ chatroom.messages.push({
83
+ id: msgId,
84
+ senderId: context.agentId || 'agent',
85
+ senderName,
86
+ role: 'assistant' as const,
87
+ text: message,
88
+ mentions: [],
89
+ reactions: [],
90
+ time: Date.now(),
91
+ })
92
+ chatroom.updatedAt = Date.now()
93
+ saveChatrooms(chatrooms)
94
+ notify(`chatroom:${chatroomId}`)
95
+ return JSON.stringify({ ok: true, messageId: msgId })
96
+ }
75
97
 
76
- if (action === 'remove_agent') {
77
- if (!agentId) return 'Error: agentId is required.'
78
- chatroom.agentIds = chatroom.agentIds.filter((id: string) => id !== agentId)
79
- chatroom.updatedAt = Date.now()
80
- chatrooms[chatroomId] = chatroom
81
- saveChatrooms(chatrooms)
82
- notify('chatrooms')
83
- notify(`chatroom:${chatroomId}`)
84
- return JSON.stringify({ ok: true, agentIds: chatroom.agentIds })
85
- }
98
+ return `Unknown action "${action}".`
99
+ } catch (err: unknown) {
100
+ return `Error: ${err instanceof Error ? err.message : String(err)}`
101
+ }
102
+ }
86
103
 
87
- if (action === 'list_members') {
88
- const agents = loadAgents()
89
- const members = chatroom.agentIds.map((id: string) => {
90
- const agent = agents[id]
91
- return agent ? { id, name: agent.name, description: agent.description } : { id, name: 'Unknown' }
92
- })
93
- return JSON.stringify(members)
94
- }
104
+ /**
105
+ * Register as a Built-in Plugin
106
+ */
107
+ const ChatroomPlugin: Plugin = {
108
+ name: 'Core Chatrooms',
109
+ description: 'Manage SwarmClaw routing rules and multi-agent chatrooms.',
110
+ hooks: {} as PluginHooks,
111
+ tools: [
112
+ {
113
+ name: 'manage_chatrooms',
114
+ description: 'Manage multi-agent chatrooms and collaboration.',
115
+ parameters: {
116
+ type: 'object',
117
+ properties: {
118
+ action: { type: 'string', enum: ['list_chatrooms', 'create_chatroom', 'add_agent', 'remove_agent', 'list_members', 'send_message'] },
119
+ chatroomId: { type: 'string' },
120
+ name: { type: 'string' },
121
+ agentId: { type: 'string' },
122
+ message: { type: 'string' }
123
+ },
124
+ required: ['action']
125
+ },
126
+ execute: async (args, context) => executeChatroomAction(args, { agentId: context.session.agentId })
127
+ }
128
+ ]
129
+ }
95
130
 
96
- if (action === 'send_message') {
97
- if (!message) return 'Error: message is required.'
98
- const msgId = genId()
99
- const senderName = bctx.ctx?.agentId
100
- ? (loadAgents()[bctx.ctx.agentId]?.name || 'Agent')
101
- : 'Agent'
102
- chatroom.messages.push({
103
- id: msgId,
104
- senderId: bctx.ctx?.agentId || 'agent',
105
- senderName,
106
- role: 'assistant' as const,
107
- text: message,
108
- mentions: [],
109
- reactions: [],
110
- time: Date.now(),
111
- })
112
- chatroom.updatedAt = Date.now()
113
- chatrooms[chatroomId] = chatroom
114
- saveChatrooms(chatrooms)
115
- notify(`chatroom:${chatroomId}`)
116
- return JSON.stringify({ ok: true, messageId: msgId })
117
- }
131
+ getPluginManager().registerBuiltin('chatroom', ChatroomPlugin)
118
132
 
119
- return `Error: unknown action "${action}". Valid actions: list_chatrooms, create_chatroom, add_agent, remove_agent, list_members, send_message`
120
- } catch (err: unknown) {
121
- return `Error: ${err instanceof Error ? err.message : String(err)}`
122
- }
123
- },
124
- {
125
- name: 'manage_chatrooms',
126
- description: 'Manage chatrooms for multi-agent collaboration. Actions: list_chatrooms, create_chatroom, add_agent, remove_agent, list_members, send_message.',
127
- schema: z.object({
128
- action: z.enum(['list_chatrooms', 'create_chatroom', 'add_agent', 'remove_agent', 'list_members', 'send_message'])
129
- .describe('The action to perform'),
130
- chatroomId: z.string().optional().describe('Chatroom ID (required for most actions except list/create)'),
131
- name: z.string().optional().describe('Chatroom name (for create_chatroom)'),
132
- description: z.string().optional().describe('Chatroom description (for create_chatroom)'),
133
- agentIds: z.array(z.string()).optional().describe('Initial agent IDs (for create_chatroom)'),
134
- chatMode: z.enum(['sequential', 'parallel']).optional().describe('Optional orchestration mode for create_chatroom'),
135
- autoAddress: z.boolean().optional().describe('Whether to auto-address all members when no @mention is present'),
136
- agentId: z.string().optional().describe('Agent ID (for add_agent/remove_agent)'),
137
- message: z.string().optional().describe('Message text (for send_message)'),
138
- }),
139
- },
140
- ),
133
+ /**
134
+ * Legacy Bridge
135
+ */
136
+ export function buildChatroomTools(bctx: ToolBuildContext): StructuredToolInterface[] {
137
+ if (!bctx.hasTool('manage_chatrooms')) return []
138
+ return [
139
+ tool(
140
+ async (args) => executeChatroomAction(args, { agentId: bctx.ctx?.agentId }),
141
+ {
142
+ name: 'manage_chatrooms',
143
+ description: ChatroomPlugin.tools![0].description,
144
+ schema: z.object({}).passthrough()
145
+ }
141
146
  )
142
- }
143
-
144
- return tools
147
+ ]
145
148
  }