@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
@@ -29,7 +29,7 @@ import type {
29
29
  ProtocolSwarmConfig,
30
30
  ProtocolTemplate,
31
31
  } from '@/types'
32
- import { loadProtocolRun } from '@/lib/server/storage'
32
+ import { loadProtocolRun } from '@/lib/server/protocols/protocol-run-repository'
33
33
  import { normalizeStepOutputs } from '@/lib/server/protocols/step-outputs'
34
34
  import { cleanText, uniqueIds } from '@/lib/server/protocols/protocol-types'
35
35
 
@@ -10,15 +10,20 @@ import type {
10
10
  ProtocolTemplate,
11
11
  } from '@/types'
12
12
  import {
13
- loadChatrooms,
13
+ loadChatroom,
14
+ loadChatroomMany,
15
+ } from '@/lib/server/chatrooms/chatroom-repository'
16
+ import {
14
17
  loadMission,
18
+ } from '@/lib/server/missions/mission-repository'
19
+ import {
15
20
  loadProtocolRun,
16
21
  loadProtocolRuns,
17
- loadTask,
18
22
  deleteProtocolRun,
19
23
  deleteProtocolRunEvent,
20
- upsertChatroom,
21
- } from '@/lib/server/storage'
24
+ } from '@/lib/server/protocols/protocol-run-repository'
25
+ import { loadTask } from '@/lib/server/tasks/task-repository'
26
+ import { upsertChatroom } from '@/lib/server/chatrooms/chatroom-repository'
22
27
  import { notify } from '@/lib/server/ws-hub'
23
28
  import type { ProtocolRunDetail } from '@/lib/server/protocols/protocol-types'
24
29
  import { loadProtocolRunById, normalizeProtocolRun } from '@/lib/server/protocols/protocol-normalization'
@@ -77,8 +82,7 @@ export function deleteProtocolRunById(runId: string): boolean {
77
82
 
78
83
  // Archive transcript chatroom
79
84
  if (run.transcriptChatroomId) {
80
- const chatrooms = loadChatrooms()
81
- const transcript = chatrooms[run.transcriptChatroomId]
85
+ const transcript = loadChatroom(run.transcriptChatroomId)
82
86
  if (transcript) {
83
87
  upsertChatroom(transcript.id, { ...transcript, archivedAt: transcript.archivedAt || Date.now() })
84
88
  }
@@ -97,7 +101,9 @@ export function deleteProtocolRunById(runId: string): boolean {
97
101
  export function getProtocolRunDetail(runId: string): ProtocolRunDetail | null {
98
102
  const run = loadProtocolRunById(runId)
99
103
  if (!run) return null
100
- const chatrooms = loadChatrooms()
104
+ const chatrooms = loadChatroomMany(
105
+ [run.transcriptChatroomId, run.parentChatroomId].filter((value): value is string => Boolean(value)),
106
+ )
101
107
  return {
102
108
  run,
103
109
  template: loadTemplate(run.templateId),
@@ -14,13 +14,10 @@ import type {
14
14
  Schedule,
15
15
  } from '@/types'
16
16
  import { computeStepReadiness } from '@/lib/server/protocols/dag-scheduler'
17
- import {
18
- loadAgents,
19
- loadChatrooms,
20
- loadProtocolRuns,
21
- loadTask,
22
- upsertChatroom,
23
- } from '@/lib/server/storage'
17
+ import { getAgents } from '@/lib/server/agents/agent-repository'
18
+ import { patchChatroom, upsertChatroom } from '@/lib/server/chatrooms/chatroom-repository'
19
+ import { loadProtocolRuns } from '@/lib/server/protocols/protocol-run-repository'
20
+ import { loadTask } from '@/lib/server/tasks/task-repository'
24
21
  import { errorMessage, hmrSingleton } from '@/lib/shared-utils'
25
22
  import { requestMissionTick } from '@/lib/server/missions/mission-service'
26
23
  import { cleanText, isDiscussionStepKind, now, uniqueIds } from '@/lib/server/protocols/protocol-types'
@@ -35,6 +32,7 @@ import {
35
32
  persistRun,
36
33
  updateRun,
37
34
  } from '@/lib/server/protocols/protocol-agent-turn'
35
+ import { claimSwarmWorkItem, syncSwarmClaimCompletion } from '@/lib/server/protocols/protocol-swarm'
38
36
  import {
39
37
  completeProtocolRun,
40
38
  currentStep,
@@ -42,7 +40,6 @@ import {
42
40
  syncProtocolParentFromChildRun,
43
41
  } from '@/lib/server/protocols/protocol-step-helpers'
44
42
  import { stepProtocolRun } from '@/lib/server/protocols/protocol-step-processors'
45
- import { syncSwarmClaimCompletion } from '@/lib/server/protocols/protocol-swarm'
46
43
 
47
44
  // ---- Singletons ----
48
45
 
@@ -197,8 +194,8 @@ export function ensureProtocolEngineRecovered(deps?: ProtocolRunDeps): void {
197
194
  // ---- Create/Run/Action (G18) ----
198
195
 
199
196
  export function createProtocolRun(input: CreateProtocolRunInput, deps?: ProtocolRunDeps): ProtocolRun {
200
- const agents = loadAgents()
201
197
  const participantAgentIds = uniqueIds(input.participantAgentIds, 64)
198
+ const agents = getAgents(participantAgentIds)
202
199
  if (participantAgentIds.length === 0) {
203
200
  throw new Error('Structured sessions require at least one participant.')
204
201
  }
@@ -330,8 +327,8 @@ export async function runProtocolRun(runId: string, deps?: ProtocolRunDeps): Pro
330
327
  appendProtocolEvent(run.id, { type: 'failed', summary: `Exceeded maximum step iterations (${MAX_STEP_ITERATIONS}).` }, deps)
331
328
  break
332
329
  }
333
- // Yield to the event loop so the server can process other HTTP requests
334
- await new Promise((resolve) => setTimeout(resolve, 0))
330
+ // Yield between steps so I/O, HTTP responses, and timers can run.
331
+ await new Promise(r => setTimeout(r, 0))
335
332
  const latest = loadProtocolRunById(run.id)
336
333
  if (!latest) return null
337
334
  if (latest.status === 'paused' || latest.status === 'cancelled' || latest.status === 'archived' || latest.status === 'completed') {
@@ -397,7 +394,6 @@ export async function runProtocolRun(runId: string, deps?: ProtocolRunDeps): Pro
397
394
  }
398
395
 
399
396
  export function performProtocolRunAction(runId: string, input: ProtocolRunActionInput): ProtocolRun | null {
400
- const { claimSwarmWorkItem } = require('@/lib/server/protocols/protocol-swarm') as typeof import('@/lib/server/protocols/protocol-swarm')
401
397
  const run = loadProtocolRunById(runId)
402
398
  if (!run) return null
403
399
  const action = input.action
@@ -437,20 +433,20 @@ export function performProtocolRunAction(runId: string, input: ProtocolRunAction
437
433
  return updated
438
434
  }
439
435
  if (action === 'archive') {
436
+ const archivedAt = Date.now()
440
437
  const updated = updateRun(runId, (current) => ({
441
438
  ...current,
442
439
  status: 'archived',
443
- archivedAt: current.archivedAt || Date.now(),
444
- updatedAt: Date.now(),
440
+ archivedAt: current.archivedAt || archivedAt,
441
+ updatedAt: archivedAt,
445
442
  }))
446
443
  if (updated) {
447
444
  if (updated.transcriptChatroomId) {
448
- const chatrooms = loadChatrooms()
449
- const transcript = chatrooms[updated.transcriptChatroomId]
450
- if (transcript) {
451
- transcript.archivedAt = Date.now()
452
- upsertChatroom(transcript.id, transcript)
453
- }
445
+ patchChatroom(updated.transcriptChatroomId, (current) => (
446
+ current
447
+ ? { ...current, archivedAt: current.archivedAt || archivedAt }
448
+ : null
449
+ ))
454
450
  }
455
451
  appendProtocolEvent(runId, {
456
452
  type: 'archived',
@@ -0,0 +1,81 @@
1
+ import type { ProtocolRun, ProtocolRunEvent } from '@/types'
2
+
3
+ import {
4
+ deleteProtocolRun as deleteStoredProtocolRun,
5
+ deleteProtocolRunEvent as deleteStoredProtocolRunEvent,
6
+ loadProtocolRun as loadStoredProtocolRun,
7
+ loadProtocolRunEvent as loadStoredProtocolRunEvent,
8
+ loadProtocolRunEvents as loadStoredProtocolRunEvents,
9
+ loadProtocolRunEventsByRunId as loadStoredProtocolRunEventsByRunId,
10
+ loadProtocolRuns as loadStoredProtocolRuns,
11
+ patchProtocolRun as patchStoredProtocolRun,
12
+ saveProtocolRunEvents as saveStoredProtocolRunEvents,
13
+ saveProtocolRuns as saveStoredProtocolRuns,
14
+ upsertProtocolRun as upsertStoredProtocolRun,
15
+ upsertProtocolRunEvent as upsertStoredProtocolRunEvent,
16
+ upsertProtocolRunEvents as upsertStoredProtocolRunEvents,
17
+ } from '@/lib/server/storage'
18
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
19
+
20
+ export const protocolRunRepository = createRecordRepository<ProtocolRun>(
21
+ 'protocol-runs',
22
+ {
23
+ get(id) {
24
+ return loadStoredProtocolRun(id) as ProtocolRun | null
25
+ },
26
+ list() {
27
+ return loadStoredProtocolRuns() as Record<string, ProtocolRun>
28
+ },
29
+ upsert(id, value) {
30
+ upsertStoredProtocolRun(id, value as ProtocolRun)
31
+ },
32
+ replace(data) {
33
+ saveStoredProtocolRuns(data as Record<string, ProtocolRun>)
34
+ },
35
+ patch(id, updater) {
36
+ return patchStoredProtocolRun(id, updater as (current: ProtocolRun | null) => ProtocolRun | null) as ProtocolRun | null
37
+ },
38
+ delete(id) {
39
+ deleteStoredProtocolRun(id)
40
+ },
41
+ },
42
+ )
43
+
44
+ export const protocolRunEventRepository = createRecordRepository<ProtocolRunEvent>(
45
+ 'protocol-run-events',
46
+ {
47
+ get(id) {
48
+ return loadStoredProtocolRunEvent(id) as ProtocolRunEvent | null
49
+ },
50
+ list() {
51
+ return loadStoredProtocolRunEvents() as Record<string, ProtocolRunEvent>
52
+ },
53
+ upsert(id, value) {
54
+ upsertStoredProtocolRunEvent(id, value as ProtocolRunEvent)
55
+ },
56
+ upsertMany(entries) {
57
+ upsertStoredProtocolRunEvents(entries as Array<[string, ProtocolRunEvent]>)
58
+ },
59
+ replace(data) {
60
+ saveStoredProtocolRunEvents(data as Record<string, ProtocolRunEvent>)
61
+ },
62
+ delete(id) {
63
+ deleteStoredProtocolRunEvent(id)
64
+ },
65
+ },
66
+ )
67
+
68
+ export const loadProtocolRuns = () => protocolRunRepository.list()
69
+ export const loadProtocolRun = (id: string) => protocolRunRepository.get(id)
70
+ export const saveProtocolRuns = (items: Record<string, ProtocolRun | Record<string, unknown>>) => protocolRunRepository.replace(items as Record<string, ProtocolRun>)
71
+ export const upsertProtocolRun = (id: string, value: ProtocolRun | Record<string, unknown>) => protocolRunRepository.upsert(id, value as ProtocolRun)
72
+ export const patchProtocolRun = (id: string, updater: (current: ProtocolRun | null) => ProtocolRun | null) => protocolRunRepository.patch(id, updater)
73
+ export const deleteProtocolRun = (id: string) => protocolRunRepository.delete(id)
74
+
75
+ export const loadProtocolRunEvents = () => protocolRunEventRepository.list()
76
+ export const loadProtocolRunEvent = (id: string) => protocolRunEventRepository.get(id)
77
+ export const saveProtocolRunEvents = (items: Record<string, ProtocolRunEvent | Record<string, unknown>>) => protocolRunEventRepository.replace(items as Record<string, ProtocolRunEvent>)
78
+ export const upsertProtocolRunEvent = (id: string, value: ProtocolRunEvent | Record<string, unknown>) => protocolRunEventRepository.upsert(id, value as ProtocolRunEvent)
79
+ export const upsertProtocolRunEvents = (entries: Array<[string, ProtocolRunEvent | Record<string, unknown>]>) => protocolRunEventRepository.upsertMany(entries as Array<[string, ProtocolRunEvent]>)
80
+ export const deleteProtocolRunEvent = (id: string) => protocolRunEventRepository.delete(id)
81
+ export const loadProtocolRunEventsByRunId = (runId: string) => loadStoredProtocolRunEventsByRunId(runId)
@@ -12,15 +12,18 @@ import type {
12
12
  ProtocolRunPhaseState,
13
13
  ProtocolStepDefinition,
14
14
  } from '@/types'
15
- import {
16
- loadAgents,
17
- upsertTask,
18
- } from '@/lib/server/storage'
15
+ import { errorMessage } from '@/lib/shared-utils'
16
+ import { getAgents } from '@/lib/server/agents/agent-repository'
17
+ import { upsertTask } from '@/lib/server/tasks/task-repository'
19
18
  import { notify } from '@/lib/server/ws-hub'
20
19
  import { ensureMissionForTask } from '@/lib/server/missions/mission-service'
21
20
  import { enqueueTask } from '@/lib/server/runtime/queue'
22
21
  import { cleanText, isDiscussionStepKind, now, uniqueIds } from '@/lib/server/protocols/protocol-types'
23
22
  import type { ProtocolRunDeps } from '@/lib/server/protocols/protocol-types'
23
+ import type * as ProtocolRunLifecycle from '@/lib/server/protocols/protocol-run-lifecycle'
24
+ import { processForEachStep } from '@/lib/server/protocols/protocol-foreach'
25
+ import { processSubflowStep } from '@/lib/server/protocols/protocol-subflow'
26
+ import { processSwarmStep } from '@/lib/server/protocols/protocol-swarm'
24
27
  import { findRunStep } from '@/lib/server/protocols/protocol-normalization'
25
28
  import {
26
29
  appendProtocolEvent,
@@ -28,7 +31,6 @@ import {
28
31
  buildPhasePrompt,
29
32
  chooseFacilitator,
30
33
  createArtifact,
31
- createTranscriptRoom,
32
34
  defaultExecuteAgentTurn,
33
35
  defaultExtractActionItems,
34
36
  persistRun,
@@ -91,6 +93,7 @@ export async function collectResponses(
91
93
  let current = run
92
94
  const responded = new Set(current.phaseState?.respondedAgentIds || [])
93
95
  const cachedResponses = Array.isArray(current.phaseState?.responses) ? [...current.phaseState.responses] : []
96
+ const participantAgents = getAgents(current.participantAgentIds)
94
97
 
95
98
  for (const agentId of current.participantAgentIds) {
96
99
  if (responded.has(agentId)) continue
@@ -104,8 +107,7 @@ export async function collectResponses(
104
107
  prompt: buildPhasePrompt(current, phase, agentId),
105
108
  })
106
109
  } catch (err: unknown) {
107
- const { errorMessage: getErrorMessage } = require('@/lib/shared-utils') as typeof import('@/lib/shared-utils')
108
- const errMsg = cleanText(getErrorMessage(err), 200) || 'unknown error'
110
+ const errMsg = cleanText(errorMessage(err), 200) || 'unknown error'
109
111
  appendProtocolEvent(current.id, {
110
112
  type: 'warning',
111
113
  phaseId: phase.id,
@@ -128,10 +130,9 @@ export async function collectResponses(
128
130
  updatedAt: now(deps),
129
131
  })
130
132
  if (appendImmediately && current.transcriptChatroomId) {
131
- const agents = loadAgents()
132
133
  appendTranscriptMessage(current.transcriptChatroomId, {
133
134
  senderId: agentId,
134
- senderName: agents[agentId]?.name || agentId,
135
+ senderName: participantAgents[agentId]?.name || agentId,
135
136
  role: 'assistant',
136
137
  text: response.text,
137
138
  mentions: [],
@@ -142,17 +143,16 @@ export async function collectResponses(
142
143
  type: 'participant_response',
143
144
  phaseId: phase.id,
144
145
  agentId,
145
- summary: `Captured a response from ${agents[agentId]?.name || agentId}.`,
146
+ summary: `Captured a response from ${participantAgents[agentId]?.name || agentId}.`,
146
147
  }, deps)
147
148
  }
148
149
  }
149
150
 
150
151
  if (!appendImmediately && current.transcriptChatroomId && current.phaseState?.appendedToTranscript !== true) {
151
- const agents = loadAgents()
152
152
  for (const response of cachedResponses) {
153
153
  appendTranscriptMessage(current.transcriptChatroomId, {
154
154
  senderId: response.agentId,
155
- senderName: agents[response.agentId]?.name || response.agentId,
155
+ senderName: participantAgents[response.agentId]?.name || response.agentId,
156
156
  role: 'assistant',
157
157
  text: response.text,
158
158
  mentions: [],
@@ -163,7 +163,7 @@ export async function collectResponses(
163
163
  type: 'participant_response',
164
164
  phaseId: phase.id,
165
165
  agentId: response.agentId,
166
- summary: `Captured an independent response from ${agents[response.agentId]?.name || response.agentId}.`,
166
+ summary: `Captured an independent response from ${participantAgents[response.agentId]?.name || response.agentId}.`,
167
167
  }, deps)
168
168
  }
169
169
  current = persistRun({
@@ -199,7 +199,7 @@ export async function processFacilitatorArtifactPhase(
199
199
  prompt: buildPhasePrompt(run, phase, facilitatorId),
200
200
  })
201
201
  const artifact = createArtifact(run, phase, kind, phase.label, result.text, deps)
202
- const agents = loadAgents()
202
+ const agents = getAgents([facilitatorId])
203
203
  if (run.transcriptChatroomId) {
204
204
  appendTranscriptMessage(run.transcriptChatroomId, {
205
205
  senderId: facilitatorId,
@@ -221,8 +221,11 @@ export async function processEmitTasksPhase(run: ProtocolRun, phase: ProtocolPha
221
221
  if (!artifact) return finishPhase(run, phase, deps)
222
222
  const extractActionItems = deps?.extractActionItems || defaultExtractActionItems
223
223
  const extracted = await extractActionItems({ run, phase, artifact })
224
- const agents = loadAgents()
225
224
  const fallbackAssignee = chooseFacilitator(run) || run.participantAgentIds[0] || ''
225
+ const agents = getAgents(uniqueIds([
226
+ fallbackAssignee,
227
+ ...extracted.map((item) => item.agentId || ''),
228
+ ], 64))
226
229
  const createdTaskIds: string[] = []
227
230
  const linkedMissionId = typeof run.missionId === 'string' ? run.missionId : null
228
231
  const taskProjectId = run.config?.taskProjectId || null
@@ -396,6 +399,8 @@ function buildJoinArtifactContent(branches: ProtocolRunParallelBranchState[]): s
396
399
  }
397
400
 
398
401
  export async function processParallelStep(run: ProtocolRun, step: ProtocolStepDefinition, deps?: ProtocolRunDeps): Promise<ProtocolRun> {
402
+ // Lazy import to avoid circular dependency
403
+ const { createProtocolRun, requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof ProtocolRunLifecycle
399
404
  const parallel = step.parallel
400
405
  if (!parallel?.branches?.length) {
401
406
  throw new Error(`Parallel step "${step.label}" is missing branches.`)
@@ -417,10 +422,6 @@ export async function processParallelStep(run: ProtocolRun, step: ProtocolStepDe
417
422
  data: { joinStepId, branchCount: parallel.branches.length },
418
423
  }, deps)
419
424
 
420
- // Lazy import to avoid circular dependency
421
- const { createProtocolRun } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof import('@/lib/server/protocols/protocol-run-lifecycle')
422
- const { requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof import('@/lib/server/protocols/protocol-run-lifecycle')
423
-
424
425
  for (const branch of parallel.branches) {
425
426
  const participantAgentIds = uniqueIds(
426
427
  Array.isArray(branch.participantAgentIds) && branch.participantAgentIds.length > 0
@@ -706,18 +707,9 @@ export async function stepProtocolRun(run: ProtocolRun, deps?: ProtocolRunDeps):
706
707
  if (step.kind === 'repeat') return processRepeatStep(run, step, deps)
707
708
  if (step.kind === 'parallel') return processParallelStep(run, step, deps)
708
709
  if (step.kind === 'join') return processJoinStep(run, step, deps)
709
- if (step.kind === 'for_each') {
710
- const { processForEachStep } = require('@/lib/server/protocols/protocol-foreach') as typeof import('@/lib/server/protocols/protocol-foreach')
711
- return processForEachStep(run, step, deps)
712
- }
713
- if (step.kind === 'subflow') {
714
- const { processSubflowStep } = require('@/lib/server/protocols/protocol-subflow') as typeof import('@/lib/server/protocols/protocol-subflow')
715
- return processSubflowStep(run, step, deps)
716
- }
717
- if (step.kind === 'swarm_claim') {
718
- const { processSwarmStep } = require('@/lib/server/protocols/protocol-swarm') as typeof import('@/lib/server/protocols/protocol-swarm')
719
- return processSwarmStep(run, step, deps)
720
- }
710
+ if (step.kind === 'for_each') return processForEachStep(run, step, deps)
711
+ if (step.kind === 'subflow') return processSubflowStep(run, step, deps)
712
+ if (step.kind === 'swarm_claim') return processSwarmStep(run, step, deps)
721
713
  if (step.kind === 'complete') {
722
714
  const started = beginStep(run, step, deps)
723
715
  const finished = finishStep(started, step, null, deps)
@@ -10,14 +10,12 @@ import type {
10
10
  ProtocolStepDefinition,
11
11
  ProtocolSwarmConfig,
12
12
  } from '@/types'
13
- import {
14
- loadProtocolRuns,
15
- loadTask,
16
- upsertTask,
17
- } from '@/lib/server/storage'
13
+ import { loadProtocolRuns } from '@/lib/server/protocols/protocol-run-repository'
14
+ import { loadTask, upsertTask } from '@/lib/server/tasks/task-repository'
18
15
  import { notify } from '@/lib/server/ws-hub'
19
16
  import { enqueueTask } from '@/lib/server/runtime/queue'
20
- import { cleanText, now } from '@/lib/server/protocols/protocol-types'
17
+ import type * as ProtocolRunLifecycle from '@/lib/server/protocols/protocol-run-lifecycle'
18
+ import { now } from '@/lib/server/protocols/protocol-types'
21
19
  import type { ProtocolRunDeps } from '@/lib/server/protocols/protocol-types'
22
20
  import { findRunStep, loadProtocolRunById, normalizeProtocolRun } from '@/lib/server/protocols/protocol-normalization'
23
21
  import {
@@ -237,7 +235,8 @@ export function claimSwarmWorkItem(
237
235
  }
238
236
 
239
237
  export function syncSwarmClaimCompletion(taskId: string, deps?: ProtocolRunDeps): void {
240
- const { requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof import('@/lib/server/protocols/protocol-run-lifecycle')
238
+ // Lazy import to avoid circular dependency
239
+ const { requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof ProtocolRunLifecycle
241
240
  const task = loadTask(taskId)
242
241
  if (!task?.protocolRunId) return
243
242
  const run = loadProtocolRunById(task.protocolRunId)
@@ -302,7 +301,8 @@ export function syncSwarmClaimCompletion(taskId: string, deps?: ProtocolRunDeps)
302
301
  }
303
302
 
304
303
  export function checkSwarmTimeouts(deps?: ProtocolRunDeps): void {
305
- const { requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof import('@/lib/server/protocols/protocol-run-lifecycle')
304
+ // Lazy import to avoid circular dependency
305
+ const { requestProtocolRunExecution } = require('@/lib/server/protocols/protocol-run-lifecycle') as typeof ProtocolRunLifecycle
306
306
  const runs = Object.values(loadProtocolRuns()).map(normalizeProtocolRun)
307
307
  const timestamp = now(deps)
308
308
  for (const run of runs) {
@@ -0,0 +1,42 @@
1
+ import type { ProtocolTemplate } from '@/types'
2
+
3
+ import {
4
+ deleteProtocolTemplate as deleteStoredProtocolTemplate,
5
+ loadProtocolTemplate as loadStoredProtocolTemplate,
6
+ loadProtocolTemplates as loadStoredProtocolTemplates,
7
+ patchProtocolTemplate as patchStoredProtocolTemplate,
8
+ saveProtocolTemplates as saveStoredProtocolTemplates,
9
+ upsertProtocolTemplate as upsertStoredProtocolTemplate,
10
+ } from '@/lib/server/storage'
11
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
12
+
13
+ export const protocolTemplateRepository = createRecordRepository<ProtocolTemplate>(
14
+ 'protocol-templates',
15
+ {
16
+ get(id) {
17
+ return loadStoredProtocolTemplate(id) as ProtocolTemplate | null
18
+ },
19
+ list() {
20
+ return loadStoredProtocolTemplates() as Record<string, ProtocolTemplate>
21
+ },
22
+ upsert(id, value) {
23
+ upsertStoredProtocolTemplate(id, value as ProtocolTemplate)
24
+ },
25
+ replace(data) {
26
+ saveStoredProtocolTemplates(data as Record<string, ProtocolTemplate>)
27
+ },
28
+ patch(id, updater) {
29
+ return patchStoredProtocolTemplate(id, updater as (current: ProtocolTemplate | null) => ProtocolTemplate | null) as ProtocolTemplate | null
30
+ },
31
+ delete(id) {
32
+ deleteStoredProtocolTemplate(id)
33
+ },
34
+ },
35
+ )
36
+
37
+ export const loadProtocolTemplates = () => protocolTemplateRepository.list()
38
+ export const loadProtocolTemplate = (id: string) => protocolTemplateRepository.get(id)
39
+ export const saveProtocolTemplates = (items: Record<string, ProtocolTemplate | Record<string, unknown>>) => protocolTemplateRepository.replace(items as Record<string, ProtocolTemplate>)
40
+ export const upsertProtocolTemplate = (id: string, value: ProtocolTemplate | Record<string, unknown>) => protocolTemplateRepository.upsert(id, value as ProtocolTemplate)
41
+ export const patchProtocolTemplate = (id: string, updater: (current: ProtocolTemplate | null) => ProtocolTemplate | null) => protocolTemplateRepository.patch(id, updater)
42
+ export const deleteProtocolTemplate = (id: string) => protocolTemplateRepository.delete(id)
@@ -9,11 +9,13 @@ import {
9
9
  loadProtocolTemplate,
10
10
  loadProtocolTemplates,
11
11
  patchProtocolTemplate,
12
+ upsertProtocolTemplate,
13
+ } from '@/lib/server/protocols/protocol-template-repository'
14
+ import {
12
15
  releaseRuntimeLock,
13
16
  renewRuntimeLock,
14
17
  tryAcquireRuntimeLock,
15
- upsertProtocolTemplate,
16
- } from '@/lib/server/storage'
18
+ } from '@/lib/server/runtime/runtime-lock-repository'
17
19
  import { notify } from '@/lib/server/ws-hub'
18
20
  import { cleanText, now, PROTOCOL_LOCK_TTL_MS, uniqueIds } from '@/lib/server/protocols/protocol-types'
19
21
  import type { ProtocolRunDeps, UpsertProtocolTemplateInput } from '@/lib/server/protocols/protocol-types'
@@ -3,7 +3,10 @@
3
3
  * Groups G1 + G2 from protocol-service.ts
4
4
  */
5
5
  import type {
6
+ BoardTask,
7
+ Chatroom,
6
8
  MessageToolEvent,
9
+ Mission,
7
10
  ProtocolBranchCase,
8
11
  ProtocolPhaseDefinition,
9
12
  ProtocolRepeatConfig,
@@ -26,10 +29,10 @@ export const AGENT_TURN_TIMEOUT_MS = 90_000
26
29
  export interface ProtocolRunDetail {
27
30
  run: ProtocolRun
28
31
  template: ProtocolTemplate | null
29
- transcript: import('@/types').Chatroom | null
30
- parentChatroom: import('@/types').Chatroom | null
31
- linkedMission: ReturnType<typeof import('@/lib/server/storage').loadMission>
32
- linkedTask: ReturnType<typeof import('@/lib/server/storage').loadTask>
32
+ transcript: Chatroom | null
33
+ parentChatroom: Chatroom | null
34
+ linkedMission: Mission | null
35
+ linkedTask: BoardTask | null
33
36
  events: ProtocolRunEvent[]
34
37
  }
35
38
 
@@ -115,9 +118,9 @@ export function now(deps?: ProtocolRunDeps): number {
115
118
  return deps?.now ? deps.now() : Date.now()
116
119
  }
117
120
 
118
- export function cleanText(value: unknown, max = 1200): string {
119
- return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim().slice(0, max) : ''
120
- }
121
+ import { cleanText } from '@/lib/server/text-normalization'
122
+
123
+ export { cleanText }
121
124
 
122
125
  export function uniqueIds(values: unknown, maxItems = 64): string[] {
123
126
  const source = Array.isArray(values) ? values : []
@@ -1,7 +1,8 @@
1
1
  import { normalizeProviderEndpoint } from '@/lib/openclaw/openclaw-endpoint'
2
2
  import { getProvider } from '@/lib/providers'
3
+ import { loadCredential } from '@/lib/server/credentials/credential-repository'
4
+ import { listCredentialIdsByProvider, resolveCredentialSecret } from '@/lib/server/credentials/credential-service'
3
5
  import { resolveOllamaRuntimeConfig } from '@/lib/server/ollama-runtime'
4
- import { decryptKey, loadCredentials } from '@/lib/server/storage'
5
6
 
6
7
  function clean(value: string | null | undefined): string | null {
7
8
  if (typeof value !== 'string') return null
@@ -16,14 +17,14 @@ export function resolveProviderCredentialId(input: {
16
17
  }): string | null {
17
18
  const normalizedId = clean(input.credentialId)
18
19
  if (!normalizedId) return null
19
- const credentials = loadCredentials()
20
- if (normalizedId && credentials[normalizedId]) return normalizedId
20
+ if (loadCredential(normalizedId)) return normalizedId
21
21
 
22
22
  const provider = clean(input.provider)
23
23
  if (!provider) return normalizedId
24
24
 
25
- const matchingEntries = Object.entries(credentials)
26
- .filter(([, credential]) => credential?.provider === provider)
25
+ const matchingEntries = listCredentialIdsByProvider(provider)
26
+ .map((id) => [id, loadCredential(id)] as const)
27
+ .filter(([, credential]) => Boolean(credential))
27
28
 
28
29
  if (provider === 'ollama' && clean(input.ollamaMode) === 'cloud' && matchingEntries.length > 0) {
29
30
  return [...matchingEntries]
@@ -43,13 +44,7 @@ export function resolveProviderCredentialId(input: {
43
44
  function resolveCredentialApiKey(credentialId?: string | null): string | null {
44
45
  const normalized = resolveProviderCredentialId({ credentialId })
45
46
  if (!normalized) return null
46
- const credential = loadCredentials()[normalized]
47
- if (!credential?.encryptedKey) return null
48
- try {
49
- return decryptKey(credential.encryptedKey)
50
- } catch {
51
- return null
52
- }
47
+ return resolveCredentialSecret(normalized)
53
48
  }
54
49
 
55
50
  export function resolveProviderApiEndpoint(input: {
@@ -3,7 +3,7 @@ import { hmrSingleton } from '@/lib/shared-utils'
3
3
  import { getProviderList } from '@/lib/providers'
4
4
  import { isOllamaCloudEndpoint, resolveStoredOllamaMode } from '@/lib/ollama-mode'
5
5
  import { OPENAI_COMPATIBLE_DEFAULTS } from '@/lib/server/provider-health'
6
- import { decryptKey, loadCredentials } from '@/lib/server/storage'
6
+ import { resolveCredentialSecret } from '@/lib/server/credentials/credential-service'
7
7
  import type { ProviderInfo, ProviderModelDiscoveryResult } from '@/types'
8
8
 
9
9
  type DiscoveryStrategy = 'openai-compatible' | 'anthropic' | 'google' | 'ollama' | 'openclaw'
@@ -192,16 +192,7 @@ export function parseErrorMessage(text: string, fallback: string): string {
192
192
  }
193
193
 
194
194
  function resolveCredentialApiKey(credentialId: string | null | undefined): string | null {
195
- const id = clean(credentialId)
196
- if (!id) return null
197
- try {
198
- const credentials = loadCredentials()
199
- const credential = credentials[id]
200
- if (!credential?.encryptedKey) return null
201
- return decryptKey(credential.encryptedKey)
202
- } catch {
203
- return null
204
- }
195
+ return resolveCredentialSecret(credentialId)
205
196
  }
206
197
 
207
198
  function hashApiKey(apiKey: string | null): string {
@@ -1,4 +1,6 @@
1
- import { loadAgents, loadSettings, loadCredentials, decryptKey } from './storage'
1
+ import { getAgent } from './agents/agent-repository'
2
+ import { resolveCredentialSecret } from './credentials/credential-service'
3
+ import { loadSettings } from './settings/settings-repository'
2
4
  import { getProvider } from '../providers'
3
5
  import { log } from '@/lib/server/logger'
4
6
 
@@ -9,18 +11,15 @@ const TAG = 'query-expansion'
9
11
  * to improve vector database recall (OpenClaw-style).
10
12
  */
11
13
  export async function expandQuery(query: string): Promise<string[]> {
12
- const agents = loadAgents()
13
14
  const settings = loadSettings()
14
15
  const defaultAgentId = typeof settings.defaultAgentId === 'string' ? settings.defaultAgentId : ''
15
- const defaultAgent = defaultAgentId ? agents[defaultAgentId] : null
16
+ const defaultAgent = defaultAgentId ? getAgent(defaultAgentId) : null
16
17
  if (!defaultAgent) return [query]
17
18
 
18
19
  const providerEntry = getProvider(defaultAgent.provider)
19
20
  if (!providerEntry?.handler?.streamChat) return [query]
20
21
 
21
- const creds = loadCredentials()
22
- const cred = creds[defaultAgent.credentialId || '']
23
- const apiKey = cred ? decryptKey(cred.encryptedKey) : undefined
22
+ const apiKey = resolveCredentialSecret(defaultAgent.credentialId) || undefined
24
23
 
25
24
  const systemPrompt = `You are a search query expansion assistant.
26
25
  Given a user's question, generate 3 different semantic search queries that would help find the answer in a vector database.