@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
@@ -2,8 +2,19 @@
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useState } from 'react'
4
4
  import { useRouter, useSearchParams } from 'next/navigation'
5
- import { api } from '@/lib/app/api-client'
6
- import { useWs } from '@/hooks/use-ws'
5
+ import { useAgentsQuery } from '@/features/agents/queries'
6
+ import { useChatroomsQuery } from '@/features/chatrooms/queries'
7
+ import { useMissionsQuery } from '@/features/missions/queries'
8
+ import {
9
+ useCreateProtocolRunMutation,
10
+ useDeleteProtocolTemplateMutation,
11
+ useProtocolRunActionMutation,
12
+ useProtocolRunDetailQuery,
13
+ useProtocolRunsQuery,
14
+ useProtocolTemplatesQuery,
15
+ useUpsertProtocolTemplateMutation,
16
+ } from '@/features/protocols/queries'
17
+ import { useTasksQuery } from '@/features/tasks/queries'
7
18
  import { MainContent } from '@/components/layout/main-content'
8
19
  import { StructuredSessionLauncher } from '@/components/protocols/structured-session-launcher'
9
20
  import { timeAgo } from '@/lib/time-format'
@@ -67,10 +78,6 @@ const DEFAULT_TEMPLATE_DRAFT: TemplateDraft = {
67
78
  entryStepId: 'present',
68
79
  }
69
80
 
70
- async function postRunAction(runId: string, payload: RunActionPayload) {
71
- await api('POST', `/protocols/runs/${runId}/actions`, payload)
72
- }
73
-
74
81
  function toTemplateDraft(template: ProtocolTemplate | null): TemplateDraft {
75
82
  if (!template) return DEFAULT_TEMPLATE_DRAFT
76
83
  return {
@@ -125,16 +132,7 @@ function splitCsv(value: string): string[] {
125
132
  export default function ProtocolsPage() {
126
133
  const router = useRouter()
127
134
  const searchParams = useSearchParams()
128
- const [templates, setTemplates] = useState<ProtocolTemplate[]>([])
129
- const [runs, setRuns] = useState<ProtocolRun[]>([])
130
- const [detail, setDetail] = useState<ProtocolRunDetail | null>(null)
131
135
  const [selectedRunId, setSelectedRunId] = useState<string | null>(null)
132
- const [agents, setAgents] = useState<AgentList>({})
133
- const [chatrooms, setChatrooms] = useState<Record<string, Chatroom>>({})
134
- const [missions, setMissions] = useState<Mission[]>([])
135
- const [tasks, setTasks] = useState<Record<string, BoardTask>>({})
136
- const [loading, setLoading] = useState(true)
137
- const [detailLoading, setDetailLoading] = useState(false)
138
136
  const [actionPending, setActionPending] = useState<string | null>(null)
139
137
  const [templatePending, setTemplatePending] = useState<string | null>(null)
140
138
  const [templateEditorOpen, setTemplateEditorOpen] = useState(false)
@@ -160,66 +158,55 @@ export default function ProtocolsPage() {
160
158
  autoStart: true,
161
159
  })
162
160
  const requestedRunId = searchParams.get('runId')
163
-
164
- const loadRuns = useCallback(async () => {
165
- const [templateList, runList, agentList, roomList, missionList, taskList] = await Promise.all([
166
- api<ProtocolTemplate[]>('GET', '/protocols/templates'),
167
- api<ProtocolRun[]>('GET', '/protocols/runs?limit=120'),
168
- api<AgentList>('GET', '/agents'),
169
- api<Record<string, Chatroom>>('GET', '/chatrooms'),
170
- api<Mission[]>('GET', '/missions?limit=80'),
171
- api<Record<string, BoardTask>>('GET', '/tasks'),
172
- ])
173
- setTemplates(Array.isArray(templateList) ? templateList : [])
174
- const normalizedRuns = Array.isArray(runList) ? runList : []
175
- setRuns(normalizedRuns)
176
- setAgents(agentList || {})
177
- setChatrooms(roomList || {})
178
- setMissions(Array.isArray(missionList) ? missionList : [])
179
- setTasks(taskList || {})
180
- setSelectedRunId((current) => {
181
- if (current && normalizedRuns.some((run) => run.id === current)) return current
182
- return normalizedRuns[0]?.id || null
183
- })
184
- setLoading(false)
185
- }, [])
161
+ const templatesQuery = useProtocolTemplatesQuery()
162
+ const runsQuery = useProtocolRunsQuery({ limit: 120 })
163
+ const agentsQuery = useAgentsQuery()
164
+ const chatroomsQuery = useChatroomsQuery()
165
+ const missionsQuery = useMissionsQuery({ limit: 80 })
166
+ const tasksQuery = useTasksQuery({ includeArchived: true })
167
+ const detailQuery = useProtocolRunDetailQuery(selectedRunId, { enabled: Boolean(selectedRunId) })
168
+ const createRunMutation = useCreateProtocolRunMutation()
169
+ const runActionMutation = useProtocolRunActionMutation()
170
+ const upsertTemplateMutation = useUpsertProtocolTemplateMutation()
171
+ const deleteTemplateMutation = useDeleteProtocolTemplateMutation()
172
+ const templates = templatesQuery.data ?? []
173
+ const runs = runsQuery.data ?? []
174
+ const detail = detailQuery.data ?? null
175
+ const agents = agentsQuery.data ?? {}
176
+ const chatrooms = chatroomsQuery.data ?? {}
177
+ const missions = missionsQuery.data ?? []
178
+ const tasks = tasksQuery.data ?? {}
179
+ const loading = (
180
+ templatesQuery.isLoading
181
+ || runsQuery.isLoading
182
+ || agentsQuery.isLoading
183
+ || chatroomsQuery.isLoading
184
+ || missionsQuery.isLoading
185
+ || tasksQuery.isLoading
186
+ )
187
+ const detailLoading = detailQuery.isLoading || detailQuery.isFetching
188
+ const queryError = [
189
+ templatesQuery.error,
190
+ runsQuery.error,
191
+ agentsQuery.error,
192
+ chatroomsQuery.error,
193
+ missionsQuery.error,
194
+ tasksQuery.error,
195
+ detailQuery.error,
196
+ ].find(Boolean)
197
+ const resolvedError = error || (queryError instanceof Error ? queryError.message : null)
186
198
 
187
199
  // Apply URL-requested run selection separately so WS refreshes don't snap back
188
200
  useEffect(() => {
189
201
  if (requestedRunId) setSelectedRunId(requestedRunId)
190
202
  }, [requestedRunId])
191
203
 
192
- const loadDetail = useCallback(async (runId: string | null) => {
193
- if (!runId) {
194
- setDetail(null)
195
- return
196
- }
197
- setDetailLoading(true)
198
- try {
199
- const value = await api<ProtocolRunDetail>('GET', `/protocols/runs/${runId}`)
200
- setDetail(value)
201
- setError(null)
202
- } catch (err) {
203
- setError(err instanceof Error ? err.message : 'Unable to load structured session.')
204
- setDetail(null)
205
- } finally {
206
- setDetailLoading(false)
207
- }
208
- }, [])
209
-
210
204
  useEffect(() => {
211
- void loadRuns().catch((err) => {
212
- setError(err instanceof Error ? err.message : 'Unable to load structured sessions.')
213
- setLoading(false)
205
+ setSelectedRunId((current) => {
206
+ if (current && runs.some((run) => run.id === current)) return current
207
+ return runs[0]?.id || null
214
208
  })
215
- }, [loadRuns])
216
-
217
- useEffect(() => {
218
- void loadDetail(selectedRunId)
219
- }, [loadDetail, selectedRunId])
220
-
221
- useWs('protocol_runs', loadRuns, 2000)
222
- useWs('protocol_templates', loadRuns, 2000)
209
+ }, [runs])
223
210
 
224
211
  const selectedTemplate = useMemo(() => templates.find((template) => template.id === form.templateId) || null, [form.templateId, templates])
225
212
  const customTemplates = useMemo(() => templates.filter((template) => !template.builtIn), [templates])
@@ -244,7 +231,7 @@ export default function ProtocolsPage() {
244
231
  return
245
232
  }
246
233
  try {
247
- const run = await api<ProtocolRun>('POST', '/protocols/runs', {
234
+ const run = await createRunMutation.mutateAsync({
248
235
  title: form.title.trim(),
249
236
  templateId: form.templateId,
250
237
  participantAgentIds: form.participantAgentIds,
@@ -269,37 +256,34 @@ export default function ProtocolsPage() {
269
256
  decisionMode: '',
270
257
  }))
271
258
  setSelectedRunId(run.id)
272
- await loadRuns()
273
259
  } catch (err) {
274
260
  setError(err instanceof Error ? err.message : 'Unable to create structured session.')
275
261
  }
276
- }, [form, loadRuns])
262
+ }, [createRunMutation, form])
277
263
 
278
264
  const handleAction = useCallback(async (payload: RunActionPayload) => {
279
265
  if (!detail?.run.id) return
280
266
  setActionPending(payload.action)
281
267
  try {
282
- await postRunAction(detail.run.id, payload)
283
- await Promise.all([loadRuns(), loadDetail(detail.run.id)])
268
+ await runActionMutation.mutateAsync({ runId: detail.run.id, payload })
284
269
  if (payload.action === 'inject_context') setContextDraft('')
285
270
  } catch (err) {
286
271
  setError(err instanceof Error ? err.message : 'Unable to update structured session.')
287
272
  } finally {
288
273
  setActionPending(null)
289
274
  }
290
- }, [detail, loadDetail, loadRuns])
275
+ }, [detail, runActionMutation])
291
276
 
292
277
  const handleBranchAction = useCallback(async (runId: string, payload: RunActionPayload) => {
293
278
  setActionPending(`${payload.action}:${runId}`)
294
279
  try {
295
- await postRunAction(runId, payload)
296
- await Promise.all([loadRuns(), detail?.run.id ? loadDetail(detail.run.id) : Promise.resolve()])
280
+ await runActionMutation.mutateAsync({ runId, payload })
297
281
  } catch (err) {
298
282
  setError(err instanceof Error ? err.message : 'Unable to update branch run.')
299
283
  } finally {
300
284
  setActionPending(null)
301
285
  }
302
- }, [detail?.run.id, loadDetail, loadRuns])
286
+ }, [runActionMutation])
303
287
 
304
288
  const openTemplateEditor = useCallback((template: ProtocolTemplate | null = null) => {
305
289
  setEditingTemplateId(template?.builtIn ? null : template?.id || null)
@@ -328,27 +312,27 @@ export default function ProtocolsPage() {
328
312
  return
329
313
  }
330
314
  setTemplatePending(editingTemplateId ? 'save-edit' : 'save-new')
331
- if (editingTemplateId) {
332
- await api('PATCH', `/protocols/templates/${editingTemplateId}`, payload)
333
- } else {
334
- const created = await api<ProtocolTemplate>('POST', '/protocols/templates', payload)
315
+ const created = await upsertTemplateMutation.mutateAsync({
316
+ templateId: editingTemplateId,
317
+ payload,
318
+ })
319
+ if (!editingTemplateId) {
335
320
  setForm((current) => ({ ...current, templateId: created.id }))
336
321
  }
337
322
  setTemplateEditorOpen(false)
338
323
  setEditingTemplateId(null)
339
324
  setTemplateDraft(DEFAULT_TEMPLATE_DRAFT)
340
- await loadRuns()
341
325
  } catch (err) {
342
326
  setError(err instanceof Error ? err.message : 'Unable to save structured-session template.')
343
327
  } finally {
344
328
  setTemplatePending(null)
345
329
  }
346
- }, [editingTemplateId, loadRuns, templateDraft])
330
+ }, [editingTemplateId, templateDraft, upsertTemplateMutation])
347
331
 
348
332
  const handleDeleteTemplate = useCallback(async (templateId: string) => {
349
333
  setTemplatePending(`delete:${templateId}`)
350
334
  try {
351
- await api('DELETE', `/protocols/templates/${templateId}`)
335
+ await deleteTemplateMutation.mutateAsync(templateId)
352
336
  setTemplateEditorOpen(false)
353
337
  setEditingTemplateId(null)
354
338
  setTemplateDraft(DEFAULT_TEMPLATE_DRAFT)
@@ -356,13 +340,12 @@ export default function ProtocolsPage() {
356
340
  ...current,
357
341
  templateId: current.templateId === templateId ? 'facilitated_discussion' : current.templateId,
358
342
  }))
359
- await loadRuns()
360
343
  } catch (err) {
361
344
  setError(err instanceof Error ? err.message : 'Unable to delete structured-session template.')
362
345
  } finally {
363
346
  setTemplatePending(null)
364
347
  }
365
- }, [loadRuns])
348
+ }, [deleteTemplateMutation])
366
349
 
367
350
  const handleSelectRun = useCallback((runId: string) => {
368
351
  setSelectedRunId(runId)
@@ -715,9 +698,9 @@ export default function ProtocolsPage() {
715
698
  )}
716
699
  </div>
717
700
  </div>
718
- {error && (
701
+ {resolvedError && (
719
702
  <div className="mt-4 rounded-[14px] border border-red-500/20 bg-red-500/10 px-4 py-3 text-[13px] text-red-200">
720
- {error}
703
+ {resolvedError}
721
704
  </div>
722
705
  )}
723
706
  </section>
@@ -1272,9 +1255,8 @@ export default function ProtocolsPage() {
1272
1255
  open={launcherOpen}
1273
1256
  onClose={() => setLauncherOpen(false)}
1274
1257
  onCreated={(run) => {
1258
+ setLauncherOpen(false)
1275
1259
  setSelectedRunId(run.id)
1276
- void loadRuns()
1277
- void loadDetail(run.id)
1278
1260
  router.push(`/protocols?runId=${encodeURIComponent(run.id)}`)
1279
1261
  }}
1280
1262
  allowContextSelection
@@ -2,8 +2,15 @@
2
2
 
3
3
  import { useEffect, useCallback, useState, useRef, useMemo } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
- import { useWs } from '@/hooks/use-ws'
6
- import { updateTask, bulkUpdateTasks, importGitHubIssues, type GitHubIssueImportResult } from '@/lib/tasks'
5
+ import { useAgentsQuery } from '@/features/agents/queries'
6
+ import { useProjectsQuery } from '@/features/projects/queries'
7
+ import {
8
+ useBulkUpdateTasksMutation,
9
+ useImportGitHubIssuesMutation,
10
+ useTasksQuery,
11
+ useUpdateTaskMutation,
12
+ type GitHubIssueImportResult,
13
+ } from '@/features/tasks/queries'
7
14
  import { TaskColumn } from '@/components/tasks/task-column'
8
15
  import { TaskCard } from '@/components/tasks/task-card'
9
16
  import { Skeleton } from '@/components/shared/skeleton'
@@ -63,18 +70,18 @@ function attentionRank(task: BoardTask, now: number | null): number {
63
70
 
64
71
  export default function TasksPage() {
65
72
  const now = useNow()
66
- const tasks = useAppStore((s) => s.tasks)
67
- const loadTasks = useAppStore((s) => s.loadTasks)
68
- const loadAgents = useAppStore((s) => s.loadAgents)
69
73
  const setTaskSheetOpen = useAppStore((s) => s.setTaskSheetOpen)
70
74
  const setEditingTaskId = useAppStore((s) => s.setEditingTaskId)
71
- const agents = useAppStore((s) => s.agents)
72
- const projects = useAppStore((s) => s.projects)
73
- const loadProjects = useAppStore((s) => s.loadProjects)
74
75
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
75
76
  const setActiveProjectFilter = useAppStore((s) => s.setActiveProjectFilter)
76
77
  const showArchived = useAppStore((s) => s.showArchivedTasks)
77
78
  const setShowArchived = useAppStore((s) => s.setShowArchivedTasks)
79
+ const { data: tasks = {}, isLoading: tasksLoading } = useTasksQuery({ includeArchived: true })
80
+ const { data: agents = {}, isLoading: agentsLoading } = useAgentsQuery()
81
+ const { data: projects = {}, isLoading: projectsLoading } = useProjectsQuery()
82
+ const bulkUpdateTasksMutation = useBulkUpdateTasksMutation()
83
+ const updateTaskMutation = useUpdateTaskMutation()
84
+ const importGitHubIssuesMutation = useImportGitHubIssuesMutation()
78
85
 
79
86
  // Bulk selection
80
87
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
@@ -97,8 +104,7 @@ export default function TasksPage() {
97
104
  if (selectedIds.size === 0) return
98
105
  setBulkActing(true)
99
106
  try {
100
- await bulkUpdateTasks([...selectedIds], { status })
101
- await loadTasks()
107
+ await bulkUpdateTasksMutation.mutateAsync({ ids: [...selectedIds], patch: { status } })
102
108
  toast.success(`Moved ${selectedIds.size} task(s) to ${status}`)
103
109
  clearSelection()
104
110
  } catch {
@@ -106,15 +112,13 @@ export default function TasksPage() {
106
112
  } finally {
107
113
  setBulkActing(false)
108
114
  }
109
- // eslint-disable-next-line react-hooks/exhaustive-deps
110
- }, [selectedIds])
115
+ }, [bulkUpdateTasksMutation, clearSelection, selectedIds])
111
116
 
112
117
  const handleBulkAgent = useCallback(async (agentId: string) => {
113
118
  if (selectedIds.size === 0) return
114
119
  setBulkActing(true)
115
120
  try {
116
- await bulkUpdateTasks([...selectedIds], { agentId })
117
- await loadTasks()
121
+ await bulkUpdateTasksMutation.mutateAsync({ ids: [...selectedIds], patch: { agentId } })
118
122
  const name = agents[agentId]?.name || 'agent'
119
123
  toast.success(`Assigned ${selectedIds.size} task(s) to ${name}`)
120
124
  clearSelection()
@@ -123,15 +127,13 @@ export default function TasksPage() {
123
127
  } finally {
124
128
  setBulkActing(false)
125
129
  }
126
- // eslint-disable-next-line react-hooks/exhaustive-deps
127
- }, [selectedIds, agents])
130
+ }, [agents, bulkUpdateTasksMutation, clearSelection, selectedIds])
128
131
 
129
132
  const handleBulkProject = useCallback(async (projectId: string | null) => {
130
133
  if (selectedIds.size === 0) return
131
134
  setBulkActing(true)
132
135
  try {
133
- await bulkUpdateTasks([...selectedIds], { projectId })
134
- await loadTasks()
136
+ await bulkUpdateTasksMutation.mutateAsync({ ids: [...selectedIds], patch: { projectId } })
135
137
  toast.success(projectId ? `Assigned ${selectedIds.size} task(s) to project` : `Cleared project from ${selectedIds.size} task(s)`)
136
138
  clearSelection()
137
139
  } catch {
@@ -139,8 +141,7 @@ export default function TasksPage() {
139
141
  } finally {
140
142
  setBulkActing(false)
141
143
  }
142
- // eslint-disable-next-line react-hooks/exhaustive-deps
143
- }, [selectedIds])
144
+ }, [bulkUpdateTasksMutation, clearSelection, selectedIds])
144
145
 
145
146
  // Bulk action bar dropdowns
146
147
  const [bulkAgentOpen, setBulkAgentOpen] = useState(false)
@@ -196,11 +197,7 @@ export default function TasksPage() {
196
197
  window.history.replaceState(null, '', newUrl)
197
198
  }, [activeProjectFilter, filterAgentId, filterTag, filtersHydrated, taskScopeFilter])
198
199
 
199
- const [loaded, setLoaded] = useState(Object.keys(tasks).length > 0)
200
- useEffect(() => {
201
- Promise.all([loadTasks(), loadAgents(), loadProjects()]).then(() => setLoaded(true))
202
- }, [loadAgents, loadProjects, loadTasks])
203
- useWs('tasks', loadTasks, 5000)
200
+ const loaded = !tasksLoading && !agentsLoading && !projectsLoading
204
201
 
205
202
  // Collect all unique tags across tasks
206
203
  const allTags = dedup(Object.values(tasks).flatMap((t) => t.tags || [])).sort()
@@ -259,10 +256,8 @@ export default function TasksPage() {
259
256
  const handleDrop = useCallback(async (taskId: string, newStatus: BoardTaskStatus) => {
260
257
  const task = tasks[taskId]
261
258
  if (!task || task.status === newStatus) return
262
- await updateTask(taskId, { status: newStatus })
263
- await loadTasks()
264
- // eslint-disable-next-line react-hooks/exhaustive-deps
265
- }, [tasks])
259
+ await updateTaskMutation.mutateAsync({ id: taskId, patch: { status: newStatus } })
260
+ }, [tasks, updateTaskMutation])
266
261
 
267
262
  const archivedCount = Object.values(tasks).filter((t) => t.status === 'archived').length
268
263
 
@@ -284,7 +279,7 @@ export default function TasksPage() {
284
279
  try {
285
280
  const rawLimit = Number.parseInt(githubLimit, 10)
286
281
  const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 200)) : 25
287
- const result = await importGitHubIssues({
282
+ const result = await importGitHubIssuesMutation.mutateAsync({
288
283
  repo: githubRepo.trim(),
289
284
  token: githubToken.trim() || undefined,
290
285
  state: githubState,
@@ -296,7 +291,6 @@ export default function TasksPage() {
296
291
  projectId: activeProjectFilter,
297
292
  })
298
293
  setGitHubImportResult(result)
299
- await loadTasks()
300
294
  const summary = result.created.length > 0
301
295
  ? `Imported ${result.created.length} issue(s) from ${result.repo}`
302
296
  : `No new issues imported from ${result.repo}`
@@ -316,7 +310,7 @@ export default function TasksPage() {
316
310
  githubRepo,
317
311
  githubState,
318
312
  githubToken,
319
- loadTasks,
313
+ importGitHubIssuesMutation,
320
314
  ])
321
315
 
322
316
  // Task counts per project (non-archived)
@@ -759,6 +753,9 @@ export default function TasksPage() {
759
753
  <TaskColumn
760
754
  status={status}
761
755
  tasks={tasksByStatus(status)}
756
+ agents={agents}
757
+ projects={projects}
758
+ tasksById={tasks}
762
759
  onDrop={handleDrop}
763
760
  selectionMode={selectionMode}
764
761
  selectedIds={selectedIds}
@@ -804,6 +801,9 @@ export default function TasksPage() {
804
801
  <TaskCard
805
802
  key={task.id}
806
803
  task={task}
804
+ agents={agents}
805
+ projects={projects}
806
+ tasksById={tasks}
807
807
  index={idx}
808
808
  selectionMode={selectionMode}
809
809
  selected={selectedIds.has(task.id)}
package/src/cli/index.js CHANGED
@@ -596,6 +596,7 @@ const COMMAND_GROUPS = [
596
596
  defaultBody: { action: 'status' },
597
597
  }),
598
598
  cmd('checkpoints', 'GET', '/chats/:id/checkpoints', 'List checkpoint history for a chat'),
599
+ cmd('migrate-messages', 'POST', '/chats/migrate-messages', 'Migrate messages from session blobs to relational table'),
599
600
  ],
600
601
  },
601
602
  {
package/src/cli/spec.js CHANGED
@@ -428,6 +428,7 @@ const COMMAND_GROUPS = {
428
428
  delete: { description: 'Delete one chat', method: 'DELETE', path: '/chats/:id', params: ['id'] },
429
429
  'delete-many': { description: 'Delete multiple chats (body: {"ids":[...]})', method: 'DELETE', path: '/chats' },
430
430
  'heartbeat-disable-all': { description: 'Disable all chat heartbeats and cancel queued heartbeat runs', method: 'POST', path: '/chats/heartbeat' },
431
+ 'migrate-messages': { description: 'Migrate messages from session blobs to relational table', method: 'POST', path: '/chats/migrate-messages' },
431
432
  messages: { description: 'Get chat message history', method: 'GET', path: '/chats/:id/messages', params: ['id'] },
432
433
  'messages-update': { description: 'Update chat message metadata (e.g. bookmark)', method: 'PUT', path: '/chats/:id/messages', params: ['id'] },
433
434
  'messages-send': { description: 'Append a user/system message to a chat', method: 'POST', path: '/chats/:id/messages', params: ['id'] },