@swarmclawai/swarmclaw 1.2.4 → 1.2.6

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 (262) hide show
  1. package/README.md +14 -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]/route.test.ts +49 -0
  49. package/src/app/api/providers/ollama/route.ts +6 -5
  50. package/src/app/api/schedules/[id]/route.ts +14 -108
  51. package/src/app/api/schedules/[id]/run/route.ts +6 -67
  52. package/src/app/api/schedules/route.ts +9 -51
  53. package/src/app/api/settings/route.ts +4 -3
  54. package/src/app/api/setup/check-provider/route.ts +23 -1
  55. package/src/app/api/setup/openclaw-device/route.ts +2 -2
  56. package/src/app/api/system/status/route.ts +2 -2
  57. package/src/app/api/tasks/[id]/route.ts +16 -202
  58. package/src/app/api/tasks/bulk/route.ts +5 -86
  59. package/src/app/api/tasks/metrics/route.ts +2 -1
  60. package/src/app/api/tasks/route.ts +11 -171
  61. package/src/app/api/upload/route.ts +1 -1
  62. package/src/app/api/uploads/[filename]/route.ts +1 -1
  63. package/src/app/api/uploads/route.ts +1 -1
  64. package/src/app/api/webhooks/[id]/history/route.ts +2 -2
  65. package/src/app/layout.tsx +9 -6
  66. package/src/app/protocols/page.tsx +71 -89
  67. package/src/app/tasks/page.tsx +32 -32
  68. package/src/cli/index.js +1 -0
  69. package/src/cli/spec.js +1 -0
  70. package/src/components/agents/agent-sheet.tsx +5 -5
  71. package/src/components/auth/setup-wizard/index.tsx +4 -4
  72. package/src/components/auth/setup-wizard/step-agents.tsx +1 -1
  73. package/src/components/auth/setup-wizard/step-connect.tsx +1 -1
  74. package/src/components/auth/setup-wizard/utils.ts +1 -1
  75. package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
  76. package/src/components/connectors/connector-list.tsx +26 -40
  77. package/src/components/connectors/connector-sheet.tsx +95 -149
  78. package/src/components/gateways/gateway-sheet.tsx +61 -110
  79. package/src/components/layout/live-query-sync.tsx +121 -0
  80. package/src/components/protocols/structured-session-launcher.tsx +24 -45
  81. package/src/components/providers/app-query-provider.tsx +17 -0
  82. package/src/components/providers/provider-list.tsx +60 -61
  83. package/src/components/providers/provider-sheet.tsx +74 -56
  84. package/src/components/skills/skill-list.tsx +5 -18
  85. package/src/components/skills/skill-sheet.tsx +21 -20
  86. package/src/components/skills/skills-workspace.tsx +48 -87
  87. package/src/components/tasks/task-card.tsx +20 -13
  88. package/src/components/tasks/task-column.tsx +22 -7
  89. package/src/components/tasks/task-list.tsx +8 -11
  90. package/src/components/tasks/task-sheet.tsx +111 -103
  91. package/src/features/agents/queries.ts +20 -0
  92. package/src/features/chatrooms/queries.ts +20 -0
  93. package/src/features/chats/queries.ts +27 -0
  94. package/src/features/connectors/queries.ts +145 -0
  95. package/src/features/credentials/queries.ts +37 -0
  96. package/src/features/extensions/queries.ts +26 -0
  97. package/src/features/external-agents/queries.ts +36 -0
  98. package/src/features/gateways/queries.ts +274 -0
  99. package/src/features/missions/queries.ts +23 -0
  100. package/src/features/projects/queries.ts +20 -0
  101. package/src/features/protocols/queries.ts +149 -0
  102. package/src/features/providers/queries.ts +142 -0
  103. package/src/features/settings/queries.ts +20 -0
  104. package/src/features/skills/queries.ts +182 -0
  105. package/src/features/tasks/queries.ts +189 -0
  106. package/src/hooks/use-ws.ts +3 -2
  107. package/src/lib/app/api-client.ts +2 -2
  108. package/src/lib/providers/index.test.ts +108 -0
  109. package/src/lib/providers/index.ts +38 -15
  110. package/src/lib/query/client.ts +17 -0
  111. package/src/lib/server/agents/agent-runtime-config.ts +1 -1
  112. package/src/lib/server/agents/agent-service.ts +429 -0
  113. package/src/lib/server/agents/agent-thread-session.ts +6 -5
  114. package/src/lib/server/agents/autonomy-contract.ts +1 -4
  115. package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
  116. package/src/lib/server/agents/delegation-advisory.ts +251 -0
  117. package/src/lib/server/agents/main-agent-loop.ts +98 -40
  118. package/src/lib/server/agents/subagent-runtime.ts +12 -0
  119. package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
  120. package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
  121. package/src/lib/server/build-llm.ts +7 -15
  122. package/src/lib/server/capability-router.test.ts +70 -1
  123. package/src/lib/server/capability-router.ts +24 -99
  124. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
  125. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
  126. package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
  127. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
  128. package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
  129. package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
  130. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
  131. package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
  132. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
  133. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
  134. package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
  135. package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
  136. package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
  137. package/src/lib/server/chat-execution/message-classifier.ts +74 -32
  138. package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
  139. package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
  140. package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
  141. package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
  142. package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
  143. package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
  144. package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
  145. package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
  146. package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
  147. package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
  148. package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
  149. package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
  150. package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
  151. package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
  152. package/src/lib/server/chats/chat-session-service.ts +410 -0
  153. package/src/lib/server/connectors/access.ts +1 -1
  154. package/src/lib/server/connectors/commands.ts +7 -6
  155. package/src/lib/server/connectors/connector-inbound.ts +14 -7
  156. package/src/lib/server/connectors/connector-outbound.ts +16 -11
  157. package/src/lib/server/connectors/connector-service.ts +453 -0
  158. package/src/lib/server/connectors/delivery.ts +17 -12
  159. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
  160. package/src/lib/server/connectors/media.ts +1 -1
  161. package/src/lib/server/connectors/response-media.ts +1 -1
  162. package/src/lib/server/connectors/session-consolidation.ts +11 -7
  163. package/src/lib/server/connectors/session.ts +9 -7
  164. package/src/lib/server/connectors/voice-note.ts +2 -1
  165. package/src/lib/server/context-manager.ts +20 -1
  166. package/src/lib/server/cost.ts +2 -3
  167. package/src/lib/server/credentials/credential-repository.ts +43 -4
  168. package/src/lib/server/credentials/credential-service.ts +112 -0
  169. package/src/lib/server/daemon/admin-metadata.ts +64 -0
  170. package/src/lib/server/daemon/controller.ts +577 -0
  171. package/src/lib/server/daemon/daemon-runtime.ts +352 -0
  172. package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
  173. package/src/lib/server/daemon/types.ts +101 -0
  174. package/src/lib/server/embeddings.ts +3 -9
  175. package/src/lib/server/eval/agent-regression.ts +3 -2
  176. package/src/lib/server/eval/runner.ts +2 -2
  177. package/src/lib/server/execution-brief.test.ts +167 -0
  178. package/src/lib/server/execution-brief.ts +295 -0
  179. package/src/lib/server/execution-engine/chat-turn.ts +9 -0
  180. package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
  181. package/src/lib/server/execution-engine/index.ts +35 -0
  182. package/src/lib/server/execution-engine/task-attempt.ts +303 -0
  183. package/src/lib/server/execution-engine/types.ts +33 -0
  184. package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
  185. package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
  186. package/src/lib/server/memory/session-archive-memory.ts +12 -10
  187. package/src/lib/server/messages/message-repository.ts +330 -0
  188. package/src/lib/server/missions/mission-service/core.ts +8 -6
  189. package/src/lib/server/openclaw/agent-resolver.ts +2 -3
  190. package/src/lib/server/openclaw/doctor.ts +1 -1
  191. package/src/lib/server/openclaw/gateway.test.ts +10 -1
  192. package/src/lib/server/openclaw/gateway.ts +5 -14
  193. package/src/lib/server/openclaw/health.ts +3 -11
  194. package/src/lib/server/openclaw/sync.ts +8 -6
  195. package/src/lib/server/persistence/storage-context.ts +3 -0
  196. package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
  197. package/src/lib/server/protocols/protocol-normalization.ts +1 -1
  198. package/src/lib/server/protocols/protocol-queries.ts +13 -7
  199. package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
  200. package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
  201. package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
  202. package/src/lib/server/protocols/protocol-swarm.ts +8 -8
  203. package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
  204. package/src/lib/server/protocols/protocol-templates.ts +4 -2
  205. package/src/lib/server/protocols/protocol-types.ts +10 -7
  206. package/src/lib/server/provider-endpoint.ts +7 -12
  207. package/src/lib/server/provider-model-discovery.ts +2 -11
  208. package/src/lib/server/query-expansion.ts +5 -6
  209. package/src/lib/server/run-context.test.ts +365 -0
  210. package/src/lib/server/run-context.ts +367 -0
  211. package/src/lib/server/runtime/heartbeat-service.ts +7 -5
  212. package/src/lib/server/runtime/queue/core.ts +61 -190
  213. package/src/lib/server/runtime/run-ledger.ts +8 -0
  214. package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
  215. package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
  216. package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
  217. package/src/lib/server/schedules/schedule-route-service.ts +230 -0
  218. package/src/lib/server/service-result.ts +16 -0
  219. package/src/lib/server/session-note.ts +2 -3
  220. package/src/lib/server/session-reset-policy.ts +4 -3
  221. package/src/lib/server/session-tools/connector.ts +9 -6
  222. package/src/lib/server/session-tools/context-mgmt.ts +58 -9
  223. package/src/lib/server/session-tools/crud.ts +162 -10
  224. package/src/lib/server/session-tools/delegate.ts +1 -1
  225. package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
  226. package/src/lib/server/session-tools/memory.ts +6 -4
  227. package/src/lib/server/session-tools/session-info.test.ts +56 -0
  228. package/src/lib/server/session-tools/session-info.ts +119 -12
  229. package/src/lib/server/session-tools/skill-runtime.ts +3 -1
  230. package/src/lib/server/session-tools/skills.ts +15 -15
  231. package/src/lib/server/session-tools/subagent.test.ts +115 -1
  232. package/src/lib/server/session-tools/subagent.ts +125 -7
  233. package/src/lib/server/session-tools/team-context.ts +4 -3
  234. package/src/lib/server/session-tools/wallet.ts +0 -58
  235. package/src/lib/server/sessions/session-lineage.ts +55 -0
  236. package/src/lib/server/sessions/session-repository.ts +2 -2
  237. package/src/lib/server/skills/learned-skills.ts +24 -23
  238. package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
  239. package/src/lib/server/skills/skill-repository.ts +136 -13
  240. package/src/lib/server/skills/skill-suggestions.ts +25 -28
  241. package/src/lib/server/storage-normalization.test.ts +44 -267
  242. package/src/lib/server/storage-normalization.ts +75 -0
  243. package/src/lib/server/storage.ts +19 -0
  244. package/src/lib/server/structured-extract.ts +3 -14
  245. package/src/lib/server/tasks/task-followups.ts +16 -11
  246. package/src/lib/server/tasks/task-result.test.ts +25 -29
  247. package/src/lib/server/tasks/task-result.ts +5 -9
  248. package/src/lib/server/tasks/task-route-service.ts +449 -0
  249. package/src/lib/server/text-normalization.ts +41 -0
  250. package/src/lib/server/tool-planning.ts +6 -42
  251. package/src/lib/server/upload-path.ts +5 -0
  252. package/src/lib/server/working-state/extraction.ts +614 -0
  253. package/src/lib/server/working-state/normalization.ts +866 -0
  254. package/src/lib/server/working-state/prompt.ts +60 -0
  255. package/src/lib/server/working-state/repository.ts +38 -0
  256. package/src/lib/server/working-state/service.test.ts +253 -0
  257. package/src/lib/server/working-state/service.ts +293 -0
  258. package/src/lib/validation/schemas.ts +1 -0
  259. package/src/lib/ws-client.ts +3 -3
  260. package/src/stores/slices/task-slice.ts +1 -4
  261. package/src/stores/use-chatroom-store.ts +2 -2
  262. package/src/types/index.ts +277 -12
@@ -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 Promise.all([loadProviderConfigs(), loadProviders()])
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 Promise.all([loadProviderConfigs(), loadProviders()])
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'
@@ -265,7 +258,13 @@ export function ProviderList({ inSidebar }: { inSidebar?: boolean }) {
265
258
  return acc
266
259
  }, {})
267
260
 
268
- if (!loaded) {
261
+ if (
262
+ providersQuery.isPending
263
+ || providerConfigsQuery.isPending
264
+ || gatewayProfilesQuery.isPending
265
+ || externalAgentsQuery.isPending
266
+ || credentialsQuery.isPending
267
+ ) {
269
268
  return <PageLoader label="Loading providers..." />
270
269
  }
271
270
 
@@ -1,26 +1,42 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useState } from 'react'
3
+ import { useEffect, useMemo, useState } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
- import { createProviderConfig, updateProviderConfig, deleteProviderConfig } from '@/lib/provider-config'
6
- import { api } from '@/lib/app/api-client'
7
- import { fetchProviderModelDiscovery } from '@/lib/provider-model-discovery-client'
8
5
  import { BottomSheet } from '@/components/shared/bottom-sheet'
9
6
  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
10
7
  import { toast } from 'sonner'
11
8
  import { errorMessage } from '@/lib/shared-utils'
9
+ import {
10
+ useCheckProviderConnectionMutation,
11
+ useDeleteProviderMutation,
12
+ useProviderConfigsQuery,
13
+ useProviderModelDiscoveryMutation,
14
+ useProvidersQuery,
15
+ useResetProviderModelsMutation,
16
+ useSaveBuiltinProviderMutation,
17
+ useSaveCustomProviderMutation,
18
+ } from '@/features/providers/queries'
19
+ import { useCreateCredentialMutation, useCredentialsQuery } from '@/features/credentials/queries'
12
20
 
13
21
  export function ProviderSheet() {
14
22
  const open = useAppStore((s) => s.providerSheetOpen)
15
23
  const setOpen = useAppStore((s) => s.setProviderSheetOpen)
16
24
  const editingId = useAppStore((s) => s.editingProviderId)
17
25
  const setEditingId = useAppStore((s) => s.setEditingProviderId)
18
- const providerConfigs = useAppStore((s) => s.providerConfigs)
19
- const loadProviderConfigs = useAppStore((s) => s.loadProviderConfigs)
20
- const providers = useAppStore((s) => s.providers)
21
- const loadProviders = useAppStore((s) => s.loadProviders)
22
- const credentials = useAppStore((s) => s.credentials)
23
- const loadCredentials = useAppStore((s) => s.loadCredentials)
26
+ const providerConfigsQuery = useProviderConfigsQuery({ enabled: open })
27
+ const providersQuery = useProvidersQuery({ enabled: open })
28
+ const credentialsQuery = useCredentialsQuery({ enabled: open })
29
+ const saveBuiltinProviderMutation = useSaveBuiltinProviderMutation()
30
+ const saveCustomProviderMutation = useSaveCustomProviderMutation()
31
+ const deleteProviderMutation = useDeleteProviderMutation()
32
+ const resetProviderModelsMutation = useResetProviderModelsMutation()
33
+ const checkProviderConnectionMutation = useCheckProviderConnectionMutation()
34
+ const providerModelDiscoveryMutation = useProviderModelDiscoveryMutation()
35
+ const createCredentialMutation = useCreateCredentialMutation()
36
+
37
+ const providerConfigs = providerConfigsQuery.data ?? []
38
+ const providers = providersQuery.data ?? []
39
+ const credentials = useMemo(() => credentialsQuery.data ?? {}, [credentialsQuery.data])
24
40
 
25
41
  const [name, setName] = useState('')
26
42
  const [baseUrl, setBaseUrl] = useState('')
@@ -54,7 +70,6 @@ export function ProviderSheet() {
54
70
 
55
71
  useEffect(() => {
56
72
  if (open) {
57
- loadCredentials()
58
73
  setNewModel('')
59
74
  setLiveModels([])
60
75
  setLiveMessage('')
@@ -86,7 +101,7 @@ export function ProviderSheet() {
86
101
  setIsEnabled(true)
87
102
  }
88
103
  }
89
- }, [open, editingId, credentials, editingBuiltin, editingBuiltinOverride, editingCustom, loadCredentials])
104
+ }, [open, editingId, credentials, editingBuiltin, editingBuiltinOverride, editingCustom])
90
105
 
91
106
  // Reset test status when connection params change
92
107
  useEffect(() => {
@@ -105,7 +120,7 @@ export function ProviderSheet() {
105
120
  setTestStatus('testing')
106
121
  setTestMessage('')
107
122
  try {
108
- const result = await api<{ ok: boolean; message: string }>('POST', '/setup/check-provider', {
123
+ const result = await checkProviderConnectionMutation.mutateAsync({
109
124
  provider: editingId || 'custom',
110
125
  credentialId,
111
126
  endpoint: baseUrl,
@@ -137,15 +152,13 @@ export function ProviderSheet() {
137
152
  const handleSave = async () => {
138
153
  try {
139
154
  if (isBuiltin) {
140
- // Save model overrides for built-in providers
141
155
  const modelList = models.split(',').map((m) => m.trim()).filter(Boolean)
142
- await api('PUT', `/providers/${editingId}/models`, { models: modelList })
143
- await api('PUT', `/providers/${editingId}`, {
144
- type: 'builtin',
156
+ await saveBuiltinProviderMutation.mutateAsync({
157
+ id: editingId || '',
158
+ models: modelList,
145
159
  isEnabled,
146
160
  })
147
161
  toast.success('Built-in provider updated')
148
- await Promise.all([loadProviders(), loadProviderConfigs()])
149
162
  onClose()
150
163
  return
151
164
  }
@@ -158,14 +171,11 @@ export function ProviderSheet() {
158
171
  credentialId,
159
172
  isEnabled,
160
173
  }
161
- if (editingCustom) {
162
- await updateProviderConfig(editingCustom.id, data)
163
- toast.success('Provider updated')
164
- } else {
165
- await createProviderConfig(data)
166
- toast.success('Provider created')
167
- }
168
- await Promise.all([loadProviderConfigs(), loadProviders()])
174
+ await saveCustomProviderMutation.mutateAsync({
175
+ id: editingCustom?.id,
176
+ data,
177
+ })
178
+ toast.success(editingCustom ? 'Provider updated' : 'Provider created')
169
179
  onClose()
170
180
  } catch (err: unknown) {
171
181
  toast.error(err instanceof Error ? err.message : 'Failed to save provider')
@@ -176,9 +186,8 @@ export function ProviderSheet() {
176
186
  if (editingCustom) {
177
187
  setDeleting(true)
178
188
  try {
179
- await deleteProviderConfig(editingCustom.id)
189
+ await deleteProviderMutation.mutateAsync(editingCustom.id)
180
190
  toast.success('Provider deleted')
181
- await Promise.all([loadProviderConfigs(), loadProviders()])
182
191
  setConfirmDelete(false)
183
192
  onClose()
184
193
  } catch (err: unknown) {
@@ -190,26 +199,24 @@ export function ProviderSheet() {
190
199
  }
191
200
 
192
201
  const handleResetModels = async () => {
193
- if (isBuiltin && editingId) {
194
- await api('DELETE', `/providers/${editingId}/models`)
195
- await loadProviders()
196
- // Re-read from fresh store state (closure captures stale providers)
197
- const updated = useAppStore.getState().providers.find((p) => p.id === editingId)
198
- if (updated) setModels(updated.models.join(', '))
199
- }
202
+ if (!isBuiltin || !editingId) return
203
+ await resetProviderModelsMutation.mutateAsync(editingId)
204
+ const refreshedProviders = (await providersQuery.refetch()).data ?? []
205
+ const updated = refreshedProviders.find((provider) => provider.id === editingId)
206
+ if (updated) setModels(updated.models.join(', '))
200
207
  }
201
208
 
202
- const handleAddModel = () => {
203
- if (!newModel.trim()) return
204
- const current = models ? models + ', ' + newModel.trim() : newModel.trim()
205
- setModels(current)
206
- setNewModel('')
207
- }
208
-
209
- const handleRemoveModel = (index: number) => {
210
- const list = models.split(',').map((m) => m.trim()).filter(Boolean)
211
- list.splice(index, 1)
212
- setModels(list.join(', '))
209
+ const handleCreateCredential = async () => {
210
+ const cred = await createCredentialMutation.mutateAsync({
211
+ provider: editingId || name || 'custom',
212
+ name: newKeyName.trim() || `${name || editingId || 'Custom'} key`,
213
+ apiKey: newKeyValue.trim(),
214
+ })
215
+ await credentialsQuery.refetch()
216
+ setCredentialId(cred.id)
217
+ setAddingKey(false)
218
+ setNewKeyName('')
219
+ setNewKeyValue('')
213
220
  }
214
221
 
215
222
  const handleLoadLiveModels = async (force = false) => {
@@ -218,7 +225,7 @@ export function ProviderSheet() {
218
225
  setLiveLoading(true)
219
226
  setLiveMessage('')
220
227
  try {
221
- const result = await fetchProviderModelDiscovery({
228
+ const result = await providerModelDiscoveryMutation.mutateAsync({
222
229
  providerId,
223
230
  credentialId,
224
231
  endpoint: baseUrl,
@@ -243,6 +250,19 @@ export function ProviderSheet() {
243
250
  }
244
251
  }
245
252
 
253
+ const handleAddModel = () => {
254
+ if (!newModel.trim()) return
255
+ const current = models ? models + ', ' + newModel.trim() : newModel.trim()
256
+ setModels(current)
257
+ setNewModel('')
258
+ }
259
+
260
+ const handleRemoveModel = (index: number) => {
261
+ const list = models.split(',').map((m) => m.trim()).filter(Boolean)
262
+ list.splice(index, 1)
263
+ setModels(list.join(', '))
264
+ }
265
+
246
266
  const credList = Object.values(credentials)
247
267
  const modelList = models.split(',').map((m) => m.trim()).filter(Boolean)
248
268
  const showApiKey = isBuiltin ? editingBuiltin?.requiresApiKey || editingBuiltin?.optionalApiKey : requiresApiKey
@@ -300,7 +320,7 @@ export function ProviderSheet() {
300
320
  </button>
301
321
  )}
302
322
  {isBuiltin && (
303
- <button onClick={handleResetModels}
323
+ <button onClick={() => { void handleResetModels() }}
304
324
  className="text-[11px] text-text-3 hover:text-text-2 transition-colors cursor-pointer bg-transparent border-none"
305
325
  style={{ fontFamily: 'inherit' }}>
306
326
  Reset to defaults
@@ -456,14 +476,12 @@ export function ProviderSheet() {
456
476
  onClick={async () => {
457
477
  setSavingKey(true)
458
478
  try {
459
- const cred = await api<{ id: string }>('POST', '/credentials', { provider: editingId || name || 'custom', name: newKeyName.trim() || `${name || editingId || 'Custom'} key`, apiKey: newKeyValue.trim() })
460
- await loadCredentials()
461
- setCredentialId(cred.id)
462
- setAddingKey(false)
463
- setNewKeyName('')
464
- setNewKeyValue('')
465
- } catch (err: unknown) { toast.error(`Failed to save: ${errorMessage(err)}`) }
466
- finally { setSavingKey(false) }
479
+ await handleCreateCredential()
480
+ } catch (err: unknown) {
481
+ toast.error(`Failed to save: ${errorMessage(err)}`)
482
+ } finally {
483
+ setSavingKey(false)
484
+ }
467
485
  }}
468
486
  className="px-4 py-1.5 rounded-[8px] bg-accent-bright text-white text-[12px] font-600 cursor-pointer border-none hover:brightness-110 transition-all disabled:opacity-40"
469
487
  style={{ fontFamily: 'inherit' }}
@@ -1,11 +1,11 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useEffect, useMemo, useState } from 'react'
3
+ import { useCallback, useMemo, useState } from 'react'
4
4
  import { useRouter, useSearchParams } from 'next/navigation'
5
5
  import { useAppStore } from '@/stores/use-app-store'
6
- import { useWs } from '@/hooks/use-ws'
7
6
  import type { Skill } from '@/types'
8
7
  import { SkillsWorkspace } from './skills-workspace'
8
+ import { useSkillsQuery } from '@/features/skills/queries'
9
9
 
10
10
  export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
11
11
  if (!inSidebar) return <SkillsWorkspace />
@@ -15,30 +15,17 @@ export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
15
15
  function SidebarSkillList() {
16
16
  const router = useRouter()
17
17
  const searchParams = useSearchParams()
18
- const skills = useAppStore((s) => s.skills)
19
- const loadSkills = useAppStore((s) => s.loadSkills)
20
18
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
21
19
  const setEditingSkillId = useAppStore((s) => s.setEditingSkillId)
22
20
  const setSkillSheetOpen = useAppStore((s) => s.setSkillSheetOpen)
21
+ const skillsQuery = useSkillsQuery()
22
+ const skills = useMemo(() => skillsQuery.data ?? {}, [skillsQuery.data])
23
23
 
24
24
  const [query, setQuery] = useState('')
25
- const [ready, setReady] = useState(false)
26
25
 
27
26
  const activeTab = searchParams.get('tab') === 'clawhub' ? 'clawhub' : 'skills'
28
27
  const selectedSkillId = activeTab === 'skills' ? searchParams.get('skill') : null
29
28
 
30
- useEffect(() => {
31
- let active = true
32
- void loadSkills().finally(() => {
33
- if (active) setReady(true)
34
- })
35
- return () => {
36
- active = false
37
- }
38
- }, [loadSkills])
39
-
40
- useWs('skills', () => { void loadSkills() })
41
-
42
29
  const setPageState = useCallback((patch: Record<string, string | null | undefined>) => {
43
30
  const next = new URLSearchParams(searchParams.toString())
44
31
  for (const [key, value] of Object.entries(patch)) {
@@ -92,7 +79,7 @@ function SidebarSkillList() {
92
79
  </div>
93
80
 
94
81
  <div className="mt-3 flex-1 overflow-y-auto">
95
- {!ready ? (
82
+ {skillsQuery.isPending ? (
96
83
  <div className="flex items-center justify-center py-10 text-[12px] text-text-3/65">
97
84
  <span className="mr-3 h-4 w-4 animate-spin rounded-full border-2 border-white/[0.12] border-t-accent-bright" />
98
85
  Loading skills...
@@ -5,20 +5,27 @@ import { useAppStore } from '@/stores/use-app-store'
5
5
  import { BottomSheet } from '@/components/shared/bottom-sheet'
6
6
  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
7
7
  import { AgentAvatar } from '@/components/agents/agent-avatar'
8
- import { api } from '@/lib/app/api-client'
9
8
  import { buildSkillSavePayload } from '@/lib/skill-save-payload'
10
9
  import { toast } from 'sonner'
11
10
  import type { Skill, SkillSecuritySummary } from '@/types'
11
+ import {
12
+ useDeleteSkillMutation,
13
+ useImportSkillFromUrlMutation,
14
+ useSaveSkillMutation,
15
+ useSkillsQuery,
16
+ } from '@/features/skills/queries'
17
+ import { useAgentsQuery } from '@/features/agents/queries'
12
18
 
13
19
  export function SkillSheet() {
14
20
  const open = useAppStore((s) => s.skillSheetOpen)
15
21
  const setOpen = useAppStore((s) => s.setSkillSheetOpen)
16
22
  const editingId = useAppStore((s) => s.editingSkillId)
17
23
  const setEditingId = useAppStore((s) => s.setEditingSkillId)
18
- const skills = useAppStore((s) => s.skills)
19
- const loadSkills = useAppStore((s) => s.loadSkills)
20
- const agents = useAppStore((s) => s.agents)
21
- const loadAgents = useAppStore((s) => s.loadAgents)
24
+ const skillsQuery = useSkillsQuery({ enabled: open })
25
+ const agentsQuery = useAgentsQuery({ enabled: open })
26
+ const importSkillFromUrlMutation = useImportSkillFromUrlMutation()
27
+ const saveSkillMutation = useSaveSkillMutation()
28
+ const deleteSkillMutation = useDeleteSkillMutation()
22
29
  const fileRef = useRef<HTMLInputElement>(null)
23
30
 
24
31
  const [name, setName] = useState('')
@@ -35,6 +42,8 @@ export function SkillSheet() {
35
42
  const [confirmDelete, setConfirmDelete] = useState(false)
36
43
  const [deleting, setDeleting] = useState(false)
37
44
 
45
+ const skills = skillsQuery.data ?? {}
46
+ const agents = agentsQuery.data ?? {}
38
47
  const editing = editingId ? skills[editingId] : null
39
48
  const agentList = Object.values(agents)
40
49
 
@@ -44,7 +53,7 @@ export function SkillSheet() {
44
53
  setImportError('')
45
54
  setImportNotice('')
46
55
  try {
47
- const result = await api<Partial<Skill> & { name: string; filename: string; description?: string; content: string; sourceFormat?: 'openclaw' | 'plain' }>('POST', '/skills/import', { url: importUrl.trim() })
56
+ const result = await importSkillFromUrlMutation.mutateAsync(importUrl.trim())
48
57
  setName(result.name || '')
49
58
  setFilename(result.filename || '')
50
59
  setDescription(result.description || '')
@@ -62,10 +71,6 @@ export function SkillSheet() {
62
71
  }
63
72
  }
64
73
 
65
- useEffect(() => {
66
- if (open) loadAgents()
67
- }, [open, loadAgents])
68
-
69
74
  useEffect(() => {
70
75
  if (open) {
71
76
  setImportUrl('')
@@ -133,14 +138,11 @@ export function SkillSheet() {
133
138
  agentIds,
134
139
  }, metadataPreview)
135
140
  try {
136
- if (editing) {
137
- await api('PUT', `/skills/${editing.id}`, data)
138
- toast.success('Skill updated successfully')
139
- } else {
140
- await api('POST', '/skills', data)
141
- toast.success('Skill created successfully')
142
- }
143
- await loadSkills()
141
+ await saveSkillMutation.mutateAsync({
142
+ id: editing?.id,
143
+ data: data as Record<string, unknown>,
144
+ })
145
+ toast.success(editing ? 'Skill updated successfully' : 'Skill created successfully')
144
146
  onClose()
145
147
  } catch (err: unknown) {
146
148
  toast.error(err instanceof Error ? err.message : 'Failed to save skill')
@@ -151,9 +153,8 @@ export function SkillSheet() {
151
153
  if (!editing) return
152
154
  setDeleting(true)
153
155
  try {
154
- await api('DELETE', `/skills/${editing.id}`)
156
+ await deleteSkillMutation.mutateAsync(editing.id)
155
157
  toast.success('Skill deleted')
156
- await loadSkills()
157
158
  setConfirmDelete(false)
158
159
  onClose()
159
160
  } catch (err: unknown) {