@vellumai/assistant 0.5.5 → 0.5.7

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 (382) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +4 -5
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docs/architecture/keychain-broker.md +45 -240
  7. package/docs/architecture/security.md +0 -17
  8. package/docs/credential-execution-service.md +2 -2
  9. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  10. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
  11. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  12. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  13. package/package.json +2 -3
  14. package/src/__tests__/actor-token-service.test.ts +1 -2
  15. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  16. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  17. package/src/__tests__/btw-routes.test.ts +0 -39
  18. package/src/__tests__/call-domain.test.ts +0 -128
  19. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  20. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  21. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  22. package/src/__tests__/checker.test.ts +4 -2
  23. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  24. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  25. package/src/__tests__/config-schema.test.ts +3 -3
  26. package/src/__tests__/context-window-manager.test.ts +78 -0
  27. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  28. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  29. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  30. package/src/__tests__/conversation-title-service.test.ts +117 -1
  31. package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
  32. package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
  33. package/src/__tests__/credential-security-e2e.test.ts +0 -66
  34. package/src/__tests__/credential-security-invariants.test.ts +4 -45
  35. package/src/__tests__/credentials-cli.test.ts +78 -0
  36. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  37. package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
  38. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  39. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  40. package/src/__tests__/host-shell-tool.test.ts +6 -7
  41. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  42. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  43. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  44. package/src/__tests__/intent-routing.test.ts +0 -13
  45. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  46. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  47. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  48. package/src/__tests__/memory-regressions.test.ts +8 -30
  49. package/src/__tests__/migration-export-http.test.ts +2 -2
  50. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  51. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  52. package/src/__tests__/migration-validate-http.test.ts +2 -2
  53. package/src/__tests__/non-member-access-request.test.ts +0 -5
  54. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  55. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  56. package/src/__tests__/permission-types.test.ts +1 -0
  57. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  58. package/src/__tests__/qdrant-manager.test.ts +28 -2
  59. package/src/__tests__/registry.test.ts +0 -6
  60. package/src/__tests__/require-fresh-approval.test.ts +4 -0
  61. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  62. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  63. package/src/__tests__/secure-keys.test.ts +83 -263
  64. package/src/__tests__/shell-identity.test.ts +96 -6
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  66. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  67. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  68. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  69. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  70. package/src/__tests__/skill-load-tool.test.ts +0 -2
  71. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  72. package/src/__tests__/skills.test.ts +0 -2
  73. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  74. package/src/__tests__/suggestion-routes.test.ts +1 -32
  75. package/src/__tests__/system-prompt.test.ts +0 -1
  76. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
  77. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  78. package/src/__tests__/tool-executor.test.ts +4 -0
  79. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  80. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  81. package/src/__tests__/update-bulletin.test.ts +0 -2
  82. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  83. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
  84. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  85. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
  86. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  87. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  88. package/src/calls/audio-store.test.ts +97 -0
  89. package/src/calls/audio-store.ts +205 -0
  90. package/src/calls/call-controller.ts +85 -7
  91. package/src/calls/call-domain.ts +3 -0
  92. package/src/calls/call-store.ts +10 -3
  93. package/src/calls/fish-audio-client.ts +117 -0
  94. package/src/calls/relay-server.ts +27 -0
  95. package/src/calls/twilio-routes.ts +2 -1
  96. package/src/calls/types.ts +1 -0
  97. package/src/calls/voice-ingress-preflight.ts +0 -42
  98. package/src/calls/voice-quality.ts +26 -5
  99. package/src/calls/voice-session-bridge.ts +6 -12
  100. package/src/cli/commands/config.ts +1 -4
  101. package/src/cli/commands/conversations.ts +0 -18
  102. package/src/cli/commands/credentials.ts +34 -4
  103. package/src/cli/commands/oauth/index.ts +7 -0
  104. package/src/cli/commands/oauth/platform.ts +179 -0
  105. package/src/cli/commands/platform.ts +3 -3
  106. package/src/config/assistant-feature-flags.ts +186 -5
  107. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  108. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  109. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  110. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  111. package/src/config/bundled-tool-registry.ts +1 -11
  112. package/src/config/env-registry.ts +1 -1
  113. package/src/config/env.ts +16 -16
  114. package/src/config/feature-flag-registry.json +48 -16
  115. package/src/config/loader.ts +98 -31
  116. package/src/config/schema.ts +4 -25
  117. package/src/config/schemas/calls.ts +13 -0
  118. package/src/config/schemas/fish-audio.ts +39 -0
  119. package/src/config/schemas/memory.ts +0 -4
  120. package/src/config/schemas/platform.ts +1 -1
  121. package/src/config/schemas/security.ts +4 -4
  122. package/src/config/types.ts +0 -1
  123. package/src/contacts/contact-store.ts +39 -0
  124. package/src/contacts/types.ts +2 -0
  125. package/src/context/window-manager.ts +53 -2
  126. package/src/credential-execution/approval-bridge.ts +1 -0
  127. package/src/credential-execution/executable-discovery.ts +28 -4
  128. package/src/credential-execution/feature-gates.ts +16 -0
  129. package/src/credential-execution/process-manager.ts +38 -0
  130. package/src/daemon/assistant-attachments.ts +9 -0
  131. package/src/daemon/config-watcher.ts +6 -4
  132. package/src/daemon/conversation-agent-loop.ts +0 -60
  133. package/src/daemon/conversation-memory.ts +0 -117
  134. package/src/daemon/conversation-runtime-assembly.ts +0 -2
  135. package/src/daemon/conversation-tool-setup.ts +0 -105
  136. package/src/daemon/conversation.ts +10 -1
  137. package/src/daemon/handlers/config-vercel.ts +92 -0
  138. package/src/daemon/handlers/conversations.ts +0 -11
  139. package/src/daemon/handlers/skills.ts +2 -15
  140. package/src/daemon/install-symlink.ts +195 -0
  141. package/src/daemon/lifecycle.ts +229 -96
  142. package/src/daemon/message-types/conversations.ts +3 -4
  143. package/src/daemon/message-types/diagnostics.ts +3 -22
  144. package/src/daemon/message-types/messages.ts +0 -2
  145. package/src/daemon/message-types/upgrades.ts +8 -0
  146. package/src/daemon/server.ts +30 -92
  147. package/src/events/domain-events.ts +2 -1
  148. package/src/followups/followup-store.ts +5 -2
  149. package/src/inbound/platform-callback-registration.ts +3 -3
  150. package/src/instrument.ts +8 -5
  151. package/src/memory/conversation-crud.ts +0 -236
  152. package/src/memory/conversation-title-service.ts +76 -11
  153. package/src/memory/db-init.ts +15 -11
  154. package/src/memory/indexer.ts +15 -106
  155. package/src/memory/items-extractor.ts +15 -1
  156. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  157. package/src/memory/job-handlers/embedding.ts +0 -79
  158. package/src/memory/job-utils.ts +1 -1
  159. package/src/memory/jobs-store.ts +30 -13
  160. package/src/memory/jobs-worker.ts +31 -27
  161. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  162. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  163. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  164. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  165. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  166. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  167. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  168. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  169. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  170. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  171. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  172. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  173. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  174. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  175. package/src/memory/migrations/116-messages-fts.ts +106 -1
  176. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  177. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  178. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  179. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  180. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  181. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  182. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  183. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  184. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  185. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  186. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  187. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  188. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  189. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  190. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  191. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  192. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  193. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  194. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  195. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  196. package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
  197. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  198. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  199. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  200. package/src/memory/migrations/index.ts +5 -3
  201. package/src/memory/migrations/registry.ts +90 -0
  202. package/src/memory/migrations/validate-migration-state.ts +137 -11
  203. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  204. package/src/memory/qdrant-client.ts +4 -6
  205. package/src/memory/qdrant-manager.ts +64 -7
  206. package/src/memory/schema/calls.ts +1 -0
  207. package/src/memory/schema/contacts.ts +1 -0
  208. package/src/memory/schema/conversations.ts +0 -3
  209. package/src/memory/schema/index.ts +0 -2
  210. package/src/messaging/draft-store.ts +2 -2
  211. package/src/notifications/decision-engine.ts +4 -1
  212. package/src/oauth/connection-resolver.ts +6 -4
  213. package/src/permissions/checker.ts +0 -38
  214. package/src/permissions/defaults.ts +3 -3
  215. package/src/permissions/shell-identity.ts +76 -22
  216. package/src/permissions/trust-client.ts +2 -13
  217. package/src/permissions/trust-store.ts +8 -3
  218. package/src/permissions/types.ts +4 -2
  219. package/src/platform/client.ts +35 -7
  220. package/src/prompts/persona-resolver.ts +138 -0
  221. package/src/prompts/system-prompt.ts +36 -4
  222. package/src/prompts/templates/users/default.md +1 -0
  223. package/src/providers/registry.ts +27 -40
  224. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  225. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  226. package/src/runtime/auth/external-assistant-id.ts +13 -59
  227. package/src/runtime/auth/route-policy.ts +29 -1
  228. package/src/runtime/auth/token-service.ts +53 -15
  229. package/src/runtime/channel-readiness-service.ts +1 -16
  230. package/src/runtime/http-server.ts +29 -2
  231. package/src/runtime/middleware/error-handler.ts +1 -9
  232. package/src/runtime/routes/audio-routes.ts +40 -0
  233. package/src/runtime/routes/btw-routes.ts +0 -17
  234. package/src/runtime/routes/conversation-management-routes.ts +0 -36
  235. package/src/runtime/routes/conversation-query-routes.ts +106 -2
  236. package/src/runtime/routes/conversation-routes.ts +4 -43
  237. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  238. package/src/runtime/routes/identity-routes.ts +18 -29
  239. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  240. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  241. package/src/runtime/routes/integrations/vercel.ts +89 -0
  242. package/src/runtime/routes/log-export-routes.ts +5 -0
  243. package/src/runtime/routes/memory-item-routes.test.ts +221 -3
  244. package/src/runtime/routes/memory-item-routes.ts +144 -4
  245. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  246. package/src/runtime/routes/migration-routes.ts +17 -1
  247. package/src/runtime/routes/notification-routes.ts +58 -0
  248. package/src/runtime/routes/schedule-routes.ts +65 -0
  249. package/src/runtime/routes/settings-routes.ts +41 -1
  250. package/src/runtime/routes/tts-routes.ts +86 -0
  251. package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
  252. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  253. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  254. package/src/runtime/routes/workspace-routes.ts +1 -1
  255. package/src/runtime/routes/workspace-utils.ts +86 -2
  256. package/src/schedule/schedule-store.ts +0 -21
  257. package/src/security/ces-credential-client.ts +59 -22
  258. package/src/security/ces-rpc-credential-backend.ts +85 -0
  259. package/src/security/credential-backend.ts +12 -88
  260. package/src/security/keychain-broker-client.ts +10 -2
  261. package/src/security/secure-keys.ts +94 -113
  262. package/src/skills/catalog-install.ts +13 -7
  263. package/src/skills/inline-command-render.ts +5 -1
  264. package/src/skills/inline-command-runner.ts +30 -2
  265. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  266. package/src/tools/calls/call-start.ts +1 -0
  267. package/src/tools/executor.ts +0 -4
  268. package/src/tools/memory/handlers.ts +1 -129
  269. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  270. package/src/tools/network/web-fetch.ts +3 -1
  271. package/src/tools/permission-checker.ts +18 -0
  272. package/src/tools/skills/execute.ts +1 -1
  273. package/src/tools/skills/load.ts +9 -2
  274. package/src/tools/types.ts +0 -8
  275. package/src/util/errors.ts +0 -12
  276. package/src/util/platform.ts +8 -55
  277. package/src/util/xml.ts +8 -0
  278. package/src/workspace/git-service.ts +5 -2
  279. package/src/workspace/heartbeat-service.ts +5 -24
  280. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  281. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  282. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  283. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  284. package/src/workspace/migrations/006-services-config.ts +49 -0
  285. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  286. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  287. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  288. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  289. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  290. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  291. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  292. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  293. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  294. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  295. package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
  296. package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
  297. package/src/workspace/migrations/registry.ts +8 -0
  298. package/src/workspace/migrations/runner.ts +106 -2
  299. package/src/workspace/migrations/types.ts +4 -0
  300. package/src/__tests__/archive-recall.test.ts +0 -560
  301. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  302. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  303. package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
  304. package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
  305. package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
  306. package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
  307. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
  308. package/src/__tests__/diagnostics-export.test.ts +0 -288
  309. package/src/__tests__/local-gateway-health.test.ts +0 -209
  310. package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
  311. package/src/__tests__/memory-brief-time.test.ts +0 -285
  312. package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
  313. package/src/__tests__/memory-chunk-archive.test.ts +0 -400
  314. package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
  315. package/src/__tests__/memory-episode-archive.test.ts +0 -370
  316. package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
  317. package/src/__tests__/memory-observation-archive.test.ts +0 -375
  318. package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
  319. package/src/__tests__/memory-reducer-job.test.ts +0 -538
  320. package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
  321. package/src/__tests__/memory-reducer-store.test.ts +0 -728
  322. package/src/__tests__/memory-reducer-types.test.ts +0 -707
  323. package/src/__tests__/memory-reducer.test.ts +0 -704
  324. package/src/__tests__/memory-simplified-config.test.ts +0 -281
  325. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  326. package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
  327. package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
  328. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  329. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  330. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  331. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  332. package/src/__tests__/swarm-recursion.test.ts +0 -197
  333. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  334. package/src/__tests__/swarm-tool.test.ts +0 -185
  335. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  336. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  337. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  338. package/src/commands/cc-command-registry.ts +0 -248
  339. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  340. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  341. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  342. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  343. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  344. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  345. package/src/config/schemas/memory-simplified.ts +0 -101
  346. package/src/config/schemas/swarm.ts +0 -82
  347. package/src/logfire.ts +0 -135
  348. package/src/memory/archive-recall.ts +0 -516
  349. package/src/memory/archive-store.ts +0 -400
  350. package/src/memory/brief-formatting.ts +0 -33
  351. package/src/memory/brief-open-loops.ts +0 -266
  352. package/src/memory/brief-time.ts +0 -162
  353. package/src/memory/brief.ts +0 -75
  354. package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
  355. package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
  356. package/src/memory/migrations/185-memory-brief-state.ts +0 -52
  357. package/src/memory/migrations/186-memory-archive.ts +0 -109
  358. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
  359. package/src/memory/reducer-scheduler.ts +0 -242
  360. package/src/memory/reducer-store.ts +0 -271
  361. package/src/memory/reducer-types.ts +0 -106
  362. package/src/memory/reducer.ts +0 -467
  363. package/src/memory/schema/memory-archive.ts +0 -121
  364. package/src/memory/schema/memory-brief.ts +0 -55
  365. package/src/runtime/local-gateway-health.ts +0 -275
  366. package/src/security/secret-ingress.ts +0 -68
  367. package/src/swarm/backend-claude-code.ts +0 -225
  368. package/src/swarm/checkpoint.ts +0 -137
  369. package/src/swarm/graph-utils.ts +0 -53
  370. package/src/swarm/index.ts +0 -55
  371. package/src/swarm/limits.ts +0 -66
  372. package/src/swarm/orchestrator.ts +0 -424
  373. package/src/swarm/plan-validator.ts +0 -117
  374. package/src/swarm/router-planner.ts +0 -162
  375. package/src/swarm/router-prompts.ts +0 -39
  376. package/src/swarm/synthesizer.ts +0 -81
  377. package/src/swarm/types.ts +0 -72
  378. package/src/swarm/worker-backend.ts +0 -131
  379. package/src/swarm/worker-prompts.ts +0 -80
  380. package/src/swarm/worker-runner.ts +0 -170
  381. package/src/tools/claude-code/claude-code.ts +0 -610
  382. package/src/tools/swarm/delegate.ts +0 -205
@@ -1,229 +0,0 @@
1
- /**
2
- * Job handler for `reduce_conversation_memory`.
3
- *
4
- * Ties together the reducer service ({@link runReducer}) and the transactional
5
- * store ({@link applyReducerResult}) to process unreduced conversation turns
6
- * as a background job.
7
- *
8
- * The handler:
9
- * 1. Loads the conversation and validates the dirty tail marker.
10
- * 2. Loads the unreduced message span (messages since the dirty tail).
11
- * 3. Loads active time contexts and open loops for the conversation's scope.
12
- * 4. Includes the current `contextSummary` when present (prepended as a
13
- * synthetic system message so the reducer has compacted context).
14
- * 5. Calls `runReducer` with the assembled input.
15
- * 6. Applies the result transactionally via `applyReducerResult`.
16
- *
17
- * If the reducer fails or returns the {@link EMPTY_REDUCER_RESULT} sentinel
18
- * (unparseable output), the checkpoint is NOT advanced — the dirty tail stays
19
- * in place so the next run retries. A valid-but-empty model response (e.g.
20
- * `{}`) returns a normal empty result that advances the checkpoint normally.
21
- */
22
-
23
- import { and, asc, eq, gte } from "drizzle-orm";
24
-
25
- import { getLogger } from "../../util/logger.js";
26
- import { type ConversationRow, getConversation } from "../conversation-crud.js";
27
- import { getDb } from "../db.js";
28
- import { asString } from "../job-utils.js";
29
- import type { MemoryJob } from "../jobs-store.js";
30
- import { type ReducerPromptInput, runReducer } from "../reducer.js";
31
- import {
32
- applyReducerResult,
33
- getActiveOpenLoops,
34
- getActiveTimeContexts,
35
- } from "../reducer-store.js";
36
- import { EMPTY_REDUCER_RESULT } from "../reducer-types.js";
37
- import { messages } from "../schema.js";
38
-
39
- const log = getLogger("reduce-conversation-memory-job");
40
-
41
- export interface ReduceConversationMemoryPayload {
42
- conversationId: string;
43
- }
44
-
45
- /**
46
- * Process a `reduce_conversation_memory` job.
47
- *
48
- * @throws Re-throws reducer errors so the job worker can classify and retry.
49
- */
50
- export async function reduceConversationMemoryJob(
51
- job: MemoryJob,
52
- ): Promise<void> {
53
- const conversationId = asString(job.payload.conversationId);
54
- if (!conversationId) {
55
- log.warn({ jobId: job.id }, "Missing conversationId in job payload");
56
- return;
57
- }
58
-
59
- // ── 1. Load conversation and validate dirty tail ────────────────
60
- const conversation = getConversation(conversationId);
61
- if (!conversation) {
62
- log.warn(
63
- { jobId: job.id, conversationId },
64
- "Conversation not found, skipping reduction",
65
- );
66
- return;
67
- }
68
-
69
- const dirtyTailMessageId = conversation.memoryDirtyTailSinceMessageId;
70
- if (!dirtyTailMessageId) {
71
- log.debug(
72
- { jobId: job.id, conversationId },
73
- "No dirty tail marker — conversation is already fully reduced",
74
- );
75
- return;
76
- }
77
-
78
- // ── 2. Load unreduced message span ──────────────────────────────
79
- const unreducedMessages = loadUnreducedMessages(
80
- conversationId,
81
- dirtyTailMessageId,
82
- );
83
-
84
- if (unreducedMessages.length === 0) {
85
- log.debug(
86
- { jobId: job.id, conversationId, dirtyTailMessageId },
87
- "No messages found from dirty tail — nothing to reduce",
88
- );
89
- return;
90
- }
91
-
92
- // ── 3. Load active brief-state context ──────────────────────────
93
- const scopeId = conversation.memoryScopeId;
94
- const now = Date.now();
95
-
96
- const existingTimeContexts = getActiveTimeContexts(scopeId, now);
97
- const existingOpenLoops = getActiveOpenLoops(scopeId);
98
-
99
- // ── 4. Build reducer input ──────────────────────────────────────
100
- const newMessages = buildNewMessages(conversation, unreducedMessages);
101
-
102
- const reducerInput: ReducerPromptInput = {
103
- conversationId,
104
- newMessages,
105
- existingTimeContexts: existingTimeContexts.map((tc) => ({
106
- id: tc.id,
107
- summary: tc.summary,
108
- })),
109
- existingOpenLoops: existingOpenLoops.map((ol) => ({
110
- id: ol.id,
111
- summary: ol.summary,
112
- status: ol.status,
113
- })),
114
- nowMs: now,
115
- scopeId,
116
- };
117
-
118
- // ── 5. Run the reducer ──────────────────────────────────────────
119
- const result = await runReducer(reducerInput);
120
-
121
- // If the reducer returns the empty sentinel, skip applying — the dirty
122
- // tail stays in place so a future run can retry.
123
- if (result === EMPTY_REDUCER_RESULT) {
124
- log.warn(
125
- { jobId: job.id, conversationId },
126
- "Reducer returned empty result — not advancing checkpoint",
127
- );
128
- return;
129
- }
130
-
131
- // ── 6. Apply result transactionally ─────────────────────────────
132
- const lastMessage = unreducedMessages[unreducedMessages.length - 1];
133
- applyReducerResult({
134
- result,
135
- conversationId,
136
- scopeId,
137
- reducedThroughMessageId: lastMessage.id,
138
- now,
139
- });
140
-
141
- log.info(
142
- {
143
- jobId: job.id,
144
- conversationId,
145
- reducedThroughMessageId: lastMessage.id,
146
- messageCount: unreducedMessages.length,
147
- timeContextOps: result.timeContexts.length,
148
- openLoopOps: result.openLoops.length,
149
- },
150
- "Conversation memory reduction completed",
151
- );
152
- }
153
-
154
- // ── Internal helpers ────────────────────────────────────────────────
155
-
156
- interface MessageRow {
157
- id: string;
158
- role: string;
159
- content: string;
160
- createdAt: number;
161
- }
162
-
163
- /**
164
- * Load messages from `dirtyTailMessageId` onward (inclusive), ordered by
165
- * createdAt ascending. Uses the message's createdAt as the boundary since
166
- * message ordering is timestamp-based.
167
- */
168
- function loadUnreducedMessages(
169
- conversationId: string,
170
- dirtyTailMessageId: string,
171
- ): MessageRow[] {
172
- const db = getDb();
173
-
174
- // First, find the createdAt of the dirty tail message
175
- const tailMessage = db
176
- .select({ createdAt: messages.createdAt })
177
- .from(messages)
178
- .where(eq(messages.id, dirtyTailMessageId))
179
- .get();
180
-
181
- if (!tailMessage) {
182
- return [];
183
- }
184
-
185
- // Load all messages from that timestamp onward
186
- return db
187
- .select({
188
- id: messages.id,
189
- role: messages.role,
190
- content: messages.content,
191
- createdAt: messages.createdAt,
192
- })
193
- .from(messages)
194
- .where(
195
- and(
196
- eq(messages.conversationId, conversationId),
197
- gte(messages.createdAt, tailMessage.createdAt),
198
- ),
199
- )
200
- .orderBy(asc(messages.createdAt))
201
- .all();
202
- }
203
-
204
- /**
205
- * Build the `newMessages` array for the reducer input.
206
- *
207
- * When the conversation has a `contextSummary` (from context window
208
- * compaction), it is prepended as a synthetic `system` message so the
209
- * reducer has access to prior compacted context.
210
- */
211
- function buildNewMessages(
212
- conversation: ConversationRow,
213
- unreducedMessages: MessageRow[],
214
- ): Array<{ role: string; content: string }> {
215
- const result: Array<{ role: string; content: string }> = [];
216
-
217
- if (conversation.contextSummary) {
218
- result.push({
219
- role: "system",
220
- content: `[Prior context summary] ${conversation.contextSummary}`,
221
- });
222
- }
223
-
224
- for (const msg of unreducedMessages) {
225
- result.push({ role: msg.role, content: msg.content });
226
- }
227
-
228
- return result;
229
- }
@@ -1,52 +0,0 @@
1
- import type { DrizzleDb } from "../db-connection.js";
2
- import { getSqliteFrom } from "../db-connection.js";
3
-
4
- /**
5
- * Create the memory brief state tables: time_contexts and open_loops.
6
- *
7
- * Both tables use CREATE TABLE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS,
8
- * making this migration inherently idempotent — safe to re-run on every startup
9
- * without a checkpoint guard.
10
- */
11
- export function migrateMemoryBriefState(database: DrizzleDb): void {
12
- const raw = getSqliteFrom(database);
13
-
14
- // -- time_contexts: bounded temporal windows for the brief --
15
- raw.exec(/*sql*/ `
16
- CREATE TABLE IF NOT EXISTS time_contexts (
17
- id TEXT PRIMARY KEY,
18
- scope_id TEXT NOT NULL,
19
- summary TEXT NOT NULL,
20
- source TEXT NOT NULL,
21
- active_from INTEGER NOT NULL,
22
- active_until INTEGER NOT NULL,
23
- created_at INTEGER NOT NULL,
24
- updated_at INTEGER NOT NULL
25
- )
26
- `);
27
-
28
- raw.exec(/*sql*/ `
29
- CREATE INDEX IF NOT EXISTS idx_time_contexts_scope_active_until
30
- ON time_contexts (scope_id, active_until)
31
- `);
32
-
33
- // -- open_loops: unresolved items the brief should surface --
34
- raw.exec(/*sql*/ `
35
- CREATE TABLE IF NOT EXISTS open_loops (
36
- id TEXT PRIMARY KEY,
37
- scope_id TEXT NOT NULL,
38
- summary TEXT NOT NULL,
39
- status TEXT NOT NULL DEFAULT 'open',
40
- source TEXT NOT NULL,
41
- due_at INTEGER,
42
- surfaced_at INTEGER,
43
- created_at INTEGER NOT NULL,
44
- updated_at INTEGER NOT NULL
45
- )
46
- `);
47
-
48
- raw.exec(/*sql*/ `
49
- CREATE INDEX IF NOT EXISTS idx_open_loops_scope_status_due
50
- ON open_loops (scope_id, status, due_at)
51
- `);
52
- }
@@ -1,109 +0,0 @@
1
- import type { DrizzleDb } from "../db-connection.js";
2
- import { getSqliteFrom } from "../db-connection.js";
3
-
4
- /**
5
- * Create the memory archive tables (memory_observations, memory_chunks,
6
- * memory_episodes) with prefetch indexes on scopeId, conversationId, and
7
- * createdAt.
8
- *
9
- * All statements use IF NOT EXISTS / IF NOT EXISTS guards so the migration
10
- * is safe to re-run on every startup.
11
- */
12
- export function migrateMemoryArchiveTables(database: DrizzleDb): void {
13
- const raw = getSqliteFrom(database);
14
-
15
- // -- memory_observations --------------------------------------------------
16
- raw.exec(/*sql*/ `
17
- CREATE TABLE IF NOT EXISTS memory_observations (
18
- id TEXT PRIMARY KEY,
19
- scope_id TEXT NOT NULL DEFAULT 'default',
20
- conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
21
- message_id TEXT REFERENCES messages(id) ON DELETE SET NULL,
22
- role TEXT NOT NULL,
23
- content TEXT NOT NULL,
24
- modality TEXT NOT NULL DEFAULT 'text',
25
- source TEXT,
26
- created_at INTEGER NOT NULL
27
- )
28
- `);
29
-
30
- raw.exec(/*sql*/ `
31
- CREATE INDEX IF NOT EXISTS idx_memory_observations_scope_id
32
- ON memory_observations (scope_id)
33
- `);
34
-
35
- raw.exec(/*sql*/ `
36
- CREATE INDEX IF NOT EXISTS idx_memory_observations_conversation_id
37
- ON memory_observations (conversation_id)
38
- `);
39
-
40
- raw.exec(/*sql*/ `
41
- CREATE INDEX IF NOT EXISTS idx_memory_observations_created_at
42
- ON memory_observations (created_at)
43
- `);
44
-
45
- // -- memory_chunks --------------------------------------------------------
46
- raw.exec(/*sql*/ `
47
- CREATE TABLE IF NOT EXISTS memory_chunks (
48
- id TEXT PRIMARY KEY,
49
- scope_id TEXT NOT NULL DEFAULT 'default',
50
- observation_id TEXT NOT NULL REFERENCES memory_observations(id) ON DELETE CASCADE,
51
- content TEXT NOT NULL,
52
- token_estimate INTEGER NOT NULL,
53
- content_hash TEXT NOT NULL,
54
- created_at INTEGER NOT NULL
55
- )
56
- `);
57
-
58
- raw.exec(/*sql*/ `
59
- CREATE INDEX IF NOT EXISTS idx_memory_chunks_scope_id
60
- ON memory_chunks (scope_id)
61
- `);
62
-
63
- raw.exec(/*sql*/ `
64
- CREATE INDEX IF NOT EXISTS idx_memory_chunks_observation_id
65
- ON memory_chunks (observation_id)
66
- `);
67
-
68
- raw.exec(/*sql*/ `
69
- CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_chunks_content_hash
70
- ON memory_chunks (scope_id, content_hash)
71
- `);
72
-
73
- raw.exec(/*sql*/ `
74
- CREATE INDEX IF NOT EXISTS idx_memory_chunks_created_at
75
- ON memory_chunks (created_at)
76
- `);
77
-
78
- // -- memory_episodes ------------------------------------------------------
79
- raw.exec(/*sql*/ `
80
- CREATE TABLE IF NOT EXISTS memory_episodes (
81
- id TEXT PRIMARY KEY,
82
- scope_id TEXT NOT NULL DEFAULT 'default',
83
- conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
84
- title TEXT NOT NULL,
85
- summary TEXT NOT NULL,
86
- token_estimate INTEGER NOT NULL,
87
- source TEXT,
88
- start_at INTEGER NOT NULL,
89
- end_at INTEGER NOT NULL,
90
- created_at INTEGER NOT NULL,
91
- updated_at INTEGER NOT NULL
92
- )
93
- `);
94
-
95
- raw.exec(/*sql*/ `
96
- CREATE INDEX IF NOT EXISTS idx_memory_episodes_scope_id
97
- ON memory_episodes (scope_id)
98
- `);
99
-
100
- raw.exec(/*sql*/ `
101
- CREATE INDEX IF NOT EXISTS idx_memory_episodes_conversation_id
102
- ON memory_episodes (conversation_id)
103
- `);
104
-
105
- raw.exec(/*sql*/ `
106
- CREATE INDEX IF NOT EXISTS idx_memory_episodes_created_at
107
- ON memory_episodes (created_at)
108
- `);
109
- }
@@ -1,19 +0,0 @@
1
- import type { DrizzleDb } from "../db-connection.js";
2
- import { getSqliteFrom } from "../db-connection.js";
3
-
4
- export function migrateMemoryReducerCheckpoints(database: DrizzleDb): void {
5
- const raw = getSqliteFrom(database);
6
- const columns = [
7
- "memory_reduced_through_message_id TEXT",
8
- "memory_dirty_tail_since_message_id TEXT",
9
- "memory_last_reduced_at INTEGER",
10
- ];
11
-
12
- for (const column of columns) {
13
- try {
14
- raw.exec(`ALTER TABLE conversations ADD COLUMN ${column}`);
15
- } catch {
16
- // Column already exists — nothing to do.
17
- }
18
- }
19
- }
@@ -1,242 +0,0 @@
1
- /**
2
- * Reducer scheduler — synchronous pre-switch/create reduction of the most
3
- * recently updated dirty conversation.
4
- *
5
- * When the user switches conversations or starts a new one, we want the
6
- * *previous* conversation's memory to be reduced before the next memory
7
- * read. This module exposes {@link reduceBeforeSwitch} which:
8
- *
9
- * 1. Finds the single most recently updated dirty conversation (excluding
10
- * the target conversation).
11
- * 2. Runs the same reduction pipeline the background job uses (load
12
- * unreduced messages, call {@link runReducer}, apply via
13
- * {@link applyReducerResult}).
14
- * 3. Awaits the result so the caller can proceed knowing memory is fresh.
15
- *
16
- * If no eligible dirty conversation exists, the function returns immediately.
17
- */
18
-
19
- import { and, asc, desc, eq, gte, isNotNull, ne } from "drizzle-orm";
20
-
21
- import { getLogger } from "../util/logger.js";
22
- import { type ConversationRow, getConversation } from "./conversation-crud.js";
23
- import { getDb } from "./db.js";
24
- import { type ReducerPromptInput, runReducer } from "./reducer.js";
25
- import {
26
- applyReducerResult,
27
- getActiveOpenLoops,
28
- getActiveTimeContexts,
29
- } from "./reducer-store.js";
30
- import { EMPTY_REDUCER_RESULT } from "./reducer-types.js";
31
- import { conversations, messages } from "./schema.js";
32
-
33
- const log = getLogger("reducer-scheduler");
34
-
35
- // ── Internal helpers ────────────────────────────────────────────────
36
-
37
- interface MessageRow {
38
- id: string;
39
- role: string;
40
- content: string;
41
- createdAt: number;
42
- }
43
-
44
- /**
45
- * Find the single most recently updated dirty conversation, excluding
46
- * the target conversation. Returns the conversation ID or null if none.
47
- */
48
- export function findMostRecentDirtyConversation(
49
- excludeConversationId: string,
50
- ): string | null {
51
- const db = getDb();
52
- const row = db
53
- .select({ id: conversations.id })
54
- .from(conversations)
55
- .where(
56
- and(
57
- isNotNull(conversations.memoryDirtyTailSinceMessageId),
58
- ne(conversations.id, excludeConversationId),
59
- ),
60
- )
61
- .orderBy(desc(conversations.updatedAt))
62
- .limit(1)
63
- .get();
64
-
65
- return row?.id ?? null;
66
- }
67
-
68
- /**
69
- * Load messages from `dirtyTailMessageId` onward (inclusive), ordered by
70
- * createdAt ascending.
71
- */
72
- function loadUnreducedMessages(
73
- conversationId: string,
74
- dirtyTailMessageId: string,
75
- ): MessageRow[] {
76
- const db = getDb();
77
-
78
- const tailMessage = db
79
- .select({ createdAt: messages.createdAt })
80
- .from(messages)
81
- .where(eq(messages.id, dirtyTailMessageId))
82
- .get();
83
-
84
- if (!tailMessage) {
85
- return [];
86
- }
87
-
88
- return db
89
- .select({
90
- id: messages.id,
91
- role: messages.role,
92
- content: messages.content,
93
- createdAt: messages.createdAt,
94
- })
95
- .from(messages)
96
- .where(
97
- and(
98
- eq(messages.conversationId, conversationId),
99
- gte(messages.createdAt, tailMessage.createdAt),
100
- ),
101
- )
102
- .orderBy(asc(messages.createdAt))
103
- .all();
104
- }
105
-
106
- /**
107
- * Build the `newMessages` array for the reducer input, optionally
108
- * prepending the conversation's contextSummary as a synthetic system message.
109
- */
110
- function buildNewMessages(
111
- conversation: ConversationRow,
112
- unreducedMessages: MessageRow[],
113
- ): Array<{ role: string; content: string }> {
114
- const result: Array<{ role: string; content: string }> = [];
115
-
116
- if (conversation.contextSummary) {
117
- result.push({
118
- role: "system",
119
- content: `[Prior context summary] ${conversation.contextSummary}`,
120
- });
121
- }
122
-
123
- for (const msg of unreducedMessages) {
124
- result.push({ role: msg.role, content: msg.content });
125
- }
126
-
127
- return result;
128
- }
129
-
130
- // ── Public API ──────────────────────────────────────────────────────
131
-
132
- /**
133
- * Reduce the most recently updated dirty conversation (excluding
134
- * `targetConversationId`) before a conversation switch or create.
135
- *
136
- * This runs the full reduction pipeline synchronously (awaiting the
137
- * provider call) so the caller can proceed knowing memory is fresh.
138
- *
139
- * Returns the conversation ID that was reduced, or null if none were eligible.
140
- */
141
- export async function reduceBeforeSwitch(
142
- targetConversationId: string,
143
- ): Promise<string | null> {
144
- const dirtyConversationId =
145
- findMostRecentDirtyConversation(targetConversationId);
146
-
147
- if (!dirtyConversationId) {
148
- return null;
149
- }
150
-
151
- const conversation = getConversation(dirtyConversationId);
152
- if (!conversation) {
153
- return null;
154
- }
155
-
156
- const dirtyTailMessageId = conversation.memoryDirtyTailSinceMessageId;
157
- if (!dirtyTailMessageId) {
158
- return null;
159
- }
160
-
161
- // ── Load unreduced messages ──────────────────────────────────
162
- const unreducedMessages = loadUnreducedMessages(
163
- dirtyConversationId,
164
- dirtyTailMessageId,
165
- );
166
-
167
- if (unreducedMessages.length === 0) {
168
- log.debug(
169
- { conversationId: dirtyConversationId, dirtyTailMessageId },
170
- "No messages found from dirty tail — nothing to reduce on switch",
171
- );
172
- return null;
173
- }
174
-
175
- // ── Load active brief-state context ──────────────────────────
176
- const scopeId = conversation.memoryScopeId;
177
- const now = Date.now();
178
-
179
- const existingTimeContexts = getActiveTimeContexts(scopeId, now);
180
- const existingOpenLoops = getActiveOpenLoops(scopeId);
181
-
182
- // ── Build reducer input ──────────────────────────────────────
183
- const newMessages = buildNewMessages(conversation, unreducedMessages);
184
-
185
- const reducerInput: ReducerPromptInput = {
186
- conversationId: dirtyConversationId,
187
- newMessages,
188
- existingTimeContexts: existingTimeContexts.map((tc) => ({
189
- id: tc.id,
190
- summary: tc.summary,
191
- })),
192
- existingOpenLoops: existingOpenLoops.map((ol) => ({
193
- id: ol.id,
194
- summary: ol.summary,
195
- status: ol.status,
196
- })),
197
- nowMs: now,
198
- scopeId,
199
- };
200
-
201
- // ── Run the reducer ──────────────────────────────────────────
202
- try {
203
- const result = await runReducer(reducerInput);
204
-
205
- if (result === EMPTY_REDUCER_RESULT) {
206
- log.debug(
207
- { conversationId: dirtyConversationId },
208
- "Reducer returned empty result on switch — not advancing checkpoint",
209
- );
210
- return null;
211
- }
212
-
213
- // ── Apply result transactionally ───────────────────────────
214
- const lastMessage = unreducedMessages[unreducedMessages.length - 1];
215
- applyReducerResult({
216
- result,
217
- conversationId: dirtyConversationId,
218
- scopeId,
219
- reducedThroughMessageId: lastMessage.id,
220
- now,
221
- });
222
-
223
- log.info(
224
- {
225
- conversationId: dirtyConversationId,
226
- reducedThroughMessageId: lastMessage.id,
227
- messageCount: unreducedMessages.length,
228
- timeContextOps: result.timeContexts.length,
229
- openLoopOps: result.openLoops.length,
230
- },
231
- "Pre-switch memory reduction completed",
232
- );
233
-
234
- return dirtyConversationId;
235
- } catch (err) {
236
- log.warn(
237
- { err, conversationId: dirtyConversationId },
238
- "Pre-switch memory reduction failed — continuing with switch",
239
- );
240
- return null;
241
- }
242
- }