@swarmclawai/swarmclaw 0.8.4 → 0.8.7

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 (394) hide show
  1. package/README.md +9 -9
  2. package/bin/swarmclaw.js +5 -1
  3. package/bin/worker-cmd.js +73 -0
  4. package/package.json +2 -1
  5. package/src/app/api/agents/[id]/route.ts +17 -7
  6. package/src/app/api/agents/route.ts +21 -8
  7. package/src/app/api/approvals/route.test.ts +6 -6
  8. package/src/app/api/approvals/route.ts +2 -1
  9. package/src/app/api/auth/route.ts +2 -3
  10. package/src/app/api/chatrooms/[id]/chat/route.test.ts +299 -0
  11. package/src/app/api/chatrooms/[id]/chat/route.ts +3 -2
  12. package/src/app/api/chatrooms/[id]/route.ts +7 -6
  13. package/src/app/api/chats/[id]/chat/route.test.ts +496 -0
  14. package/src/app/api/chats/[id]/chat/route.ts +7 -3
  15. package/src/app/api/chats/[id]/clear/route.ts +9 -9
  16. package/src/app/api/chats/[id]/devserver/route.ts +2 -1
  17. package/src/app/api/chats/[id]/edit-resend/route.ts +3 -4
  18. package/src/app/api/chats/[id]/fork/route.ts +3 -5
  19. package/src/app/api/chats/[id]/restore/route.ts +6 -7
  20. package/src/app/api/chats/[id]/retry/route.ts +3 -4
  21. package/src/app/api/chats/[id]/route.ts +61 -62
  22. package/src/app/api/chats/route.ts +7 -1
  23. package/src/app/api/connectors/[id]/route.ts +7 -8
  24. package/src/app/api/connectors/route.ts +5 -4
  25. package/src/app/api/eval/run/route.ts +2 -1
  26. package/src/app/api/eval/suite/route.ts +2 -1
  27. package/src/app/api/external-agents/route.test.ts +1 -1
  28. package/src/app/api/external-agents/route.ts +2 -2
  29. package/src/app/api/files/serve/route.ts +1 -1
  30. package/src/app/api/gateways/[id]/route.ts +7 -5
  31. package/src/app/api/gateways/route.ts +1 -1
  32. package/src/app/api/knowledge/upload/route.ts +1 -1
  33. package/src/app/api/logs/route.ts +5 -7
  34. package/src/app/api/memory-images/[filename]/route.ts +2 -3
  35. package/src/app/api/openclaw/agent-files/route.ts +4 -3
  36. package/src/app/api/openclaw/approvals/route.ts +3 -4
  37. package/src/app/api/openclaw/config-sync/route.ts +3 -2
  38. package/src/app/api/openclaw/cron/route.ts +3 -2
  39. package/src/app/api/openclaw/dotenv-keys/route.ts +2 -1
  40. package/src/app/api/openclaw/exec-config/route.ts +3 -2
  41. package/src/app/api/openclaw/gateway/route.ts +5 -4
  42. package/src/app/api/openclaw/history/route.ts +3 -2
  43. package/src/app/api/openclaw/media/route.ts +2 -1
  44. package/src/app/api/openclaw/permissions/route.ts +3 -2
  45. package/src/app/api/openclaw/sandbox-env/route.ts +3 -2
  46. package/src/app/api/openclaw/skills/install/route.ts +2 -1
  47. package/src/app/api/openclaw/skills/remove/route.ts +2 -1
  48. package/src/app/api/openclaw/skills/route.ts +3 -2
  49. package/src/app/api/orchestrator/run/route.ts +5 -14
  50. package/src/app/api/perf/route.ts +43 -0
  51. package/src/app/api/plugins/dependencies/route.ts +2 -1
  52. package/src/app/api/plugins/install/route.ts +2 -1
  53. package/src/app/api/plugins/marketplace/route.ts +3 -2
  54. package/src/app/api/plugins/settings/route.ts +2 -1
  55. package/src/app/api/preview-server/route.ts +11 -10
  56. package/src/app/api/projects/[id]/route.ts +1 -1
  57. package/src/app/api/schedules/[id]/route.test.ts +128 -0
  58. package/src/app/api/schedules/[id]/route.ts +43 -43
  59. package/src/app/api/schedules/[id]/run/route.ts +11 -62
  60. package/src/app/api/schedules/route.ts +21 -87
  61. package/src/app/api/settings/route.ts +2 -0
  62. package/src/app/api/setup/doctor/route.ts +9 -8
  63. package/src/app/api/tasks/[id]/approve/route.ts +33 -30
  64. package/src/app/api/tasks/[id]/route.ts +12 -35
  65. package/src/app/api/tasks/import/github/route.ts +2 -1
  66. package/src/app/api/tasks/route.ts +79 -91
  67. package/src/app/api/wallets/[id]/approve/route.ts +2 -1
  68. package/src/app/api/wallets/[id]/route.ts +13 -19
  69. package/src/app/api/wallets/[id]/send/route.ts +2 -1
  70. package/src/app/api/wallets/route.ts +2 -1
  71. package/src/app/api/webhooks/[id]/route.ts +2 -1
  72. package/src/app/api/webhooks/route.test.ts +3 -1
  73. package/src/app/page.tsx +23 -331
  74. package/src/cli/index.js +19 -0
  75. package/src/cli/index.ts +38 -7
  76. package/src/cli/spec.js +9 -0
  77. package/src/components/activity/activity-feed.tsx +7 -4
  78. package/src/components/agents/agent-card.tsx +32 -6
  79. package/src/components/agents/agent-chat-list.tsx +55 -22
  80. package/src/components/agents/agent-files-editor.tsx +3 -2
  81. package/src/components/agents/agent-sheet.tsx +123 -22
  82. package/src/components/agents/inspector-panel.tsx +1 -1
  83. package/src/components/agents/openclaw-skills-panel.tsx +2 -1
  84. package/src/components/agents/trash-list.tsx +1 -1
  85. package/src/components/auth/access-key-gate.tsx +8 -2
  86. package/src/components/auth/setup-wizard.tsx +10 -9
  87. package/src/components/auth/user-picker.tsx +3 -2
  88. package/src/components/chat/chat-area.tsx +20 -1
  89. package/src/components/chat/chat-card.tsx +18 -3
  90. package/src/components/chat/chat-header.tsx +24 -4
  91. package/src/components/chat/chat-list.tsx +2 -11
  92. package/src/components/chat/heartbeat-history-panel.tsx +2 -1
  93. package/src/components/chat/message-bubble.tsx +45 -6
  94. package/src/components/chat/message-list.tsx +280 -145
  95. package/src/components/chat/streaming-bubble.tsx +217 -60
  96. package/src/components/chat/swarm-panel.test.ts +274 -0
  97. package/src/components/chat/swarm-panel.tsx +410 -0
  98. package/src/components/chat/swarm-status-card.tsx +346 -0
  99. package/src/components/chat/tool-call-bubble.tsx +48 -23
  100. package/src/components/chatrooms/chatroom-list.tsx +8 -5
  101. package/src/components/chatrooms/chatroom-message.tsx +10 -7
  102. package/src/components/chatrooms/chatroom-view.tsx +12 -9
  103. package/src/components/connectors/connector-health.tsx +6 -4
  104. package/src/components/connectors/connector-list.tsx +16 -11
  105. package/src/components/connectors/connector-sheet.tsx +12 -6
  106. package/src/components/home/home-view.tsx +38 -24
  107. package/src/components/input/chat-input.tsx +10 -1
  108. package/src/components/layout/app-layout.tsx +2 -38
  109. package/src/components/layout/sheet-layer.tsx +50 -0
  110. package/src/components/mcp-servers/mcp-server-list.tsx +37 -5
  111. package/src/components/mcp-servers/mcp-server-sheet.tsx +12 -2
  112. package/src/components/plugins/plugin-list.tsx +8 -4
  113. package/src/components/plugins/plugin-sheet.tsx +2 -1
  114. package/src/components/providers/provider-list.tsx +3 -2
  115. package/src/components/providers/provider-sheet.tsx +2 -1
  116. package/src/components/runs/run-list.tsx +11 -7
  117. package/src/components/schedules/schedule-card.tsx +5 -3
  118. package/src/components/shared/agent-switch-dialog.tsx +1 -1
  119. package/src/components/shared/attachment-chip.tsx +19 -3
  120. package/src/components/shared/notification-center.tsx +6 -3
  121. package/src/components/shared/settings/plugin-manager.tsx +3 -2
  122. package/src/components/shared/settings/section-embedding.tsx +2 -1
  123. package/src/components/shared/settings/section-orchestrator.tsx +2 -1
  124. package/src/components/shared/settings/section-user-preferences.tsx +107 -0
  125. package/src/components/shared/settings/settings-page.tsx +13 -9
  126. package/src/components/skills/clawhub-browser.tsx +15 -4
  127. package/src/components/skills/skill-list.tsx +15 -4
  128. package/src/components/tasks/approvals-panel.tsx +2 -1
  129. package/src/components/tasks/task-board.tsx +35 -37
  130. package/src/components/tasks/task-sheet.tsx +4 -3
  131. package/src/components/ui/full-screen-loader.tsx +164 -0
  132. package/src/components/wallets/wallet-approval-dialog.tsx +2 -1
  133. package/src/components/wallets/wallet-panel.tsx +6 -5
  134. package/src/components/wallets/wallet-section.tsx +3 -2
  135. package/src/components/webhooks/webhook-list.tsx +4 -5
  136. package/src/components/webhooks/webhook-sheet.tsx +6 -6
  137. package/src/hooks/use-app-bootstrap.ts +202 -0
  138. package/src/hooks/use-mounted-ref.ts +14 -0
  139. package/src/hooks/use-now.ts +31 -0
  140. package/src/hooks/use-openclaw-gateway.ts +2 -1
  141. package/src/instrumentation.ts +20 -8
  142. package/src/lib/agent-default-tools.test.ts +52 -0
  143. package/src/lib/agent-default-tools.ts +40 -0
  144. package/src/lib/api-client.test.ts +21 -0
  145. package/src/lib/api-client.ts +6 -11
  146. package/src/lib/canvas-content.test.ts +360 -0
  147. package/src/lib/chat-streaming-state.test.ts +49 -2
  148. package/src/lib/chat-streaming-state.ts +26 -10
  149. package/src/lib/fetch-timeout.test.ts +54 -0
  150. package/src/lib/fetch-timeout.ts +60 -3
  151. package/src/lib/live-tool-events.test.ts +77 -0
  152. package/src/lib/live-tool-events.ts +73 -0
  153. package/src/lib/local-observability.test.ts +2 -2
  154. package/src/lib/openclaw-endpoint.test.ts +1 -1
  155. package/src/lib/providers/anthropic.ts +12 -16
  156. package/src/lib/providers/index.ts +4 -2
  157. package/src/lib/providers/ollama.ts +9 -6
  158. package/src/lib/providers/openai.ts +11 -14
  159. package/src/lib/runtime-env.test.ts +8 -8
  160. package/src/lib/schedule-dedupe-advanced.test.ts +2 -2
  161. package/src/lib/schedule-dedupe.test.ts +1 -1
  162. package/src/lib/schedule-dedupe.ts +3 -2
  163. package/src/lib/server/agent-thread-session.test.ts +6 -6
  164. package/src/lib/server/agent-thread-session.ts +6 -9
  165. package/src/lib/server/alert-dispatch.ts +2 -1
  166. package/src/lib/server/api-routes.test.ts +6 -6
  167. package/src/lib/server/approval-connector-notify.test.ts +4 -4
  168. package/src/lib/server/approvals-auto-approve.test.ts +29 -29
  169. package/src/lib/server/approvals.test.ts +317 -0
  170. package/src/lib/server/approvals.ts +5 -4
  171. package/src/lib/server/autonomy-runtime.test.ts +11 -11
  172. package/src/lib/server/browser-state.ts +2 -2
  173. package/src/lib/server/capability-router.test.ts +1 -1
  174. package/src/lib/server/capability-router.ts +3 -2
  175. package/src/lib/server/chat-execution-advanced.test.ts +15 -2
  176. package/src/lib/server/chat-execution-connector-delivery.ts +67 -0
  177. package/src/lib/server/chat-execution-disabled.test.ts +3 -3
  178. package/src/lib/server/chat-execution-eval-history.test.ts +3 -3
  179. package/src/lib/server/chat-execution-heartbeat.test.ts +42 -1
  180. package/src/lib/server/chat-execution-session-sync.test.ts +119 -0
  181. package/src/lib/server/chat-execution-tool-events.ts +116 -0
  182. package/src/lib/server/chat-execution-utils.test.ts +479 -0
  183. package/src/lib/server/chat-execution-utils.ts +533 -0
  184. package/src/lib/server/chat-execution.ts +153 -748
  185. package/src/lib/server/chat-streaming-utils.ts +174 -0
  186. package/src/lib/server/chat-turn-tool-routing.ts +310 -0
  187. package/src/lib/server/chatroom-session-persistence.test.ts +2 -2
  188. package/src/lib/server/clawhub-client.ts +2 -1
  189. package/src/lib/server/collection-helpers.test.ts +92 -0
  190. package/src/lib/server/collection-helpers.ts +25 -3
  191. package/src/lib/server/connectors/access.ts +146 -0
  192. package/src/lib/server/connectors/bluebubbles.test.ts +1 -1
  193. package/src/lib/server/connectors/bluebubbles.ts +4 -4
  194. package/src/lib/server/connectors/commands.ts +367 -0
  195. package/src/lib/server/connectors/connector-routing.test.ts +4 -4
  196. package/src/lib/server/connectors/delivery.ts +142 -0
  197. package/src/lib/server/connectors/discord.ts +37 -40
  198. package/src/lib/server/connectors/email.ts +11 -10
  199. package/src/lib/server/connectors/googlechat.ts +4 -4
  200. package/src/lib/server/connectors/inbound-audio-transcription.ts +2 -1
  201. package/src/lib/server/connectors/ingress-delivery.ts +23 -0
  202. package/src/lib/server/connectors/manager-roundtrip.test.ts +300 -0
  203. package/src/lib/server/connectors/manager.test.ts +352 -77
  204. package/src/lib/server/connectors/manager.ts +134 -673
  205. package/src/lib/server/connectors/matrix.ts +4 -4
  206. package/src/lib/server/connectors/message-sentinel.ts +7 -0
  207. package/src/lib/server/connectors/openclaw.test.ts +1 -1
  208. package/src/lib/server/connectors/openclaw.ts +8 -10
  209. package/src/lib/server/connectors/outbox.test.ts +192 -0
  210. package/src/lib/server/connectors/outbox.ts +369 -0
  211. package/src/lib/server/connectors/pairing.test.ts +18 -1
  212. package/src/lib/server/connectors/pairing.ts +49 -4
  213. package/src/lib/server/connectors/policy.ts +9 -3
  214. package/src/lib/server/connectors/reconnect-state.ts +71 -0
  215. package/src/lib/server/connectors/response-media.ts +256 -0
  216. package/src/lib/server/connectors/runtime-state.ts +67 -0
  217. package/src/lib/server/connectors/session.test.ts +357 -0
  218. package/src/lib/server/connectors/session.ts +422 -0
  219. package/src/lib/server/connectors/signal.ts +7 -7
  220. package/src/lib/server/connectors/slack.ts +43 -43
  221. package/src/lib/server/connectors/teams.ts +4 -4
  222. package/src/lib/server/connectors/telegram.ts +37 -43
  223. package/src/lib/server/connectors/types.ts +31 -1
  224. package/src/lib/server/connectors/whatsapp.test.ts +108 -0
  225. package/src/lib/server/connectors/whatsapp.ts +106 -34
  226. package/src/lib/server/context-manager.test.ts +409 -0
  227. package/src/lib/server/cost.test.ts +1 -1
  228. package/src/lib/server/daemon-policy.ts +78 -0
  229. package/src/lib/server/daemon-state-connectors.test.ts +167 -0
  230. package/src/lib/server/daemon-state.test.ts +283 -55
  231. package/src/lib/server/daemon-state.ts +106 -109
  232. package/src/lib/server/data-dir.test.ts +5 -5
  233. package/src/lib/server/data-dir.ts +4 -0
  234. package/src/lib/server/delegation-jobs-advanced.test.ts +1 -1
  235. package/src/lib/server/delegation-jobs.test.ts +87 -0
  236. package/src/lib/server/delegation-jobs.ts +42 -48
  237. package/src/lib/server/devserver-launch.ts +1 -1
  238. package/src/lib/server/document-utils.ts +7 -9
  239. package/src/lib/server/elevenlabs.ts +2 -1
  240. package/src/lib/server/embeddings.test.ts +105 -0
  241. package/src/lib/server/ethereum.ts +3 -2
  242. package/src/lib/server/eval/agent-regression.ts +3 -2
  243. package/src/lib/server/eval/runner.ts +2 -1
  244. package/src/lib/server/eval/scorer.ts +2 -1
  245. package/src/lib/server/evm-swap.ts +2 -1
  246. package/src/lib/server/gateway/protocol.test.ts +1 -1
  247. package/src/lib/server/guardian.ts +2 -1
  248. package/src/lib/server/heartbeat-blocked-suppression.test.ts +151 -0
  249. package/src/lib/server/heartbeat-service-timer.test.ts +6 -6
  250. package/src/lib/server/heartbeat-service.test.ts +406 -0
  251. package/src/lib/server/heartbeat-service.ts +54 -7
  252. package/src/lib/server/heartbeat-wake.test.ts +19 -0
  253. package/src/lib/server/heartbeat-wake.ts +17 -16
  254. package/src/lib/server/integrity-monitor.test.ts +149 -0
  255. package/src/lib/server/json-utils.ts +22 -0
  256. package/src/lib/server/knowledge-db.test.ts +13 -13
  257. package/src/lib/server/link-understanding.ts +2 -1
  258. package/src/lib/server/llm-response-cache.test.ts +1 -1
  259. package/src/lib/server/main-agent-loop-advanced.test.ts +65 -3
  260. package/src/lib/server/main-agent-loop.test.ts +6 -6
  261. package/src/lib/server/main-agent-loop.ts +21 -7
  262. package/src/lib/server/mcp-client.test.ts +1 -1
  263. package/src/lib/server/mcp-conformance.test.ts +1 -1
  264. package/src/lib/server/mcp-conformance.ts +3 -2
  265. package/src/lib/server/memory-consolidation.ts +2 -1
  266. package/src/lib/server/memory-db.test.ts +485 -0
  267. package/src/lib/server/memory-db.ts +39 -26
  268. package/src/lib/server/memory-graph.test.ts +2 -2
  269. package/src/lib/server/memory-policy.test.ts +7 -7
  270. package/src/lib/server/memory-retrieval.test.ts +1 -1
  271. package/src/lib/server/openclaw-config-sync.ts +2 -1
  272. package/src/lib/server/openclaw-deploy.test.ts +1 -1
  273. package/src/lib/server/openclaw-deploy.ts +8 -12
  274. package/src/lib/server/openclaw-exec-config.ts +2 -1
  275. package/src/lib/server/openclaw-gateway.ts +6 -7
  276. package/src/lib/server/openclaw-skills-normalize.ts +2 -1
  277. package/src/lib/server/openclaw-sync.ts +7 -5
  278. package/src/lib/server/orchestrator-lg-structure.test.ts +17 -0
  279. package/src/lib/server/orchestrator-lg.ts +199 -327
  280. package/src/lib/server/path-utils.ts +31 -0
  281. package/src/lib/server/perf.ts +161 -0
  282. package/src/lib/server/plugins-approval-guidance.ts +115 -0
  283. package/src/lib/server/plugins.test.ts +1 -1
  284. package/src/lib/server/plugins.ts +22 -132
  285. package/src/lib/server/process-manager.ts +5 -8
  286. package/src/lib/server/provider-health.test.ts +137 -0
  287. package/src/lib/server/provider-health.ts +3 -3
  288. package/src/lib/server/provider-model-discovery.ts +3 -12
  289. package/src/lib/server/queue-followups.test.ts +9 -9
  290. package/src/lib/server/queue-reconcile.test.ts +2 -2
  291. package/src/lib/server/queue-recovery.test.ts +269 -0
  292. package/src/lib/server/queue.test.ts +570 -0
  293. package/src/lib/server/queue.ts +62 -455
  294. package/src/lib/server/resolve-image.ts +30 -0
  295. package/src/lib/server/runtime-settings.test.ts +4 -4
  296. package/src/lib/server/runtime-storage-write-paths.test.ts +60 -0
  297. package/src/lib/server/schedule-normalization.test.ts +279 -0
  298. package/src/lib/server/schedule-service.ts +263 -0
  299. package/src/lib/server/scheduler.ts +17 -74
  300. package/src/lib/server/session-mailbox.test.ts +191 -0
  301. package/src/lib/server/session-run-manager.test.ts +640 -0
  302. package/src/lib/server/session-run-manager.ts +59 -15
  303. package/src/lib/server/session-tools/autonomy-tools.test.ts +20 -20
  304. package/src/lib/server/session-tools/calendar.ts +2 -1
  305. package/src/lib/server/session-tools/canvas.ts +2 -1
  306. package/src/lib/server/session-tools/chatroom.ts +2 -1
  307. package/src/lib/server/session-tools/connector.ts +26 -28
  308. package/src/lib/server/session-tools/context-mgmt.ts +3 -2
  309. package/src/lib/server/session-tools/crawl.ts +4 -3
  310. package/src/lib/server/session-tools/crud.ts +105 -324
  311. package/src/lib/server/session-tools/delegate-fallback.test.ts +9 -9
  312. package/src/lib/server/session-tools/delegate.ts +6 -8
  313. package/src/lib/server/session-tools/discovery-approvals.test.ts +15 -15
  314. package/src/lib/server/session-tools/discovery.ts +4 -3
  315. package/src/lib/server/session-tools/document.ts +2 -1
  316. package/src/lib/server/session-tools/email.ts +2 -1
  317. package/src/lib/server/session-tools/extract.ts +2 -1
  318. package/src/lib/server/session-tools/file.ts +4 -3
  319. package/src/lib/server/session-tools/http.ts +2 -1
  320. package/src/lib/server/session-tools/human-loop.ts +2 -1
  321. package/src/lib/server/session-tools/image-gen.ts +4 -3
  322. package/src/lib/server/session-tools/index.ts +26 -30
  323. package/src/lib/server/session-tools/mailbox.ts +2 -1
  324. package/src/lib/server/session-tools/manage-connectors.test.ts +4 -4
  325. package/src/lib/server/session-tools/manage-schedules.test.ts +12 -12
  326. package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +5 -5
  327. package/src/lib/server/session-tools/manage-tasks.test.ts +2 -2
  328. package/src/lib/server/session-tools/monitor.ts +2 -1
  329. package/src/lib/server/session-tools/platform.ts +2 -1
  330. package/src/lib/server/session-tools/plugin-creator.ts +2 -1
  331. package/src/lib/server/session-tools/replicate.ts +3 -2
  332. package/src/lib/server/session-tools/session-tools-wiring.test.ts +6 -6
  333. package/src/lib/server/session-tools/shell.ts +4 -9
  334. package/src/lib/server/session-tools/subagent.ts +322 -170
  335. package/src/lib/server/session-tools/table.ts +6 -5
  336. package/src/lib/server/session-tools/wallet-tool.test.ts +3 -3
  337. package/src/lib/server/session-tools/wallet.ts +7 -6
  338. package/src/lib/server/session-tools/web-browser-config.test.ts +1 -0
  339. package/src/lib/server/session-tools/web-utils.ts +317 -0
  340. package/src/lib/server/session-tools/web.ts +62 -328
  341. package/src/lib/server/skill-prompt-budget.test.ts +1 -1
  342. package/src/lib/server/skills-normalize.ts +2 -1
  343. package/src/lib/server/storage-item-access.test.ts +302 -0
  344. package/src/lib/server/storage.ts +366 -314
  345. package/src/lib/server/stream-agent-chat.test.ts +82 -3
  346. package/src/lib/server/stream-agent-chat.ts +146 -510
  347. package/src/lib/server/stream-continuation.ts +412 -0
  348. package/src/lib/server/subagent-lineage.test.ts +647 -0
  349. package/src/lib/server/subagent-lineage.ts +435 -0
  350. package/src/lib/server/subagent-runtime.test.ts +484 -0
  351. package/src/lib/server/subagent-runtime.ts +419 -0
  352. package/src/lib/server/subagent-swarm.test.ts +391 -0
  353. package/src/lib/server/subagent-swarm.ts +564 -0
  354. package/src/lib/server/system-events.ts +3 -3
  355. package/src/lib/server/task-followups.test.ts +491 -0
  356. package/src/lib/server/task-followups.ts +391 -0
  357. package/src/lib/server/task-lifecycle.test.ts +205 -0
  358. package/src/lib/server/task-lifecycle.ts +200 -0
  359. package/src/lib/server/task-quality-gate.test.ts +1 -1
  360. package/src/lib/server/task-resume.ts +208 -0
  361. package/src/lib/server/task-service.test.ts +108 -0
  362. package/src/lib/server/task-service.ts +264 -0
  363. package/src/lib/server/task-validation.test.ts +1 -1
  364. package/src/lib/server/test-utils/run-with-temp-data-dir.ts +42 -0
  365. package/src/lib/server/tool-capability-policy.test.ts +2 -2
  366. package/src/lib/server/tool-capability-policy.ts +3 -2
  367. package/src/lib/server/tool-planning.ts +2 -1
  368. package/src/lib/server/tool-retry.ts +2 -3
  369. package/src/lib/server/wake-dispatcher.test.ts +303 -0
  370. package/src/lib/server/wake-dispatcher.ts +318 -0
  371. package/src/lib/server/wake-mode.test.ts +161 -0
  372. package/src/lib/server/wake-mode.ts +174 -0
  373. package/src/lib/server/wallet-service.ts +8 -9
  374. package/src/lib/server/watch-jobs.ts +2 -1
  375. package/src/lib/server/workspace-context.ts +2 -2
  376. package/src/lib/shared-utils.test.ts +142 -0
  377. package/src/lib/shared-utils.ts +62 -0
  378. package/src/lib/tool-event-summary.ts +2 -1
  379. package/src/lib/view-routes.test.ts +100 -0
  380. package/src/lib/wallet.test.ts +322 -6
  381. package/src/proxy.test.ts +4 -4
  382. package/src/proxy.ts +2 -3
  383. package/src/stores/set-if-changed.ts +40 -0
  384. package/src/stores/slices/agent-slice.ts +111 -0
  385. package/src/stores/slices/auth-slice.ts +25 -0
  386. package/src/stores/slices/data-slice.ts +301 -0
  387. package/src/stores/slices/index.ts +7 -0
  388. package/src/stores/slices/session-slice.ts +112 -0
  389. package/src/stores/slices/task-slice.ts +63 -0
  390. package/src/stores/slices/ui-slice.ts +192 -0
  391. package/src/stores/use-app-store.ts +17 -822
  392. package/src/stores/use-approval-store.ts +2 -1
  393. package/src/stores/use-chat-store.ts +8 -1
  394. package/src/types/index.ts +10 -0
@@ -1,6 +1,6 @@
1
1
  import { genId } from '@/lib/id'
2
2
  import type { SSEEvent } from '@/types'
3
- import { active, loadSessions } from './storage'
3
+ import { active, loadSession } from './storage'
4
4
  import { executeSessionChatTurn, type ExecuteChatTurnResult } from './chat-execution'
5
5
  import { loadRuntimeSettings } from './runtime-settings'
6
6
  import { log } from './logger'
@@ -8,6 +8,7 @@ import { isInternalHeartbeatRun } from './heartbeat-source'
8
8
  import { cleanupSessionBrowser } from './session-tools/web'
9
9
  import { cancelDelegationJobsForParentSession } from './delegation-jobs'
10
10
  import { handleMainLoopRunResult } from './main-agent-loop'
11
+ import { errorMessage, hmrSingleton } from '@/lib/shared-utils'
11
12
 
12
13
  export type SessionRunStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'
13
14
  export type SessionQueueMode = 'followup' | 'steer' | 'collect'
@@ -39,7 +40,13 @@ interface QueueEntry {
39
40
  signalController: AbortController
40
41
  maxRuntimeMs?: number
41
42
  modelOverride?: string
42
- heartbeatConfig?: { ackMaxChars: number; showOk: boolean; showAlerts: boolean; target: string | null }
43
+ heartbeatConfig?: {
44
+ ackMaxChars: number
45
+ showOk: boolean
46
+ showAlerts: boolean
47
+ target: string | null
48
+ deliveryMode?: 'default' | 'tool_only'
49
+ }
43
50
  replyToId?: string
44
51
  resolve: (value: ExecuteChatTurnResult) => void
45
52
  reject: (error: Error) => void
@@ -56,14 +63,13 @@ interface RuntimeState {
56
63
 
57
64
  const MAX_RECENT_RUNS = 500
58
65
  const COLLECT_COALESCE_WINDOW_MS = 1500
59
- const globalKey = '__swarmclaw_session_run_manager__' as const
60
- const state: RuntimeState = (globalThis as any)[globalKey] ?? ((globalThis as any)[globalKey] = {
66
+ const state: RuntimeState = hmrSingleton<RuntimeState>('__swarmclaw_session_run_manager__', () => ({
61
67
  runningByExecution: new Map<string, QueueEntry>(),
62
68
  queueByExecution: new Map<string, QueueEntry[]>(),
63
69
  runs: new Map<string, SessionRunRecord>(),
64
70
  recentRunIds: [],
65
71
  promises: new Map<string, Promise<ExecuteChatTurnResult>>(),
66
- })
72
+ }))
67
73
 
68
74
  function now() {
69
75
  return Date.now()
@@ -305,17 +311,17 @@ async function drainExecution(executionKey: string): Promise<void> {
305
311
  })
306
312
  } catch (err: unknown) {
307
313
  log.warn('session-run', `Main loop follow-up enqueue failed for ${next.run.sessionId}`, {
308
- error: err instanceof Error ? err.message : String(err),
314
+ error: errorMessage(err),
309
315
  })
310
316
  }
311
317
  }, Math.max(0, followup.delayMs || 0))
312
318
  }
313
319
  next.resolve(result)
314
- } catch (err: any) {
320
+ } catch (err: unknown) {
315
321
  const aborted = next.signalController.signal.aborted
316
322
  next.run.status = aborted ? 'cancelled' : 'failed'
317
323
  next.run.endedAt = now()
318
- next.run.error = err?.message || String(err)
324
+ next.run.error = errorMessage(err)
319
325
  emitRunMeta(next, next.run.status, { error: next.run.error })
320
326
  log.error('session-run', `Run failed ${next.run.id}`, {
321
327
  sessionId: next.run.sessionId,
@@ -353,7 +359,13 @@ export interface EnqueueSessionRunInput {
353
359
  dedupeKey?: string
354
360
  maxRuntimeMs?: number
355
361
  modelOverride?: string
356
- heartbeatConfig?: { ackMaxChars: number; showOk: boolean; showAlerts: boolean; target: string | null }
362
+ heartbeatConfig?: {
363
+ ackMaxChars: number
364
+ showOk: boolean
365
+ showAlerts: boolean
366
+ target: string | null
367
+ deliveryMode?: 'default' | 'tool_only'
368
+ }
357
369
  replyToId?: string
358
370
  /** External abort signal (e.g. from the HTTP request) — chained to the run's internal AbortController */
359
371
  callerSignal?: AbortSignal
@@ -367,9 +379,15 @@ export interface EnqueueSessionRunResult {
367
379
  promise: Promise<ExecuteChatTurnResult>
368
380
  /** Abort the run's internal AbortController (cancels the LLM stream). */
369
381
  abort: () => void
382
+ /** Remove this caller's onEvent listener from the run (call on client disconnect). */
383
+ unsubscribe: () => void
370
384
  }
371
385
 
372
386
  const LONG_TOOL_NAMES: ReadonlySet<string> = new Set(['claude_code', 'codex_cli', 'opencode_cli'])
387
+ type SessionToolConfig = {
388
+ plugins?: string[] | null
389
+ tools?: string[] | null
390
+ }
373
391
 
374
392
  function computeEffectiveRunTimeoutMs(
375
393
  baseTimeoutMs: number,
@@ -389,9 +407,12 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
389
407
  const executionKey = executionKeyForSession(input.sessionId)
390
408
  const runtime = loadRuntimeSettings()
391
409
  const defaultMaxRuntimeMs = runtime.ongoingLoopMaxRuntimeMs ?? (10 * 60_000)
392
- const sessions = loadSessions()
393
- const sessionData = sessions[input.sessionId]
394
- const sessionTools: string[] = sessionData?.tools || []
410
+ const sessionData = loadSession(input.sessionId) as SessionToolConfig | null
411
+ const sessionTools = Array.isArray(sessionData?.plugins)
412
+ ? sessionData.plugins
413
+ : Array.isArray(sessionData?.tools)
414
+ ? sessionData.tools
415
+ : []
395
416
  const adjustedDefaultMs = computeEffectiveRunTimeoutMs(defaultMaxRuntimeMs, sessionTools, runtime)
396
417
  const effectiveMaxRuntimeMs = typeof input.maxRuntimeMs === 'number'
397
418
  ? input.maxRuntimeMs
@@ -399,7 +420,8 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
399
420
 
400
421
  const dedupe = findDedupeMatch(input.sessionId, input.dedupeKey)
401
422
  if (dedupe) {
402
- if (input.onEvent) dedupe.onEvents.push(input.onEvent)
423
+ const cb = input.onEvent
424
+ if (cb) dedupe.onEvents.push(cb)
403
425
  if (input.callerSignal) chainCallerSignal(input.callerSignal, dedupe.signalController)
404
426
  return {
405
427
  runId: dedupe.run.id,
@@ -407,6 +429,11 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
407
429
  deduped: true,
408
430
  promise: dedupe.promise,
409
431
  abort: () => dedupe.signalController.abort(),
432
+ unsubscribe: () => {
433
+ if (!cb) return
434
+ const idx = dedupe.onEvents.indexOf(cb)
435
+ if (idx >= 0) dedupe.onEvents.splice(idx, 1)
436
+ },
410
437
  }
411
438
  }
412
439
 
@@ -455,7 +482,8 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
455
482
  candidate.run.messagePreview = messagePreview(candidate.message)
456
483
  candidate.run.queuedAt = nowMs
457
484
  }
458
- if (input.onEvent) candidate.onEvents.push(input.onEvent)
485
+ const coalesceCb = input.onEvent
486
+ if (coalesceCb) candidate.onEvents.push(coalesceCb)
459
487
  if (input.callerSignal) chainCallerSignal(input.callerSignal, candidate.signalController)
460
488
  emitRunMeta(candidate, 'queued', { position: 0, coalesced: true, mergedIntoRunId: candidate.run.id })
461
489
  return {
@@ -464,6 +492,11 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
464
492
  coalesced: true,
465
493
  promise: candidate.promise,
466
494
  abort: () => candidate.signalController.abort(),
495
+ unsubscribe: () => {
496
+ if (!coalesceCb) return
497
+ const idx = candidate.onEvents.indexOf(coalesceCb)
498
+ if (idx >= 0) candidate.onEvents.splice(idx, 1)
499
+ },
467
500
  }
468
501
  }
469
502
  }
@@ -515,7 +548,18 @@ export function enqueueSessionRun(input: EnqueueSessionRunInput): EnqueueSession
515
548
  emitRunMeta(entry, 'queued', { position })
516
549
  void drainExecution(executionKey)
517
550
 
518
- return { runId, position, promise, abort: () => entry.signalController.abort() }
551
+ const entryCb = input.onEvent
552
+ return {
553
+ runId,
554
+ position,
555
+ promise,
556
+ abort: () => entry.signalController.abort(),
557
+ unsubscribe: () => {
558
+ if (!entryCb) return
559
+ const idx = entry.onEvents.indexOf(entryCb)
560
+ if (idx >= 0) entry.onEvents.splice(idx, 1)
561
+ },
562
+ }
519
563
  }
520
564
 
521
565
  export function getSessionRunState(sessionId: string): {
@@ -16,29 +16,29 @@ function readServerSource(fileName: string): string {
16
16
  }
17
17
 
18
18
  describe('browser workflow surface', () => {
19
- it('advertises the higher-level browser actions in web.ts', () => {
20
- const src = readToolSource('web.ts')
19
+ it('advertises the higher-level browser actions in web', () => {
20
+ const src = readToolSource('web')
21
21
  for (const action of ['read_page', 'extract_links', 'extract_form_fields', 'extract_table', 'fill_form', 'submit_form', 'scroll_until', 'download_file', 'complete_web_task']) {
22
22
  assert.equal(src.includes(`'${action}'`), true, `web.ts should expose ${action}`)
23
23
  }
24
24
  })
25
25
 
26
26
  it('supports the shorthand form-map path for fill_form', () => {
27
- const src = readToolSource('web.ts')
27
+ const src = readToolSource('web')
28
28
  assert.equal(src.includes('params.form'), true)
29
29
  assert.equal(src.includes('fields is required for fill_form.'), true)
30
30
  })
31
31
 
32
32
  it('flags pages that require human-provided input', () => {
33
- const src = readToolSource('web.ts')
33
+ const src = readToolSource('web')
34
34
  assert.equal(src.includes("type: 'human_input_required'"), true)
35
35
  assert.equal(src.includes('Ask the human instead of guessing'), true)
36
36
  })
37
37
  })
38
38
 
39
39
  describe('durable wait surface', () => {
40
- it('advertises the durable wait actions in monitor.ts', () => {
41
- const src = readToolSource('monitor.ts')
40
+ it('advertises the durable wait actions in monitor', () => {
41
+ const src = readToolSource('monitor')
42
42
  for (const action of ['wait_until', 'wait_for_http', 'wait_for_file', 'wait_for_task', 'wait_for_webhook', 'wait_for_page_change']) {
43
43
  assert.equal(src.includes(`'${action}'`), true, `monitor.ts should expose ${action}`)
44
44
  }
@@ -46,7 +46,7 @@ describe('durable wait surface', () => {
46
46
  })
47
47
 
48
48
  it('routes schedule_wake through durable watch storage', () => {
49
- const src = readToolSource('schedule.ts')
49
+ const src = readToolSource('schedule')
50
50
  assert.equal(src.includes('createWatchJob'), true)
51
51
  assert.equal(src.includes("type: 'time'"), true)
52
52
  })
@@ -54,7 +54,7 @@ describe('durable wait surface', () => {
54
54
 
55
55
  describe('sandbox surface', () => {
56
56
  it('advertises a Deno-only sandbox and steers simple APIs to http_request', () => {
57
- const src = readToolSource('sandbox.ts')
57
+ const src = readToolSource('sandbox')
58
58
  assert.equal(src.includes("enum: ['javascript', 'typescript']"), true)
59
59
  assert.equal(src.includes('http_request'), true)
60
60
  assert.equal(src.includes('plugin_creator'), true)
@@ -65,7 +65,7 @@ describe('sandbox surface', () => {
65
65
 
66
66
  describe('delegation job handles', () => {
67
67
  it('exposes subagent control actions', () => {
68
- const src = readToolSource('subagent.ts')
68
+ const src = readToolSource('subagent')
69
69
  for (const action of ['status', 'list', 'wait', 'cancel']) {
70
70
  assert.equal(src.includes(`action === '${action}'`), true, `subagent.ts should handle ${action}`)
71
71
  }
@@ -73,15 +73,15 @@ describe('delegation job handles', () => {
73
73
  })
74
74
 
75
75
  it('builds delegate context from the invoking session and uses job records', () => {
76
- const src = readToolSource('delegate.ts')
76
+ const src = readToolSource('delegate')
77
77
  assert.equal(src.includes('buildDelegateContextFromSessionish'), true)
78
78
  assert.equal(src.includes('createDelegationJob'), true)
79
79
  assert.equal(src.includes('waitForDelegateJob'), true)
80
80
  })
81
81
 
82
82
  it('scheduler and daemon recover the durable autonomy jobs', () => {
83
- const schedulerSrc = readServerSource('scheduler.ts')
84
- const daemonSrc = readServerSource('daemon-state.ts')
83
+ const schedulerSrc = readServerSource('scheduler')
84
+ const daemonSrc = readServerSource('daemon-state')
85
85
  assert.equal(schedulerSrc.includes('processDueWatchJobs'), true)
86
86
  assert.equal(daemonSrc.includes('recoverStaleDelegationJobs'), true)
87
87
  })
@@ -89,8 +89,8 @@ describe('delegation job handles', () => {
89
89
 
90
90
  describe('primitive plugin surfaces', () => {
91
91
  it('advertises mailbox and human-loop actions', () => {
92
- const mailboxSrc = readToolSource('mailbox.ts')
93
- const humanSrc = readToolSource('human-loop.ts')
92
+ const mailboxSrc = readToolSource('mailbox')
93
+ const humanSrc = readToolSource('human-loop')
94
94
  for (const action of ['list_messages', 'list_threads', 'search_messages', 'read_message', 'download_attachment', 'reply', 'wait_for_email']) {
95
95
  assert.equal(mailboxSrc.includes(`'${action}'`), true, `mailbox.ts should expose ${action}`)
96
96
  }
@@ -100,10 +100,10 @@ describe('primitive plugin surfaces', () => {
100
100
  })
101
101
 
102
102
  it('advertises document, extract, table, and crawl actions', () => {
103
- const documentSrc = readToolSource('document.ts')
104
- const extractSrc = readToolSource('extract.ts')
105
- const tableSrc = readToolSource('table.ts')
106
- const crawlSrc = readToolSource('crawl.ts')
103
+ const documentSrc = readToolSource('document')
104
+ const extractSrc = readToolSource('extract')
105
+ const tableSrc = readToolSource('table')
106
+ const crawlSrc = readToolSource('crawl')
107
107
 
108
108
  for (const action of ['read', 'metadata', 'ocr', 'extract_tables', 'store', 'list', 'search', 'get', 'delete']) {
109
109
  assert.equal(documentSrc.includes(`'${action}'`), true, `document.ts should expose ${action}`)
@@ -119,8 +119,8 @@ describe('primitive plugin surfaces', () => {
119
119
  }
120
120
  })
121
121
 
122
- it('registers the primitive plugins in builtin-plugins.ts', () => {
123
- const src = readServerSource('builtin-plugins.ts')
122
+ it('registers the primitive plugins in builtin-plugins', () => {
123
+ const src = readServerSource('builtin-plugins')
124
124
  for (const moduleName of ['mailbox', 'human-loop', 'document', 'extract', 'table', 'crawl']) {
125
125
  assert.equal(src.includes(`session-tools/${moduleName}`), true, `builtin-plugins.ts should import ${moduleName}`)
126
126
  }
@@ -4,6 +4,7 @@ import type { Plugin, PluginHooks } from '@/types'
4
4
  import { getPluginManager } from '../plugins'
5
5
  import { normalizeToolInputArgs } from './normalize-tool-args'
6
6
  import type { ToolBuildContext } from './context'
7
+ import { errorMessage } from '@/lib/shared-utils'
7
8
 
8
9
  type CalendarProvider = 'google' | 'outlook'
9
10
 
@@ -249,7 +250,7 @@ async function executeCalendar(args: Record<string, unknown>): Promise<string> {
249
250
  return `Error: Unknown action "${action}". Use: list, create, update, delete, status.`
250
251
  }
251
252
  } catch (err: unknown) {
252
- return `Error: ${err instanceof Error ? err.message : String(err)}`
253
+ return `Error: ${errorMessage(err)}`
253
254
  }
254
255
  }
255
256
 
@@ -7,6 +7,7 @@ import type { Plugin, PluginHooks } from '@/types'
7
7
  import { getPluginManager } from '../plugins'
8
8
  import { normalizeToolInputArgs } from './normalize-tool-args'
9
9
  import { normalizeCanvasContent, summarizeCanvasContent } from '@/lib/canvas-content'
10
+ import { errorMessage } from '@/lib/shared-utils'
10
11
 
11
12
  /**
12
13
  * Core Canvas Execution Logic
@@ -55,7 +56,7 @@ async function executeCanvasAction(args: Record<string, unknown>, context: { ses
55
56
 
56
57
  return `Unknown canvas action "${action}".`
57
58
  } catch (err: unknown) {
58
- return `Error: ${err instanceof Error ? err.message : String(err)}`
59
+ return `Error: ${errorMessage(err)}`
59
60
  }
60
61
  }
61
62
 
@@ -7,6 +7,7 @@ import type { ToolBuildContext } from './context'
7
7
  import type { Chatroom, Plugin, PluginHooks } from '@/types'
8
8
  import { getPluginManager } from '../plugins'
9
9
  import { normalizeToolInputArgs } from './normalize-tool-args'
10
+ import { errorMessage } from '@/lib/shared-utils'
10
11
 
11
12
  /**
12
13
  * Core Chatroom Execution Logic
@@ -97,7 +98,7 @@ async function executeChatroomAction(args: Record<string, unknown>, context: { a
97
98
 
98
99
  return `Unknown action "${action}".`
99
100
  } catch (err: unknown) {
100
- return `Error: ${err instanceof Error ? err.message : String(err)}`
101
+ return `Error: ${errorMessage(err)}`
101
102
  }
102
103
  }
103
104
 
@@ -10,6 +10,9 @@ import type { ToolBuildContext } from './context'
10
10
  import type { Plugin, PluginHooks } from '@/types'
11
11
  import { getPluginManager } from '../plugins'
12
12
  import { normalizeToolInputArgs } from './normalize-tool-args'
13
+ import { safeJsonParseObject } from '../json-utils'
14
+ import { tryResolvePathWithinBaseDir } from '../path-utils'
15
+ import { dedup, errorMessage } from '@/lib/shared-utils'
13
16
 
14
17
  const CONNECTOR_ACTION_DEDUPE_TTL_MS = 30_000
15
18
  const CONNECTOR_TURN_SEND_TTL_MS = 180_000
@@ -157,29 +160,24 @@ function buildConnectorActionKey(parts: Array<string | number | boolean | null |
157
160
  }
158
161
 
159
162
  function normalizeDedupedReplayResult(raw: string, fallback: { connectorId: string; platform: string; to: string }): string {
160
- try {
161
- const parsed = JSON.parse(raw)
162
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid')
163
- const record = parsed as Record<string, unknown>
164
- if (String(record.status || '') === 'deduped') {
165
- return JSON.stringify({
166
- status: 'sent',
167
- connectorId: String(record.connectorId || fallback.connectorId),
168
- platform: String(record.platform || fallback.platform),
169
- to: String(record.to || fallback.to),
170
- deduped: true,
171
- })
172
- }
173
- return raw
174
- } catch {
163
+ const record = safeJsonParseObject(raw)
164
+ if (record && String(record.status || '') === 'deduped') {
175
165
  return JSON.stringify({
176
166
  status: 'sent',
177
- connectorId: fallback.connectorId,
178
- platform: fallback.platform,
179
- to: fallback.to,
167
+ connectorId: String(record.connectorId || fallback.connectorId),
168
+ platform: String(record.platform || fallback.platform),
169
+ to: String(record.to || fallback.to),
180
170
  deduped: true,
181
171
  })
182
172
  }
173
+ if (record) return raw
174
+ return JSON.stringify({
175
+ status: 'sent',
176
+ connectorId: fallback.connectorId,
177
+ platform: fallback.platform,
178
+ to: fallback.to,
179
+ deduped: true,
180
+ })
183
181
  }
184
182
 
185
183
  export function normalizeConnectorActionName(action: string): string {
@@ -441,7 +439,7 @@ function pickChannelTarget(params: {
441
439
  ...parseCsv(connector.config?.allowedJids),
442
440
  ...parseCsv(connector.config?.allowFrom),
443
441
  ].filter(Boolean) as string[]
444
- const unique = [...new Set(knownTargets)]
442
+ const unique = dedup(knownTargets)
445
443
  if (unique.length) {
446
444
  return {
447
445
  channelId: '',
@@ -487,9 +485,9 @@ export function resolveConnectorMediaInput(params: {
487
485
  const candidatePaths = [
488
486
  path.resolve(params.cwd, resolvedMediaPath),
489
487
  path.resolve(params.cwd, 'uploads', resolvedMediaPath),
490
- path.join(UPLOAD_DIR, resolvedMediaPath),
491
- path.join(UPLOAD_DIR, path.basename(resolvedMediaPath)),
492
- ]
488
+ tryResolvePathWithinBaseDir(UPLOAD_DIR, resolvedMediaPath),
489
+ tryResolvePathWithinBaseDir(UPLOAD_DIR, path.basename(resolvedMediaPath)),
490
+ ].filter((candidate): candidate is string => !!candidate)
493
491
  const found = candidatePaths.find((p) => fs.existsSync(p))
494
492
  if (found) {
495
493
  resolvedMediaPath = found
@@ -605,9 +603,9 @@ async function executeConnectorAction(input: ConnectorActionInput, bctx: Connect
605
603
  if (!connectorId) {
606
604
  const allConnectors = loadConnectors()
607
605
  const stopped = Object.values(allConnectors)
608
- .filter((c) => !platform || c.platform === platform)
609
- .filter((c) => !running.find((r) => r.id === c.id))
610
- .map((c) => ({ id: c.id, name: c.name, platform: c.platform }))
606
+ .filter((c: any) => !platform || c.platform === platform)
607
+ .filter((c: any) => !running.find((r) => r.id === c.id))
608
+ .map((c: any) => ({ id: c.id, name: c.name, platform: c.platform }))
611
609
  if (!stopped.length) return 'All connectors are already running.'
612
610
  return `Error: connectorId is required. Stopped connectors available to start: ${JSON.stringify(stopped)}`
613
611
  }
@@ -627,8 +625,8 @@ async function executeConnectorAction(input: ConnectorActionInput, bctx: Connect
627
625
  if (!running.length) {
628
626
  const allConnectors = loadConnectors()
629
627
  const configured = Object.values(allConnectors)
630
- .filter((c) => !platform || c.platform === platform)
631
- .map((c) => ({ id: c.id, name: c.name, platform: c.platform, agentId: c.agentId || null }))
628
+ .filter((c: any) => !platform || c.platform === platform)
629
+ .map((c: any) => ({ id: c.id, name: c.name, platform: c.platform, agentId: c.agentId || null }))
632
630
  if (configured.length) {
633
631
  return {
634
632
  error: `Error: no running connectors found. Ask user to start one. Configured: ${JSON.stringify(configured)}`,
@@ -842,7 +840,7 @@ async function executeConnectorAction(input: ConnectorActionInput, bctx: Connect
842
840
 
843
841
  return 'Unknown action.'
844
842
  } catch (err: unknown) {
845
- return `Error: ${err instanceof Error ? err.message : String(err)}`
843
+ return `Error: ${errorMessage(err)}`
846
844
  }
847
845
  }
848
846
 
@@ -7,6 +7,7 @@ import type { ToolBuildContext } from './context'
7
7
  import type { Plugin, PluginHooks, Session } from '@/types'
8
8
  import { getPluginManager } from '../plugins'
9
9
  import { normalizeToolInputArgs } from './normalize-tool-args'
10
+ import { errorMessage } from '@/lib/shared-utils'
10
11
 
11
12
  interface ContextToolContext {
12
13
  ctx?: { agentId?: string | null; sessionId?: string | null }
@@ -23,7 +24,7 @@ async function executeContextStatus(bctx: ContextToolContext) {
23
24
  if (!session) return 'Error: no current session context.'
24
25
  const status = getContextStatus(session.messages || [], 2000, session.provider as string, session.model as string)
25
26
  return JSON.stringify(status)
26
- } catch (err: unknown) { return `Error: ${err instanceof Error ? err.message : String(err)}` }
27
+ } catch (err: unknown) { return `Error: ${errorMessage(err)}` }
27
28
  }
28
29
 
29
30
  async function executeContextSummarize(args: { keepLastN?: number }, bctx: ContextToolContext) {
@@ -55,7 +56,7 @@ async function executeContextSummarize(args: { keepLastN?: number }, bctx: Conte
55
56
  saveSessions(sessions)
56
57
  }
57
58
  return JSON.stringify({ status: 'compacted', remaining: result.messages.length })
58
- } catch (err: unknown) { return `Error: ${err instanceof Error ? err.message : String(err)}` }
59
+ } catch (err: unknown) { return `Error: ${errorMessage(err)}` }
59
60
  }
60
61
 
61
62
  /**
@@ -8,6 +8,7 @@ import { getPluginManager } from '../plugins'
8
8
  import { runStructuredExtraction } from '../structured-extract'
9
9
  import type { ToolBuildContext } from './context'
10
10
  import { normalizeToolInputArgs } from './normalize-tool-args'
11
+ import { dedup, errorMessage } from '@/lib/shared-utils'
11
12
 
12
13
  interface CrawledPage {
13
14
  url: string
@@ -93,7 +94,7 @@ async function fetchCrawlPage(url: string, depth: number): Promise<CrawledPage>
93
94
  depth,
94
95
  textPreview,
95
96
  headings,
96
- links: Array.from(new Set(links)),
97
+ links: dedup(links),
97
98
  hash: pageHash(`${title || ''}\n${textPreview}`),
98
99
  }
99
100
  }
@@ -194,7 +195,7 @@ async function fetchSitemapUrls(sitemapUrl: string): Promise<string[]> {
194
195
  })
195
196
  const xml = await res.text()
196
197
  const matches = Array.from(xml.matchAll(/<loc>\s*([^<]+)\s*<\/loc>/gi))
197
- return Array.from(new Set(matches.map((match) => match[1]?.trim()).filter((value): value is string => !!value)))
198
+ return dedup(matches.map((match) => match[1]?.trim()).filter((value): value is string => !!value))
198
199
  }
199
200
 
200
201
  function normalizeSelectorMap(value: unknown): Record<string, string> {
@@ -369,7 +370,7 @@ async function executeCrawlAction(args: Record<string, unknown>, bctx: ToolBuild
369
370
 
370
371
  return `Error: Unknown action "${action}".`
371
372
  } catch (err: unknown) {
372
- return `Error: ${err instanceof Error ? err.message : String(err)}`
373
+ return `Error: ${errorMessage(err)}`
373
374
  }
374
375
  }
375
376