@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,4 +1,5 @@
1
1
  import type { AppSettings } from '@/types'
2
+ import { dedup } from '@/lib/shared-utils'
2
3
  import { getToolsForCapability, matchToolCapabilitiesForMessage, TOOL_CAPABILITY } from './tool-planning'
3
4
 
4
5
  export type TaskIntent =
@@ -29,7 +30,7 @@ function containsAny(text: string, terms: string[]): boolean {
29
30
  }
30
31
 
31
32
  function dedupe(values: string[]): string[] {
32
- return Array.from(new Set(values.filter(Boolean)))
33
+ return dedup(values.filter(Boolean))
33
34
  }
34
35
 
35
36
  function isMonitoringOrCurrentEventsRequest(text: string): boolean {
@@ -78,7 +79,7 @@ function normalizeDelegateOrder(value: unknown): DelegateTool[] {
78
79
  else if (raw === 'gemini') mapped.push('delegate_to_gemini_cli')
79
80
  }
80
81
  if (!mapped.length) return fallback
81
- const deduped = Array.from(new Set(mapped))
82
+ const deduped = dedup(mapped)
82
83
  for (const tool of fallback) {
83
84
  if (!deduped.includes(tool)) deduped.push(tool)
84
85
  }
@@ -494,6 +494,11 @@ describe('buildToolDisciplineLines advanced', () => {
494
494
  const lines = buildToolDisciplineLines(['delegate', 'shell', 'files'])
495
495
  assert.ok(lines.some((line) => line.includes('prefer using them directly for straightforward coding')))
496
496
  })
497
+
498
+ it('tells research-capable agents to try another enabled acquisition path before manual fallback', () => {
499
+ const lines = buildToolDisciplineLines(['web_search', 'web_fetch', 'http_request', 'shell'])
500
+ assert.ok(lines.some((line) => line.includes('try one other enabled acquisition path') && line.includes('`shell`') && line.includes('`http_request`')))
501
+ })
497
502
  })
498
503
 
499
504
  // ---------------------------------------------------------------------------
@@ -640,12 +645,12 @@ describe('normalizeAssistantArtifactLinks', () => {
640
645
  // getExplicitRequiredToolNames
641
646
  // ---------------------------------------------------------------------------
642
647
  describe('getExplicitRequiredToolNames', () => {
643
- it('requires web_search for research-oriented query when web_search is enabled', () => {
648
+ it('does not force web_search for generic research phrasing when the tool was not explicitly named', () => {
644
649
  const result = getExplicitRequiredToolNames(
645
650
  'Search the web for the latest news about AI regulation',
646
651
  ['web_search', 'web_fetch', 'browser'],
647
652
  )
648
- assert.ok(result.includes('web_search') || result.includes('web'))
653
+ assert.deepEqual(result, [])
649
654
  })
650
655
 
651
656
  it('returns empty when no tool matches the message', () => {
@@ -655,4 +660,12 @@ describe('getExplicitRequiredToolNames', () => {
655
660
  )
656
661
  assert.deepEqual(result, [])
657
662
  })
663
+
664
+ it('forces shell when the user explicitly asks for curl execution', () => {
665
+ const result = getExplicitRequiredToolNames(
666
+ 'Can you run the curl request in the terminal?',
667
+ ['files', 'shell'],
668
+ )
669
+ assert.deepEqual(result, ['shell'])
670
+ })
658
671
  })
@@ -0,0 +1,67 @@
1
+ import type { MessageToolEvent } from '@/types'
2
+ import { dedupeConsecutiveToolEvents } from './chat-execution-tool-events'
3
+
4
+ function parseToolJsonObject(raw: string): Record<string, unknown> | null {
5
+ const trimmed = raw.trim()
6
+ if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) return null
7
+ try {
8
+ const parsed = JSON.parse(trimmed)
9
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
10
+ ? parsed as Record<string, unknown>
11
+ : null
12
+ } catch {
13
+ return null
14
+ }
15
+ }
16
+
17
+ function summarizeConnectorToolFailure(output: string): string {
18
+ const trimmed = output.trim()
19
+ const withoutPrefix = trimmed.replace(/^Error:\s*/i, '')
20
+ const parsed = parseToolJsonObject(withoutPrefix) || parseToolJsonObject(trimmed)
21
+ if (parsed) {
22
+ const detail = parsed.detail
23
+ if (detail && typeof detail === 'object' && !Array.isArray(detail)) {
24
+ const detailRecord = detail as Record<string, unknown>
25
+ const message = typeof detailRecord.message === 'string' ? detailRecord.message.trim() : ''
26
+ if (message) return message
27
+ const code = typeof detailRecord.code === 'string' ? detailRecord.code.trim() : ''
28
+ const status = typeof detailRecord.status === 'string' ? detailRecord.status.trim() : ''
29
+ if (code && status) return `${code}: ${status}`
30
+ if (code) return code
31
+ if (status) return status
32
+ }
33
+ const message = typeof parsed.message === 'string' ? parsed.message.trim() : ''
34
+ if (message) return message
35
+ const error = typeof parsed.error === 'string' ? parsed.error.trim() : ''
36
+ if (error) return error
37
+ }
38
+ return withoutPrefix.replace(/\s+/g, ' ').trim() || 'Connector delivery failed.'
39
+ }
40
+
41
+ function connectorToolEventSucceeded(event: MessageToolEvent): boolean {
42
+ if (!event.output) return false
43
+ const parsed = parseToolJsonObject(event.output)
44
+ const status = typeof parsed?.status === 'string' ? parsed.status.trim().toLowerCase() : ''
45
+ return status === 'sent' || status === 'voice_sent' || status === 'scheduled'
46
+ }
47
+
48
+ const POSITIVE_CONNECTOR_DELIVERY_RE = /\b(?:i(?:'ve| have)?(?: successfully)? sent|i sent|successfully sent|sent to your|voice note (?:has been|was) sent|message (?:has been|was) sent)\b/i
49
+
50
+ export function reconcileConnectorDeliveryText(text: string, events: MessageToolEvent[]): string {
51
+ const trimmed = text.trim()
52
+ if (!trimmed || !POSITIVE_CONNECTOR_DELIVERY_RE.test(trimmed)) return text
53
+
54
+ const connectorEvents = dedupeConsecutiveToolEvents(events).filter((event) => event.name === 'connector_message_tool')
55
+ if (connectorEvents.length === 0) return text
56
+ if (connectorEvents.some((event) => connectorToolEventSucceeded(event))) return text
57
+
58
+ const latestFailure = [...connectorEvents]
59
+ .reverse()
60
+ .find((event) => event.error === true && typeof event.output === 'string' && event.output.trim())
61
+
62
+ const failureSummary = latestFailure?.output
63
+ ? summarizeConnectorToolFailure(latestFailure.output)
64
+ : 'I could not confirm that the connector actually sent anything.'
65
+
66
+ return `I couldn't send that through the configured connector. ${failureSummary}`.trim()
67
+ }
@@ -35,13 +35,13 @@ function runWithTempDataDir(script: string) {
35
35
 
36
36
  test('executeSessionChatTurn persists a visible error for disabled agents', () => {
37
37
  const output = runWithTempDataDir(`
38
- const storageMod = await import('./src/lib/server/storage.ts')
38
+ const storageMod = await import('./src/lib/server/storage')
39
39
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
40
- const threadMod = await import('./src/lib/server/agent-thread-session.ts')
40
+ const threadMod = await import('./src/lib/server/agent-thread-session')
41
41
  const ensureAgentThreadSession = threadMod.ensureAgentThreadSession
42
42
  || threadMod.default?.ensureAgentThreadSession
43
43
  || threadMod['module.exports']?.ensureAgentThreadSession
44
- const execMod = await import('./src/lib/server/chat-execution.ts')
44
+ const execMod = await import('./src/lib/server/chat-execution')
45
45
  const executeSessionChatTurn = execMod.executeSessionChatTurn
46
46
  || execMod.default?.executeSessionChatTurn
47
47
  || execMod['module.exports']?.executeSessionChatTurn
@@ -35,10 +35,10 @@ function runWithTempDataDir(script: string) {
35
35
 
36
36
  test('executeSessionChatTurn persists internal eval user turns for same-thread recall', () => {
37
37
  const output = runWithTempDataDir(`
38
- const storageMod = await import('./src/lib/server/storage.ts')
38
+ const storageMod = await import('./src/lib/server/storage')
39
39
  const storage = storageMod.default || storageMod['module.exports'] || storageMod
40
- const providersMod = await import('./src/lib/providers/index.ts')
41
- const execMod = await import('./src/lib/server/chat-execution.ts')
40
+ const providersMod = await import('./src/lib/providers/index')
41
+ const execMod = await import('./src/lib/server/chat-execution')
42
42
  const executeSessionChatTurn = execMod.executeSessionChatTurn
43
43
  || execMod.default?.executeSessionChatTurn
44
44
  || execMod['module.exports']?.executeSessionChatTurn
@@ -1,7 +1,13 @@
1
1
  import assert from 'node:assert/strict'
2
2
  import { describe, it } from 'node:test'
3
3
  import type { Message } from '@/types'
4
- import { pruneSuppressedHeartbeatStreamMessage, shouldApplySessionFreshnessReset } from './chat-execution'
4
+ import {
5
+ buildAgentRuntimeCapabilities,
6
+ buildEnabledToolsAutonomyGuidance,
7
+ buildNoToolsGuidance,
8
+ pruneSuppressedHeartbeatStreamMessage,
9
+ shouldApplySessionFreshnessReset,
10
+ } from './chat-execution'
5
11
 
6
12
  describe('pruneSuppressedHeartbeatStreamMessage', () => {
7
13
  it('removes a trailing streaming assistant heartbeat artifact', () => {
@@ -37,4 +43,39 @@ describe('pruneSuppressedHeartbeatStreamMessage', () => {
37
43
  assert.equal(shouldApplySessionFreshnessReset('heartbeat'), true)
38
44
  assert.equal(shouldApplySessionFreshnessReset('eval'), false)
39
45
  })
46
+
47
+ it('does not advertise tool capabilities when no plugins are enabled', () => {
48
+ assert.deepEqual(buildAgentRuntimeCapabilities([]), ['heartbeats', 'autonomous_loop', 'multi_agent_chat'])
49
+ assert.deepEqual(buildAgentRuntimeCapabilities(['web']), ['tools', 'heartbeats', 'autonomous_loop', 'multi_agent_chat'])
50
+ })
51
+
52
+ it('tells no-tool agents to report missing capability instead of asking for approval', () => {
53
+ const guidance = buildNoToolsGuidance().join('\n')
54
+ assert.match(guidance, /No session tools are enabled/i)
55
+ assert.match(guidance, /Do not imply that a normal read-only action is waiting on user permission or approval/i)
56
+ assert.match(guidance, /state that the capability is not enabled in this session/i)
57
+ })
58
+
59
+ it('tells tool-enabled agents to use enabled tools autonomously before asking for permission', () => {
60
+ const guidance = buildEnabledToolsAutonomyGuidance().join('\n')
61
+ assert.match(guidance, /Enabled session tools are already available for normal use/i)
62
+ assert.match(guidance, /Do not ask the user for permission before using enabled tools/i)
63
+ assert.match(guidance, /attempt that tool path before asking the user to do the work manually/i)
64
+ assert.match(guidance, /Only surface approval or permission as a blocker when a real runtime tool result explicitly requires approval/i)
65
+ })
66
+
67
+ it('tells tool-enabled agents when approvals are disabled platform-wide', () => {
68
+ const guidance = buildEnabledToolsAutonomyGuidance({ approvalsEnabled: false }).join('\n')
69
+ assert.match(guidance, /Approvals are disabled platform-wide in this runtime/i)
70
+ assert.match(guidance, /Do not tell the user that enabled tool use is waiting on approval/i)
71
+ })
72
+
73
+ it('tells tool-enabled agents which approval categories auto-approve', () => {
74
+ const guidance = buildEnabledToolsAutonomyGuidance({
75
+ approvalsEnabled: true,
76
+ approvalAutoApproveCategories: ['tool_access', 'wallet_action'],
77
+ }).join('\n')
78
+ assert.match(guidance, /These approval categories auto-approve in this runtime: tool_access, wallet_action/i)
79
+ assert.match(guidance, /call the tool and let the runtime auto-approve it instead of asking the user first in prose/i)
80
+ })
40
81
  })
@@ -0,0 +1,119 @@
1
+ import assert from 'node:assert/strict'
2
+ import fs from 'node:fs'
3
+ import os from 'node:os'
4
+ import path from 'node:path'
5
+ import { spawnSync } from 'node:child_process'
6
+ import test from 'node:test'
7
+
8
+ const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '../../..')
9
+
10
+ function runWithTempDataDir(script: string) {
11
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-chat-session-sync-'))
12
+ try {
13
+ const result = spawnSync(process.execPath, ['--import', 'tsx', '--input-type=module', '--eval', script], {
14
+ cwd: repoRoot,
15
+ env: {
16
+ ...process.env,
17
+ DATA_DIR: path.join(tempDir, 'data'),
18
+ WORKSPACE_DIR: path.join(tempDir, 'workspace'),
19
+ BROWSER_PROFILES_DIR: path.join(tempDir, 'browser-profiles'),
20
+ },
21
+ encoding: 'utf-8',
22
+ })
23
+ assert.equal(result.status, 0, result.stderr || result.stdout || 'subprocess failed')
24
+ const lines = (result.stdout || '')
25
+ .trim()
26
+ .split('\n')
27
+ .map((line) => line.trim())
28
+ .filter(Boolean)
29
+ const jsonLine = [...lines].reverse().find((line) => line.startsWith('{'))
30
+ return JSON.parse(jsonLine || '{}')
31
+ } finally {
32
+ fs.rmSync(tempDir, { recursive: true, force: true })
33
+ }
34
+ }
35
+
36
+ test('executeSessionChatTurn syncs updated agent runtime fields onto its thread session', () => {
37
+ const output = runWithTempDataDir(`
38
+ const storageMod = await import('./src/lib/server/storage')
39
+ const storage = storageMod.default || storageMod['module.exports'] || storageMod
40
+ const providersMod = await import('./src/lib/providers/index')
41
+ const threadMod = await import('./src/lib/server/agent-thread-session')
42
+ const execMod = await import('./src/lib/server/chat-execution')
43
+ const ensureAgentThreadSession = threadMod.ensureAgentThreadSession
44
+ || threadMod.default?.ensureAgentThreadSession
45
+ || threadMod['module.exports']?.ensureAgentThreadSession
46
+ const executeSessionChatTurn = execMod.executeSessionChatTurn
47
+ || execMod.default?.executeSessionChatTurn
48
+ || execMod['module.exports']?.executeSessionChatTurn
49
+ const providers = providersMod.PROVIDERS
50
+ || providersMod.default?.PROVIDERS
51
+ || providersMod['module.exports']?.PROVIDERS
52
+
53
+ providers['test-provider'] = {
54
+ id: 'test-provider',
55
+ name: 'Test Provider',
56
+ models: ['unit'],
57
+ requiresApiKey: false,
58
+ requiresEndpoint: false,
59
+ handler: {
60
+ async streamChat() {
61
+ return 'synced'
62
+ },
63
+ },
64
+ }
65
+
66
+ const now = Date.now()
67
+ storage.saveAgents({
68
+ molly: {
69
+ id: 'molly',
70
+ name: 'Molly',
71
+ description: 'Thread session sync test',
72
+ provider: 'openai',
73
+ model: 'old-model',
74
+ credentialId: null,
75
+ apiEndpoint: null,
76
+ fallbackCredentialIds: [],
77
+ disabled: false,
78
+ heartbeatEnabled: false,
79
+ heartbeatIntervalSec: null,
80
+ plugins: ['memory'],
81
+ createdAt: now,
82
+ updatedAt: now,
83
+ },
84
+ })
85
+
86
+ const session = ensureAgentThreadSession('molly')
87
+ const agents = storage.loadAgents()
88
+ agents.molly.provider = 'test-provider'
89
+ agents.molly.model = 'unit'
90
+ agents.molly.plugins = []
91
+ agents.molly.heartbeatEnabled = true
92
+ agents.molly.heartbeatIntervalSec = 90
93
+ agents.molly.updatedAt = now + 1
94
+ storage.saveAgents(agents)
95
+
96
+ const result = await executeSessionChatTurn({
97
+ sessionId: session.id,
98
+ message: 'hello',
99
+ runId: 'run-session-sync',
100
+ })
101
+
102
+ const persisted = storage.loadSession(session.id)
103
+ console.log(JSON.stringify({
104
+ text: result.text || null,
105
+ provider: persisted?.provider || null,
106
+ model: persisted?.model || null,
107
+ plugins: persisted?.plugins || [],
108
+ heartbeatEnabled: persisted?.heartbeatEnabled ?? null,
109
+ heartbeatIntervalSec: persisted?.heartbeatIntervalSec ?? null,
110
+ }))
111
+ `)
112
+
113
+ assert.equal(output.text, 'synced')
114
+ assert.equal(output.provider, 'test-provider')
115
+ assert.equal(output.model, 'unit')
116
+ assert.deepEqual(output.plugins, [])
117
+ assert.equal(output.heartbeatEnabled, true)
118
+ assert.equal(output.heartbeatIntervalSec, 90)
119
+ })
@@ -0,0 +1,116 @@
1
+ import type { MessageToolEvent, SSEEvent } from '@/types'
2
+
3
+ export function extractEventJson(line: string): SSEEvent | null {
4
+ if (!line.startsWith('data: ')) return null
5
+ try {
6
+ return JSON.parse(line.slice(6).trim()) as SSEEvent
7
+ } catch {
8
+ return null
9
+ }
10
+ }
11
+
12
+ export function isLikelyToolErrorOutput(output: string): boolean {
13
+ const trimmed = String(output || '').trim()
14
+ if (!trimmed) return false
15
+ if (/^(Error(?::|\s*\(exit\b[^)]*\):?)|error:)/i.test(trimmed)) return true
16
+ if (/\b(MCP error|ECONNREFUSED|ETIMEDOUT|ERR_CONNECTION_REFUSED|ENOENT|EACCES)\b/i.test(trimmed)) return true
17
+ if (/\binvalid_type\b/i.test(trimmed) && /\b(issue|issues|expected|required|received|zod)\b/i.test(trimmed)) return true
18
+ try {
19
+ const parsed = JSON.parse(trimmed) as Record<string, unknown>
20
+ const status = typeof parsed.status === 'string' ? parsed.status.trim().toLowerCase() : ''
21
+ if (status === 'error' || status === 'failed') return true
22
+ if (typeof parsed.error === 'string' && parsed.error.trim()) return true
23
+ } catch {
24
+ // Ignore non-JSON tool output.
25
+ }
26
+ return false
27
+ }
28
+
29
+ export function collectToolEvent(ev: SSEEvent, bag: MessageToolEvent[]) {
30
+ if (ev.t === 'tool_call') {
31
+ const previous = bag[bag.length - 1]
32
+ if (
33
+ previous
34
+ && previous.name === (ev.toolName || 'unknown')
35
+ && previous.input === (ev.toolInput || '')
36
+ && previous.toolCallId === (ev.toolCallId || previous.toolCallId)
37
+ && !previous.output
38
+ ) {
39
+ return
40
+ }
41
+ bag.push({
42
+ name: ev.toolName || 'unknown',
43
+ input: ev.toolInput || '',
44
+ toolCallId: ev.toolCallId,
45
+ })
46
+ return
47
+ }
48
+ if (ev.t === 'tool_result') {
49
+ const idx = ev.toolCallId
50
+ ? bag.findLastIndex((event) => event.toolCallId === ev.toolCallId && !event.output)
51
+ : bag.findLastIndex((event) => event.name === (ev.toolName || 'unknown') && !event.output)
52
+ if (idx === -1) return
53
+ const output = ev.toolOutput || ''
54
+ bag[idx] = {
55
+ ...bag[idx],
56
+ output,
57
+ error: isLikelyToolErrorOutput(output) || undefined,
58
+ }
59
+ }
60
+ }
61
+
62
+ export function dedupeConsecutiveToolEvents(events: MessageToolEvent[]): MessageToolEvent[] {
63
+ const sameEvent = (left: MessageToolEvent, right: MessageToolEvent): boolean => (
64
+ left.name === right.name
65
+ && left.input === right.input
66
+ && (left.output || '') === (right.output || '')
67
+ && (left.error === true) === (right.error === true)
68
+ )
69
+ const sameBlock = (startA: number, startB: number, size: number): boolean => {
70
+ for (let offset = 0; offset < size; offset += 1) {
71
+ if (!sameEvent(events[startA + offset], events[startB + offset])) return false
72
+ }
73
+ return true
74
+ }
75
+
76
+ const deduped: MessageToolEvent[] = []
77
+ for (let index = 0; index < events.length;) {
78
+ const remaining = events.length - index
79
+ let collapsed = false
80
+ for (let blockSize = Math.floor(remaining / 2); blockSize >= 1; blockSize -= 1) {
81
+ if (!sameBlock(index, index + blockSize, blockSize)) continue
82
+ for (let offset = 0; offset < blockSize; offset += 1) deduped.push(events[index + offset])
83
+ const blockStart = index
84
+ index += blockSize
85
+ while (index + blockSize <= events.length && sameBlock(blockStart, index, blockSize)) {
86
+ index += blockSize
87
+ }
88
+ collapsed = true
89
+ break
90
+ }
91
+ if (collapsed) continue
92
+ deduped.push(events[index])
93
+ index += 1
94
+ }
95
+ return deduped
96
+ }
97
+
98
+ export function deriveTerminalRunError(params: {
99
+ errorMessage?: string
100
+ fullResponse: string
101
+ streamErrors: string[]
102
+ toolEvents: MessageToolEvent[]
103
+ internal: boolean
104
+ }): string | undefined {
105
+ if (params.errorMessage) return params.errorMessage
106
+
107
+ if (params.streamErrors.length > 0 && !params.fullResponse.trim()) {
108
+ return params.streamErrors[params.streamErrors.length - 1]
109
+ }
110
+
111
+ if (!params.internal && !params.fullResponse.trim() && params.toolEvents.length === 0) {
112
+ return 'Run completed without any response text, tool calls, or explicit error details. Check the provider configuration and try again.'
113
+ }
114
+
115
+ return undefined
116
+ }