@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,626 +0,0 @@
1
- /**
2
- * Tests for dual-writing archive episodes from compaction summaries.
3
- *
4
- * Verifies:
5
- * - Normal compaction triggers an episode insertion
6
- * - Overflow (preflight) compaction triggers an episode insertion
7
- * - No episode is created when compaction does not produce a new summary
8
- */
9
- import { beforeEach, describe, expect, mock, test } from "bun:test";
10
-
11
- import type {
12
- AgentEvent,
13
- CheckpointDecision,
14
- CheckpointInfo,
15
- } from "../agent/loop.js";
16
- import type { ContextWindowResult } from "../context/window-manager.js";
17
- import type { ServerMessage } from "../daemon/message-protocol.js";
18
- import type { Message } from "../providers/types.js";
19
-
20
- // ── Module mocks (must precede imports of the module under test) ─────
21
-
22
- mock.module("../util/logger.js", () => ({
23
- getLogger: () =>
24
- new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
25
- }));
26
-
27
- mock.module("../util/platform.js", () => ({
28
- getDataDir: () => "/tmp",
29
- }));
30
-
31
- mock.module("../config/loader.js", () => ({
32
- getConfig: () => ({
33
- provider: "mock-provider",
34
- maxTokens: 4096,
35
- thinking: false,
36
- contextWindow: {
37
- maxInputTokens: 100000,
38
- thresholdTokens: 80000,
39
- preserveRecentMessages: 6,
40
- summaryModel: "mock-model",
41
- maxSummaryTokens: 512,
42
- overflowRecovery: {
43
- enabled: true,
44
- safetyMarginRatio: 0.05,
45
- maxAttempts: 3,
46
- interactiveLatestTurnCompression: "summarize",
47
- nonInteractiveLatestTurnCompression: "truncate",
48
- },
49
- },
50
- rateLimit: { maxRequestsPerMinute: 0 },
51
- workspaceGit: { turnCommitMaxWaitMs: 10 },
52
- ui: {},
53
- }),
54
- loadRawConfig: () => ({}),
55
- saveRawConfig: () => {},
56
- invalidateConfigCache: () => {},
57
- }));
58
-
59
- // Token estimator — small by default to avoid preflight trigger
60
- let mockEstimateTokens = 1000;
61
- mock.module("../context/token-estimator.js", () => ({
62
- estimatePromptTokens: () => mockEstimateTokens,
63
- }));
64
-
65
- // Reducer
66
- let mockReducerStepFn:
67
- | ((msgs: Message[], cfg: unknown, state: unknown) => unknown)
68
- | null = null;
69
- mock.module("../daemon/context-overflow-reducer.js", () => ({
70
- createInitialReducerState: () => ({
71
- appliedTiers: [],
72
- injectionMode: "full" as const,
73
- exhausted: false,
74
- }),
75
- reduceContextOverflow: async (
76
- msgs: Message[],
77
- cfg: unknown,
78
- state: unknown,
79
- ) => {
80
- if (mockReducerStepFn) return mockReducerStepFn(msgs, cfg, state);
81
- return {
82
- messages: msgs,
83
- tier: "forced_compaction",
84
- state: {
85
- appliedTiers: [
86
- "forced_compaction",
87
- "tool_result_truncation",
88
- "media_stubbing",
89
- "injection_downgrade",
90
- ],
91
- injectionMode: "full",
92
- exhausted: true,
93
- },
94
- estimatedTokens: 1000,
95
- };
96
- },
97
- }));
98
-
99
- mock.module("../daemon/context-overflow-policy.js", () => ({
100
- resolveOverflowAction: () => "fail_gracefully",
101
- }));
102
-
103
- mock.module("../daemon/context-overflow-approval.js", () => ({
104
- requestCompressionApproval: async () => ({ approved: false }),
105
- CONTEXT_OVERFLOW_TOOL_NAME: "context_overflow_compression",
106
- }));
107
-
108
- mock.module("../hooks/manager.js", () => ({
109
- getHookManager: () => ({
110
- trigger: async () => ({ blocked: false }),
111
- }),
112
- }));
113
-
114
- mock.module("../memory/conversation-crud.js", () => ({
115
- getConversationType: () => "default",
116
- setConversationOriginChannelIfUnset: () => {},
117
- updateConversationUsage: () => {},
118
- getMessages: () => [],
119
- getConversation: () => ({
120
- id: "conv-1",
121
- contextSummary: null,
122
- contextCompactedMessageCount: 0,
123
- totalInputTokens: 0,
124
- totalOutputTokens: 0,
125
- totalEstimatedCost: 0,
126
- title: null,
127
- }),
128
- provenanceFromTrustContext: () => ({
129
- source: "user",
130
- trustContext: undefined,
131
- }),
132
- getConversationOriginInterface: () => null,
133
- addMessage: () => ({ id: "mock-msg-id" }),
134
- deleteMessageById: () => {},
135
- updateConversationContextWindow: () => {},
136
- updateConversationTitle: () => {},
137
- getConversationOriginChannel: () => null,
138
- }));
139
-
140
- mock.module("../memory/conversation-disk-view.js", () => ({
141
- syncMessageToDisk: () => {},
142
- rebuildConversationDiskViewFromDbState: () => {},
143
- }));
144
-
145
- mock.module("../memory/retriever.js", () => ({
146
- buildMemoryRecall: async () => ({
147
- enabled: false,
148
- degraded: false,
149
- injectedText: "",
150
- semanticHits: 0,
151
- recencyHits: 0,
152
- injectedTokens: 0,
153
- latencyMs: 0,
154
- }),
155
- injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
156
- }));
157
-
158
- mock.module("../memory/app-store.js", () => ({
159
- getApp: () => null,
160
- listAppFiles: () => [],
161
- getAppsDir: () => "/tmp/apps",
162
- }));
163
-
164
- mock.module("../memory/app-git-service.js", () => ({
165
- commitAppTurnChanges: () => Promise.resolve(),
166
- }));
167
-
168
- mock.module("../daemon/conversation-memory.js", () => ({
169
- prepareMemoryContext: async (
170
- _ctx: unknown,
171
- _content: string,
172
- _id: string,
173
- _signal: AbortSignal,
174
- ) => ({
175
- runMessages: [],
176
- recall: {
177
- enabled: false,
178
- degraded: false,
179
- injectedText: "",
180
- semanticHits: 0,
181
- recencyHits: 0,
182
- injectedTokens: 0,
183
- latencyMs: 0,
184
- tier1Count: 0,
185
- tier2Count: 0,
186
- hybridSearchMs: 0,
187
- },
188
- }),
189
- }));
190
-
191
- mock.module("../daemon/conversation-runtime-assembly.js", () => ({
192
- applyRuntimeInjections: (msgs: Message[]) => msgs,
193
- stripInjectedContext: (msgs: Message[]) => msgs,
194
- }));
195
-
196
- mock.module("../daemon/date-context.js", () => ({
197
- buildTemporalContext: () => null,
198
- }));
199
-
200
- mock.module("../daemon/history-repair.js", () => ({
201
- repairHistory: (msgs: Message[]) => ({
202
- messages: msgs,
203
- stats: {
204
- assistantToolResultsMigrated: 0,
205
- missingToolResultsInserted: 0,
206
- orphanToolResultsDowngraded: 0,
207
- consecutiveSameRoleMerged: 0,
208
- },
209
- }),
210
- deepRepairHistory: (msgs: Message[]) => ({ messages: msgs, stats: {} }),
211
- }));
212
-
213
- mock.module("../daemon/conversation-history.js", () => ({
214
- consolidateAssistantMessages: () => false,
215
- }));
216
-
217
- mock.module("../daemon/conversation-usage.js", () => ({
218
- recordUsage: () => {},
219
- }));
220
-
221
- mock.module("../daemon/conversation-attachments.js", () => ({
222
- resolveAssistantAttachments: async () => ({
223
- assistantAttachments: [],
224
- emittedAttachments: [],
225
- directiveWarnings: [],
226
- }),
227
- approveHostAttachmentRead: async () => true,
228
- formatAttachmentWarnings: () => "",
229
- }));
230
-
231
- mock.module("../daemon/assistant-attachments.js", () => ({
232
- cleanAssistantContent: (content: unknown[]) => ({
233
- cleanedContent: content,
234
- directives: [],
235
- warnings: [],
236
- }),
237
- drainDirectiveDisplayBuffer: (buffer: string) => ({
238
- emitText: buffer,
239
- bufferedRemainder: "",
240
- }),
241
- }));
242
-
243
- mock.module("../daemon/conversation-media-retry.js", () => ({
244
- stripMediaPayloadsForRetry: (msgs: Message[]) => ({
245
- messages: msgs,
246
- modified: false,
247
- replacedBlocks: 0,
248
- latestUserIndex: null,
249
- }),
250
- raceWithTimeout: async () => "completed" as const,
251
- }));
252
-
253
- mock.module("../workspace/turn-commit.js", () => ({
254
- commitTurnChanges: async () => {},
255
- }));
256
-
257
- mock.module("../workspace/git-service.js", () => ({
258
- getWorkspaceGitService: () => ({
259
- ensureInitialized: async () => {},
260
- }),
261
- }));
262
-
263
- mock.module("../daemon/conversation-error.js", () => ({
264
- classifyConversationError: (_err: unknown, _ctx: unknown) => ({
265
- code: "CONVERSATION_PROCESSING_FAILED",
266
- userMessage: "Something went wrong processing your message.",
267
- retryable: false,
268
- errorCategory: "processing_failed",
269
- }),
270
- isUserCancellation: (err: unknown, ctx: { aborted?: boolean }) => {
271
- if (!ctx.aborted) return false;
272
- if (err instanceof DOMException && err.name === "AbortError") return true;
273
- if (err instanceof Error && err.name === "AbortError") return true;
274
- return false;
275
- },
276
- buildConversationErrorMessage: (
277
- conversationId: string,
278
- classified: Record<string, unknown>,
279
- ) => ({
280
- type: "conversation_error",
281
- conversationId,
282
- ...classified,
283
- }),
284
- isContextTooLarge: (msg: string) => /context.?length.?exceeded/i.test(msg),
285
- }));
286
-
287
- mock.module("../daemon/conversation-slash.js", () => ({
288
- isProviderOrderingError: (msg: string) =>
289
- /ordering|before.*after|messages.*order/i.test(msg),
290
- }));
291
-
292
- mock.module("../util/truncate.js", () => ({
293
- truncate: (s: string, maxLen: number) =>
294
- s.length <= maxLen ? s : s.slice(0, maxLen),
295
- }));
296
-
297
- mock.module("../agent/message-types.js", () => ({
298
- createAssistantMessage: (text: string) => ({
299
- role: "assistant" as const,
300
- content: [{ type: "text", text }],
301
- }),
302
- }));
303
-
304
- mock.module("../memory/llm-request-log-store.js", () => ({
305
- recordRequestLog: () => {},
306
- backfillMessageIdOnLogs: () => {},
307
- }));
308
-
309
- // ── Archive store mock — tracks insertCompactionEpisode calls ────────
310
-
311
- const insertCompactionEpisodeCalls: Array<{
312
- conversationId: string;
313
- scopeId?: string;
314
- title: string;
315
- summary: string;
316
- tokenEstimate: number;
317
- }> = [];
318
-
319
- mock.module("../memory/archive-store.js", () => ({
320
- insertCompactionEpisode: (params: {
321
- conversationId: string;
322
- scopeId?: string;
323
- title: string;
324
- summary: string;
325
- tokenEstimate: number;
326
- startAt: number;
327
- endAt: number;
328
- }) => {
329
- insertCompactionEpisodeCalls.push({
330
- conversationId: params.conversationId,
331
- scopeId: params.scopeId,
332
- title: params.title,
333
- summary: params.summary,
334
- tokenEstimate: params.tokenEstimate,
335
- });
336
- return { episodeId: "mock-episode-id", jobId: "mock-job-id" };
337
- },
338
- }));
339
-
340
- // ── Imports (after mocks) ────────────────────────────────────────────
341
-
342
- import {
343
- type AgentLoopConversationContext,
344
- runAgentLoopImpl,
345
- } from "../daemon/conversation-agent-loop.js";
346
-
347
- // ── Test helpers ─────────────────────────────────────────────────────
348
-
349
- type AgentLoopRun = (
350
- messages: Message[],
351
- onEvent: (event: AgentEvent) => void,
352
- signal?: AbortSignal,
353
- requestId?: string,
354
- onCheckpoint?: (checkpoint: CheckpointInfo) => CheckpointDecision,
355
- ) => Promise<Message[]>;
356
-
357
- function makeCompactResult(
358
- summaryText: string,
359
- overrides?: Partial<ContextWindowResult>,
360
- ): ContextWindowResult {
361
- return {
362
- messages: [
363
- {
364
- role: "user",
365
- content: [{ type: "text", text: `[Summary] ${summaryText}` }],
366
- },
367
- ] as Message[],
368
- compacted: true,
369
- previousEstimatedInputTokens: 80000,
370
- estimatedInputTokens: 30000,
371
- maxInputTokens: 100000,
372
- thresholdTokens: 80000,
373
- compactedMessages: 10,
374
- compactedPersistedMessages: 8,
375
- summaryCalls: 1,
376
- summaryInputTokens: 500,
377
- summaryOutputTokens: 150,
378
- summaryModel: "mock-model",
379
- summaryText,
380
- ...overrides,
381
- };
382
- }
383
-
384
- function makeCtx(
385
- overrides?: Partial<AgentLoopConversationContext> & {
386
- agentLoopRun?: AgentLoopRun;
387
- },
388
- ): AgentLoopConversationContext {
389
- const agentLoopRun =
390
- overrides?.agentLoopRun ??
391
- (async (messages: Message[]) => [
392
- ...messages,
393
- {
394
- role: "assistant" as const,
395
- content: [{ type: "text" as const, text: "response" }],
396
- },
397
- ]);
398
-
399
- return {
400
- conversationId: "test-conv",
401
- messages: [
402
- { role: "user", content: [{ type: "text", text: "Hello" }] },
403
- ] as Message[],
404
- processing: true,
405
- abortController: new AbortController(),
406
- currentRequestId: "test-req",
407
-
408
- agentLoop: {
409
- run: agentLoopRun,
410
- getToolTokenBudget: () => 0,
411
- } as unknown as AgentLoopConversationContext["agentLoop"],
412
- provider: {
413
- name: "mock-provider",
414
- sendMessage: async () => ({
415
- content: [{ type: "text", text: "title" }],
416
- model: "mock",
417
- usage: { inputTokens: 0, outputTokens: 0 },
418
- stopReason: "end_turn",
419
- }),
420
- } as unknown as AgentLoopConversationContext["provider"],
421
- systemPrompt: "system prompt",
422
-
423
- contextWindowManager: {
424
- shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
425
- maybeCompact: async () => ({ compacted: false }),
426
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
427
- contextCompactedMessageCount: 0,
428
- contextCompactedAt: null,
429
-
430
- memoryPolicy: { scopeId: "default", includeDefaultFallback: true },
431
-
432
- currentActiveSurfaceId: undefined,
433
- currentPage: undefined,
434
- surfaceState: new Map(),
435
- pendingSurfaceActions: new Map(),
436
- surfaceActionRequestIds: new Set<string>(),
437
- currentTurnSurfaces: [],
438
-
439
- workingDir: "/tmp",
440
- workspaceTopLevelContext: null,
441
- workspaceTopLevelDirty: false,
442
- channelCapabilities: undefined,
443
- commandIntent: undefined,
444
- trustContext: undefined,
445
-
446
- coreToolNames: new Set(),
447
- allowedToolNames: undefined,
448
- preactivatedSkillIds: undefined,
449
- skillProjectionState: new Map(),
450
- skillProjectionCache:
451
- new Map() as unknown as AgentLoopConversationContext["skillProjectionCache"],
452
-
453
- traceEmitter: {
454
- emit: () => {},
455
- } as unknown as AgentLoopConversationContext["traceEmitter"],
456
- profiler: {
457
- startRequest: () => {},
458
- emitSummary: () => {},
459
- } as unknown as AgentLoopConversationContext["profiler"],
460
- usageStats: {
461
- totalInputTokens: 0,
462
- totalOutputTokens: 0,
463
- totalEstimatedCost: 0,
464
- model: "",
465
- },
466
- turnCount: 0,
467
-
468
- lastAssistantAttachments: [],
469
- lastAttachmentWarnings: [],
470
-
471
- hasNoClient: false,
472
- streamThinking: false,
473
- prompter: {} as unknown as AgentLoopConversationContext["prompter"],
474
- queue: {} as unknown as AgentLoopConversationContext["queue"],
475
-
476
- getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
477
- commitTurnChanges: async () => {},
478
-
479
- refreshWorkspaceTopLevelContextIfNeeded: () => {},
480
- markWorkspaceTopLevelDirty: () => {},
481
- emitActivityState: () => {},
482
- emitConfirmationStateChanged: () => {},
483
- getQueueDepth: () => 0,
484
- hasQueuedMessages: () => false,
485
- canHandoffAtCheckpoint: () => false,
486
- drainQueue: () => {},
487
- getTurnInterfaceContext: () => null,
488
- getTurnChannelContext: () => ({
489
- userMessageChannel: "vellum" as const,
490
- assistantMessageChannel: "vellum" as const,
491
- }),
492
-
493
- toolsDisabledDepth: 0,
494
-
495
- ...overrides,
496
- } as AgentLoopConversationContext;
497
- }
498
-
499
- // ── Tests ────────────────────────────────────────────────────────────
500
-
501
- beforeEach(() => {
502
- insertCompactionEpisodeCalls.length = 0;
503
- mockEstimateTokens = 1000;
504
- mockReducerStepFn = null;
505
- });
506
-
507
- describe("memory episode dual-write from compaction", () => {
508
- test("normal compaction creates a compaction episode", async () => {
509
- const summaryText =
510
- "User discussed project blockers and asked about deployment timeline.";
511
- const compactResult = makeCompactResult(summaryText);
512
-
513
- const ctx = makeCtx({
514
- contextWindowManager: {
515
- shouldCompact: () => ({ needed: true, estimatedTokens: 85000 }),
516
- maybeCompact: async () => compactResult,
517
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
518
- });
519
-
520
- await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
521
-
522
- expect(insertCompactionEpisodeCalls.length).toBe(1);
523
- expect(insertCompactionEpisodeCalls[0]!.conversationId).toBe("test-conv");
524
- expect(insertCompactionEpisodeCalls[0]!.scopeId).toBe("default");
525
- expect(insertCompactionEpisodeCalls[0]!.summary).toBe(summaryText);
526
- expect(insertCompactionEpisodeCalls[0]!.tokenEstimate).toBe(150);
527
- });
528
-
529
- test("overflow (preflight) compaction creates a compaction episode", async () => {
530
- // Make the preflight budget check trigger by returning a high token count
531
- mockEstimateTokens = 200000;
532
-
533
- const summaryText = "Overflow compaction summary of earlier conversation.";
534
- const compactResult = makeCompactResult(summaryText, {
535
- summaryOutputTokens: 200,
536
- });
537
-
538
- // The reducer step must trigger compaction via its compactionResult
539
- mockReducerStepFn = (_msgs: Message[]) => ({
540
- messages: compactResult.messages,
541
- tier: "forced_compaction",
542
- state: {
543
- appliedTiers: [
544
- "forced_compaction",
545
- "tool_result_truncation",
546
- "media_stubbing",
547
- "injection_downgrade",
548
- ],
549
- injectionMode: "full",
550
- exhausted: true,
551
- },
552
- estimatedTokens: 30000,
553
- compactionResult: compactResult,
554
- });
555
-
556
- const ctx = makeCtx({
557
- contextWindowManager: {
558
- shouldCompact: () => ({ needed: false, estimatedTokens: 200000 }),
559
- maybeCompact: async () => ({ compacted: false }),
560
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
561
- });
562
-
563
- await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
564
-
565
- expect(insertCompactionEpisodeCalls.length).toBe(1);
566
- expect(insertCompactionEpisodeCalls[0]!.conversationId).toBe("test-conv");
567
- expect(insertCompactionEpisodeCalls[0]!.summary).toBe(summaryText);
568
- expect(insertCompactionEpisodeCalls[0]!.tokenEstimate).toBe(200);
569
- });
570
-
571
- test("no episode created when compaction does not produce a new summary", async () => {
572
- // Compaction returns compacted: false — no new summary was produced
573
- const ctx = makeCtx({
574
- contextWindowManager: {
575
- shouldCompact: () => ({ needed: false, estimatedTokens: 5000 }),
576
- maybeCompact: async () => ({ compacted: false }),
577
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
578
- });
579
-
580
- await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
581
-
582
- expect(insertCompactionEpisodeCalls.length).toBe(0);
583
- });
584
-
585
- test("episode uses the conversation's memory scope", async () => {
586
- const summaryText = "Scoped compaction summary.";
587
- const compactResult = makeCompactResult(summaryText);
588
-
589
- const ctx = makeCtx({
590
- memoryPolicy: { scopeId: "project-alpha", includeDefaultFallback: false },
591
- contextWindowManager: {
592
- shouldCompact: () => ({ needed: true, estimatedTokens: 85000 }),
593
- maybeCompact: async () => compactResult,
594
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
595
- });
596
-
597
- await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
598
-
599
- expect(insertCompactionEpisodeCalls.length).toBe(1);
600
- expect(insertCompactionEpisodeCalls[0]!.scopeId).toBe("project-alpha");
601
- });
602
-
603
- test("existing contextSummary persistence is unchanged alongside episode write", async () => {
604
- const events: ServerMessage[] = [];
605
- const summaryText =
606
- "Compaction summary that should be persisted in both places.";
607
- const compactResult = makeCompactResult(summaryText);
608
-
609
- const ctx = makeCtx({
610
- contextWindowManager: {
611
- shouldCompact: () => ({ needed: true, estimatedTokens: 85000 }),
612
- maybeCompact: async () => compactResult,
613
- } as unknown as AgentLoopConversationContext["contextWindowManager"],
614
- });
615
-
616
- await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
617
-
618
- // The context_compacted event should still be emitted (existing behavior)
619
- const compactEvent = events.find((e) => e.type === "context_compacted");
620
- expect(compactEvent).toBeDefined();
621
-
622
- // And the episode should also be created (new dual-write behavior)
623
- expect(insertCompactionEpisodeCalls.length).toBe(1);
624
- expect(insertCompactionEpisodeCalls[0]!.summary).toBe(summaryText);
625
- });
626
- });