@swarmclawai/swarmclaw 1.2.6 → 1.2.9

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 (269) hide show
  1. package/README.md +54 -23
  2. package/next.config.ts +1 -0
  3. package/package.json +4 -3
  4. package/scripts/easy-setup.mjs +1 -1
  5. package/scripts/postinstall.mjs +1 -1
  6. package/skills/swarmclaw.md +115 -0
  7. package/skills/tools/browser.md +131 -0
  8. package/skills/tools/execute.md +98 -0
  9. package/skills/tools/files.md +98 -0
  10. package/skills/tools/memory.md +104 -0
  11. package/skills/tools/platform.md +144 -0
  12. package/skills/tools/skills.md +83 -0
  13. package/src/app/agents/[id]/page.tsx +1 -18
  14. package/src/app/api/agents/thread-route.test.ts +0 -1
  15. package/src/app/api/approvals/route.test.ts +6 -22
  16. package/src/app/api/chats/[id]/messages/route.ts +23 -19
  17. package/src/app/api/chats/messages-route.test.ts +105 -51
  18. package/src/app/api/connectors/route.ts +2 -2
  19. package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
  20. package/src/app/api/openclaw/deploy/route.ts +2 -0
  21. package/src/app/api/portability/export/route.ts +8 -0
  22. package/src/app/api/portability/import/route.test.ts +80 -0
  23. package/src/app/api/portability/import/route.ts +28 -0
  24. package/src/app/api/settings/route.ts +0 -2
  25. package/src/app/api/setup/doctor/route.ts +4 -4
  26. package/src/app/api/wallets/[id]/route.ts +15 -157
  27. package/src/app/api/wallets/generate/route.ts +22 -0
  28. package/src/app/api/wallets/route.test.ts +147 -0
  29. package/src/app/api/wallets/route.ts +13 -95
  30. package/src/app/autonomy/page.tsx +2 -57
  31. package/src/app/protocols/page.tsx +2 -21
  32. package/src/app/settings/page.tsx +0 -9
  33. package/src/app/wallets/page.tsx +105 -5
  34. package/src/cli/index.js +21 -33
  35. package/src/cli/spec.js +19 -30
  36. package/src/components/agents/agent-chat-list.tsx +23 -1
  37. package/src/components/agents/agent-sheet.tsx +2 -40
  38. package/src/components/agents/inspector-panel.tsx +165 -131
  39. package/src/components/chat/chat-area.tsx +38 -9
  40. package/src/components/chat/chat-card.tsx +0 -31
  41. package/src/components/chat/message-bubble.tsx +1 -108
  42. package/src/components/chat/message-list.tsx +33 -19
  43. package/src/components/connectors/connector-sheet.tsx +25 -1
  44. package/src/components/gateways/gateway-sheet.tsx +5 -2
  45. package/src/components/layout/sidebar-rail.tsx +6 -10
  46. package/src/components/projects/project-detail.tsx +3 -35
  47. package/src/components/projects/tabs/overview-tab.tsx +3 -59
  48. package/src/components/projects/tabs/work-tab.tsx +7 -77
  49. package/src/components/protocols/structured-session-launcher.tsx +1 -22
  50. package/src/components/shared/connector-platform-icon.tsx +1 -0
  51. package/src/components/tasks/task-card.tsx +4 -34
  52. package/src/components/tasks/task-sheet.tsx +6 -36
  53. package/src/components/wallets/wallet-list.tsx +150 -0
  54. package/src/lib/agent-execute-defaults.test.ts +24 -0
  55. package/src/lib/agent-execute-defaults.ts +62 -0
  56. package/src/lib/app/navigation.test.ts +0 -13
  57. package/src/lib/app/navigation.ts +2 -7
  58. package/src/lib/app/view-constants.ts +14 -19
  59. package/src/lib/chat/queued-message-queue.test.ts +134 -1
  60. package/src/lib/chat/queued-message-queue.ts +77 -2
  61. package/src/lib/server/agents/agent-service.ts +5 -0
  62. package/src/lib/server/agents/agent-thread-session.ts +0 -1
  63. package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
  64. package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
  65. package/src/lib/server/agents/delegation-jobs.ts +0 -25
  66. package/src/lib/server/agents/main-agent-loop.ts +1 -49
  67. package/src/lib/server/agents/subagent-runtime.ts +0 -1
  68. package/src/lib/server/approval-match.ts +0 -85
  69. package/src/lib/server/approvals.test.ts +6 -6
  70. package/src/lib/server/approvals.ts +0 -6
  71. package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
  72. package/src/lib/server/builtin-extensions.ts +1 -2
  73. package/src/lib/server/capability-router.test.ts +0 -2
  74. package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
  75. package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
  76. package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
  77. package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
  78. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
  79. package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
  80. package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
  81. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
  82. package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
  83. package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
  84. package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
  85. package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
  86. package/src/lib/server/chat-execution/message-classifier.ts +11 -16
  87. package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
  88. package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
  89. package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
  90. package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
  91. package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
  92. package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
  93. package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
  94. package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
  95. package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
  96. package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
  97. package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
  98. package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
  99. package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
  100. package/src/lib/server/chats/chat-session-service.ts +3 -5
  101. package/src/lib/server/connectors/connector-inbound.ts +0 -1
  102. package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
  103. package/src/lib/server/connectors/connector-service.ts +39 -9
  104. package/src/lib/server/connectors/discord.ts +2 -2
  105. package/src/lib/server/connectors/matrix.ts +3 -2
  106. package/src/lib/server/connectors/signal.ts +5 -4
  107. package/src/lib/server/connectors/slack.ts +10 -9
  108. package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
  109. package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
  110. package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
  111. package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
  112. package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
  113. package/src/lib/server/connectors/swarmdock.ts +255 -0
  114. package/src/lib/server/connectors/teams.ts +3 -2
  115. package/src/lib/server/connectors/telegram.ts +4 -4
  116. package/src/lib/server/connectors/whatsapp.ts +2 -2
  117. package/src/lib/server/daemon/controller.ts +7 -0
  118. package/src/lib/server/execution-brief.test.ts +2 -25
  119. package/src/lib/server/execution-brief.ts +12 -35
  120. package/src/lib/server/execution-engine/task-attempt.ts +0 -1
  121. package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
  122. package/src/lib/server/messages/message-repository.test.ts +70 -0
  123. package/src/lib/server/messages/message-repository.ts +11 -6
  124. package/src/lib/server/openclaw/deploy.ts +32 -2
  125. package/src/lib/server/persistence/storage-context.ts +0 -5
  126. package/src/lib/server/plugins-advanced.test.ts +1 -2
  127. package/src/lib/server/portability/export.ts +109 -0
  128. package/src/lib/server/portability/import.ts +159 -0
  129. package/src/lib/server/protocols/protocol-normalization.ts +0 -4
  130. package/src/lib/server/protocols/protocol-queries.ts +0 -6
  131. package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
  132. package/src/lib/server/protocols/protocol-service.ts +0 -1
  133. package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
  134. package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
  135. package/src/lib/server/protocols/protocol-swarm.ts +0 -2
  136. package/src/lib/server/protocols/protocol-types.ts +0 -2
  137. package/src/lib/server/provider-health.ts +1 -10
  138. package/src/lib/server/runtime/daemon-state/core.ts +0 -9
  139. package/src/lib/server/runtime/daemon-state.test.ts +0 -35
  140. package/src/lib/server/runtime/heartbeat-service.ts +3 -23
  141. package/src/lib/server/runtime/process-manager.ts +13 -9
  142. package/src/lib/server/runtime/queue/core.ts +11 -33
  143. package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
  144. package/src/lib/server/runtime/scheduler.ts +0 -13
  145. package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
  146. package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
  147. package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
  148. package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
  149. package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
  150. package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
  151. package/src/lib/server/sandbox/session-runtime.ts +40 -28
  152. package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
  153. package/src/lib/server/session-tools/context.ts +1 -1
  154. package/src/lib/server/session-tools/credential-env.ts +109 -0
  155. package/src/lib/server/session-tools/crud.ts +3 -17
  156. package/src/lib/server/session-tools/delegate.ts +0 -4
  157. package/src/lib/server/session-tools/edit_file.ts +3 -2
  158. package/src/lib/server/session-tools/execute.test.ts +58 -0
  159. package/src/lib/server/session-tools/execute.ts +334 -0
  160. package/src/lib/server/session-tools/files-tool.ts +635 -0
  161. package/src/lib/server/session-tools/index.ts +14 -8
  162. package/src/lib/server/session-tools/memory-tool.ts +242 -0
  163. package/src/lib/server/session-tools/memory.ts +1 -1
  164. package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
  165. package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
  166. package/src/lib/server/session-tools/platform-tool.ts +617 -0
  167. package/src/lib/server/session-tools/session-info.ts +3 -2
  168. package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
  169. package/src/lib/server/session-tools/shell.ts +7 -122
  170. package/src/lib/server/session-tools/skills-tool.ts +396 -0
  171. package/src/lib/server/session-tools/team-context.ts +0 -3
  172. package/src/lib/server/session-tools/web.ts +2 -2
  173. package/src/lib/server/storage-normalization.ts +10 -0
  174. package/src/lib/server/storage.ts +18 -45
  175. package/src/lib/server/tasks/task-checkout.ts +59 -0
  176. package/src/lib/server/tasks/task-lifecycle.ts +2 -0
  177. package/src/lib/server/tasks/task-route-service.ts +4 -26
  178. package/src/lib/server/tasks/task-service.ts +0 -7
  179. package/src/lib/server/tool-aliases.ts +2 -2
  180. package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
  181. package/src/lib/server/tool-capability-policy.test.ts +2 -1
  182. package/src/lib/server/tool-capability-policy.ts +60 -35
  183. package/src/lib/server/tool-planning.ts +11 -12
  184. package/src/lib/server/universal-tool-access.ts +0 -1
  185. package/src/lib/server/wallets/wallet-crypto.ts +33 -0
  186. package/src/lib/server/wallets/wallet-repository.ts +24 -0
  187. package/src/lib/server/wallets/wallet-service.ts +119 -0
  188. package/src/lib/server/working-state/extraction.ts +8 -42
  189. package/src/lib/server/working-state/normalization.ts +10 -103
  190. package/src/lib/server/working-state/service.ts +12 -21
  191. package/src/lib/setup-defaults.ts +5 -0
  192. package/src/lib/strip-internal-metadata.test.ts +1 -1
  193. package/src/lib/strip-internal-metadata.ts +1 -1
  194. package/src/lib/tool-definitions.ts +1 -1
  195. package/src/lib/validation/schemas.test.ts +16 -0
  196. package/src/lib/validation/schemas.ts +49 -2
  197. package/src/stores/slices/data-slice.ts +5 -1
  198. package/src/stores/slices/ui-slice.ts +0 -4
  199. package/src/stores/use-chat-store.test.ts +231 -0
  200. package/src/stores/use-chat-store.ts +62 -13
  201. package/src/types/agent.ts +264 -0
  202. package/src/types/app-settings.ts +173 -0
  203. package/src/types/approval.ts +25 -0
  204. package/src/types/connector.ts +188 -0
  205. package/src/types/extension.ts +386 -0
  206. package/src/types/index.ts +16 -3555
  207. package/src/types/message.ts +56 -0
  208. package/src/types/misc.ts +737 -0
  209. package/src/types/protocol.ts +420 -0
  210. package/src/types/provider.ts +52 -0
  211. package/src/types/run.ts +180 -0
  212. package/src/types/schedule.ts +59 -0
  213. package/src/types/session.ts +215 -0
  214. package/src/types/skill.ts +157 -0
  215. package/src/types/swarmdock.ts +29 -0
  216. package/src/types/task.ts +144 -0
  217. package/src/types/working-state.ts +204 -0
  218. package/src/views/settings/section-heartbeat.tsx +2 -2
  219. package/src/views/settings/section-runtime-loop.tsx +0 -14
  220. package/src/app/api/canvas/[sessionId]/route.ts +0 -35
  221. package/src/app/api/missions/[id]/actions/route.ts +0 -31
  222. package/src/app/api/missions/[id]/events/route.ts +0 -14
  223. package/src/app/api/missions/[id]/route.ts +0 -10
  224. package/src/app/api/missions/route.test.ts +0 -244
  225. package/src/app/api/missions/route.ts +0 -57
  226. package/src/app/api/wallets/[id]/approve/route.ts +0 -79
  227. package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
  228. package/src/app/api/wallets/[id]/send/route.ts +0 -113
  229. package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
  230. package/src/app/missions/[id]/page.tsx +0 -3
  231. package/src/app/missions/page.tsx +0 -685
  232. package/src/components/canvas/canvas-panel.tsx +0 -267
  233. package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
  234. package/src/components/wallets/wallet-panel.tsx +0 -1010
  235. package/src/components/wallets/wallet-section.tsx +0 -260
  236. package/src/features/missions/queries.ts +0 -23
  237. package/src/lib/canvas-content.test.ts +0 -360
  238. package/src/lib/canvas-content.ts +0 -198
  239. package/src/lib/server/canvas-content.test.ts +0 -32
  240. package/src/lib/server/canvas-content.ts +0 -6
  241. package/src/lib/server/ethereum.ts +0 -591
  242. package/src/lib/server/evm-swap.ts +0 -476
  243. package/src/lib/server/missions/mission-intent.test.ts +0 -63
  244. package/src/lib/server/missions/mission-intent.ts +0 -569
  245. package/src/lib/server/missions/mission-repository.ts +0 -74
  246. package/src/lib/server/missions/mission-service/actions.ts +0 -6
  247. package/src/lib/server/missions/mission-service/bindings.ts +0 -9
  248. package/src/lib/server/missions/mission-service/context.ts +0 -4
  249. package/src/lib/server/missions/mission-service/core.ts +0 -2271
  250. package/src/lib/server/missions/mission-service/queries.ts +0 -12
  251. package/src/lib/server/missions/mission-service/recovery.ts +0 -5
  252. package/src/lib/server/missions/mission-service/ticks.ts +0 -9
  253. package/src/lib/server/missions/mission-service.test.ts +0 -888
  254. package/src/lib/server/missions/mission-service.ts +0 -6
  255. package/src/lib/server/session-tools/canvas.ts +0 -105
  256. package/src/lib/server/session-tools/sandbox.ts +0 -281
  257. package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
  258. package/src/lib/server/session-tools/wallet.ts +0 -1287
  259. package/src/lib/server/solana.ts +0 -327
  260. package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
  261. package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
  262. package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
  263. package/src/lib/server/wallet/wallet-service.test.ts +0 -81
  264. package/src/lib/server/wallet/wallet-service.ts +0 -225
  265. package/src/lib/wallet/wallet-transactions.test.ts +0 -75
  266. package/src/lib/wallet/wallet-transactions.ts +0 -43
  267. package/src/lib/wallet/wallet.test.ts +0 -333
  268. package/src/lib/wallet/wallet.ts +0 -183
  269. package/src/views/settings/section-wallets.tsx +0 -35
@@ -78,7 +78,6 @@ import {
78
78
  buildToolAvailabilityLines,
79
79
  buildToolDisciplineLines,
80
80
  buildToolSection,
81
- buildExternalWalletExecutionBlock,
82
81
  buildForcedExternalServiceSummary,
83
82
  shouldForceAttachmentFollowthrough,
84
83
  joinPromptSegments,
@@ -101,7 +100,6 @@ import { finalizeStreamResult } from '@/lib/server/chat-execution/post-stream-fi
101
100
  import {
102
101
  classifyMessage,
103
102
  isDeliverableTask as classifiedIsDeliverableTask,
104
- hasTransactionalWalletIntent as classifiedHasTransactionalWalletIntent,
105
103
  isResearchSynthesis as classifiedIsResearchSynthesis,
106
104
  type MessageClassification,
107
105
  } from '@/lib/server/chat-execution/message-classifier'
@@ -125,7 +123,6 @@ export {
125
123
  buildToolAvailabilityLines,
126
124
  buildToolDisciplineLines,
127
125
  buildToolSection,
128
- buildExternalWalletExecutionBlock,
129
126
  shouldForceAttachmentFollowthrough,
130
127
  buildForcedExternalServiceSummary,
131
128
  }
@@ -142,7 +139,6 @@ export {
142
139
  } from '@/lib/server/chat-execution/stream-continuation'
143
140
 
144
141
  export {
145
- isWalletSimulationResult,
146
142
  resolveSuccessfulTerminalToolBoundary,
147
143
  shouldForceExternalServiceSummary,
148
144
  } from '@/lib/server/chat-execution/chat-streaming-utils'
@@ -190,6 +186,7 @@ interface StreamAgentChatOpts {
190
186
  fallbackCredentialIds?: string[]
191
187
  signal?: AbortSignal
192
188
  promptMode?: PromptMode
189
+ classification?: MessageClassification | null
193
190
  /** Run source (e.g. 'heartbeat', 'chat', 'scheduler') — used for heartbeat-specific tuning. */
194
191
  source?: string
195
192
  }
@@ -223,10 +220,23 @@ export async function streamAgentChat(opts: StreamAgentChatOpts): Promise<Stream
223
220
 
224
221
  async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAgentChatResult> {
225
222
  const startTs = Date.now()
226
- const { session, message, imagePath, imageUrl, attachedFiles, apiKey, systemPrompt, executionBrief, extraSystemContext, write, history, fallbackCredentialIds, signal } = opts
223
+ const {
224
+ session,
225
+ message,
226
+ imagePath,
227
+ imageUrl,
228
+ attachedFiles,
229
+ apiKey,
230
+ systemPrompt,
231
+ executionBrief,
232
+ extraSystemContext,
233
+ write,
234
+ history,
235
+ fallbackCredentialIds,
236
+ signal,
237
+ classification: providedClassification,
238
+ } = opts
227
239
  const isHeartbeat = isHeartbeatSource(opts.source)
228
- const promptMode: PromptMode = opts.promptMode ?? resolvePromptMode(session)
229
- const isMinimalPrompt = promptMode === 'minimal'
230
240
  const isConnectorSession = isDirectConnectorSession(session)
231
241
  const rawExtensions = getEnabledCapabilityIds(session)
232
242
  const hasShellCapability = rawExtensions.some((toolId) => ['shell', 'execute_command'].includes(String(toolId)))
@@ -241,6 +251,23 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
241
251
 
242
252
  const sessionAgent = session.agentId ? getAgent(session.agentId) : null
243
253
 
254
+ const classificationPromise = providedClassification !== undefined
255
+ ? Promise.resolve(providedClassification)
256
+ : classifyMessage({
257
+ sessionId: session.id,
258
+ agentId: session.agentId,
259
+ message,
260
+ history,
261
+ }).catch(() => null as MessageClassification | null)
262
+ const classification = await classificationPromise
263
+ const lightweightDirectChat = classification?.isLightweightDirectChat === true
264
+ && !isConnectorSession
265
+ && !isHeartbeat
266
+ const promptMode: PromptMode = opts.promptMode ?? resolvePromptMode(session, {
267
+ preferMinimalPrompt: lightweightDirectChat,
268
+ })
269
+ const isMinimalPrompt = promptMode === 'minimal'
270
+
244
271
  // Resolve agent's thinking level for provider-native params
245
272
  let agentThinkingLevel: 'minimal' | 'low' | 'medium' | 'high' | undefined
246
273
  if (session.thinkingLevel) {
@@ -248,6 +275,9 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
248
275
  } else if (sessionAgent) {
249
276
  agentThinkingLevel = sessionAgent.thinkingLevel
250
277
  }
278
+ if (lightweightDirectChat) {
279
+ agentThinkingLevel = 'minimal'
280
+ }
251
281
 
252
282
  const llm = buildChatModel({
253
283
  provider: session.provider,
@@ -296,16 +326,6 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
296
326
  return Math.max(0, Math.min(3600, Math.trunc(parsed)))
297
327
  })()
298
328
 
299
- // -------------------------------------------------------------------------
300
- // Start message classification in the background (LLM-based, ~200-800ms)
301
- // -------------------------------------------------------------------------
302
- const classificationPromise = classifyMessage({
303
- sessionId: session.id,
304
- agentId: session.agentId,
305
- message,
306
- history,
307
- }).catch(() => null as MessageClassification | null)
308
-
309
329
  // -------------------------------------------------------------------------
310
330
  // System prompt assembly (stays inline — many async calls + local state)
311
331
  // -------------------------------------------------------------------------
@@ -426,8 +446,6 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
426
446
  const suggestionsBlock = buildSuggestionsSection(settings.suggestionsEnabled, isMinimalPrompt)
427
447
  if (suggestionsBlock) promptParts.push(suggestionsBlock)
428
448
 
429
- // Await classification before building the agentic execution policy
430
- const classification = await classificationPromise
431
449
  const delegationAdvisory = sessionAgent && agentDelegationEnabled
432
450
  ? resolveDelegationAdvisory({
433
451
  currentAgent: sessionAgent,
@@ -867,7 +885,7 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
867
885
  const routingDecision = routeTaskIntent(message, sessionExtensions, null, classification)
868
886
  const explicitRequiredToolNames = getExplicitRequiredToolNames(message, sessionExtensions)
869
887
 
870
- const boundedExternalExecutionTask = classifiedHasTransactionalWalletIntent(classification, message)
888
+ const boundedExternalExecutionTask = false
871
889
  const likelyResearchSynthesisTask = classifiedIsResearchSynthesis(classification, routingDecision.intent)
872
890
  const shouldEnforceEarlyRequiredToolKickoff = explicitRequiredToolNames.length > 0
873
891
  && classifiedIsDeliverableTask(classification, message)
@@ -1138,7 +1156,14 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
1138
1156
  }
1139
1157
 
1140
1158
  // Async LLM-based incomplete-action check: catches "I'll run the deployment:" with no tool calls
1141
- if (!shouldContinue && outcome && !state.hasToolCalls && state.fullText.trim().length > 0 && state.fullText.trim().length < 500) {
1159
+ if (
1160
+ !shouldContinue
1161
+ && outcome
1162
+ && !state.hasToolCalls
1163
+ && classification?.isLightweightDirectChat !== true
1164
+ && state.fullText.trim().length > 0
1165
+ && state.fullText.trim().length < 500
1166
+ ) {
1142
1167
  const completeness = await evaluateResponseCompleteness({
1143
1168
  sessionId: session.id,
1144
1169
  agentId: session.agentId,
@@ -46,36 +46,6 @@ describe('stream-continuation', () => {
46
46
  })
47
47
  })
48
48
 
49
- // ---- looksLikeExternalWalletTask ----
50
- describe('looksLikeExternalWalletTask', () => {
51
- it('matches wallet keywords', () => {
52
- assert.equal(mod.looksLikeExternalWalletTask('swap 100 USDC on Arbitrum'), true)
53
- assert.equal(mod.looksLikeExternalWalletTask('check my wallet balance'), true)
54
- assert.equal(mod.looksLikeExternalWalletTask('trade ETH for SOL'), true)
55
- })
56
-
57
- it('returns false for empty/unrelated text', () => {
58
- assert.equal(mod.looksLikeExternalWalletTask(''), false)
59
- assert.equal(mod.looksLikeExternalWalletTask('write me a poem about cats'), false)
60
- })
61
- })
62
-
63
- // ---- looksLikeBoundedExternalExecutionTask ----
64
- describe('looksLikeBoundedExternalExecutionTask', () => {
65
- it('requires wallet keywords + action verbs', () => {
66
- assert.equal(mod.looksLikeBoundedExternalExecutionTask('swap 100 USDC on Arbitrum'), true)
67
- assert.equal(mod.looksLikeBoundedExternalExecutionTask('buy ETH on the exchange'), true)
68
- })
69
-
70
- it('returns false without action verbs', () => {
71
- assert.equal(mod.looksLikeBoundedExternalExecutionTask('check my wallet balance'), false)
72
- })
73
-
74
- it('returns false for non-wallet text', () => {
75
- assert.equal(mod.looksLikeBoundedExternalExecutionTask('execute the test suite'), false)
76
- })
77
- })
78
-
79
49
  // ---- looksLikeOpenEndedDeliverableTask ----
80
50
  describe('looksLikeOpenEndedDeliverableTask', () => {
81
51
  it('matches deliverable patterns', () => {
@@ -112,24 +82,6 @@ describe('stream-continuation', () => {
112
82
  })
113
83
  })
114
84
 
115
- // ---- hasStateChangingWalletEvidence ----
116
- describe('hasStateChangingWalletEvidence', () => {
117
- it('detects send_transaction action in wallet_tool', () => {
118
- const events = [{ name: 'wallet_tool', input: '{"action":"send_transaction"}', output: '{}' }]
119
- assert.equal(mod.hasStateChangingWalletEvidence(events), true)
120
- })
121
-
122
- it('returns false for non-wallet tools', () => {
123
- const events = [{ name: 'web', input: 'search', output: 'results' }]
124
- assert.equal(mod.hasStateChangingWalletEvidence(events), false)
125
- })
126
-
127
- it('returns false for read-only wallet actions', () => {
128
- const events = [{ name: 'wallet_tool', input: '{"action":"balance"}', output: '{}' }]
129
- assert.equal(mod.hasStateChangingWalletEvidence(events), false)
130
- })
131
- })
132
-
133
85
  // ---- countExternalExecutionResearchSteps ----
134
86
  describe('countExternalExecutionResearchSteps', () => {
135
87
  it('counts http/web/browser tools', () => {
@@ -141,12 +93,12 @@ describe('stream-continuation', () => {
141
93
  assert.equal(mod.countExternalExecutionResearchSteps(events), 2)
142
94
  })
143
95
 
144
- it('counts read-only wallet actions', () => {
96
+ it('does not count non-research tools', () => {
145
97
  const events = [
146
- { name: 'wallet_tool', input: '{"action":"balance"}', output: '{}' },
147
- { name: 'wallet_tool', input: '{"action":"send_transaction"}', output: '{}' },
98
+ { name: 'shell', input: 'ls', output: 'files' },
99
+ { name: 'files', input: 'read', output: 'content' },
148
100
  ]
149
- assert.equal(mod.countExternalExecutionResearchSteps(events), 1)
101
+ assert.equal(mod.countExternalExecutionResearchSteps(events), 0)
150
102
  })
151
103
  })
152
104
 
@@ -194,25 +194,9 @@ function getRequestedArtifactStatus(params: {
194
194
  // Tool evidence analysis
195
195
  // ---------------------------------------------------------------------------
196
196
 
197
- export function hasStateChangingWalletEvidence(toolEvents: MessageToolEvent[]): boolean {
198
- return toolEvents.some((event) => {
199
- const input = `${event.input || ''}\n${event.output || ''}`
200
- return event.name === 'wallet_tool' && (
201
- /"action":"send_transaction"/.test(input)
202
- || /"action":"send"/.test(input)
203
- || /"action":"sign_transaction"/.test(input)
204
- || /"type":"extension_wallet_action_request"/.test(input)
205
- || /"type":"extension_wallet_transfer_request"/.test(input)
206
- || /"status":"broadcast"/.test(input)
207
- )
208
- })
209
- }
210
-
211
197
  export function countExternalExecutionResearchSteps(toolEvents: MessageToolEvent[]): number {
212
198
  return toolEvents.filter((event) => {
213
- if (['http_request', 'web', 'web_search', 'web_fetch', 'browser'].includes(event.name)) return true
214
- if (event.name !== 'wallet_tool') return false
215
- return /"action":"(balance|address|transactions|call_contract|encode_contract_call)"/.test(event.input || '')
199
+ return ['http_request', 'web', 'web_search', 'web_fetch', 'browser'].includes(event.name)
216
200
  }).length
217
201
  }
218
202
 
@@ -238,49 +222,24 @@ export function countDistinctExternalResearchHosts(toolEvents: MessageToolEvent[
238
222
  // Continuation decision helpers
239
223
  // ---------------------------------------------------------------------------
240
224
 
241
- export function shouldForceExternalExecutionFollowthrough(params: {
225
+ export function shouldForceExternalExecutionFollowthrough(_params: {
242
226
  userMessage: string
243
227
  finalResponse: string
244
228
  hasToolCalls: boolean
245
229
  toolEvents: MessageToolEvent[]
246
230
  classification?: MessageClassification | null
247
231
  }): boolean {
248
- const isTransactional = params.classification?.walletIntent === 'transactional'
249
- if (!isTransactional) return false
250
- if (!params.hasToolCalls || params.toolEvents.length < 4) return false
251
- if (hasStateChangingWalletEvidence(params.toolEvents)) return false
252
- const distinctHosts = countDistinctExternalResearchHosts(params.toolEvents)
253
- const trimmed = params.finalResponse.trim()
254
- if (!trimmed) return countExternalExecutionResearchSteps(params.toolEvents) >= 4 || distinctHosts >= 3
255
- if (/\b(last reversible step|exact blocker|safest next action|blocked|cannot|can't|missing capability|no-key route unavailable)\b/i.test(trimmed)) {
256
- return false
257
- }
258
- if (countExternalExecutionResearchSteps(params.toolEvents) < 4 && distinctHosts < 3) return false
259
- return /(let me|i'll|i will|trying|research|query|check|look|promising|now let me|good -|good,)/i.test(trimmed) || trimmed.length < 500
232
+ return false
260
233
  }
261
234
 
262
- export function shouldForceExternalExecutionKickoffFollowthrough(params: {
235
+ export function shouldForceExternalExecutionKickoffFollowthrough(_params: {
263
236
  userMessage: string
264
237
  finalResponse: string
265
238
  hasToolCalls: boolean
266
239
  toolEvents: MessageToolEvent[]
267
240
  classification?: MessageClassification | null
268
241
  }): boolean {
269
- const isTransactional = params.classification?.walletIntent === 'transactional'
270
- if (!isTransactional) return false
271
- if (params.hasToolCalls || params.toolEvents.length > 0) return false
272
-
273
- const trimmed = params.finalResponse.trim()
274
- if (!trimmed) return true
275
- if (/^(?:HEARTBEAT_OK|NO_MESSAGE)\b/i.test(trimmed)) return false
276
- if (/\?\s*$/.test(trimmed)) return false
277
- if (/\b(last reversible step|exact blocker|blocked|cannot|can't|missing capability|need approval|requires approval|approval boundary|requires human|ask_human|credential|authentication|login|2fa|mfa|captcha)\b/i.test(trimmed)) {
278
- return false
279
- }
280
- if (/\b(done|completed|finished|sent|broadcast|minted|purchased|bought|swapped|claimed)\b/i.test(trimmed)) {
281
- return false
282
- }
283
- return looksLikeIncompleteDeliverableResponse(trimmed) || trimmed.length < 220
242
+ return false
284
243
  }
285
244
 
286
245
  export function shouldForceDeliverableFollowthrough(params: {
@@ -454,8 +413,7 @@ function buildExternalExecutionFollowthroughPrompt(params: {
454
413
  'You are in a bounded external execution task and have already done enough research.',
455
414
  'Do not restart broad discovery. Do not ask the user for another prompt.',
456
415
  'Do not spend this continuation on more venue shopping. Use the already confirmed route unless one last fetch is strictly required to prepare execution.',
457
- 'If several venue or aggregator APIs already failed, stop searching for more venues. Either use a direct onchain read path with the available wallet tools, or state the blocker.',
458
- 'A prose approval request does not count as completion. If the next step is a sign/send/approve action, call the real wallet tool action so the runtime can create the approval request.',
416
+ 'If several venue or aggregator APIs already failed, stop searching for more venues and state the blocker.',
459
417
  'Do not mutate already confirmed token addresses, router addresses, spender addresses, or network identifiers unless newer tool evidence proves the earlier value was wrong.',
460
418
  'Within this continuation, do exactly one of the following:',
461
419
  '1. Take the next concrete execution step now using the existing tools and stop at the first approval boundary for a state-changing action.',
@@ -16,6 +16,8 @@ const agents: Record<string, Agent> = {
16
16
  model: 'gpt-test',
17
17
  systemPrompt: '',
18
18
  capabilities: ['deploy', 'infrastructure'],
19
+ createdAt: Date.now(),
20
+ updatedAt: Date.now(),
19
21
  },
20
22
  design: {
21
23
  id: 'design',
@@ -25,6 +27,8 @@ const agents: Record<string, Agent> = {
25
27
  model: 'gpt-test',
26
28
  systemPrompt: '',
27
29
  capabilities: ['design', 'ui'],
30
+ createdAt: Date.now(),
31
+ updatedAt: Date.now(),
28
32
  },
29
33
  }
30
34
 
@@ -1,7 +1,6 @@
1
1
  import { genId } from '@/lib/id'
2
2
  import type { MailboxEnvelope } from '@/types'
3
3
  import { loadSession, patchSession } from '@/lib/server/sessions/session-repository'
4
- import { requestMissionTicksForHumanReply } from '@/lib/server/missions/mission-service'
5
4
 
6
5
  interface MailboxOptions {
7
6
  limit?: number
@@ -167,15 +166,6 @@ export function sendMailboxEnvelope(input: {
167
166
  lastActiveAt: now,
168
167
  }
169
168
  })
170
- if (envelope.type === 'human_reply') {
171
- requestMissionTicksForHumanReply({
172
- sessionId: input.toSessionId,
173
- correlationId: envelope.correlationId || null,
174
- envelopeId: envelope.id,
175
- payload: envelope.payload,
176
- fromSessionId: envelope.fromSessionId || null,
177
- })
178
- }
179
169
  import('@/lib/server/runtime/watch-jobs')
180
170
  .then(({ triggerMailboxWatchJobs }) => {
181
171
  triggerMailboxWatchJobs({ sessionId: input.toSessionId, envelope })
@@ -7,7 +7,6 @@ import { buildAgentDisabledMessage, isAgentDisabled } from '@/lib/server/agents/
7
7
  import { loadAgent } from '@/lib/server/agents/agent-repository'
8
8
  import { clearMainLoopStateForSession } from '@/lib/server/agents/main-agent-loop'
9
9
  import { applyResolvedRoute, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
10
- import { enrichSessionWithMissionSummary } from '@/lib/server/missions/mission-service'
11
10
  import { cleanupSessionProcesses } from '@/lib/server/runtime/process-manager'
12
11
  import { stopActiveSessionProcess } from '@/lib/server/runtime/runtime-state'
13
12
  import {
@@ -60,7 +59,7 @@ export function listChatsForApi(): Record<string, ReturnType<typeof buildSession
60
59
  sessions[id].currentRunId = run.runningRunId || null
61
60
  }
62
61
  return Object.fromEntries(
63
- Object.entries(sessions).map(([id, session]) => [id, buildSessionListSummary(enrichSessionWithMissionSummary(session))]),
62
+ Object.entries(sessions).map(([id, session]) => [id, buildSessionListSummary(session)]),
64
63
  )
65
64
  }
66
65
 
@@ -72,7 +71,7 @@ export function getChatSessionForApi(sessionId: string): Session | null {
72
71
  session.active = !!run.runningRunId
73
72
  session.queuedCount = queue.queueLength
74
73
  session.currentRunId = run.runningRunId || null
75
- return enrichSessionWithMissionSummary(session)
74
+ return session
76
75
  }
77
76
 
78
77
  export function createChatSession(input: Record<string, unknown>): ServiceResult<Session> {
@@ -285,7 +284,7 @@ export function updateChatSession(sessionId: string, updates: Record<string, unk
285
284
 
286
285
  saveSession(sessionId, original)
287
286
  notify('sessions')
288
- return enrichSessionWithMissionSummary(original)
287
+ return original
289
288
  }
290
289
 
291
290
  export function deleteChatSession(sessionId: string): boolean {
@@ -320,7 +319,6 @@ export function queueChatMessage(sessionId: string, body: Record<string, unknown
320
319
  }
321
320
  const queued = enqueueSessionRun({
322
321
  sessionId,
323
- missionId: session.missionId || null,
324
322
  message,
325
323
  imagePath,
326
324
  imageUrl,
@@ -1095,7 +1095,6 @@ If media sending fails, report the exact error and retry with a corrected path/t
1095
1095
 
1096
1096
  const queued = enqueueSessionRun({
1097
1097
  sessionId: session.id,
1098
- missionId: session.missionId || null,
1099
1098
  message: modelInputText,
1100
1099
  imagePath: firstImagePath,
1101
1100
  imageUrl: firstImageUrl,
@@ -19,6 +19,7 @@ import {
19
19
  setReconnectState,
20
20
  } from './reconnect-state'
21
21
  import { connectorRuntimeState, runningConnectors } from './runtime-state'
22
+ import { ensureSwarmdockConnectorCredential } from './swarmdock-secret'
22
23
 
23
24
  const TAG = 'connector-lifecycle'
24
25
 
@@ -70,6 +71,7 @@ export async function getPlatform(platform: string) {
70
71
  case 'googlechat': return (await import('./googlechat')).default
71
72
  case 'matrix': return (await import('./matrix')).default
72
73
  case 'email': return (await import('./email')).default
74
+ case 'swarmdock': return (await import('./swarmdock')).default
73
75
  }
74
76
 
75
77
  // 2. Check Extension-provided connectors
@@ -134,8 +136,9 @@ async function _startConnectorImpl(connectorId: string): Promise<void> {
134
136
  }
135
137
 
136
138
  const connectors = loadConnectors()
137
- const connector = connectors[connectorId] as Connector | undefined
138
- if (!connector) throw new Error('Connector not found')
139
+ const storedConnector = connectors[connectorId] as Connector | undefined
140
+ if (!storedConnector) throw new Error('Connector not found')
141
+ let connector: Connector = storedConnector
139
142
 
140
143
  // Starting a connector expresses durable intent: keep it enabled across
141
144
  // transient failures so daemon recovery and server restarts can retry it.
@@ -148,6 +151,16 @@ async function _startConnectorImpl(connectorId: string): Promise<void> {
148
151
  }
149
152
 
150
153
  try {
154
+ let swarmdockFallbackPrivateKey: string | null = null
155
+ if (connector.platform === 'swarmdock') {
156
+ const prepared = ensureSwarmdockConnectorCredential(connector, {
157
+ allowMigrationFailureFallback: true,
158
+ })
159
+ connector = prepared.connector
160
+ connectors[connectorId] = connector
161
+ swarmdockFallbackPrivateKey = prepared.fallbackPrivateKey
162
+ }
163
+
151
164
  // Resolve bot token from credential
152
165
  let botToken = ''
153
166
  if (connector.credentialId) {
@@ -164,8 +177,11 @@ async function _startConnectorImpl(connectorId: string): Promise<void> {
164
177
  if (!botToken && connector.platform === 'bluebubbles' && connector.config.password) {
165
178
  botToken = connector.config.password
166
179
  }
180
+ if (!botToken && swarmdockFallbackPrivateKey) {
181
+ botToken = swarmdockFallbackPrivateKey
182
+ }
167
183
 
168
- if (!botToken && connector.platform !== 'whatsapp' && connector.platform !== 'openclaw' && connector.platform !== 'signal' && connector.platform !== 'email') {
184
+ if (!botToken && connector.platform !== 'whatsapp' && connector.platform !== 'openclaw' && connector.platform !== 'signal' && connector.platform !== 'email' && connector.platform !== 'swarmdock') {
169
185
  throw new Error('No bot token configured')
170
186
  }
171
187
 
@@ -43,6 +43,11 @@ import type {
43
43
  } from '@/types'
44
44
  import type { ServiceResult } from '@/lib/server/service-result'
45
45
  import type { DaemonConnectorRuntimeState } from '@/lib/server/daemon/types'
46
+ import {
47
+ ensureSwarmdockConnectorCredential,
48
+ prepareSwarmdockConnectorInput,
49
+ redactConnectorSecrets,
50
+ } from './swarmdock-secret'
46
51
 
47
52
  function cloneConnector<T extends Connector>(connector: T): T {
48
53
  return {
@@ -124,35 +129,52 @@ function requireSenderId(body: Record<string, unknown>): string {
124
129
  export async function listConnectorsWithRuntime(): Promise<Record<string, Connector>> {
125
130
  await ensureDaemonProcessRunning('api/connectors:get')
126
131
  const connectors = Object.fromEntries(
127
- Object.entries(loadConnectors()).map(([id, connector]) => [id, cloneConnector(connector)]),
132
+ Object.entries(loadConnectors()).map(([id, connector]) => {
133
+ const prepared = ensureSwarmdockConnectorCredential(connector, {
134
+ allowMigrationFailureFallback: true,
135
+ })
136
+ return [id, cloneConnector(prepared.connector)]
137
+ }),
128
138
  ) as Record<string, Connector>
129
139
  const runtimeByConnector = await listDaemonConnectorRuntime()
130
140
  for (const connector of Object.values(connectors)) {
131
141
  applyRuntimeFields(connector, runtimeByConnector[connector.id] || null)
132
142
  }
133
- return connectors
143
+ return Object.fromEntries(
144
+ Object.entries(connectors).map(([id, connector]) => [id, redactConnectorSecrets(connector)]),
145
+ )
134
146
  }
135
147
 
136
148
  export async function getConnectorWithRuntime(id: string): Promise<Connector | null> {
137
149
  await ensureDaemonProcessRunning('api/connectors/[id]:get')
138
150
  const connector = loadConnector(id)
139
151
  if (!connector) return null
140
- const current = cloneConnector(connector)
141
- return applyRuntimeFields(current, await getDaemonConnectorRuntime(id))
152
+ const prepared = ensureSwarmdockConnectorCredential(connector, {
153
+ allowMigrationFailureFallback: true,
154
+ })
155
+ const current = cloneConnector(prepared.connector)
156
+ return redactConnectorSecrets(applyRuntimeFields(current, await getDaemonConnectorRuntime(id)))
142
157
  }
143
158
 
144
159
  export function createConnector(body: Record<string, unknown>): Connector {
145
160
  const id = genId()
161
+ const rawConfig = body.config && typeof body.config === 'object' && !Array.isArray(body.config)
162
+ ? body.config as Record<string, string>
163
+ : {}
164
+ const prepared = prepareSwarmdockConnectorInput({
165
+ platform: body.platform as Connector['platform'],
166
+ name: (body.name as string) || `${String(body.platform || '')} Connector`,
167
+ credentialId: (body.credentialId as string | null | undefined) || null,
168
+ config: rawConfig,
169
+ })
146
170
  const connector: Connector = {
147
171
  id,
148
172
  name: (body.name as string) || `${String(body.platform || '')} Connector`,
149
173
  platform: body.platform as Connector['platform'],
150
174
  agentId: (body.agentId as string | null | undefined) || null,
151
175
  chatroomId: (body.chatroomId as string | null | undefined) || null,
152
- credentialId: (body.credentialId as string | null | undefined) || null,
153
- config: body.config && typeof body.config === 'object' && !Array.isArray(body.config)
154
- ? body.config as Record<string, string>
155
- : {},
176
+ credentialId: prepared.credentialId,
177
+ config: prepared.config,
156
178
  isEnabled: false,
157
179
  status: 'stopped',
158
180
  lastError: null,
@@ -210,6 +232,14 @@ export async function updateConnectorFromRoute(id: string, body: Record<string,
210
232
  if (body.credentialId !== undefined) next.credentialId = typeof body.credentialId === 'string' || body.credentialId === null ? body.credentialId : next.credentialId
211
233
  if (body.config !== undefined) next.config = body.config && typeof body.config === 'object' && !Array.isArray(body.config) ? body.config as Record<string, string> : next.config
212
234
  if (body.isEnabled !== undefined) next.isEnabled = typeof body.isEnabled === 'boolean' ? body.isEnabled : next.isEnabled
235
+ const prepared = prepareSwarmdockConnectorInput({
236
+ platform: next.platform,
237
+ name: next.name,
238
+ credentialId: next.credentialId || null,
239
+ config: next.config,
240
+ })
241
+ next.credentialId = prepared.credentialId
242
+ next.config = prepared.config
213
243
  persistConnector(next)
214
244
 
215
245
  try {
@@ -235,7 +265,7 @@ export async function updateConnectorFromRoute(id: string, body: Record<string,
235
265
  }
236
266
 
237
267
  notify('connectors')
238
- return serviceOk(await getConnectorWithRuntime(id) || next)
268
+ return serviceOk(await getConnectorWithRuntime(id) || redactConnectorSecrets(next))
239
269
  }
240
270
 
241
271
  export async function deleteConnectorFromRoute(id: string): Promise<ServiceResult<{ ok: true }>> {
@@ -217,8 +217,8 @@ const discord: PlatformConnector = {
217
217
  return String(sent.id || '')
218
218
  },
219
219
  })
220
- } catch (err: any) {
221
- log.error(TAG, 'Error handling message:', err.message)
220
+ } catch (err: unknown) {
221
+ log.error(TAG, 'Error handling message:', errorMessage(err))
222
222
  try {
223
223
  await message.reply('Sorry, I encountered an error processing your message.')
224
224
  } catch { /* ignore */ }
@@ -4,6 +4,7 @@ import path from 'path'
4
4
  import { DATA_DIR } from '../data-dir'
5
5
  import type { PlatformConnector, ConnectorInstance, InboundMessage } from './types'
6
6
  import { resolveConnectorIngressReply } from './ingress-delivery'
7
+ import { errorMessage } from '@/lib/shared-utils'
7
8
 
8
9
  const TAG = 'matrix'
9
10
 
@@ -54,8 +55,8 @@ const matrix: PlatformConnector = {
54
55
  const reply = await resolveConnectorIngressReply(onMessage, inbound)
55
56
  if (!reply) return
56
57
  await client.sendText(roomId, reply.visibleText)
57
- } catch (err: any) {
58
- log.error(TAG, 'Error handling message:', err.message)
58
+ } catch (err: unknown) {
59
+ log.error(TAG, 'Error handling message:', errorMessage(err))
59
60
  try {
60
61
  await client.sendText(roomId, 'Sorry, I encountered an error processing your message.')
61
62
  } catch { /* ignore */ }
@@ -4,6 +4,7 @@ import type { ChildProcess } from 'child_process'
4
4
  import type { Connector } from '@/types'
5
5
  import type { PlatformConnector, ConnectorInstance, InboundMessage, ConnectorIngressResult } from './types'
6
6
  import { resolveConnectorIngressReply } from './ingress-delivery'
7
+ import { errorMessage } from '@/lib/shared-utils'
7
8
 
8
9
  const TAG = 'signal'
9
10
 
@@ -107,8 +108,8 @@ const signal: PlatformConnector = {
107
108
  `${cliPath} -u ${phoneNumber} send -m ${JSON.stringify(text)} ${channelId}`,
108
109
  { timeout: 15_000 },
109
110
  )
110
- } catch (err: any) {
111
- throw new Error(`Signal send failed: ${err.message}`)
111
+ } catch (err: unknown) {
112
+ throw new Error(`Signal send failed: ${errorMessage(err)}`)
112
113
  }
113
114
  }
114
115
  },
@@ -179,8 +180,8 @@ export async function handleSignalEvent(
179
180
  { timeout: 15_000 },
180
181
  )
181
182
  }
182
- } catch (err: any) {
183
- log.error(TAG, 'Error handling message:', err.message)
183
+ } catch (err: unknown) {
184
+ log.error(TAG, 'Error handling message:', errorMessage(err))
184
185
  }
185
186
  }
186
187