@swarmclawai/swarmclaw 0.7.2 → 0.7.4

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 (274) hide show
  1. package/README.md +116 -50
  2. package/bin/package-manager.js +157 -0
  3. package/bin/package-manager.test.js +90 -0
  4. package/bin/server-cmd.js +38 -7
  5. package/bin/swarmclaw.js +54 -4
  6. package/bin/update-cmd.js +48 -10
  7. package/bin/update-cmd.test.js +55 -0
  8. package/package.json +8 -3
  9. package/scripts/postinstall.mjs +26 -0
  10. package/src/app/api/agents/[id]/route.ts +43 -0
  11. package/src/app/api/agents/[id]/thread/route.ts +39 -8
  12. package/src/app/api/agents/route.ts +35 -2
  13. package/src/app/api/auth/route.ts +77 -8
  14. package/src/app/api/chatrooms/[id]/chat/route.ts +22 -6
  15. package/src/app/api/chatrooms/[id]/pins/route.ts +2 -1
  16. package/src/app/api/chatrooms/[id]/reactions/route.ts +2 -1
  17. package/src/app/api/chatrooms/[id]/route.ts +6 -0
  18. package/src/app/api/chats/[id]/browser/route.ts +5 -1
  19. package/src/app/api/chats/[id]/chat/route.ts +7 -3
  20. package/src/app/api/chats/[id]/messages/route.ts +19 -13
  21. package/src/app/api/chats/[id]/route.ts +30 -0
  22. package/src/app/api/chats/[id]/stop/route.ts +6 -1
  23. package/src/app/api/chats/heartbeat/route.ts +2 -1
  24. package/src/app/api/chats/route.ts +23 -1
  25. package/src/app/api/connectors/[id]/doctor/route.ts +26 -0
  26. package/src/app/api/connectors/doctor/route.ts +13 -0
  27. package/src/app/api/external-agents/[id]/heartbeat/route.ts +33 -0
  28. package/src/app/api/external-agents/[id]/route.ts +31 -0
  29. package/src/app/api/external-agents/register/route.ts +3 -0
  30. package/src/app/api/external-agents/route.ts +66 -0
  31. package/src/app/api/files/open/route.ts +16 -14
  32. package/src/app/api/gateways/[id]/health/route.ts +28 -0
  33. package/src/app/api/gateways/[id]/route.ts +79 -0
  34. package/src/app/api/gateways/route.ts +57 -0
  35. package/src/app/api/memory/maintenance/route.ts +11 -1
  36. package/src/app/api/openclaw/agent-files/route.ts +27 -4
  37. package/src/app/api/openclaw/gateway/route.ts +10 -7
  38. package/src/app/api/openclaw/skills/route.ts +12 -4
  39. package/src/app/api/plugins/dependencies/route.ts +24 -0
  40. package/src/app/api/plugins/install/route.ts +15 -92
  41. package/src/app/api/plugins/route.ts +3 -26
  42. package/src/app/api/plugins/settings/route.ts +17 -12
  43. package/src/app/api/plugins/ui/route.ts +1 -0
  44. package/src/app/api/providers/[id]/discover-models/route.ts +27 -0
  45. package/src/app/api/schedules/[id]/route.ts +38 -9
  46. package/src/app/api/schedules/route.ts +51 -28
  47. package/src/app/api/settings/route.ts +55 -17
  48. package/src/app/api/setup/doctor/route.ts +6 -4
  49. package/src/app/api/tasks/[id]/route.ts +16 -6
  50. package/src/app/api/tasks/bulk/route.ts +3 -3
  51. package/src/app/api/tasks/route.ts +9 -4
  52. package/src/app/api/webhooks/[id]/route.ts +8 -1
  53. package/src/app/page.tsx +135 -17
  54. package/src/cli/binary.test.js +142 -0
  55. package/src/cli/index.js +38 -11
  56. package/src/cli/index.test.js +195 -0
  57. package/src/cli/index.ts +21 -12
  58. package/src/cli/server-cmd.test.js +59 -0
  59. package/src/cli/spec.js +20 -2
  60. package/src/components/agents/agent-card.tsx +15 -12
  61. package/src/components/agents/agent-chat-list.tsx +101 -1
  62. package/src/components/agents/agent-list.tsx +46 -9
  63. package/src/components/agents/agent-sheet.tsx +456 -23
  64. package/src/components/agents/inspector-panel.tsx +110 -49
  65. package/src/components/agents/sandbox-env-panel.tsx +4 -1
  66. package/src/components/auth/access-key-gate.tsx +36 -97
  67. package/src/components/auth/setup-wizard.tsx +970 -275
  68. package/src/components/chat/chat-area.tsx +70 -27
  69. package/src/components/chat/chat-card.tsx +6 -21
  70. package/src/components/chat/chat-header.tsx +263 -366
  71. package/src/components/chat/chat-list.tsx +62 -26
  72. package/src/components/chat/checkpoint-timeline.tsx +1 -1
  73. package/src/components/chat/message-list.tsx +145 -19
  74. package/src/components/chatrooms/chatroom-input.tsx +96 -33
  75. package/src/components/chatrooms/chatroom-list.tsx +141 -72
  76. package/src/components/chatrooms/chatroom-message.tsx +7 -6
  77. package/src/components/chatrooms/chatroom-sheet.tsx +13 -1
  78. package/src/components/chatrooms/chatroom-tool-request-banner.tsx +5 -2
  79. package/src/components/chatrooms/chatroom-view.tsx +422 -209
  80. package/src/components/chatrooms/reaction-picker.tsx +38 -33
  81. package/src/components/connectors/connector-list.tsx +265 -127
  82. package/src/components/connectors/connector-sheet.tsx +217 -0
  83. package/src/components/gateways/gateway-sheet.tsx +567 -0
  84. package/src/components/home/home-view.tsx +128 -4
  85. package/src/components/input/chat-input.tsx +135 -86
  86. package/src/components/layout/app-layout.tsx +385 -194
  87. package/src/components/layout/mobile-header.tsx +26 -8
  88. package/src/components/memory/memory-browser.tsx +71 -6
  89. package/src/components/memory/memory-card.tsx +18 -0
  90. package/src/components/memory/memory-detail.tsx +58 -31
  91. package/src/components/memory/memory-sheet.tsx +32 -4
  92. package/src/components/plugins/plugin-list.tsx +15 -3
  93. package/src/components/plugins/plugin-sheet.tsx +118 -9
  94. package/src/components/projects/project-detail.tsx +189 -1
  95. package/src/components/providers/provider-list.tsx +158 -2
  96. package/src/components/providers/provider-sheet.tsx +81 -70
  97. package/src/components/shared/agent-picker-list.tsx +2 -2
  98. package/src/components/shared/bottom-sheet.tsx +31 -15
  99. package/src/components/shared/command-palette.tsx +111 -24
  100. package/src/components/shared/confirm-dialog.tsx +45 -30
  101. package/src/components/shared/model-combobox.tsx +90 -8
  102. package/src/components/shared/settings/plugin-manager.tsx +20 -4
  103. package/src/components/shared/settings/section-capability-policy.tsx +105 -0
  104. package/src/components/shared/settings/section-heartbeat.tsx +88 -6
  105. package/src/components/shared/settings/section-orchestrator.tsx +6 -3
  106. package/src/components/shared/settings/section-runtime-loop.tsx +5 -5
  107. package/src/components/shared/settings/section-secrets.tsx +6 -6
  108. package/src/components/shared/settings/section-user-preferences.tsx +1 -1
  109. package/src/components/shared/settings/section-voice.tsx +5 -1
  110. package/src/components/shared/settings/section-web-search.tsx +10 -2
  111. package/src/components/shared/settings/settings-page.tsx +248 -47
  112. package/src/components/tasks/approvals-panel.tsx +211 -18
  113. package/src/components/tasks/task-board.tsx +242 -46
  114. package/src/components/ui/dialog.tsx +2 -2
  115. package/src/components/usage/metrics-dashboard.tsx +74 -1
  116. package/src/components/wallets/wallet-approval-dialog.tsx +59 -54
  117. package/src/components/wallets/wallet-panel.tsx +17 -5
  118. package/src/components/webhooks/webhook-sheet.tsx +7 -7
  119. package/src/lib/auth.ts +17 -0
  120. package/src/lib/chat-streaming-state.test.ts +108 -0
  121. package/src/lib/chat-streaming-state.ts +108 -0
  122. package/src/lib/heartbeat-defaults.ts +48 -0
  123. package/src/lib/memory-presentation.ts +59 -0
  124. package/src/lib/openclaw-agent-id.test.ts +14 -0
  125. package/src/lib/openclaw-agent-id.ts +31 -0
  126. package/src/lib/provider-model-discovery-client.ts +29 -0
  127. package/src/lib/providers/index.ts +12 -5
  128. package/src/lib/runtime-loop.ts +105 -3
  129. package/src/lib/safe-storage.ts +6 -1
  130. package/src/lib/server/agent-assignment.test.ts +112 -0
  131. package/src/lib/server/agent-assignment.ts +169 -0
  132. package/src/lib/server/agent-runtime-config.test.ts +141 -0
  133. package/src/lib/server/agent-runtime-config.ts +277 -0
  134. package/src/lib/server/approval-connector-notify.test.ts +253 -0
  135. package/src/lib/server/approvals-auto-approve.test.ts +264 -0
  136. package/src/lib/server/approvals.ts +483 -75
  137. package/src/lib/server/autonomy-runtime.test.ts +341 -0
  138. package/src/lib/server/browser-state.test.ts +118 -0
  139. package/src/lib/server/browser-state.ts +123 -0
  140. package/src/lib/server/build-llm.test.ts +44 -0
  141. package/src/lib/server/build-llm.ts +11 -4
  142. package/src/lib/server/builtin-plugins.ts +34 -0
  143. package/src/lib/server/chat-execution-heartbeat.test.ts +40 -0
  144. package/src/lib/server/chat-execution-tool-events.test.ts +219 -0
  145. package/src/lib/server/chat-execution.ts +402 -125
  146. package/src/lib/server/chatroom-health.test.ts +26 -0
  147. package/src/lib/server/chatroom-health.ts +2 -3
  148. package/src/lib/server/chatroom-helpers.test.ts +74 -2
  149. package/src/lib/server/chatroom-helpers.ts +144 -11
  150. package/src/lib/server/chatroom-session-persistence.test.ts +87 -0
  151. package/src/lib/server/connectors/discord.ts +175 -11
  152. package/src/lib/server/connectors/doctor.test.ts +80 -0
  153. package/src/lib/server/connectors/doctor.ts +116 -0
  154. package/src/lib/server/connectors/manager.ts +994 -130
  155. package/src/lib/server/connectors/policy.test.ts +222 -0
  156. package/src/lib/server/connectors/policy.ts +452 -0
  157. package/src/lib/server/connectors/slack.ts +189 -10
  158. package/src/lib/server/connectors/telegram.ts +65 -15
  159. package/src/lib/server/connectors/thread-context.test.ts +44 -0
  160. package/src/lib/server/connectors/thread-context.ts +72 -0
  161. package/src/lib/server/connectors/types.ts +41 -11
  162. package/src/lib/server/daemon-state.ts +62 -3
  163. package/src/lib/server/data-dir.ts +13 -0
  164. package/src/lib/server/delegation-jobs.test.ts +140 -0
  165. package/src/lib/server/delegation-jobs.ts +248 -0
  166. package/src/lib/server/document-utils.test.ts +47 -0
  167. package/src/lib/server/document-utils.ts +397 -0
  168. package/src/lib/server/eval/agent-regression.test.ts +47 -0
  169. package/src/lib/server/eval/agent-regression.ts +1742 -0
  170. package/src/lib/server/eval/runner.ts +11 -1
  171. package/src/lib/server/eval/store.ts +2 -1
  172. package/src/lib/server/heartbeat-service.ts +23 -43
  173. package/src/lib/server/heartbeat-source.test.ts +22 -0
  174. package/src/lib/server/heartbeat-source.ts +7 -0
  175. package/src/lib/server/identity-continuity.test.ts +77 -0
  176. package/src/lib/server/identity-continuity.ts +127 -0
  177. package/src/lib/server/mailbox-utils.ts +347 -0
  178. package/src/lib/server/main-agent-loop.ts +31 -964
  179. package/src/lib/server/memory-db.ts +4 -6
  180. package/src/lib/server/memory-tiers.ts +40 -0
  181. package/src/lib/server/openclaw-agent-resolver.test.ts +70 -0
  182. package/src/lib/server/openclaw-agent-resolver.ts +128 -0
  183. package/src/lib/server/openclaw-exec-config.ts +6 -5
  184. package/src/lib/server/openclaw-gateway.ts +123 -36
  185. package/src/lib/server/openclaw-skills-normalize.test.ts +56 -0
  186. package/src/lib/server/openclaw-skills-normalize.ts +136 -0
  187. package/src/lib/server/openclaw-sync.ts +3 -2
  188. package/src/lib/server/orchestrator-lg.ts +18 -8
  189. package/src/lib/server/orchestrator.ts +5 -4
  190. package/src/lib/server/playwright-proxy.mjs +27 -3
  191. package/src/lib/server/plugins.test.ts +215 -0
  192. package/src/lib/server/plugins.ts +832 -69
  193. package/src/lib/server/provider-health.ts +33 -3
  194. package/src/lib/server/provider-model-discovery.ts +481 -0
  195. package/src/lib/server/queue.ts +4 -21
  196. package/src/lib/server/runtime-settings.test.ts +119 -0
  197. package/src/lib/server/runtime-settings.ts +12 -92
  198. package/src/lib/server/schedule-normalization.ts +187 -0
  199. package/src/lib/server/scheduler.ts +2 -0
  200. package/src/lib/server/session-archive-memory.test.ts +85 -0
  201. package/src/lib/server/session-archive-memory.ts +230 -0
  202. package/src/lib/server/session-mailbox.ts +8 -18
  203. package/src/lib/server/session-reset-policy.test.ts +99 -0
  204. package/src/lib/server/session-reset-policy.ts +311 -0
  205. package/src/lib/server/session-run-manager.ts +33 -80
  206. package/src/lib/server/session-tools/autonomy-tools.test.ts +128 -0
  207. package/src/lib/server/session-tools/calendar.ts +2 -12
  208. package/src/lib/server/session-tools/connector.ts +109 -8
  209. package/src/lib/server/session-tools/context.ts +14 -2
  210. package/src/lib/server/session-tools/crawl.ts +447 -0
  211. package/src/lib/server/session-tools/crud.ts +96 -34
  212. package/src/lib/server/session-tools/delegate-fallback.test.ts +219 -0
  213. package/src/lib/server/session-tools/delegate.ts +406 -20
  214. package/src/lib/server/session-tools/discovery-approvals.test.ts +170 -0
  215. package/src/lib/server/session-tools/discovery.ts +40 -12
  216. package/src/lib/server/session-tools/document.ts +283 -0
  217. package/src/lib/server/session-tools/email.ts +1 -3
  218. package/src/lib/server/session-tools/extract.ts +137 -0
  219. package/src/lib/server/session-tools/file-normalize.test.ts +98 -0
  220. package/src/lib/server/session-tools/file-send.test.ts +84 -1
  221. package/src/lib/server/session-tools/file.ts +243 -24
  222. package/src/lib/server/session-tools/http.ts +9 -3
  223. package/src/lib/server/session-tools/human-loop.ts +227 -0
  224. package/src/lib/server/session-tools/image-gen.ts +1 -3
  225. package/src/lib/server/session-tools/index.ts +87 -2
  226. package/src/lib/server/session-tools/mailbox.ts +276 -0
  227. package/src/lib/server/session-tools/manage-schedules.test.ts +137 -0
  228. package/src/lib/server/session-tools/memory.ts +35 -3
  229. package/src/lib/server/session-tools/monitor.ts +162 -12
  230. package/src/lib/server/session-tools/normalize-tool-args.ts +17 -14
  231. package/src/lib/server/session-tools/openclaw-nodes.test.ts +111 -0
  232. package/src/lib/server/session-tools/openclaw-nodes.ts +86 -20
  233. package/src/lib/server/session-tools/platform-normalize.test.ts +142 -0
  234. package/src/lib/server/session-tools/platform.ts +142 -4
  235. package/src/lib/server/session-tools/plugin-creator.ts +95 -25
  236. package/src/lib/server/session-tools/primitive-tools.test.ts +257 -0
  237. package/src/lib/server/session-tools/replicate.ts +1 -3
  238. package/src/lib/server/session-tools/sandbox.ts +51 -92
  239. package/src/lib/server/session-tools/schedule.ts +20 -10
  240. package/src/lib/server/session-tools/session-info.ts +58 -4
  241. package/src/lib/server/session-tools/session-tools-wiring.test.ts +54 -17
  242. package/src/lib/server/session-tools/shell.ts +2 -2
  243. package/src/lib/server/session-tools/subagent.ts +195 -27
  244. package/src/lib/server/session-tools/table.ts +587 -0
  245. package/src/lib/server/session-tools/wallet.ts +13 -10
  246. package/src/lib/server/session-tools/web-browser-config.test.ts +39 -0
  247. package/src/lib/server/session-tools/web.ts +947 -108
  248. package/src/lib/server/storage.ts +255 -10
  249. package/src/lib/server/stream-agent-chat.test.ts +61 -0
  250. package/src/lib/server/stream-agent-chat.ts +185 -25
  251. package/src/lib/server/structured-extract.test.ts +72 -0
  252. package/src/lib/server/structured-extract.ts +373 -0
  253. package/src/lib/server/task-mention.test.ts +16 -2
  254. package/src/lib/server/task-mention.ts +61 -11
  255. package/src/lib/server/tool-aliases.ts +80 -12
  256. package/src/lib/server/tool-capability-policy.ts +7 -1
  257. package/src/lib/server/tool-retry.ts +2 -0
  258. package/src/lib/server/watch-jobs.test.ts +173 -0
  259. package/src/lib/server/watch-jobs.ts +532 -0
  260. package/src/lib/server/ws-hub.ts +5 -3
  261. package/src/lib/setup-defaults.ts +352 -11
  262. package/src/lib/tool-definitions.ts +3 -4
  263. package/src/lib/validation/schemas.test.ts +26 -0
  264. package/src/lib/validation/schemas.ts +62 -1
  265. package/src/lib/ws-client.ts +14 -12
  266. package/src/proxy.ts +5 -5
  267. package/src/stores/use-app-store.ts +43 -7
  268. package/src/stores/use-chat-store.ts +31 -2
  269. package/src/stores/use-chatroom-store.ts +153 -26
  270. package/src/types/index.ts +470 -44
  271. package/src/app/api/chats/[id]/main-loop/route.ts +0 -94
  272. package/src/components/chat/new-chat-sheet.tsx +0 -253
  273. package/src/lib/server/main-session.ts +0 -17
  274. package/src/lib/server/session-run-manager.test.ts +0 -26
@@ -30,6 +30,29 @@ function linkify(text: string) {
30
30
  })
31
31
  }
32
32
 
33
+ interface ConnectorDoctorPolicyPreview {
34
+ scope?: string
35
+ replyMode?: string
36
+ threadBinding?: string
37
+ groupPolicy?: string
38
+ resetMode?: string
39
+ idleTimeoutSec?: number | null
40
+ maxAgeSec?: number | null
41
+ dailyResetAt?: string | null
42
+ resetTimezone?: string | null
43
+ thinkingLevel?: string | null
44
+ providerOverride?: string | null
45
+ modelOverride?: string | null
46
+ inboundDebounceMs?: number
47
+ statusReactions?: boolean
48
+ typingIndicators?: boolean
49
+ }
50
+
51
+ interface ConnectorDoctorResponse {
52
+ warnings?: string[]
53
+ policy?: ConnectorDoctorPolicyPreview | null
54
+ }
55
+
33
56
  const PLATFORMS: {
34
57
  id: ConnectorPlatform
35
58
  label: string
@@ -225,6 +248,96 @@ const PLATFORMS: {
225
248
  ]
226
249
 
227
250
  const COMMON_CONFIG_FIELDS: { key: string; label: string; placeholder: string; help?: string }[] = [
251
+ {
252
+ key: 'thinkingLevel',
253
+ label: 'Thinking Level',
254
+ placeholder: 'minimal | low | medium | high',
255
+ help: 'Default reasoning depth for new/reset direct connector sessions.',
256
+ },
257
+ {
258
+ key: 'providerOverride',
259
+ label: 'Provider Override',
260
+ placeholder: 'openai | anthropic | openclaw | ...',
261
+ help: 'Optional direct-session provider override. Useful for connector-specific routing or cheaper autonomy lanes.',
262
+ },
263
+ {
264
+ key: 'modelOverride',
265
+ label: 'Model Override',
266
+ placeholder: 'gpt-4.1-mini',
267
+ help: 'Optional direct-session model override. Defaults to the assigned agent model when empty.',
268
+ },
269
+ {
270
+ key: 'sessionScope',
271
+ label: 'Session Scope',
272
+ placeholder: 'main | channel | peer | channel-peer | thread',
273
+ help: 'Conversation identity policy. Defaults to channel-peer for DMs and channel for groups.',
274
+ },
275
+ {
276
+ key: 'replyMode',
277
+ label: 'Reply Mode',
278
+ placeholder: 'off | first | all',
279
+ help: 'Whether outbound replies should attach to the triggering inbound message.',
280
+ },
281
+ {
282
+ key: 'threadBinding',
283
+ label: 'Thread Binding',
284
+ placeholder: 'off | prefer | strict',
285
+ help: 'Prefer or require thread/topic-specific sessions when the platform exposes thread IDs.',
286
+ },
287
+ {
288
+ key: 'groupPolicy',
289
+ label: 'Group Policy',
290
+ placeholder: 'open | mention | reply-or-mention | disabled',
291
+ help: 'Controls whether the agent speaks in group chats without being mentioned or replied to.',
292
+ },
293
+ {
294
+ key: 'idleTimeoutSec',
295
+ label: 'Idle Timeout (sec)',
296
+ placeholder: '43200',
297
+ help: 'If exceeded, the connector session is reset before the next inbound turn.',
298
+ },
299
+ {
300
+ key: 'maxAgeSec',
301
+ label: 'Max Age (sec)',
302
+ placeholder: '604800',
303
+ help: 'Absolute maximum age of a connector session before it is reset.',
304
+ },
305
+ {
306
+ key: 'sessionResetMode',
307
+ label: 'Reset Mode',
308
+ placeholder: 'idle | daily',
309
+ help: 'Freshness policy for connector sessions. Daily resets use the fields below.',
310
+ },
311
+ {
312
+ key: 'sessionDailyResetAt',
313
+ label: 'Daily Reset Time',
314
+ placeholder: '04:00',
315
+ help: 'Used only when Reset Mode is daily. Format: HH:MM.',
316
+ },
317
+ {
318
+ key: 'sessionResetTimezone',
319
+ label: 'Reset Timezone',
320
+ placeholder: 'UTC or Europe/Isle_of_Man',
321
+ help: 'Optional timezone for daily reset boundaries. Defaults to the server timezone.',
322
+ },
323
+ {
324
+ key: 'inboundDebounceMs',
325
+ label: 'Inbound Debounce (ms)',
326
+ placeholder: '700',
327
+ help: 'Coalesces rapid inbound bursts from the same sender before starting a run.',
328
+ },
329
+ {
330
+ key: 'statusReactions',
331
+ label: 'Status Reactions',
332
+ placeholder: 'true | false',
333
+ help: 'When supported, add lightweight platform-native reactions for processing/sent/silent states.',
334
+ },
335
+ {
336
+ key: 'typingIndicators',
337
+ label: 'Typing Indicators',
338
+ placeholder: 'true | false',
339
+ help: 'When supported, keep a native typing/working indicator alive while the agent is running.',
340
+ },
228
341
  {
229
342
  key: 'taskFollowups',
230
343
  label: 'Task Follow-ups',
@@ -295,6 +408,9 @@ export function ConnectorSheet() {
295
408
  const [newCredName, setNewCredName] = useState('')
296
409
  const [newCredValue, setNewCredValue] = useState('')
297
410
  const [savingCred, setSavingCred] = useState(false)
411
+ const [doctorWarnings, setDoctorWarnings] = useState<string[]>([])
412
+ const [doctorPolicy, setDoctorPolicy] = useState<ConnectorDoctorPolicyPreview | null>(null)
413
+ const [doctorLoading, setDoctorLoading] = useState(false)
298
414
 
299
415
  const editing = editingId ? connectors[editingId] as Connector | undefined : null
300
416
 
@@ -360,6 +476,41 @@ export function ConnectorSheet() {
360
476
 
361
477
  useWs('connectors', pollWaStatus, isWaRunning ? 2000 : undefined)
362
478
 
479
+ const loadDoctorPreview = useCallback(async () => {
480
+ setDoctorLoading(true)
481
+ try {
482
+ const data = await api<ConnectorDoctorResponse>('POST', '/connectors/doctor', {
483
+ id: editing?.id || null,
484
+ name,
485
+ platform,
486
+ agentId: routeMode === 'agent' ? (agentId || null) : null,
487
+ chatroomId: routeMode === 'chatroom' ? (chatroomId || null) : null,
488
+ credentialId: credentialId || null,
489
+ config,
490
+ })
491
+ setDoctorWarnings(Array.isArray(data.warnings) ? data.warnings : [])
492
+ setDoctorPolicy(data.policy || null)
493
+ } catch {
494
+ setDoctorWarnings([])
495
+ setDoctorPolicy(null)
496
+ } finally {
497
+ setDoctorLoading(false)
498
+ }
499
+ }, [editing?.id, name, platform, routeMode, agentId, chatroomId, credentialId, config])
500
+
501
+ useEffect(() => {
502
+ if (!open) {
503
+ setDoctorWarnings([])
504
+ setDoctorPolicy(null)
505
+ setDoctorLoading(false)
506
+ return
507
+ }
508
+ const timer = window.setTimeout(() => {
509
+ void loadDoctorPreview()
510
+ }, 250)
511
+ return () => window.clearTimeout(timer)
512
+ }, [open, loadDoctorPreview])
513
+
363
514
  const handleSave = async () => {
364
515
  const hasTarget = routeMode === 'agent' ? !!agentId : !!chatroomId
365
516
  if (!hasTarget) return
@@ -796,6 +947,72 @@ export function ConnectorSheet() {
796
947
  )
797
948
  })()}
798
949
 
950
+ <div className="mb-6 p-4 rounded-[14px] border border-white/[0.06] bg-white/[0.01]">
951
+ <div className="flex items-center justify-between gap-3 mb-2">
952
+ <div>
953
+ <div className="text-[13px] font-600 text-text-2">Connector Doctor</div>
954
+ <div className="text-[12px] text-text-3/70">
955
+ Live autonomy and safety preview for the current connector settings.
956
+ </div>
957
+ </div>
958
+ <button
959
+ type="button"
960
+ onClick={() => void loadDoctorPreview()}
961
+ disabled={doctorLoading}
962
+ className="px-3 py-1.5 rounded-[9px] border border-white/[0.08] bg-transparent text-[12px] font-600 text-text-3 hover:text-text-2 hover:bg-white/[0.04] transition-all cursor-pointer disabled:opacity-50"
963
+ style={{ fontFamily: 'inherit' }}
964
+ >
965
+ {doctorLoading ? 'Checking...' : 'Refresh'}
966
+ </button>
967
+ </div>
968
+ {doctorPolicy && (
969
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-2 mb-3">
970
+ <div className="rounded-[10px] border border-white/[0.06] bg-white/[0.02] px-3 py-2 text-[12px] text-text-3/80">
971
+ Scope: <span className="text-text-2">{doctorPolicy.scope || 'channel-peer'}</span>{' '}
972
+ · Reply: <span className="text-text-2">{doctorPolicy.replyMode || 'first'}</span>{' '}
973
+ · Thread: <span className="text-text-2">{doctorPolicy.threadBinding || 'prefer'}</span>
974
+ </div>
975
+ <div className="rounded-[10px] border border-white/[0.06] bg-white/[0.02] px-3 py-2 text-[12px] text-text-3/80">
976
+ Group: <span className="text-text-2">{doctorPolicy.groupPolicy || 'reply-or-mention'}</span>{' '}
977
+ · Debounce: <span className="text-text-2">{doctorPolicy.inboundDebounceMs ?? 700}ms</span>
978
+ </div>
979
+ <div className="rounded-[10px] border border-white/[0.06] bg-white/[0.02] px-3 py-2 text-[12px] text-text-3/80">
980
+ Reset: <span className="text-text-2">{doctorPolicy.resetMode || 'idle'}</span>{' '}
981
+ {doctorPolicy.resetMode === 'daily'
982
+ ? `at ${doctorPolicy.dailyResetAt || 'unset'} (${doctorPolicy.resetTimezone || 'server timezone'})`
983
+ : `idle ${doctorPolicy.idleTimeoutSec ?? 0}s / max ${doctorPolicy.maxAgeSec ?? 0}s`}
984
+ </div>
985
+ <div className="rounded-[10px] border border-white/[0.06] bg-white/[0.02] px-3 py-2 text-[12px] text-text-3/80">
986
+ Runtime: <span className="text-text-2">{doctorPolicy.thinkingLevel || 'inherit'}</span>{' '}
987
+ · Provider: <span className="text-text-2">{doctorPolicy.providerOverride || 'agent default'}</span>{' '}
988
+ · Model: <span className="text-text-2">{doctorPolicy.modelOverride || 'agent default'}</span>
989
+ </div>
990
+ </div>
991
+ )}
992
+ {doctorWarnings.length > 0 ? (
993
+ <div className="space-y-2">
994
+ {doctorWarnings.map((warning, index) => (
995
+ <div key={`${index}:${warning}`} className="rounded-[10px] border border-amber-400/15 bg-amber-500/8 px-3 py-2 text-[12px] text-amber-200/85 leading-[1.5]">
996
+ {warning}
997
+ </div>
998
+ ))}
999
+ </div>
1000
+ ) : (
1001
+ <div className="text-[12px] text-emerald-300/85">
1002
+ {doctorLoading ? 'Running checks…' : 'No autonomy or safety warnings detected for the current form values.'}
1003
+ </div>
1004
+ )}
1005
+ <p className="text-[11px] text-text-3/55 mt-2">
1006
+ This preview updates from the form directly, so you can catch risky connector policy changes before saving.
1007
+ </p>
1008
+ </div>
1009
+
1010
+ {editing && (
1011
+ <div className="mb-6 p-4 rounded-[14px] border border-white/[0.06] bg-white/[0.01]">
1012
+ <ConnectorHealth connectorId={editing.id} />
1013
+ </div>
1014
+ )}
1015
+
799
1016
  {/* WhatsApp QR code */}
800
1017
  {editing && editing.platform === 'whatsapp' && (editing.status === 'running' || waConnecting) && qrDataUrl && (
801
1018
  <div className="mb-6 p-5 rounded-[14px] border border-white/[0.06] bg-white/[0.01] text-center"