@swarmclawai/swarmclaw 1.2.1 → 1.2.3

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 (149) hide show
  1. package/README.md +16 -85
  2. package/bin/server-cmd.js +64 -1
  3. package/package.json +2 -2
  4. package/skills/coding-agent/SKILL.md +111 -0
  5. package/skills/github/SKILL.md +140 -0
  6. package/skills/nano-banana-pro/SKILL.md +62 -0
  7. package/skills/nano-banana-pro/scripts/generate_image.py +235 -0
  8. package/skills/nano-pdf/SKILL.md +53 -0
  9. package/skills/openai-image-gen/SKILL.md +78 -0
  10. package/skills/openai-image-gen/scripts/gen.py +328 -0
  11. package/skills/resourceful-problem-solving/SKILL.md +49 -0
  12. package/skills/skill-creator/SKILL.md +147 -0
  13. package/skills/skill-creator/scripts/init_skill.py +378 -0
  14. package/skills/skill-creator/scripts/quick_validate.py +159 -0
  15. package/skills/summarize/SKILL.md +77 -0
  16. package/src/app/api/auth/route.ts +20 -5
  17. package/src/app/api/chats/[id]/devserver/route.ts +13 -19
  18. package/src/app/api/chats/[id]/messages/route.ts +13 -15
  19. package/src/app/api/chats/[id]/route.ts +9 -10
  20. package/src/app/api/chats/[id]/stop/route.ts +5 -7
  21. package/src/app/api/chats/messages-route.test.ts +8 -6
  22. package/src/app/api/chats/route.ts +9 -10
  23. package/src/app/api/ip/route.ts +2 -2
  24. package/src/app/api/preview-server/route.ts +1 -1
  25. package/src/app/api/projects/[id]/route.ts +7 -46
  26. package/src/cli/server-cmd.test.js +74 -0
  27. package/src/components/chat/chat-area.tsx +45 -23
  28. package/src/components/chat/message-bubble.test.ts +35 -0
  29. package/src/components/chat/message-bubble.tsx +19 -9
  30. package/src/components/chat/message-list.tsx +37 -3
  31. package/src/components/input/chat-input.tsx +34 -14
  32. package/src/components/openclaw/openclaw-deploy-panel.tsx +4 -0
  33. package/src/instrumentation.ts +1 -1
  34. package/src/lib/chat/assistant-render-id.ts +3 -0
  35. package/src/lib/chat/chat-streaming-state.test.ts +42 -3
  36. package/src/lib/chat/chat-streaming-state.ts +20 -8
  37. package/src/lib/chat/queued-message-queue.test.ts +23 -1
  38. package/src/lib/chat/queued-message-queue.ts +11 -2
  39. package/src/lib/providers/cli-utils.test.ts +124 -0
  40. package/src/lib/server/activity/activity-log.ts +21 -0
  41. package/src/lib/server/agents/agent-availability.test.ts +10 -5
  42. package/src/lib/server/agents/agent-cascade.ts +79 -59
  43. package/src/lib/server/agents/agent-registry.ts +3 -1
  44. package/src/lib/server/agents/agent-repository.ts +90 -0
  45. package/src/lib/server/agents/delegation-job-repository.ts +53 -0
  46. package/src/lib/server/agents/delegation-jobs.ts +11 -4
  47. package/src/lib/server/agents/guardian-checkpoint-repository.ts +35 -0
  48. package/src/lib/server/agents/guardian.ts +2 -2
  49. package/src/lib/server/agents/main-agent-loop.ts +10 -3
  50. package/src/lib/server/agents/main-loop-state-repository.ts +38 -0
  51. package/src/lib/server/agents/subagent-runtime.ts +9 -6
  52. package/src/lib/server/agents/subagent-swarm.ts +3 -2
  53. package/src/lib/server/agents/task-session.ts +3 -4
  54. package/src/lib/server/approvals/approval-repository.ts +30 -0
  55. package/src/lib/server/autonomy/supervisor-incident-repository.ts +42 -0
  56. package/src/lib/server/chat-execution/chat-execution-types.ts +38 -0
  57. package/src/lib/server/chat-execution/chat-execution-utils.ts +1 -1
  58. package/src/lib/server/chat-execution/chat-execution.ts +84 -1926
  59. package/src/lib/server/chat-execution/chat-turn-finalization.ts +620 -0
  60. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +221 -0
  61. package/src/lib/server/chat-execution/chat-turn-preflight.ts +133 -0
  62. package/src/lib/server/chat-execution/chat-turn-preparation.ts +817 -0
  63. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +296 -0
  64. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +5 -5
  65. package/src/lib/server/chat-execution/message-classifier.test.ts +329 -0
  66. package/src/lib/server/chat-execution/post-stream-finalization.ts +1 -1
  67. package/src/lib/server/chat-execution/prompt-builder.ts +11 -0
  68. package/src/lib/server/chat-execution/prompt-sections.ts +5 -6
  69. package/src/lib/server/chat-execution/situational-awareness.ts +12 -7
  70. package/src/lib/server/chat-execution/stream-agent-chat.ts +16 -13
  71. package/src/lib/server/chatrooms/chatroom-repository.ts +32 -0
  72. package/src/lib/server/connectors/connector-repository.ts +58 -0
  73. package/src/lib/server/connectors/runtime-state.test.ts +117 -0
  74. package/src/lib/server/credentials/credential-repository.ts +7 -0
  75. package/src/lib/server/gateways/gateway-profile-repository.ts +4 -0
  76. package/src/lib/server/memory/memory-abstract.test.ts +59 -0
  77. package/src/lib/server/missions/mission-repository.ts +74 -0
  78. package/src/lib/server/missions/mission-service/actions.ts +6 -0
  79. package/src/lib/server/missions/mission-service/bindings.ts +9 -0
  80. package/src/lib/server/missions/mission-service/context.ts +4 -0
  81. package/src/lib/server/missions/mission-service/core.ts +2269 -0
  82. package/src/lib/server/missions/mission-service/queries.ts +12 -0
  83. package/src/lib/server/missions/mission-service/recovery.ts +5 -0
  84. package/src/lib/server/missions/mission-service/ticks.ts +9 -0
  85. package/src/lib/server/missions/mission-service.test.ts +9 -2
  86. package/src/lib/server/missions/mission-service.ts +6 -2266
  87. package/src/lib/server/openclaw/deploy.test.ts +42 -3
  88. package/src/lib/server/openclaw/deploy.ts +26 -12
  89. package/src/lib/server/persistence/repository-utils.ts +154 -0
  90. package/src/lib/server/persistence/storage-context.ts +51 -0
  91. package/src/lib/server/persistence/transaction.ts +1 -0
  92. package/src/lib/server/projects/project-repository.ts +36 -0
  93. package/src/lib/server/projects/project-service.ts +79 -0
  94. package/src/lib/server/protocols/protocol-normalization.test.ts +6 -4
  95. package/src/lib/server/runtime/alert-dispatch.ts +1 -1
  96. package/src/lib/server/runtime/daemon-policy.ts +1 -1
  97. package/src/lib/server/runtime/daemon-state/core.ts +1570 -0
  98. package/src/lib/server/runtime/daemon-state/health.ts +6 -0
  99. package/src/lib/server/runtime/daemon-state/policy.ts +7 -0
  100. package/src/lib/server/runtime/daemon-state/supervisor.ts +6 -0
  101. package/src/lib/server/runtime/daemon-state.test.ts +48 -0
  102. package/src/lib/server/runtime/daemon-state.ts +3 -1470
  103. package/src/lib/server/runtime/estop-repository.ts +4 -0
  104. package/src/lib/server/runtime/estop.ts +3 -1
  105. package/src/lib/server/runtime/heartbeat-service.test.ts +2 -2
  106. package/src/lib/server/runtime/heartbeat-service.ts +55 -34
  107. package/src/lib/server/runtime/heartbeat-wake.ts +6 -4
  108. package/src/lib/server/runtime/idle-window.ts +2 -2
  109. package/src/lib/server/runtime/network.ts +11 -0
  110. package/src/lib/server/runtime/orchestrator-events.ts +2 -2
  111. package/src/lib/server/runtime/queue/claims.ts +4 -0
  112. package/src/lib/server/runtime/queue/core.ts +2079 -0
  113. package/src/lib/server/runtime/queue/execution.ts +7 -0
  114. package/src/lib/server/runtime/queue/followups.ts +4 -0
  115. package/src/lib/server/runtime/queue/queries.ts +12 -0
  116. package/src/lib/server/runtime/queue/recovery.ts +7 -0
  117. package/src/lib/server/runtime/queue-recovery.test.ts +48 -13
  118. package/src/lib/server/runtime/queue-repository.ts +17 -0
  119. package/src/lib/server/runtime/queue.ts +5 -2061
  120. package/src/lib/server/runtime/run-ledger.ts +6 -5
  121. package/src/lib/server/runtime/run-repository.ts +73 -0
  122. package/src/lib/server/runtime/runtime-lock-repository.ts +8 -0
  123. package/src/lib/server/runtime/runtime-settings.ts +1 -1
  124. package/src/lib/server/runtime/runtime-state.ts +99 -0
  125. package/src/lib/server/runtime/scheduler.ts +4 -2
  126. package/src/lib/server/runtime/session-run-manager/cancellation.ts +157 -0
  127. package/src/lib/server/runtime/session-run-manager/drain.ts +246 -0
  128. package/src/lib/server/runtime/session-run-manager/enqueue.ts +287 -0
  129. package/src/lib/server/runtime/session-run-manager/queries.ts +117 -0
  130. package/src/lib/server/runtime/session-run-manager/recovery.ts +238 -0
  131. package/src/lib/server/runtime/session-run-manager/state.ts +441 -0
  132. package/src/lib/server/runtime/session-run-manager/types.ts +74 -0
  133. package/src/lib/server/runtime/session-run-manager.ts +72 -1377
  134. package/src/lib/server/runtime/watch-job-repository.ts +35 -0
  135. package/src/lib/server/runtime/watch-jobs.ts +3 -1
  136. package/src/lib/server/schedules/schedule-repository.ts +42 -0
  137. package/src/lib/server/sessions/session-repository.ts +85 -0
  138. package/src/lib/server/settings/settings-repository.ts +25 -0
  139. package/src/lib/server/skills/skill-discovery.test.ts +2 -2
  140. package/src/lib/server/skills/skill-discovery.ts +2 -2
  141. package/src/lib/server/skills/skill-repository.ts +14 -0
  142. package/src/lib/server/storage.ts +13 -24
  143. package/src/lib/server/tasks/task-repository.ts +54 -0
  144. package/src/lib/server/usage/usage-repository.ts +30 -0
  145. package/src/lib/server/webhooks/webhook-repository.ts +10 -0
  146. package/src/lib/strip-internal-metadata.test.ts +42 -41
  147. package/src/stores/use-chat-store.test.ts +54 -0
  148. package/src/stores/use-chat-store.ts +21 -5
  149. /package/{bundled-skills → skills}/google-workspace/SKILL.md +0 -0
@@ -0,0 +1,90 @@
1
+ import type { Agent } from '@/types'
2
+
3
+ import {
4
+ deleteAgent as deleteStoredAgent,
5
+ loadAgent as loadStoredAgent,
6
+ loadAgents as loadStoredAgents,
7
+ loadTrashedAgents as loadStoredTrashedAgents,
8
+ patchAgent as patchStoredAgent,
9
+ saveAgents as saveStoredAgents,
10
+ upsertAgent as upsertStoredAgent,
11
+ } from '@/lib/server/storage'
12
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
13
+
14
+ type AgentRepositoryOptions = { includeTrashed?: boolean }
15
+
16
+ export const agentRepository = createRecordRepository<Agent, AgentRepositoryOptions>(
17
+ 'agents',
18
+ {
19
+ get(id, options) {
20
+ return loadStoredAgent(id, options) as Agent | null
21
+ },
22
+ list(options) {
23
+ return loadStoredAgents(options) as Record<string, Agent>
24
+ },
25
+ upsert(id, value) {
26
+ upsertStoredAgent(id, value)
27
+ },
28
+ replace(data) {
29
+ saveStoredAgents(data)
30
+ },
31
+ patch(id, updater) {
32
+ return patchStoredAgent(id, updater as (current: Agent | null) => Agent | null) as Agent | null
33
+ },
34
+ delete(id) {
35
+ deleteStoredAgent(id)
36
+ },
37
+ },
38
+ )
39
+
40
+ export function getAgent(id: string, options?: AgentRepositoryOptions): Agent | null {
41
+ return agentRepository.get(id, options)
42
+ }
43
+
44
+ export function getAgents(ids: string[], options?: AgentRepositoryOptions): Record<string, Agent> {
45
+ return agentRepository.getMany(ids, options)
46
+ }
47
+
48
+ export function listAgents(options?: AgentRepositoryOptions): Record<string, Agent> {
49
+ return agentRepository.list(options)
50
+ }
51
+
52
+ export function saveAgent(id: string, agent: Agent | Record<string, unknown>): void {
53
+ agentRepository.upsert(id, agent as Agent)
54
+ }
55
+
56
+ export function saveAgentMany(entries: Array<[string, Agent | Record<string, unknown>]>): void {
57
+ agentRepository.upsertMany(entries as Array<[string, Agent]>)
58
+ }
59
+
60
+ export function replaceAgents(agents: Record<string, Agent | Record<string, unknown>>): void {
61
+ agentRepository.replace(agents as Record<string, Agent>)
62
+ }
63
+
64
+ export function patchAgent(id: string, updater: (current: Agent | null) => Agent | null): Agent | null {
65
+ return agentRepository.patch(id, updater)
66
+ }
67
+
68
+ export function deleteAgent(id: string): void {
69
+ agentRepository.delete(id)
70
+ }
71
+
72
+ export function loadAgents(options?: AgentRepositoryOptions): Record<string, Agent> {
73
+ return listAgents(options)
74
+ }
75
+
76
+ export function loadAgent(id: string, options?: AgentRepositoryOptions): Agent | null {
77
+ return getAgent(id, options)
78
+ }
79
+
80
+ export function saveAgents(agents: Record<string, Agent | Record<string, unknown>>): void {
81
+ replaceAgents(agents)
82
+ }
83
+
84
+ export function upsertAgent(id: string, agent: Agent | Record<string, unknown>): void {
85
+ saveAgent(id, agent)
86
+ }
87
+
88
+ export function loadTrashedAgents(): Record<string, Agent> {
89
+ return loadStoredTrashedAgents() as Record<string, Agent>
90
+ }
@@ -0,0 +1,53 @@
1
+ import type { DelegationJobRecord } from '@/types'
2
+
3
+ import {
4
+ deleteDelegationJob as deleteStoredDelegationJob,
5
+ loadDelegationJobItem as loadStoredDelegationJob,
6
+ loadDelegationJobs as loadStoredDelegationJobs,
7
+ patchDelegationJob as patchStoredDelegationJob,
8
+ upsertDelegationJob as upsertStoredDelegationJob,
9
+ } from '@/lib/server/storage'
10
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
11
+
12
+ export const delegationJobRepository = createRecordRepository<DelegationJobRecord>(
13
+ 'delegation-jobs',
14
+ {
15
+ get(id) {
16
+ return loadStoredDelegationJob(id) as DelegationJobRecord | null
17
+ },
18
+ list() {
19
+ return loadStoredDelegationJobs() as Record<string, DelegationJobRecord>
20
+ },
21
+ upsert(id, value) {
22
+ upsertStoredDelegationJob(id, value as DelegationJobRecord)
23
+ },
24
+ patch(id, updater) {
25
+ return patchStoredDelegationJob(
26
+ id,
27
+ updater as (current: DelegationJobRecord | null) => DelegationJobRecord | null,
28
+ ) as DelegationJobRecord | null
29
+ },
30
+ delete(id) {
31
+ deleteStoredDelegationJob(id)
32
+ },
33
+ },
34
+ )
35
+
36
+ export const getDelegationJobRecord = (id: string) => delegationJobRepository.get(id)
37
+ export const getDelegationJobRecords = (ids: string[]) => delegationJobRepository.getMany(ids)
38
+ export const listDelegationJobRecords = () => delegationJobRepository.list()
39
+ export const saveDelegationJobRecord = (id: string, value: DelegationJobRecord | Record<string, unknown>) =>
40
+ delegationJobRepository.upsert(id, value as DelegationJobRecord)
41
+ export const saveDelegationJobRecords = (entries: Array<[string, DelegationJobRecord | Record<string, unknown>]>) =>
42
+ delegationJobRepository.upsertMany(entries as Array<[string, DelegationJobRecord]>)
43
+ export const patchDelegationJobRecord = (
44
+ id: string,
45
+ updater: (current: DelegationJobRecord | null) => DelegationJobRecord | null,
46
+ ) => delegationJobRepository.patch(id, updater)
47
+ export const deleteDelegationJobRecord = (id: string) => delegationJobRepository.delete(id)
48
+
49
+ export const loadDelegationJobs = listDelegationJobRecords
50
+ export const loadDelegationJob = getDelegationJobRecord
51
+ export const upsertDelegationJob = saveDelegationJobRecord
52
+ export const patchDelegationJob = patchDelegationJobRecord
53
+ export const deleteDelegationJob = deleteDelegationJobRecord
@@ -1,13 +1,20 @@
1
1
  import { genId } from '@/lib/id'
2
2
  import { hmrSingleton } from '@/lib/shared-utils'
3
3
  import type { DelegationJobArtifact, DelegationJobCheckpoint, DelegationJobRecord, DelegationJobStatus } from '@/types'
4
- import { loadDelegationJobs, loadDelegationJobItem, loadSession, logActivity, patchDelegationJob, upsertDelegationJob } from '@/lib/server/storage'
4
+ import {
5
+ loadDelegationJob,
6
+ loadDelegationJobs,
7
+ patchDelegationJob,
8
+ upsertDelegationJob,
9
+ } from '@/lib/server/agents/delegation-job-repository'
10
+ import { logActivity } from '@/lib/server/activity/activity-log'
5
11
  import { logExecution } from '@/lib/server/execution-log'
6
12
  import { log } from '@/lib/server/logger'
7
13
  import { debug } from '@/lib/server/debug'
8
14
  import { createNotification } from '@/lib/server/create-notification'
9
15
  import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
10
16
  import { ensureDelegationMission, syncDelegationMissionFromJob } from '@/lib/server/missions/mission-service'
17
+ import { loadSession } from '@/lib/server/sessions/session-repository'
11
18
  import { notify } from '@/lib/server/ws-hub'
12
19
 
13
20
  interface DelegationRuntimeHandle {
@@ -115,7 +122,7 @@ export function createDelegationJob(input: CreateDelegationJobInput): Delegation
115
122
  }
116
123
 
117
124
  export function getDelegationJob(id: string): DelegationJobRecord | null {
118
- const current = loadDelegationJobItem(id)
125
+ const current = loadDelegationJob(id)
119
126
  if (!current || typeof current !== 'object') return null
120
127
  return current as DelegationJobRecord
121
128
  }
@@ -144,9 +151,9 @@ export function updateDelegationJob(
144
151
  }
145
152
  })
146
153
  if (!result) return null
147
- const synced = syncDelegationMissionFromJob(id) || result
154
+ syncDelegationMissionFromJob(id)
148
155
  notifyDelegationJobsChanged()
149
- return getDelegationJob(id) || synced
156
+ return getDelegationJob(id) || result
150
157
  }
151
158
 
152
159
  export function appendDelegationCheckpoint(
@@ -0,0 +1,35 @@
1
+ import type { GuardianCheckpoint } from '@/types'
2
+
3
+ import {
4
+ loadGuardianCheckpoints as loadStoredGuardianCheckpoints,
5
+ patchGuardianCheckpoint as patchStoredGuardianCheckpoint,
6
+ upsertGuardianCheckpoint as upsertStoredGuardianCheckpoint,
7
+ } from '@/lib/server/storage'
8
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
9
+
10
+ export const guardianCheckpointRepository = createRecordRepository<GuardianCheckpoint>(
11
+ 'guardian-checkpoints',
12
+ {
13
+ get(id) {
14
+ return loadStoredGuardianCheckpoints()[id] || null
15
+ },
16
+ list() {
17
+ return loadStoredGuardianCheckpoints()
18
+ },
19
+ upsert(id, value) {
20
+ upsertStoredGuardianCheckpoint(id, value as GuardianCheckpoint)
21
+ },
22
+ patch(id, updater) {
23
+ return patchStoredGuardianCheckpoint(id, updater)
24
+ },
25
+ },
26
+ )
27
+
28
+ export const loadGuardianCheckpoints = () => guardianCheckpointRepository.list()
29
+ export const loadGuardianCheckpoint = (id: string) => guardianCheckpointRepository.get(id)
30
+ export const upsertGuardianCheckpoint = (id: string, value: GuardianCheckpoint | Record<string, unknown>) =>
31
+ guardianCheckpointRepository.upsert(id, value as GuardianCheckpoint)
32
+ export const patchGuardianCheckpoint = (
33
+ id: string,
34
+ updater: (current: GuardianCheckpoint | null) => GuardianCheckpoint | null,
35
+ ) => guardianCheckpointRepository.patch(id, updater)
@@ -1,12 +1,12 @@
1
1
  import { execSync } from 'node:child_process'
2
2
  import path from 'node:path'
3
3
  import type { ApprovalRequest, GuardianCheckpoint } from '@/types'
4
+ import { loadApprovals } from '@/lib/server/approvals/approval-repository'
4
5
  import {
5
- loadApprovals,
6
6
  loadGuardianCheckpoints,
7
7
  patchGuardianCheckpoint,
8
8
  upsertGuardianCheckpoint,
9
- } from '@/lib/server/storage'
9
+ } from '@/lib/server/agents/guardian-checkpoint-repository'
10
10
  import { requestApproval } from '@/lib/server/approvals'
11
11
  import { errorMessage } from '@/lib/shared-utils'
12
12
  import { genId } from '@/lib/id'
@@ -1,10 +1,17 @@
1
1
  import { hmrSingleton } from '@/lib/shared-utils'
2
2
  import type { GoalContract, Message, MessageToolEvent, Session } from '@/types'
3
3
  import { mergeGoalContracts, parseGoalContractFromText, parseMainLoopPlan, parseMainLoopReview } from '@/lib/server/agents/autonomy-contract'
4
+ import {
5
+ deletePersistedMainLoopState,
6
+ loadPersistedMainLoopState,
7
+ upsertPersistedMainLoopState,
8
+ } from '@/lib/server/agents/main-loop-state-repository'
9
+ import { loadAgents } from '@/lib/server/agents/agent-repository'
4
10
  import { assessAutonomyRun } from '@/lib/server/autonomy/supervisor-reflection'
5
11
  import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
6
- import { loadAgents, loadSessions, loadSettings, loadPersistedMainLoopState, upsertPersistedMainLoopState, deletePersistedMainLoopState } from '@/lib/server/storage'
7
12
  import { buildMissionHeartbeatPrompt as buildMissionHeartbeatPromptFromMission, getMissionForSession } from '@/lib/server/missions/mission-service'
13
+ import { loadSettings } from '@/lib/server/settings/settings-repository'
14
+ import { getSession, loadSessions } from '@/lib/server/sessions/session-repository'
8
15
 
9
16
  const LEGACY_META_LINE_RE = /\[(?:MAIN_LOOP_META|MAIN_LOOP_PLAN|MAIN_LOOP_REVIEW|AGENT_HEARTBEAT_META)\]\s*(\{[^\n]*\})?/i
10
17
  const HEARTBEAT_META_RE = /\[AGENT_HEARTBEAT_META\]\s*(\{[^\n]*\})/i
@@ -437,7 +444,7 @@ function hydrateStateFromSession(sessionId: string): MainLoopState | null {
437
444
  }
438
445
 
439
446
  function persistState(sessionId: string, state: MainLoopState): void {
440
- upsertPersistedMainLoopState(sessionId, state as unknown)
447
+ upsertPersistedMainLoopState(sessionId, state as unknown as Record<string, unknown>)
441
448
  }
442
449
 
443
450
  function getOrCreateState(sessionId: string): MainLoopState | null {
@@ -738,7 +745,7 @@ export function isMainSession(session: unknown): boolean {
738
745
  export function buildMainLoopHeartbeatPrompt(session: unknown, fallbackPrompt: string): string {
739
746
  const candidate = asSession(session)
740
747
  if (!candidate?.id) return fallbackPrompt
741
- const persistedSession = loadSessions()[String(candidate.id)] as Session | undefined
748
+ const persistedSession = getSession(String(candidate.id)) as Session | undefined
742
749
  const missionPrompt = buildMissionHeartbeatPromptFromMission(
743
750
  persistedSession || candidate as Session,
744
751
  fallbackPrompt,
@@ -0,0 +1,38 @@
1
+ import { perf } from '@/lib/server/runtime/perf'
2
+ import {
3
+ deletePersistedMainLoopState as deleteStoredMainLoopState,
4
+ loadPersistedMainLoopState as loadStoredMainLoopState,
5
+ upsertPersistedMainLoopState as upsertStoredMainLoopState,
6
+ } from '@/lib/server/storage'
7
+
8
+ export type PersistedMainLoopState = Record<string, unknown>
9
+
10
+ export function loadPersistedMainLoopState(sessionId: string): PersistedMainLoopState | null {
11
+ return perf.measureSync(
12
+ 'repository',
13
+ 'main-loop-state.get',
14
+ () => loadStoredMainLoopState(sessionId) as PersistedMainLoopState | null,
15
+ { sessionId },
16
+ )
17
+ }
18
+
19
+ export function upsertPersistedMainLoopState(
20
+ sessionId: string,
21
+ value: PersistedMainLoopState,
22
+ ): void {
23
+ perf.measureSync(
24
+ 'repository',
25
+ 'main-loop-state.upsert',
26
+ () => upsertStoredMainLoopState(sessionId, value),
27
+ { sessionId },
28
+ )
29
+ }
30
+
31
+ export function deletePersistedMainLoopState(sessionId: string): void {
32
+ perf.measureSync(
33
+ 'repository',
34
+ 'main-loop-state.delete',
35
+ () => deleteStoredMainLoopState(sessionId),
36
+ { sessionId },
37
+ )
38
+ }
@@ -8,7 +8,7 @@
8
8
 
9
9
  import { genId } from '@/lib/id'
10
10
  import { DEFAULT_DELEGATION_MAX_DEPTH } from '@/lib/runtime/runtime-loop'
11
- import { loadAgents, loadSessions, saveSessions } from '@/lib/server/storage'
11
+ import { loadAgents } from '@/lib/server/agents/agent-repository'
12
12
  import { enqueueSessionRun, type EnqueueSessionRunResult } from '@/lib/server/runtime/session-run-manager'
13
13
  import { loadRuntimeSettings } from '@/lib/server/runtime/runtime-settings'
14
14
  import { applyResolvedRoute, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
@@ -48,6 +48,7 @@ import { debug } from '@/lib/server/debug'
48
48
  import { logExecution } from '@/lib/server/execution-log'
49
49
  import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
50
50
  import { getEnabledCapabilityIds, splitCapabilityIds } from '@/lib/capability-selection'
51
+ import { getSession, loadSessions, saveSession } from '@/lib/server/sessions/session-repository'
51
52
 
52
53
  // ---------------------------------------------------------------------------
53
54
  // Types
@@ -276,7 +277,7 @@ async function spawnSubagentImpl(
276
277
  browserProfileId,
277
278
  }
278
279
  sessions[sid] = applyResolvedRoute(nextSession, resolvePrimaryAgentRoute(agent))
279
- saveSessions(sessions)
280
+ saveSession(sid, sessions[sid])
280
281
 
281
282
  log.info('subagent', 'Spawning', { agentId: agent.id, agentName: agent.name, depth: depth + 1, jobId: job.id, sessionId: sid })
282
283
  logExecution(sid, 'delegation_start', `Subagent spawning: ${agent.name}`, {
@@ -398,12 +399,13 @@ async function spawnSubagentImpl(
398
399
  `subagent:${job.id}`,
399
400
  )
400
401
  }
402
+ const completedSession = getSession(sid)
401
403
  await runCapabilityHook(
402
404
  'sessionEnd',
403
405
  {
404
406
  sessionId: sid,
405
- session: loadSessions()[sid] || null,
406
- messageCount: Array.isArray(loadSessions()[sid]?.messages) ? loadSessions()[sid].messages.length : 0,
407
+ session: completedSession,
408
+ messageCount: Array.isArray(completedSession?.messages) ? completedSession.messages.length : 0,
407
409
  durationMs: subagentResult.durationMs,
408
410
  reason: subagentResult.status,
409
411
  },
@@ -460,12 +462,13 @@ async function spawnSubagentImpl(
460
462
  `subagent:${job.id}`,
461
463
  )
462
464
  }
465
+ const failedSession = getSession(sid)
463
466
  await runCapabilityHook(
464
467
  'sessionEnd',
465
468
  {
466
469
  sessionId: sid,
467
- session: loadSessions()[sid] || null,
468
- messageCount: Array.isArray(loadSessions()[sid]?.messages) ? loadSessions()[sid].messages.length : 0,
470
+ session: failedSession,
471
+ messageCount: Array.isArray(failedSession?.messages) ? failedSession.messages.length : 0,
469
472
  durationMs: subagentResult.durationMs,
470
473
  reason: subagentResult.status,
471
474
  },
@@ -13,22 +13,23 @@ import { genId } from '@/lib/id'
13
13
  import { errorMessage, hmrSingleton, sleep } from '@/lib/shared-utils'
14
14
  import { log } from '@/lib/server/logger'
15
15
  import { logExecution } from '@/lib/server/execution-log'
16
- import { logActivity } from '@/lib/server/storage'
16
+ import { logActivity } from '@/lib/server/activity/activity-log'
17
17
  import { createNotification } from '@/lib/server/create-notification'
18
18
  import { notify } from '@/lib/server/ws-hub'
19
+ import { loadAgents } from '@/lib/server/agents/agent-repository'
19
20
  import {
20
21
  spawnSubagent,
21
22
  type SubagentContext,
22
23
  type SubagentHandle,
23
24
  type SubagentResult,
24
25
  } from '@/lib/server/agents/subagent-runtime'
25
- import { loadAgents, loadSessions } from '@/lib/server/storage'
26
26
  import { getDelegationJob } from '@/lib/server/agents/delegation-jobs'
27
27
  import {
28
28
  getLineageNode,
29
29
  cancelLineageNode,
30
30
  type SubagentState,
31
31
  } from '@/lib/server/agents/subagent-lineage'
32
+ import { loadSessions } from '@/lib/server/sessions/session-repository'
32
33
  import type { Agent } from '@/types'
33
34
 
34
35
  // ---------------------------------------------------------------------------
@@ -1,9 +1,9 @@
1
1
  import { genId } from '@/lib/id'
2
- import { loadSessions, saveSessions } from '@/lib/server/storage'
3
2
  import { WORKSPACE_DIR } from '@/lib/server/data-dir'
4
3
  import type { Agent } from '@/types'
5
4
  import { getEnabledCapabilitySelection } from '@/lib/capability-selection'
6
5
  import { applyResolvedRoute, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
6
+ import { saveSession } from '@/lib/server/sessions/session-repository'
7
7
 
8
8
  export function createAgentTaskSession(
9
9
  agent: Agent,
@@ -15,7 +15,6 @@ export function createAgentTaskSession(
15
15
  preferredGatewayUseCase?: string | null
16
16
  } | null,
17
17
  ): string {
18
- const sessions = loadSessions()
19
18
  const sessionId = genId()
20
19
  const preferredGatewayTags = Array.isArray(routePreferences?.preferredGatewayTags)
21
20
  ? routePreferences.preferredGatewayTags.filter((tag) => typeof tag === 'string' && tag.trim())
@@ -25,7 +24,7 @@ export function createAgentTaskSession(
25
24
  preferredGatewayUseCase: routePreferences?.preferredGatewayUseCase || null,
26
25
  })
27
26
 
28
- sessions[sessionId] = applyResolvedRoute({
27
+ const session = applyResolvedRoute({
29
28
  id: sessionId,
30
29
  name: `[Task] ${agent.name}: ${task.slice(0, 40)}`,
31
30
  cwd: cwd || WORKSPACE_DIR,
@@ -57,6 +56,6 @@ export function createAgentTaskSession(
57
56
  heartbeatEnabled: false,
58
57
  }, resolvedRoute)
59
58
 
60
- saveSessions(sessions)
59
+ saveSession(sessionId, session)
61
60
  return sessionId
62
61
  }
@@ -0,0 +1,30 @@
1
+ import {
2
+ deleteApproval as deleteStoredApproval,
3
+ loadApprovals as loadStoredApprovals,
4
+ upsertApproval as upsertStoredApproval,
5
+ } from '@/lib/server/storage'
6
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
7
+ import type { ApprovalRequest } from '@/types'
8
+
9
+ export const approvalRepository = createRecordRepository<ApprovalRequest>(
10
+ 'approvals',
11
+ {
12
+ get(id) {
13
+ return loadStoredApprovals()[id] || null
14
+ },
15
+ list() {
16
+ return loadStoredApprovals() as Record<string, ApprovalRequest>
17
+ },
18
+ upsert(id, value) {
19
+ upsertStoredApproval(id, value)
20
+ },
21
+ delete(id) {
22
+ deleteStoredApproval(id)
23
+ },
24
+ },
25
+ )
26
+
27
+ export const loadApprovals = () => approvalRepository.list()
28
+ export const loadApproval = (id: string) => approvalRepository.get(id)
29
+ export const upsertApproval = (id: string, value: ApprovalRequest | Record<string, unknown>) => approvalRepository.upsert(id, value as ApprovalRequest)
30
+ export const deleteApproval = (id: string) => approvalRepository.delete(id)
@@ -0,0 +1,42 @@
1
+ import type { SupervisorIncident } from '@/types'
2
+
3
+ import {
4
+ loadSupervisorIncident as loadStoredSupervisorIncident,
5
+ loadSupervisorIncidents as loadStoredSupervisorIncidents,
6
+ saveSupervisorIncidents as saveStoredSupervisorIncidents,
7
+ upsertSupervisorIncident as upsertStoredSupervisorIncident,
8
+ } from '@/lib/server/storage'
9
+ import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
10
+
11
+ export const supervisorIncidentRepository = createRecordRepository<SupervisorIncident>(
12
+ 'supervisor-incidents',
13
+ {
14
+ get(id) {
15
+ return loadStoredSupervisorIncident(id) as SupervisorIncident | null
16
+ },
17
+ list() {
18
+ return loadStoredSupervisorIncidents() as Record<string, SupervisorIncident>
19
+ },
20
+ upsert(id, value) {
21
+ upsertStoredSupervisorIncident(id, value as SupervisorIncident)
22
+ },
23
+ replace(data) {
24
+ saveStoredSupervisorIncidents(data as Record<string, SupervisorIncident>)
25
+ },
26
+ },
27
+ )
28
+
29
+ export const loadSupervisorIncidents = () => supervisorIncidentRepository.list()
30
+ export const loadSupervisorIncident = (id: string) => supervisorIncidentRepository.get(id)
31
+ export const saveSupervisorIncidents = (items: Record<string, SupervisorIncident | Record<string, unknown>>) => (
32
+ supervisorIncidentRepository.replace(items as Record<string, SupervisorIncident>)
33
+ )
34
+ export const upsertSupervisorIncident = (id: string, value: SupervisorIncident | Record<string, unknown>) => (
35
+ supervisorIncidentRepository.upsert(id, value as SupervisorIncident)
36
+ )
37
+
38
+ export function listAgentIncidents(agentId?: string): SupervisorIncident[] {
39
+ return Object.values(loadSupervisorIncidents())
40
+ .filter((incident) => !agentId || incident.agentId === agentId)
41
+ .sort((left, right) => right.createdAt - left.createdAt)
42
+ }
@@ -0,0 +1,38 @@
1
+ import type { MessageToolEvent, SSEEvent } from '@/types'
2
+
3
+ export interface ExecuteChatTurnInput {
4
+ sessionId: string
5
+ message: string
6
+ missionId?: string | null
7
+ imagePath?: string
8
+ imageUrl?: string
9
+ attachedFiles?: string[]
10
+ internal?: boolean
11
+ source?: string
12
+ runId?: string
13
+ signal?: AbortSignal
14
+ onEvent?: (event: SSEEvent) => void
15
+ modelOverride?: string
16
+ heartbeatConfig?: {
17
+ ackMaxChars: number
18
+ showOk: boolean
19
+ showAlerts: boolean
20
+ target: string | null
21
+ lightContext?: boolean
22
+ deliveryMode?: 'default' | 'tool_only' | 'silent'
23
+ }
24
+ replyToId?: string
25
+ }
26
+
27
+ export interface ExecuteChatTurnResult {
28
+ runId?: string
29
+ sessionId: string
30
+ missionId?: string | null
31
+ text: string
32
+ persisted: boolean
33
+ toolEvents: MessageToolEvent[]
34
+ error?: string
35
+ inputTokens?: number
36
+ outputTokens?: number
37
+ estimatedCost?: number
38
+ }
@@ -2,7 +2,7 @@ import fs from 'fs'
2
2
  import path from 'path'
3
3
  import type { Message, MessageToolEvent } from '@/types'
4
4
  import { dedup } from '@/lib/shared-utils'
5
- import { getUsageSpendSince } from '@/lib/server/storage'
5
+ import { getUsageSpendSince } from '@/lib/server/usage/usage-repository'
6
6
  import { extensionIdMatches } from '@/lib/server/tool-aliases'
7
7
  import { buildToolEventAssistantSummary } from '@/lib/chat/tool-event-summary'
8
8
  import { looksLikePositiveConnectorDeliveryText } from '@/lib/server/chat-execution/chat-execution-connector-delivery'