@swarmclawai/swarmclaw 1.2.3 → 1.2.5

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 (273) hide show
  1. package/README.md +20 -0
  2. package/bin/daemon-cmd.js +169 -0
  3. package/bin/server-cmd.js +3 -0
  4. package/bin/swarmclaw.js +11 -0
  5. package/package.json +17 -16
  6. package/src/app/api/agents/[id]/clone/route.ts +3 -32
  7. package/src/app/api/agents/[id]/route.ts +6 -158
  8. package/src/app/api/agents/[id]/status/route.ts +2 -3
  9. package/src/app/api/agents/[id]/thread/route.ts +4 -17
  10. package/src/app/api/agents/bulk/route.ts +5 -47
  11. package/src/app/api/agents/route.ts +5 -119
  12. package/src/app/api/agents/trash/route.ts +13 -24
  13. package/src/app/api/auth/route.ts +3 -9
  14. package/src/app/api/autonomy/estop/route.ts +5 -5
  15. package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
  16. package/src/app/api/chatrooms/[id]/route.ts +23 -2
  17. package/src/app/api/chatrooms/route.ts +13 -2
  18. package/src/app/api/chats/[id]/clear/route.ts +2 -13
  19. package/src/app/api/chats/[id]/deploy/route.ts +2 -3
  20. package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
  21. package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
  22. package/src/app/api/chats/[id]/queue/route.ts +17 -64
  23. package/src/app/api/chats/[id]/retry/route.ts +4 -22
  24. package/src/app/api/chats/[id]/route.ts +10 -138
  25. package/src/app/api/chats/heartbeat/route.ts +2 -1
  26. package/src/app/api/chats/migrate-messages/route.ts +7 -0
  27. package/src/app/api/chats/route.ts +13 -134
  28. package/src/app/api/connectors/[id]/access/route.ts +12 -229
  29. package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
  30. package/src/app/api/connectors/[id]/health/route.ts +12 -39
  31. package/src/app/api/connectors/[id]/route.ts +14 -122
  32. package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
  33. package/src/app/api/connectors/doctor/route.ts +1 -1
  34. package/src/app/api/connectors/route.ts +12 -70
  35. package/src/app/api/credentials/[id]/route.ts +2 -4
  36. package/src/app/api/credentials/route.ts +10 -19
  37. package/src/app/api/daemon/health-check/route.ts +3 -4
  38. package/src/app/api/daemon/route.ts +10 -8
  39. package/src/app/api/documents/route.ts +11 -10
  40. package/src/app/api/external-agents/route.ts +3 -3
  41. package/src/app/api/gateways/[id]/health/route.ts +2 -3
  42. package/src/app/api/gateways/[id]/route.ts +7 -122
  43. package/src/app/api/gateways/route.ts +3 -103
  44. package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
  45. package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
  46. package/src/app/api/openclaw/directory/route.ts +2 -2
  47. package/src/app/api/openclaw/history/route.ts +3 -5
  48. package/src/app/api/providers/[id]/models/route.test.ts +60 -0
  49. package/src/app/api/providers/[id]/models/route.ts +33 -1
  50. package/src/app/api/providers/[id]/route.test.ts +49 -0
  51. package/src/app/api/providers/[id]/route.ts +30 -1
  52. package/src/app/api/providers/ollama/route.ts +6 -5
  53. package/src/app/api/schedules/[id]/route.ts +14 -108
  54. package/src/app/api/schedules/[id]/run/route.ts +6 -67
  55. package/src/app/api/schedules/route.ts +9 -51
  56. package/src/app/api/settings/route.ts +4 -3
  57. package/src/app/api/setup/check-provider/route.ts +15 -1
  58. package/src/app/api/setup/openclaw-device/route.ts +2 -2
  59. package/src/app/api/system/status/route.ts +2 -2
  60. package/src/app/api/tasks/[id]/route.ts +16 -202
  61. package/src/app/api/tasks/bulk/route.ts +5 -86
  62. package/src/app/api/tasks/metrics/route.ts +2 -1
  63. package/src/app/api/tasks/route.ts +11 -171
  64. package/src/app/api/upload/route.ts +1 -1
  65. package/src/app/api/uploads/[filename]/route.ts +1 -1
  66. package/src/app/api/uploads/route.ts +1 -1
  67. package/src/app/api/webhooks/[id]/history/route.ts +2 -2
  68. package/src/app/layout.tsx +9 -6
  69. package/src/app/protocols/page.tsx +71 -89
  70. package/src/app/tasks/page.tsx +32 -32
  71. package/src/cli/index.js +1 -0
  72. package/src/cli/spec.js +1 -0
  73. package/src/components/agents/agent-sheet.tsx +51 -25
  74. package/src/components/agents/inspector-panel.tsx +15 -4
  75. package/src/components/auth/setup-wizard/index.tsx +27 -18
  76. package/src/components/auth/setup-wizard/shared.tsx +2 -2
  77. package/src/components/auth/setup-wizard/step-agents.tsx +51 -38
  78. package/src/components/auth/setup-wizard/step-connect.tsx +48 -17
  79. package/src/components/auth/setup-wizard/types.ts +6 -4
  80. package/src/components/auth/setup-wizard/utils.test.ts +38 -8
  81. package/src/components/auth/setup-wizard/utils.ts +14 -8
  82. package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
  83. package/src/components/connectors/connector-list.tsx +26 -40
  84. package/src/components/connectors/connector-sheet.tsx +95 -149
  85. package/src/components/gateways/gateway-sheet.tsx +61 -110
  86. package/src/components/layout/live-query-sync.tsx +121 -0
  87. package/src/components/protocols/structured-session-launcher.tsx +24 -45
  88. package/src/components/providers/app-query-provider.tsx +17 -0
  89. package/src/components/providers/provider-list.tsx +150 -77
  90. package/src/components/providers/provider-sheet.tsx +102 -77
  91. package/src/components/shared/model-combobox.tsx +5 -4
  92. package/src/components/skills/skill-list.tsx +5 -18
  93. package/src/components/skills/skill-sheet.tsx +21 -20
  94. package/src/components/skills/skills-workspace.tsx +48 -87
  95. package/src/components/tasks/task-card.tsx +20 -13
  96. package/src/components/tasks/task-column.tsx +22 -7
  97. package/src/components/tasks/task-list.tsx +8 -11
  98. package/src/components/tasks/task-sheet.tsx +111 -103
  99. package/src/features/agents/queries.ts +20 -0
  100. package/src/features/chatrooms/queries.ts +20 -0
  101. package/src/features/chats/queries.ts +27 -0
  102. package/src/features/connectors/queries.ts +145 -0
  103. package/src/features/credentials/queries.ts +37 -0
  104. package/src/features/extensions/queries.ts +26 -0
  105. package/src/features/external-agents/queries.ts +36 -0
  106. package/src/features/gateways/queries.ts +274 -0
  107. package/src/features/missions/queries.ts +23 -0
  108. package/src/features/projects/queries.ts +20 -0
  109. package/src/features/protocols/queries.ts +149 -0
  110. package/src/features/providers/queries.ts +142 -0
  111. package/src/features/settings/queries.ts +20 -0
  112. package/src/features/skills/queries.ts +182 -0
  113. package/src/features/tasks/queries.ts +189 -0
  114. package/src/hooks/use-ws.ts +3 -2
  115. package/src/lib/agent-provider-options.test.ts +152 -0
  116. package/src/lib/agent-provider-options.ts +84 -0
  117. package/src/lib/app/api-client.ts +2 -2
  118. package/src/lib/providers/index.test.ts +78 -0
  119. package/src/lib/providers/index.ts +13 -10
  120. package/src/lib/query/client.ts +17 -0
  121. package/src/lib/server/agents/agent-runtime-config.ts +6 -6
  122. package/src/lib/server/agents/agent-service.ts +429 -0
  123. package/src/lib/server/agents/agent-thread-session.ts +6 -5
  124. package/src/lib/server/agents/autonomy-contract.ts +1 -4
  125. package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
  126. package/src/lib/server/agents/delegation-advisory.ts +251 -0
  127. package/src/lib/server/agents/main-agent-loop.ts +98 -40
  128. package/src/lib/server/agents/subagent-runtime.ts +12 -0
  129. package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
  130. package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
  131. package/src/lib/server/build-llm.ts +7 -15
  132. package/src/lib/server/capability-router.test.ts +70 -1
  133. package/src/lib/server/capability-router.ts +24 -99
  134. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
  135. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
  136. package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
  137. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
  138. package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
  139. package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
  140. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
  141. package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
  142. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
  143. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
  144. package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
  145. package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
  146. package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
  147. package/src/lib/server/chat-execution/message-classifier.ts +74 -32
  148. package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
  149. package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
  150. package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
  151. package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
  152. package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
  153. package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
  154. package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
  155. package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
  156. package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
  157. package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
  158. package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
  159. package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
  160. package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
  161. package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
  162. package/src/lib/server/chats/chat-session-service.ts +410 -0
  163. package/src/lib/server/connectors/access.ts +1 -1
  164. package/src/lib/server/connectors/commands.ts +7 -6
  165. package/src/lib/server/connectors/connector-inbound.ts +14 -7
  166. package/src/lib/server/connectors/connector-outbound.ts +16 -11
  167. package/src/lib/server/connectors/connector-service.ts +453 -0
  168. package/src/lib/server/connectors/delivery.ts +17 -12
  169. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
  170. package/src/lib/server/connectors/media.ts +1 -1
  171. package/src/lib/server/connectors/response-media.ts +1 -1
  172. package/src/lib/server/connectors/session-consolidation.ts +11 -7
  173. package/src/lib/server/connectors/session.ts +9 -7
  174. package/src/lib/server/connectors/voice-note.ts +2 -1
  175. package/src/lib/server/context-manager.ts +20 -1
  176. package/src/lib/server/cost.ts +2 -3
  177. package/src/lib/server/credentials/credential-repository.ts +43 -4
  178. package/src/lib/server/credentials/credential-service.ts +112 -0
  179. package/src/lib/server/daemon/admin-metadata.ts +64 -0
  180. package/src/lib/server/daemon/controller.ts +577 -0
  181. package/src/lib/server/daemon/daemon-runtime.ts +352 -0
  182. package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
  183. package/src/lib/server/daemon/types.ts +101 -0
  184. package/src/lib/server/embeddings.ts +3 -9
  185. package/src/lib/server/eval/agent-regression.ts +3 -2
  186. package/src/lib/server/eval/runner.ts +2 -2
  187. package/src/lib/server/execution-brief.test.ts +167 -0
  188. package/src/lib/server/execution-brief.ts +295 -0
  189. package/src/lib/server/execution-engine/chat-turn.ts +9 -0
  190. package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
  191. package/src/lib/server/execution-engine/index.ts +35 -0
  192. package/src/lib/server/execution-engine/task-attempt.ts +303 -0
  193. package/src/lib/server/execution-engine/types.ts +33 -0
  194. package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
  195. package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
  196. package/src/lib/server/memory/session-archive-memory.ts +12 -10
  197. package/src/lib/server/messages/message-repository.ts +330 -0
  198. package/src/lib/server/missions/mission-service/core.ts +8 -6
  199. package/src/lib/server/openclaw/agent-resolver.ts +2 -3
  200. package/src/lib/server/openclaw/doctor.ts +1 -1
  201. package/src/lib/server/openclaw/gateway.test.ts +10 -1
  202. package/src/lib/server/openclaw/gateway.ts +5 -14
  203. package/src/lib/server/openclaw/health.ts +3 -11
  204. package/src/lib/server/openclaw/sync.ts +8 -6
  205. package/src/lib/server/persistence/storage-context.ts +3 -0
  206. package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
  207. package/src/lib/server/protocols/protocol-normalization.ts +1 -1
  208. package/src/lib/server/protocols/protocol-queries.ts +13 -7
  209. package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
  210. package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
  211. package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
  212. package/src/lib/server/protocols/protocol-swarm.ts +8 -8
  213. package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
  214. package/src/lib/server/protocols/protocol-templates.ts +4 -2
  215. package/src/lib/server/protocols/protocol-types.ts +10 -7
  216. package/src/lib/server/provider-endpoint.ts +7 -12
  217. package/src/lib/server/provider-model-discovery.ts +2 -11
  218. package/src/lib/server/query-expansion.ts +5 -6
  219. package/src/lib/server/run-context.test.ts +365 -0
  220. package/src/lib/server/run-context.ts +367 -0
  221. package/src/lib/server/runtime/heartbeat-service.ts +7 -5
  222. package/src/lib/server/runtime/queue/core.ts +61 -190
  223. package/src/lib/server/runtime/run-ledger.ts +8 -0
  224. package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
  225. package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
  226. package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
  227. package/src/lib/server/schedules/schedule-route-service.ts +230 -0
  228. package/src/lib/server/service-result.ts +16 -0
  229. package/src/lib/server/session-note.ts +2 -3
  230. package/src/lib/server/session-reset-policy.ts +4 -3
  231. package/src/lib/server/session-tools/connector.ts +9 -6
  232. package/src/lib/server/session-tools/context-mgmt.ts +58 -9
  233. package/src/lib/server/session-tools/crud.ts +162 -10
  234. package/src/lib/server/session-tools/delegate.ts +1 -1
  235. package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
  236. package/src/lib/server/session-tools/memory.ts +6 -4
  237. package/src/lib/server/session-tools/session-info.test.ts +56 -0
  238. package/src/lib/server/session-tools/session-info.ts +119 -12
  239. package/src/lib/server/session-tools/skill-runtime.ts +3 -1
  240. package/src/lib/server/session-tools/skills.ts +15 -15
  241. package/src/lib/server/session-tools/subagent.test.ts +115 -1
  242. package/src/lib/server/session-tools/subagent.ts +125 -7
  243. package/src/lib/server/session-tools/team-context.ts +4 -3
  244. package/src/lib/server/session-tools/wallet.ts +0 -58
  245. package/src/lib/server/sessions/session-lineage.ts +55 -0
  246. package/src/lib/server/sessions/session-repository.ts +2 -2
  247. package/src/lib/server/skills/learned-skills.ts +24 -23
  248. package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
  249. package/src/lib/server/skills/skill-repository.ts +136 -13
  250. package/src/lib/server/skills/skill-suggestions.ts +25 -28
  251. package/src/lib/server/storage-normalization.test.ts +42 -215
  252. package/src/lib/server/storage-normalization.ts +98 -0
  253. package/src/lib/server/storage.ts +19 -0
  254. package/src/lib/server/structured-extract.ts +3 -14
  255. package/src/lib/server/tasks/task-followups.ts +16 -11
  256. package/src/lib/server/tasks/task-result.test.ts +25 -29
  257. package/src/lib/server/tasks/task-result.ts +5 -9
  258. package/src/lib/server/tasks/task-route-service.ts +449 -0
  259. package/src/lib/server/text-normalization.ts +41 -0
  260. package/src/lib/server/tool-planning.ts +6 -42
  261. package/src/lib/server/upload-path.ts +5 -0
  262. package/src/lib/server/working-state/extraction.ts +614 -0
  263. package/src/lib/server/working-state/normalization.ts +866 -0
  264. package/src/lib/server/working-state/prompt.ts +60 -0
  265. package/src/lib/server/working-state/repository.ts +38 -0
  266. package/src/lib/server/working-state/service.test.ts +253 -0
  267. package/src/lib/server/working-state/service.ts +293 -0
  268. package/src/lib/validation/schemas.ts +1 -0
  269. package/src/lib/ws-client.ts +3 -3
  270. package/src/stores/slices/task-slice.ts +1 -4
  271. package/src/stores/use-chatroom-store.ts +2 -2
  272. package/src/types/index.ts +288 -22
  273. package/src/views/settings/section-providers.tsx +2 -2
@@ -1,12 +1,26 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useEffect, useState } from 'react'
3
+ import { useState } from 'react'
4
4
  import { toast } from 'sonner'
5
5
  import { OpenClawDeployPanel } from '@/components/openclaw/openclaw-deploy-panel'
6
6
  import { useAppStore } from '@/stores/use-app-store'
7
- import { useWs } from '@/hooks/use-ws'
8
- import { api } from '@/lib/app/api-client'
9
- import type { Credential, GatewayProfile } from '@/types'
7
+ import {
8
+ useProviderConfigsQuery,
9
+ useProvidersQuery,
10
+ useToggleProviderMutation,
11
+ useDeleteProviderMutation,
12
+ } from '@/features/providers/queries'
13
+ import { useCredentialsQuery, useCreateCredentialMutation } from '@/features/credentials/queries'
14
+ import {
15
+ useCloneGatewayProfileMutation,
16
+ useDeleteGatewayProfileMutation,
17
+ useGatewayHealthCheckMutation,
18
+ useGatewayProfilesQuery,
19
+ useSaveGatewayProfileMutation,
20
+ useVerifyOpenClawDeployMutation,
21
+ } from '@/features/gateways/queries'
22
+ import { useExternalAgentsQuery, useExternalAgentRuntimeMutation } from '@/features/external-agents/queries'
23
+ import type { GatewayProfile } from '@/types'
10
24
  import { dedup } from '@/lib/shared-utils'
11
25
  import { PageLoader } from '@/components/ui/page-loader'
12
26
  import { StatusDot } from '@/components/ui/status-dot'
@@ -30,33 +44,34 @@ function formatRuntimeTimestamp(value: number | null | undefined): string {
30
44
  }
31
45
 
32
46
  export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
33
- const providers = useAppStore((s) => s.providers)
34
- const providerConfigs = useAppStore((s) => s.providerConfigs)
35
- const loadProviders = useAppStore((s) => s.loadProviders)
36
- const loadProviderConfigs = useAppStore((s) => s.loadProviderConfigs)
37
- const gatewayProfiles = useAppStore((s) => s.gatewayProfiles)
38
- const loadGatewayProfiles = useAppStore((s) => s.loadGatewayProfiles)
39
- const externalAgents = useAppStore((s) => s.externalAgents)
40
- const loadExternalAgents = useAppStore((s) => s.loadExternalAgents)
41
- const credentials = useAppStore((s) => s.credentials)
42
- const loadCredentials = useAppStore((s) => s.loadCredentials)
43
47
  const setProviderSheetOpen = useAppStore((s) => s.setProviderSheetOpen)
44
48
  const setEditingProviderId = useAppStore((s) => s.setEditingProviderId)
45
49
  const setGatewaySheetOpen = useAppStore((s) => s.setGatewaySheetOpen)
46
50
  const setEditingGatewayId = useAppStore((s) => s.setEditingGatewayId)
47
- const [loaded, setLoaded] = useState(false)
48
51
  const [deployDraft, setDeployDraft] = useState<OpenClawDeployDraft | null>(null)
49
- const [savingDeploy, setSavingDeploy] = useState(false)
52
+ const providersQuery = useProvidersQuery()
53
+ const providerConfigsQuery = useProviderConfigsQuery()
54
+ const gatewayProfilesQuery = useGatewayProfilesQuery()
55
+ const externalAgentsQuery = useExternalAgentsQuery()
56
+ const credentialsQuery = useCredentialsQuery()
57
+ const toggleProviderMutation = useToggleProviderMutation()
58
+ const deleteProviderMutation = useDeleteProviderMutation()
59
+ const createCredentialMutation = useCreateCredentialMutation()
60
+ const saveGatewayMutation = useSaveGatewayProfileMutation()
61
+ const deleteGatewayMutation = useDeleteGatewayProfileMutation()
62
+ const healthCheckGatewayMutation = useGatewayHealthCheckMutation()
63
+ const verifyDeployMutation = useVerifyOpenClawDeployMutation()
64
+ const cloneGatewayMutation = useCloneGatewayProfileMutation()
65
+ const runtimeActionMutation = useExternalAgentRuntimeMutation()
50
66
 
51
- const refresh = useCallback(async () => {
52
- await Promise.all([loadProviders(), loadProviderConfigs(), loadGatewayProfiles(), loadExternalAgents(), loadCredentials()])
53
- setLoaded(true)
54
- }, [loadProviders, loadProviderConfigs, loadGatewayProfiles, loadExternalAgents, loadCredentials])
55
-
56
- useEffect(() => { void refresh() }, [refresh])
57
- useWs('providers', loadProviders, 20_000)
58
- useWs('gateways', loadGatewayProfiles, 20_000)
59
- useWs('external_agents', loadExternalAgents, 20_000)
67
+ const providers = providersQuery.data ?? []
68
+ const providerConfigs = providerConfigsQuery.data ?? []
69
+ const gatewayProfiles = gatewayProfilesQuery.data ?? []
70
+ const externalAgents = externalAgentsQuery.data ?? []
71
+ const credentials = credentialsQuery.data ?? {}
72
+ const savingDeploy = createCredentialMutation.isPending
73
+ || verifyDeployMutation.isPending
74
+ || saveGatewayMutation.isPending
60
75
 
61
76
  const handleEdit = (id: string) => {
62
77
  setEditingProviderId(id)
@@ -65,14 +80,12 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
65
80
 
66
81
  const handleToggle = async (e: React.MouseEvent, id: string, currentEnabled: boolean) => {
67
82
  e.stopPropagation()
68
- await api('PUT', `/providers/${id}`, { isEnabled: !currentEnabled })
69
- await loadProviderConfigs()
83
+ await toggleProviderMutation.mutateAsync({ id, isEnabled: !currentEnabled })
70
84
  }
71
85
 
72
86
  const handleDelete = async (e: React.MouseEvent, id: string) => {
73
87
  e.stopPropagation()
74
- await api('DELETE', `/providers/${id}`)
75
- await loadProviderConfigs()
88
+ await deleteProviderMutation.mutateAsync(id)
76
89
  }
77
90
 
78
91
  const handleEditGateway = (id: string | null) => {
@@ -82,14 +95,12 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
82
95
 
83
96
  const handleDeleteGateway = async (e: React.MouseEvent, id: string) => {
84
97
  e.stopPropagation()
85
- await api('DELETE', `/gateways/${id}`)
86
- await loadGatewayProfiles()
98
+ await deleteGatewayMutation.mutateAsync(id)
87
99
  }
88
100
 
89
101
  const handleHealthCheckGateway = async (e: React.MouseEvent, id: string) => {
90
102
  e.stopPropagation()
91
- await api('GET', `/gateways/${id}/health`)
92
- await loadGatewayProfiles()
103
+ await healthCheckGatewayMutation.mutateAsync(id)
93
104
  }
94
105
 
95
106
  const handleDeployApply = (patch: { endpoint?: string; token?: string; name?: string; notes?: string; deployment?: GatewayProfile['deployment'] | Record<string, unknown> | null }) => {
@@ -105,11 +116,10 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
105
116
 
106
117
  const handleSavePreparedGateway = async () => {
107
118
  if (!deployDraft?.endpoint) return
108
- setSavingDeploy(true)
109
119
  try {
110
120
  let nextCredentialId: string | null = null
111
121
  if (deployDraft.token?.trim()) {
112
- const credential = await api<Credential>('POST', '/credentials', {
122
+ const credential = await createCredentialMutation.mutateAsync({
113
123
  provider: 'openclaw',
114
124
  name: `${deployDraft.name || 'OpenClaw Gateway'} token`,
115
125
  apiKey: deployDraft.token.trim(),
@@ -124,17 +134,7 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
124
134
  ...(deployDraft.deployment?.useCase ? [deployDraft.deployment.useCase] : []),
125
135
  ...(deployDraft.deployment?.exposure ? [deployDraft.deployment.exposure] : []),
126
136
  ])
127
- const verify = await api<{
128
- ok: boolean
129
- verify?: {
130
- ok: boolean
131
- message?: string
132
- error?: string
133
- hint?: string
134
- models?: string[]
135
- }
136
- }>('POST', '/openclaw/deploy', {
137
- action: 'verify',
137
+ const verify = await verifyDeployMutation.mutateAsync({
138
138
  endpoint: deployDraft.endpoint,
139
139
  token: deployDraft.token?.trim() || undefined,
140
140
  }).catch(() => ({ ok: false, verify: undefined as undefined }))
@@ -150,7 +150,7 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
150
150
  ...(existing?.deployment || {}),
151
151
  ...(deployDraft.deployment || {}),
152
152
  managedBy: 'swarmclaw',
153
- lastVerifiedAt: verify.verify ? Date.now() : (existing?.deployment?.lastVerifiedAt || null),
153
+ lastVerifiedAt: verify.verify ? +new Date() : (existing?.deployment?.lastVerifiedAt || null),
154
154
  lastVerifiedOk: verify.verify ? verifiedOk : (existing?.deployment?.lastVerifiedOk ?? null),
155
155
  lastVerifiedMessage: verify.verify
156
156
  ? (verifiedOk
@@ -161,26 +161,21 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
161
161
  isDefault: existing?.isDefault === true || gatewayProfiles.length === 0,
162
162
  }
163
163
 
164
- if (existing) {
165
- await api('PUT', `/gateways/${existing.id}`, payload)
166
- } else {
167
- await api('POST', '/gateways', payload)
168
- }
169
-
170
- await Promise.all([loadGatewayProfiles(), loadCredentials()])
164
+ await saveGatewayMutation.mutateAsync({
165
+ id: existing?.id,
166
+ payload,
167
+ })
171
168
  setDeployDraft(null)
172
169
  toast.success(existing ? 'Gateway profile updated' : 'Gateway profile saved')
173
170
  } catch (err: unknown) {
174
171
  toast.error(err instanceof Error ? err.message : 'Failed to save prepared gateway')
175
- } finally {
176
- setSavingDeploy(false)
177
172
  }
178
173
  }
179
174
 
180
175
  const handleCloneGateway = async (e: React.MouseEvent, gateway: GatewayProfile) => {
181
176
  e.stopPropagation()
182
177
  try {
183
- await api('POST', '/gateways', {
178
+ await cloneGatewayMutation.mutateAsync({
184
179
  name: `${gateway.name} Copy`,
185
180
  endpoint: gateway.endpoint,
186
181
  credentialId: gateway.credentialId || null,
@@ -190,7 +185,6 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
190
185
  stats: gateway.stats || null,
191
186
  isDefault: false,
192
187
  })
193
- await loadGatewayProfiles()
194
188
  toast.success('Gateway cloned')
195
189
  } catch (err: unknown) {
196
190
  toast.error(err instanceof Error ? err.message : 'Failed to clone gateway')
@@ -204,8 +198,7 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
204
198
  ) => {
205
199
  e.stopPropagation()
206
200
  try {
207
- await api('PUT', `/external-agents/${runtimeId}`, { action })
208
- await loadExternalAgents()
201
+ await runtimeActionMutation.mutateAsync({ runtimeId, action })
209
202
  const actionLabel = action === 'activate'
210
203
  ? 'Runtime activated'
211
204
  : action === 'drain'
@@ -219,18 +212,27 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
219
212
  }
220
213
  }
221
214
 
222
- // Merge built-in providers with custom configs
223
- const builtinItems = providers.map((p) => ({
215
+ const customProviderConfigs = providerConfigs.filter((config) => config.type === 'custom')
216
+ const customConfigIds = new Set(customProviderConfigs.map((config) => config.id))
217
+ const builtinOverrides = new Map(
218
+ providerConfigs
219
+ .filter((config) => config.type === 'builtin')
220
+ .map((config) => [config.id, config]),
221
+ )
222
+
223
+ const builtinItems = providers
224
+ .filter((provider) => !customConfigIds.has(String(provider.id)))
225
+ .map((p) => ({
224
226
  id: p.id,
225
227
  name: p.name,
226
228
  type: 'builtin' as const,
227
229
  models: p.models,
228
230
  requiresApiKey: p.requiresApiKey,
229
- isEnabled: true,
231
+ isEnabled: builtinOverrides.get(String(p.id))?.isEnabled !== false,
230
232
  isConnected: !p.requiresApiKey || Object.values(credentials).some((c) => c.provider === p.id),
231
- }))
233
+ }))
232
234
 
233
- const customItems = providerConfigs.map((c) => ({
235
+ const customItems = customProviderConfigs.map((c) => ({
234
236
  id: c.id,
235
237
  name: c.name,
236
238
  type: 'custom' as const,
@@ -241,6 +243,8 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
241
243
  }))
242
244
 
243
245
  const allItems = [...builtinItems, ...customItems]
246
+ const enabledItems = allItems.filter((item) => item.isEnabled)
247
+ const disabledItems = allItems.filter((item) => !item.isEnabled)
244
248
  const gatewayNameById = new Map(gatewayProfiles.map((gateway) => [gateway.id, gateway.name]))
245
249
  const runtimeHealthByGateway = externalAgents.reduce<Record<string, { total: number; active: number; lastHeartbeatAt: number | null }>>((acc, runtime) => {
246
250
  if (!runtime.gatewayProfileId) return acc
@@ -254,7 +258,13 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
254
258
  return acc
255
259
  }, {})
256
260
 
257
- if (!loaded) {
261
+ if (
262
+ providersQuery.isPending
263
+ || providerConfigsQuery.isPending
264
+ || gatewayProfilesQuery.isPending
265
+ || externalAgentsQuery.isPending
266
+ || credentialsQuery.isPending
267
+ ) {
258
268
  return <PageLoader label="Loading providers..." />
259
269
  }
260
270
 
@@ -273,7 +283,7 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
273
283
  )}
274
284
  </div>
275
285
  <div className={inSidebar ? 'space-y-2' : 'grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3'}>
276
- {allItems.map((item, idx) => (
286
+ {enabledItems.map((item, idx) => (
277
287
  <div
278
288
  key={item.id}
279
289
  role="button"
@@ -299,7 +309,7 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
299
309
  ${item.type === 'builtin' ? 'bg-white/[0.04] text-text-3' : 'bg-accent-bright/10 text-[#6366F1]'}`}>
300
310
  {item.type === 'builtin' ? 'Built-in' : 'Custom'}
301
311
  </span>
302
- {!inSidebar && item.type === 'custom' && (
312
+ {!inSidebar && (
303
313
  <>
304
314
  <div
305
315
  onClick={(e) => handleToggle(e, item.id, item.isEnabled)}
@@ -311,15 +321,17 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
311
321
  style={item.isEnabled ? { animation: 'spring-in 0.3s var(--ease-spring)' } : undefined}
312
322
  />
313
323
  </div>
314
- <button
315
- onClick={(e) => handleDelete(e, item.id)}
316
- className="text-text-3/40 hover:text-red-400 transition-colors p-0.5"
317
- title="Delete provider"
318
- >
319
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
320
- <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
321
- </svg>
322
- </button>
324
+ {item.type === 'custom' && (
325
+ <button
326
+ onClick={(e) => handleDelete(e, item.id)}
327
+ className="text-text-3/40 hover:text-red-400 transition-colors p-0.5"
328
+ title="Delete provider"
329
+ >
330
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
331
+ <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
332
+ </svg>
333
+ </button>
334
+ )}
323
335
  </>
324
336
  )}
325
337
  <StatusDot
@@ -339,6 +351,67 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
339
351
  </div>
340
352
  ))}
341
353
  </div>
354
+ {!inSidebar && disabledItems.length > 0 && (
355
+ <>
356
+ <div className="mt-8 mb-4 flex items-center justify-between">
357
+ <div className="text-[12px] font-700 uppercase tracking-[0.08em] text-text-3/60">Disabled Providers</div>
358
+ </div>
359
+ <div className="grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3">
360
+ {disabledItems.map((item, idx) => (
361
+ <div
362
+ key={item.id}
363
+ role="button"
364
+ tabIndex={0}
365
+ onClick={() => handleEdit(item.id)}
366
+ onKeyDown={(e) => {
367
+ if (e.key === 'Enter' || e.key === ' ') {
368
+ e.preventDefault()
369
+ handleEdit(item.id)
370
+ }
371
+ }}
372
+ className="w-full text-left p-4 rounded-[14px] border transition-all duration-200
373
+ cursor-pointer bg-surface/60 border-white/[0.06] hover:bg-white/[0.02] hover:border-white/[0.12]"
374
+ style={{
375
+ animation: 'spring-in 0.5s var(--ease-spring) both',
376
+ animationDelay: `${(enabledItems.length + idx) * 0.05}s`
377
+ }}
378
+ >
379
+ <div className="flex items-center justify-between mb-1.5">
380
+ <span className="font-display text-[14px] font-600 text-text truncate">{item.name}</span>
381
+ <div className="flex items-center gap-2 shrink-0">
382
+ <span className={`text-[10px] font-600 px-2 py-0.5 rounded-[5px] uppercase tracking-wider
383
+ ${item.type === 'builtin' ? 'bg-white/[0.04] text-text-3' : 'bg-accent-bright/10 text-[#6366F1]'}`}>
384
+ {item.type === 'builtin' ? 'Built-in' : 'Custom'}
385
+ </span>
386
+ <div
387
+ onClick={(e) => handleToggle(e, item.id, item.isEnabled)}
388
+ className="w-9 h-5 rounded-full transition-all relative cursor-pointer shrink-0 bg-white/[0.08]"
389
+ >
390
+ <div className="absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white transition-all" />
391
+ </div>
392
+ {item.type === 'custom' && (
393
+ <button
394
+ onClick={(e) => handleDelete(e, item.id)}
395
+ className="text-text-3/40 hover:text-red-400 transition-colors p-0.5"
396
+ title="Delete provider"
397
+ >
398
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
399
+ <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
400
+ </svg>
401
+ </button>
402
+ )}
403
+ <StatusDot status="idle" pulse={false} />
404
+ </div>
405
+ </div>
406
+ <div className="text-[12px] text-text-3/60 font-mono truncate">
407
+ {item.models.slice(0, 3).join(', ')}
408
+ {item.models.length > 3 && ` +${item.models.length - 3}`}
409
+ </div>
410
+ </div>
411
+ ))}
412
+ </div>
413
+ </>
414
+ )}
342
415
 
343
416
  <div className="mt-8 mb-4 flex items-center justify-between">
344
417
  <div className="text-[12px] font-700 uppercase tracking-[0.08em] text-text-3/60">OpenClaw Gateways</div>