@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,42 +1,29 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useRef, useState } from 'react'
3
+ import { useCallback, useEffect, useRef, useState } from 'react'
4
4
  import { BottomSheet } from '@/components/shared/bottom-sheet'
5
5
  import { OpenClawDeployPanel } from '@/components/openclaw/openclaw-deploy-panel'
6
6
  import { useAppStore } from '@/stores/use-app-store'
7
- import { api } from '@/lib/app/api-client'
8
7
  import { toast } from 'sonner'
9
8
  import type {
10
- Credential,
11
9
  OpenClawDevicePairRequest,
12
10
  OpenClawNode,
13
11
  OpenClawNodePairRequest,
14
12
  OpenClawPairedDevice,
15
13
  GatewayProfile,
16
14
  } from '@/types'
17
-
18
- interface DiscoveryResult {
19
- host: string
20
- port: number
21
- healthy: boolean
22
- models?: string[]
23
- error?: string
24
- }
25
-
26
- interface GatewayRpcResponse<T> {
27
- ok?: boolean
28
- result?: T
29
- error?: string
30
- }
31
-
32
- interface NodeListResult {
33
- nodes?: OpenClawNode[]
34
- }
35
-
36
- interface PairingListResult<T> {
37
- pending?: T[]
38
- paired?: OpenClawPairedDevice[]
39
- }
15
+ import { useCreateCredentialMutation, useCredentialsQuery } from '@/features/credentials/queries'
16
+ import {
17
+ useCheckOpenClawGatewayMutation,
18
+ useDiscoverOpenClawGatewaysMutation,
19
+ useGatewayInvokeNodeMutation,
20
+ useGatewayPairingDecisionMutation,
21
+ useGatewayProfilesQuery,
22
+ useGatewayRemoveDeviceMutation,
23
+ useRefreshGatewayTopologyMutation,
24
+ useSaveGatewayProfileMutation,
25
+ type GatewayDiscoveryResult,
26
+ } from '@/features/gateways/queries'
40
27
 
41
28
  interface GatewayImportShape {
42
29
  name?: string
@@ -54,10 +41,19 @@ export function GatewaySheet() {
54
41
  const setOpen = useAppStore((s) => s.setGatewaySheetOpen)
55
42
  const editingId = useAppStore((s) => s.editingGatewayId)
56
43
  const setEditingId = useAppStore((s) => s.setEditingGatewayId)
57
- const gatewayProfiles = useAppStore((s) => s.gatewayProfiles)
58
- const loadGatewayProfiles = useAppStore((s) => s.loadGatewayProfiles)
59
- const credentials = useAppStore((s) => s.credentials)
60
- const loadCredentials = useAppStore((s) => s.loadCredentials)
44
+ const gatewayProfilesQuery = useGatewayProfilesQuery({ enabled: open })
45
+ const credentialsQuery = useCredentialsQuery({ enabled: open })
46
+ const createCredentialMutation = useCreateCredentialMutation()
47
+ const saveGatewayMutation = useSaveGatewayProfileMutation()
48
+ const checkGatewayMutation = useCheckOpenClawGatewayMutation()
49
+ const discoverGatewaysMutation = useDiscoverOpenClawGatewaysMutation()
50
+ const refreshGatewayTopologyMutation = useRefreshGatewayTopologyMutation()
51
+ const gatewayPairingDecisionMutation = useGatewayPairingDecisionMutation()
52
+ const gatewayRemoveDeviceMutation = useGatewayRemoveDeviceMutation()
53
+ const gatewayInvokeNodeMutation = useGatewayInvokeNodeMutation()
54
+
55
+ const gatewayProfiles = gatewayProfilesQuery.data ?? []
56
+ const credentials = credentialsQuery.data ?? {}
61
57
 
62
58
  const editing = editingId ? gatewayProfiles.find((item) => item.id === editingId) : null
63
59
  const openClawCredentials = Object.values(credentials).filter((item) => item.provider === 'openclaw')
@@ -73,7 +69,7 @@ export function GatewaySheet() {
73
69
  const [checking, setChecking] = useState(false)
74
70
  const [checkMessage, setCheckMessage] = useState('')
75
71
  const [discovering, setDiscovering] = useState(false)
76
- const [discoveries, setDiscoveries] = useState<DiscoveryResult[]>([])
72
+ const [discoveries, setDiscoveries] = useState<GatewayDiscoveryResult[]>([])
77
73
  const [nodesLoading, setNodesLoading] = useState(false)
78
74
  const [nodesError, setNodesError] = useState('')
79
75
  const [nodes, setNodes] = useState<OpenClawNode[]>([])
@@ -88,11 +84,6 @@ export function GatewaySheet() {
88
84
  const [deployment, setDeployment] = useState<GatewayProfile['deployment'] | null>(null)
89
85
  const importFileRef = useRef<HTMLInputElement>(null)
90
86
 
91
- useEffect(() => {
92
- if (!open) return
93
- void Promise.all([loadGatewayProfiles(), loadCredentials()])
94
- }, [open, loadGatewayProfiles, loadCredentials])
95
-
96
87
  useEffect(() => {
97
88
  if (!open) return
98
89
  setCheckMessage('')
@@ -127,61 +118,30 @@ export function GatewaySheet() {
127
118
  setInvokeParamsText('{}')
128
119
  }, [open, editing, gatewayProfiles.length])
129
120
 
130
- const loadNodesAndDevices = async (profileId: string) => {
121
+ const loadNodesAndDevices = useCallback(async (profileId: string) => {
131
122
  setNodesLoading(true)
132
123
  setNodesError('')
133
124
  try {
134
- const [nodesRes, nodePairRes, devicePairRes] = await Promise.all([
135
- api<GatewayRpcResponse<NodeListResult>>('POST', '/openclaw/gateway', {
136
- method: 'node.list',
137
- params: { profileId },
138
- }),
139
- api<GatewayRpcResponse<PairingListResult<OpenClawNodePairRequest>>>('POST', '/openclaw/gateway', {
140
- method: 'node.pair.list',
141
- params: { profileId },
142
- }),
143
- api<GatewayRpcResponse<PairingListResult<OpenClawDevicePairRequest>>>('POST', '/openclaw/gateway', {
144
- method: 'device.pair.list',
145
- params: { profileId },
146
- }),
147
- ])
148
-
149
- if (nodesRes.error) throw new Error(nodesRes.error)
150
- if (nodePairRes.error) throw new Error(nodePairRes.error)
151
- if (devicePairRes.error) throw new Error(devicePairRes.error)
152
-
153
- const nextNodes = Array.isArray(nodesRes.result?.nodes) ? nodesRes.result.nodes : []
154
- const nextNodePairings = Array.isArray(nodePairRes.result?.pending) ? nodePairRes.result.pending : []
155
- const nextDevicePairings = Array.isArray(devicePairRes.result?.pending) ? devicePairRes.result.pending : []
156
- const nextPairedDevices = Array.isArray(devicePairRes.result?.paired) ? devicePairRes.result.paired : []
157
-
158
- setNodes(nextNodes)
159
- setNodePairings(nextNodePairings)
160
- setDevicePairings(nextDevicePairings)
161
- setPairedDevices(nextPairedDevices)
162
- const nextStats: NonNullable<GatewayProfile['stats']> = {
163
- nodeCount: nextNodes.length,
164
- connectedNodeCount: nextNodes.filter((node) => node.connected).length,
165
- pendingNodePairings: nextNodePairings.length,
166
- pairedDeviceCount: nextPairedDevices.length,
167
- pendingDevicePairings: nextDevicePairings.length,
168
- }
169
- if (nextNodes[0]) {
170
- setInvokeNodeId((current) => current || nextNodes[0].nodeId)
171
- setInvokeCommand((current) => current || nextNodes[0].commands?.[0] || '')
125
+ const result = await refreshGatewayTopologyMutation.mutateAsync(profileId)
126
+ setNodes(result.nodes)
127
+ setNodePairings(result.nodePairings)
128
+ setDevicePairings(result.devicePairings)
129
+ setPairedDevices(result.pairedDevices)
130
+ if (result.nodes[0]) {
131
+ setInvokeNodeId((current) => current || result.nodes[0].nodeId)
132
+ setInvokeCommand((current) => current || result.nodes[0].commands?.[0] || '')
172
133
  }
173
- void api('PUT', `/gateways/${profileId}`, { stats: nextStats }).catch(() => {})
174
134
  } catch (err: unknown) {
175
135
  setNodesError(err instanceof Error ? err.message : 'Failed to load nodes for this gateway.')
176
136
  } finally {
177
137
  setNodesLoading(false)
178
138
  }
179
- }
139
+ }, [refreshGatewayTopologyMutation])
180
140
 
181
141
  useEffect(() => {
182
142
  if (!open || !editing?.id) return
183
143
  void loadNodesAndDevices(editing.id)
184
- }, [open, editing?.id])
144
+ }, [open, editing?.id, loadNodesAndDevices])
185
145
 
186
146
  const onClose = () => {
187
147
  setOpen(false)
@@ -193,7 +153,7 @@ export function GatewaySheet() {
193
153
  try {
194
154
  let nextCredentialId = credentialId
195
155
  if (tokenDraft.trim()) {
196
- const created = await api<Credential>('POST', '/credentials', {
156
+ const created = await createCredentialMutation.mutateAsync({
197
157
  provider: 'openclaw',
198
158
  name: `${name.trim() || 'OpenClaw Gateway'} token`,
199
159
  apiKey: tokenDraft.trim(),
@@ -209,14 +169,11 @@ export function GatewaySheet() {
209
169
  deployment,
210
170
  isDefault,
211
171
  }
212
- if (editing) {
213
- await api('PUT', `/gateways/${editing.id}`, payload)
214
- toast.success('Gateway updated')
215
- } else {
216
- await api('POST', '/gateways', payload)
217
- toast.success('Gateway added')
218
- }
219
- await Promise.all([loadGatewayProfiles(), loadCredentials()])
172
+ await saveGatewayMutation.mutateAsync({
173
+ id: editing?.id,
174
+ payload,
175
+ })
176
+ toast.success(editing ? 'Gateway updated' : 'Gateway added')
220
177
  onClose()
221
178
  } catch (err: unknown) {
222
179
  toast.error(err instanceof Error ? err.message : 'Failed to save gateway')
@@ -229,11 +186,11 @@ export function GatewaySheet() {
229
186
  setChecking(true)
230
187
  setCheckMessage('')
231
188
  try {
232
- const params = new URLSearchParams()
233
- params.set('endpoint', endpoint.trim() || 'http://localhost:18789')
234
- if (credentialId) params.set('credentialId', credentialId)
235
- if (tokenDraft.trim()) params.set('token', tokenDraft.trim())
236
- const result = await api<{ ok: boolean; models: string[]; message?: string; error?: string; hint?: string }>('GET', `/providers/openclaw/health?${params.toString()}`)
189
+ const result = await checkGatewayMutation.mutateAsync({
190
+ endpoint,
191
+ credentialId,
192
+ token: tokenDraft,
193
+ })
237
194
  if (result.ok) {
238
195
  setCheckMessage(result.message || `Connected. ${result.models?.length ? `${result.models.length} model${result.models.length === 1 ? '' : 's'} visible.` : 'Gateway responded normally.'}`)
239
196
  } else {
@@ -249,7 +206,7 @@ export function GatewaySheet() {
249
206
  const handleDiscover = async () => {
250
207
  setDiscovering(true)
251
208
  try {
252
- const result = await api<{ gateways: DiscoveryResult[] }>('GET', '/openclaw/discover')
209
+ const result = await discoverGatewaysMutation.mutateAsync()
253
210
  setDiscoveries((result.gateways || []).filter((item) => item.healthy))
254
211
  } catch {
255
212
  setDiscoveries([])
@@ -261,11 +218,11 @@ export function GatewaySheet() {
261
218
  const handlePairingDecision = async (kind: 'node' | 'device', requestId: string, decision: 'approve' | 'reject') => {
262
219
  if (!editing?.id) return
263
220
  try {
264
- await api<GatewayRpcResponse<unknown>>('POST', '/openclaw/gateway', {
265
- method: kind === 'node'
266
- ? (decision === 'approve' ? 'node.pair.approve' : 'node.pair.reject')
267
- : (decision === 'approve' ? 'device.pair.approve' : 'device.pair.reject'),
268
- params: { profileId: editing.id, requestId },
221
+ await gatewayPairingDecisionMutation.mutateAsync({
222
+ profileId: editing.id,
223
+ kind,
224
+ requestId,
225
+ decision,
269
226
  })
270
227
  toast.success(`${kind === 'node' ? 'Node' : 'Device'} ${decision}d`)
271
228
  await loadNodesAndDevices(editing.id)
@@ -277,10 +234,7 @@ export function GatewaySheet() {
277
234
  const handleRemoveDevice = async (deviceId: string) => {
278
235
  if (!editing?.id) return
279
236
  try {
280
- await api<GatewayRpcResponse<unknown>>('POST', '/openclaw/gateway', {
281
- method: 'device.pair.remove',
282
- params: { profileId: editing.id, deviceId },
283
- })
237
+ await gatewayRemoveDeviceMutation.mutateAsync({ profileId: editing.id, deviceId })
284
238
  toast.success('Device removed')
285
239
  await loadNodesAndDevices(editing.id)
286
240
  } catch (err: unknown) {
@@ -300,14 +254,11 @@ export function GatewaySheet() {
300
254
  parsedParams = next as Record<string, unknown>
301
255
  }
302
256
  }
303
- const result = await api<GatewayRpcResponse<unknown>>('POST', '/openclaw/gateway', {
304
- method: 'node.invoke',
305
- params: {
306
- profileId: editing.id,
307
- nodeId: invokeNodeId.trim(),
308
- command: invokeCommand.trim(),
309
- params: parsedParams,
310
- },
257
+ const result = await gatewayInvokeNodeMutation.mutateAsync({
258
+ profileId: editing.id,
259
+ nodeId: invokeNodeId.trim(),
260
+ command: invokeCommand.trim(),
261
+ params: parsedParams,
311
262
  })
312
263
  if (result.error) throw new Error(result.error)
313
264
  setInvokeResult(JSON.stringify(result.result, null, 2))
@@ -0,0 +1,121 @@
1
+ 'use client'
2
+
3
+ import { useQueryClient } from '@tanstack/react-query'
4
+ import { useWs } from '@/hooks/use-ws'
5
+ import { agentQueryKeys } from '@/features/agents/queries'
6
+ import { taskQueryKeys } from '@/features/tasks/queries'
7
+ import { protocolQueryKeys } from '@/features/protocols/queries'
8
+ import { providerQueryKeys } from '@/features/providers/queries'
9
+ import { gatewayQueryKeys } from '@/features/gateways/queries'
10
+ import { externalAgentQueryKeys } from '@/features/external-agents/queries'
11
+ import { chatQueryKeys } from '@/features/chats/queries'
12
+ import { connectorQueryKeys } from '@/features/connectors/queries'
13
+ import { skillQueryKeys, skillSuggestionQueryKeys } from '@/features/skills/queries'
14
+
15
+ function LiveQueryTopicSubscription({
16
+ topic,
17
+ fallbackMs,
18
+ onEvent,
19
+ }: {
20
+ topic: string
21
+ fallbackMs?: number
22
+ onEvent: () => void
23
+ }) {
24
+ useWs(topic, onEvent, fallbackMs)
25
+ return null
26
+ }
27
+
28
+ export function LiveQuerySync() {
29
+ const queryClient = useQueryClient()
30
+
31
+ return (
32
+ <>
33
+ <LiveQueryTopicSubscription
34
+ topic="agents"
35
+ fallbackMs={60_000}
36
+ onEvent={() => {
37
+ void queryClient.invalidateQueries({ queryKey: agentQueryKeys.all })
38
+ }}
39
+ />
40
+ <LiveQueryTopicSubscription
41
+ topic="tasks"
42
+ fallbackMs={5_000}
43
+ onEvent={() => {
44
+ void queryClient.invalidateQueries({ queryKey: taskQueryKeys.all })
45
+ }}
46
+ />
47
+ <LiveQueryTopicSubscription
48
+ topic="protocol_runs"
49
+ fallbackMs={2_000}
50
+ onEvent={() => {
51
+ void queryClient.invalidateQueries({ queryKey: protocolQueryKeys.all })
52
+ }}
53
+ />
54
+ <LiveQueryTopicSubscription
55
+ topic="protocol_templates"
56
+ fallbackMs={2_000}
57
+ onEvent={() => {
58
+ void queryClient.invalidateQueries({ queryKey: protocolQueryKeys.templates() })
59
+ }}
60
+ />
61
+ <LiveQueryTopicSubscription
62
+ topic="providers"
63
+ fallbackMs={20_000}
64
+ onEvent={() => {
65
+ void queryClient.invalidateQueries({ queryKey: providerQueryKeys.all })
66
+ }}
67
+ />
68
+ <LiveQueryTopicSubscription
69
+ topic="gateways"
70
+ fallbackMs={20_000}
71
+ onEvent={() => {
72
+ void queryClient.invalidateQueries({ queryKey: gatewayQueryKeys.all })
73
+ }}
74
+ />
75
+ <LiveQueryTopicSubscription
76
+ topic="external_agents"
77
+ fallbackMs={20_000}
78
+ onEvent={() => {
79
+ void queryClient.invalidateQueries({ queryKey: externalAgentQueryKeys.all })
80
+ }}
81
+ />
82
+ <LiveQueryTopicSubscription
83
+ topic="connectors"
84
+ fallbackMs={15_000}
85
+ onEvent={() => {
86
+ void queryClient.invalidateQueries({ queryKey: connectorQueryKeys.all })
87
+ }}
88
+ />
89
+ <LiveQueryTopicSubscription
90
+ topic="sessions"
91
+ fallbackMs={15_000}
92
+ onEvent={() => {
93
+ void queryClient.invalidateQueries({ queryKey: chatQueryKeys.all })
94
+ }}
95
+ />
96
+ <LiveQueryTopicSubscription
97
+ topic="messages"
98
+ fallbackMs={5_000}
99
+ onEvent={() => {
100
+ void queryClient.invalidateQueries({
101
+ predicate: (q) => q.queryKey[0] === 'chats' && q.queryKey[2] === 'messages',
102
+ })
103
+ }}
104
+ />
105
+ <LiveQueryTopicSubscription
106
+ topic="skills"
107
+ fallbackMs={20_000}
108
+ onEvent={() => {
109
+ void queryClient.invalidateQueries({ queryKey: skillQueryKeys.all })
110
+ }}
111
+ />
112
+ <LiveQueryTopicSubscription
113
+ topic="skill_suggestions"
114
+ fallbackMs={20_000}
115
+ onEvent={() => {
116
+ void queryClient.invalidateQueries({ queryKey: skillSuggestionQueryKeys.all })
117
+ }}
118
+ />
119
+ </>
120
+ )
121
+ }
@@ -1,7 +1,11 @@
1
1
  'use client'
2
2
 
3
3
  import { useEffect, useMemo, useState } from 'react'
4
- import { api } from '@/lib/app/api-client'
4
+ import { useAgentsQuery } from '@/features/agents/queries'
5
+ import { useChatroomsQuery } from '@/features/chatrooms/queries'
6
+ import { useMissionsQuery } from '@/features/missions/queries'
7
+ import { useCreateProtocolRunMutation, useProtocolTemplatesQuery } from '@/features/protocols/queries'
8
+ import { useTasksQuery } from '@/features/tasks/queries'
5
9
  import { BottomSheet } from '@/components/shared/bottom-sheet'
6
10
  import { SheetFooter } from '@/components/shared/sheet-footer'
7
11
  import type { BoardTask, Chatroom, Mission, ProtocolRun, ProtocolTemplate } from '@/types'
@@ -97,16 +101,28 @@ export function StructuredSessionLauncher({
97
101
  allowContextSelection = false,
98
102
  variant = 'default',
99
103
  }: Props) {
100
- const [templates, setTemplates] = useState<ProtocolTemplate[]>([])
101
- const [agents, setAgents] = useState<AgentList>({})
102
- const [chatrooms, setChatrooms] = useState<Record<string, Chatroom>>({})
103
- const [missions, setMissions] = useState<Mission[]>([])
104
- const [tasks, setTasks] = useState<TaskList>({})
105
- const [loading, setLoading] = useState(false)
106
104
  const [saving, setSaving] = useState(false)
107
105
  const [advancedOpen, setAdvancedOpen] = useState(false)
108
106
  const [error, setError] = useState<string | null>(null)
109
107
  const [form, setForm] = useState<FormState>(() => buildInitialState(initialContext))
108
+ const templatesQuery = useProtocolTemplatesQuery({ enabled: open })
109
+ const agentsQuery = useAgentsQuery({ enabled: open })
110
+ const chatroomsQuery = useChatroomsQuery({ enabled: open && allowContextSelection })
111
+ const missionsQuery = useMissionsQuery({ enabled: open && allowContextSelection, limit: 80 })
112
+ const tasksQuery = useTasksQuery({ includeArchived: true, enabled: open && allowContextSelection })
113
+ const createRunMutation = useCreateProtocolRunMutation()
114
+ const templates = templatesQuery.data ?? []
115
+ const agents = agentsQuery.data ?? {}
116
+ const chatrooms = chatroomsQuery.data ?? {}
117
+ const missions = missionsQuery.data ?? []
118
+ const tasks = tasksQuery.data ?? {}
119
+ const loading = (
120
+ templatesQuery.isLoading
121
+ || agentsQuery.isLoading
122
+ || chatroomsQuery.isLoading
123
+ || missionsQuery.isLoading
124
+ || tasksQuery.isLoading
125
+ )
110
126
  const breakoutMode = variant === 'breakout'
111
127
 
112
128
  useEffect(() => {
@@ -117,43 +133,6 @@ export function StructuredSessionLauncher({
117
133
  setSaving(false)
118
134
  }, [initialContext, open])
119
135
 
120
- useEffect(() => {
121
- if (!open) return
122
- let cancelled = false
123
- setLoading(true)
124
- void (async () => {
125
- try {
126
- const requests: Promise<unknown>[] = [
127
- api<ProtocolTemplate[]>('GET', '/protocols/templates'),
128
- api<AgentList>('GET', '/agents'),
129
- ]
130
- if (allowContextSelection) {
131
- requests.push(
132
- api<Record<string, Chatroom>>('GET', '/chatrooms'),
133
- api<Mission[]>('GET', '/missions?limit=80'),
134
- api<TaskList>('GET', '/tasks'),
135
- )
136
- }
137
- const result = await Promise.all(requests)
138
- if (cancelled) return
139
- setTemplates(Array.isArray(result[0]) ? (result[0] as ProtocolTemplate[]) : [])
140
- setAgents((result[1] as AgentList) || {})
141
- if (allowContextSelection) {
142
- setChatrooms((result[2] as Record<string, Chatroom>) || {})
143
- setMissions(Array.isArray(result[3]) ? (result[3] as Mission[]) : [])
144
- setTasks((result[4] as TaskList) || {})
145
- }
146
- } catch (err) {
147
- if (!cancelled) setError(err instanceof Error ? err.message : 'Unable to load structured-session options.')
148
- } finally {
149
- if (!cancelled) setLoading(false)
150
- }
151
- })()
152
- return () => {
153
- cancelled = true
154
- }
155
- }, [allowContextSelection, open])
156
-
157
136
  const agentOptions = useMemo(
158
137
  () => Object.values(agents).sort((a, b) => a.name.localeCompare(b.name)),
159
138
  [agents],
@@ -194,7 +173,7 @@ export function StructuredSessionLauncher({
194
173
  }
195
174
  setSaving(true)
196
175
  try {
197
- const run = await api<ProtocolRun>('POST', '/protocols/runs', {
176
+ const run = await createRunMutation.mutateAsync({
198
177
  title: form.title.trim(),
199
178
  templateId: form.templateId,
200
179
  participantAgentIds: form.participantAgentIds,
@@ -0,0 +1,17 @@
1
+ 'use client'
2
+
3
+ import { QueryClientProvider } from '@tanstack/react-query'
4
+ import { useState } from 'react'
5
+ import { LiveQuerySync } from '@/components/layout/live-query-sync'
6
+ import { createAppQueryClient } from '@/lib/query/client'
7
+
8
+ export function AppQueryProvider({ children }: { children: React.ReactNode }) {
9
+ const [queryClient] = useState(createAppQueryClient)
10
+
11
+ return (
12
+ <QueryClientProvider client={queryClient}>
13
+ <LiveQuerySync />
14
+ {children}
15
+ </QueryClientProvider>
16
+ )
17
+ }