@vellumai/assistant 0.10.4-staging.1 → 0.10.4

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 (1999) hide show
  1. package/ARCHITECTURE.md +13 -13
  2. package/bun.lock +165 -0
  3. package/docs/architecture/memory.md +26 -0
  4. package/eslint-rules/cli-no-daemon-internals.js +9 -8
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +18 -0
  6. package/openapi.yaml +677 -15
  7. package/package.json +8 -1
  8. package/scripts/generate-openapi.ts +149 -62
  9. package/src/__tests__/acp-session.test.ts +2 -2
  10. package/src/__tests__/activation-early-marking.test.ts +4 -4
  11. package/src/__tests__/actor-token-service.test.ts +2 -3
  12. package/src/__tests__/agent-loop-compaction-events.test.ts +1 -0
  13. package/src/__tests__/agent-loop-compaction-strip.test.ts +2 -0
  14. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -1
  15. package/src/__tests__/agent-loop-override-profile.test.ts +2 -2
  16. package/src/__tests__/agent-loop-regrowth-guard.test.ts +8 -0
  17. package/src/__tests__/agent-loop.test.ts +1 -0
  18. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +3 -3
  19. package/src/__tests__/agent-wake-override-profile.test.ts +3 -3
  20. package/src/__tests__/annotate-activity-metadata.test.ts +4 -4
  21. package/src/__tests__/annotate-risk-options.test.ts +4 -4
  22. package/src/__tests__/anthropic-provider.test.ts +53 -2
  23. package/src/__tests__/app-builder-tool-scripts.test.ts +2 -2
  24. package/src/__tests__/app-bundler.test.ts +1 -1
  25. package/src/__tests__/app-conversation-ids-backfill.test.ts +4 -4
  26. package/src/__tests__/app-conversation-ids.test.ts +1 -1
  27. package/src/__tests__/app-dir-path-guard.test.ts +2 -2
  28. package/src/__tests__/app-executors.test.ts +1 -1
  29. package/src/__tests__/app-git-history.test.ts +2 -2
  30. package/src/__tests__/app-git-service.test.ts +2 -2
  31. package/src/__tests__/app-routes-csp.test.ts +2 -2
  32. package/src/__tests__/app-source-watcher.test.ts +1 -1
  33. package/src/__tests__/app-store-dir-names.test.ts +1 -1
  34. package/src/__tests__/approval-cascade.test.ts +7 -7
  35. package/src/__tests__/approval-interception-trust-gates.test.ts +1 -1
  36. package/src/__tests__/approval-primitive.test.ts +3 -3
  37. package/src/__tests__/approval-routes-http.test.ts +2 -2
  38. package/src/__tests__/assistant-event-hub-machine-name.test.ts +1 -1
  39. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -2
  40. package/src/__tests__/assistant-events-sse-shed.test.ts +2 -2
  41. package/src/__tests__/attachment-upload-trusted-source.test.ts +4 -2
  42. package/src/__tests__/attachments-store.test.ts +9 -6
  43. package/src/__tests__/audit-log-rotation.test.ts +6 -4
  44. package/src/__tests__/auth-fallback-events-store.test.ts +4 -4
  45. package/src/__tests__/auto-analysis-end-to-end.test.ts +13 -9
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +12 -7
  47. package/src/__tests__/btw-routes.test.ts +4 -5
  48. package/src/__tests__/build-persisted-content.test.ts +4 -4
  49. package/src/__tests__/call-controller.test.ts +6 -6
  50. package/src/__tests__/call-conversation-messages.test.ts +4 -4
  51. package/src/__tests__/call-domain.test.ts +5 -5
  52. package/src/__tests__/call-pointer-messages.test.ts +5 -5
  53. package/src/__tests__/call-recovery.test.ts +3 -3
  54. package/src/__tests__/call-routes-http.test.ts +3 -3
  55. package/src/__tests__/call-store.test.ts +3 -3
  56. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -2
  57. package/src/__tests__/canonical-guardian-store.test.ts +3 -3
  58. package/src/__tests__/channel-approval-routes.test.ts +9 -7
  59. package/src/__tests__/channel-delivery-store.test.ts +8 -8
  60. package/src/__tests__/channel-guardian.test.ts +24 -66
  61. package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
  62. package/src/__tests__/channel-reply-delivery.test.ts +2 -2
  63. package/src/__tests__/channel-retry-sweep.test.ts +49 -4
  64. package/src/__tests__/clawhub.test.ts +4 -0
  65. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  66. package/src/__tests__/compaction-events.test.ts +8 -8
  67. package/src/__tests__/compaction-ledger-store.test.ts +4 -4
  68. package/src/__tests__/compaction-trail-store.test.ts +5 -5
  69. package/src/__tests__/compaction.benchmark.test.ts +5 -5
  70. package/src/__tests__/compactor-call-site-logging.test.ts +5 -5
  71. package/src/__tests__/compactor-image-manifest-trust.test.ts +7 -4
  72. package/src/__tests__/compactor-low-watermark-cut.test.ts +5 -5
  73. package/src/__tests__/compactor-preserved-tail-count.test.ts +4 -4
  74. package/src/__tests__/compactor-summary-call-truncation.test.ts +5 -5
  75. package/src/__tests__/compactor-web-search-strip.test.ts +4 -4
  76. package/src/__tests__/config-get-vision-flag.test.ts +1 -1
  77. package/src/__tests__/config-loader-backfill.test.ts +84 -104
  78. package/src/__tests__/config-set-route.test.ts +5 -2
  79. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +3 -3
  80. package/src/__tests__/config-watcher-skill-reseed.test.ts +39 -112
  81. package/src/__tests__/config-watcher.test.ts +54 -31
  82. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -4
  83. package/src/__tests__/contact-store-interaction-info.test.ts +3 -3
  84. package/src/__tests__/contact-store-user-file.test.ts +91 -81
  85. package/src/__tests__/contacts-relay-reads.test.ts +21 -3
  86. package/src/__tests__/contacts-tools.test.ts +2 -2
  87. package/src/__tests__/contacts-write.test.ts +2 -2
  88. package/src/__tests__/context-search-agent-protocol.test.ts +2 -2
  89. package/src/__tests__/context-search-agent-runner.test.ts +2 -2
  90. package/src/__tests__/context-search-conversations-source.test.ts +5 -5
  91. package/src/__tests__/context-search-fanout.test.ts +3 -3
  92. package/src/__tests__/context-search-memory-source.test.ts +9 -8
  93. package/src/__tests__/context-search-memory-v2-source.test.ts +9 -8
  94. package/src/__tests__/context-search-types.test.ts +2 -2
  95. package/src/__tests__/context-search-workspace-source.test.ts +2 -2
  96. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -5
  97. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -3
  98. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +39 -11
  99. package/src/__tests__/conversation-agent-loop-overflow.test.ts +6 -6
  100. package/src/__tests__/conversation-agent-loop.test.ts +51 -13
  101. package/src/__tests__/conversation-analysis-routes.test.ts +4 -4
  102. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -1
  103. package/src/__tests__/conversation-app-control-lifecycle.test.ts +7 -7
  104. package/src/__tests__/conversation-attachments.test.ts +7 -4
  105. package/src/__tests__/conversation-attention-store.test.ts +4 -4
  106. package/src/__tests__/conversation-attention-telegram.test.ts +8 -5
  107. package/src/__tests__/conversation-clear-safety.test.ts +3 -3
  108. package/src/__tests__/conversation-confirmation-signals.test.ts +7 -7
  109. package/src/__tests__/conversation-crud-inference-profile.test.ts +3 -3
  110. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +25 -25
  111. package/src/__tests__/conversation-directories-parse.test.ts +1 -1
  112. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -5
  113. package/src/__tests__/conversation-disk-view.test.ts +6 -6
  114. package/src/__tests__/conversation-evictor.test.ts +32 -7
  115. package/src/__tests__/conversation-fork-crud.test.ts +24 -21
  116. package/src/__tests__/conversation-fork-retrospective.test.ts +12 -10
  117. package/src/__tests__/conversation-fork-route.test.ts +6 -3
  118. package/src/__tests__/conversation-history-web-search.test.ts +8 -8
  119. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -3
  120. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -3
  121. package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
  122. package/src/__tests__/conversation-key-store-disk-view.test.ts +7 -4
  123. package/src/__tests__/conversation-lifecycle.test.ts +10 -13
  124. package/src/__tests__/conversation-list-source.test.ts +3 -3
  125. package/src/__tests__/conversation-load-history-repair.test.ts +4 -4
  126. package/src/__tests__/conversation-load-history-stripped.test.ts +4 -4
  127. package/src/__tests__/conversation-pairing.test.ts +4 -4
  128. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +5 -5
  129. package/src/__tests__/conversation-process-callsite.test.ts +5 -5
  130. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -5
  131. package/src/__tests__/conversation-queue.test.ts +55 -9
  132. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -5
  133. package/src/__tests__/conversation-routes-guardian-reply.test.ts +6 -6
  134. package/src/__tests__/conversation-routes-slash-commands.test.ts +57 -10
  135. package/src/__tests__/conversation-runtime-assembly.test.ts +25 -19
  136. package/src/__tests__/conversation-runtime-workspace.test.ts +8 -1
  137. package/src/__tests__/conversation-skill-tools.test.ts +155 -2
  138. package/src/__tests__/conversation-slash-queue.test.ts +6 -6
  139. package/src/__tests__/conversation-slash-unknown.test.ts +6 -6
  140. package/src/__tests__/conversation-speed-override.test.ts +7 -7
  141. package/src/__tests__/conversation-starter-routes.test.ts +2 -2
  142. package/src/__tests__/conversation-store.test.ts +6 -6
  143. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +8 -5
  144. package/src/__tests__/conversation-surfaces-data-persist.test.ts +2 -2
  145. package/src/__tests__/conversation-sync-tags.test.ts +7 -4
  146. package/src/__tests__/conversation-title-service.test.ts +2 -3
  147. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  148. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  149. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  150. package/src/__tests__/conversation-usage.test.ts +6 -6
  151. package/src/__tests__/conversation-wipe.test.ts +6 -4
  152. package/src/__tests__/conversation-workspace-cache-state.test.ts +9 -9
  153. package/src/__tests__/conversation-workspace-injection.test.ts +9 -9
  154. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +9 -9
  155. package/src/__tests__/conversations-import-system-filter.test.ts +5 -5
  156. package/src/__tests__/credential-security-invariants.test.ts +4 -4
  157. package/src/__tests__/db-acp-history.test.ts +4 -4
  158. package/src/__tests__/db-activation-state-fk-cascade.test.ts +4 -4
  159. package/src/__tests__/db-activation-state.test.ts +3 -3
  160. package/src/__tests__/db-compaction-events-migration.test.ts +3 -3
  161. package/src/__tests__/db-connection-isolation.test.ts +1 -1
  162. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +3 -3
  163. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -6
  164. package/src/__tests__/db-drop-contact-acl-columns-migration.test.ts +159 -0
  165. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +3 -3
  166. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +3 -3
  167. package/src/__tests__/db-migration-rollback.test.ts +48 -43
  168. package/src/__tests__/db-proxy-transaction.test.ts +2 -2
  169. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +3 -3
  170. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -4
  171. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +3 -3
  172. package/src/__tests__/db-slack-external-content-normalization.test.ts +4 -4
  173. package/src/__tests__/db-test-helpers.ts +7 -0
  174. package/src/__tests__/delete-propagation.test.ts +4 -4
  175. package/src/__tests__/deterministic-verification-control-plane.test.ts +3 -3
  176. package/src/__tests__/device-id.test.ts +38 -1
  177. package/src/__tests__/dm-backfill.test.ts +3 -3
  178. package/src/__tests__/dm-persistence.test.ts +5 -5
  179. package/src/__tests__/document-conversations.test.ts +3 -3
  180. package/src/__tests__/document-create-dedupe.test.ts +1 -1
  181. package/src/__tests__/document-find-replace.test.ts +1 -1
  182. package/src/__tests__/document-tool-security.test.ts +1 -1
  183. package/src/__tests__/document-update-default-surface.test.ts +1 -1
  184. package/src/__tests__/drop-capability-card-state-migration.test.ts +3 -5
  185. package/src/__tests__/edit-propagation.test.ts +6 -6
  186. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  187. package/src/__tests__/empty-state-greeting-cache.test.ts +1 -1
  188. package/src/__tests__/events-client-registration.test.ts +1 -1
  189. package/src/__tests__/exploration-drift-hook.test.ts +7 -23
  190. package/src/__tests__/file-write-tool.test.ts +3 -3
  191. package/src/__tests__/filing-service.test.ts +6 -5
  192. package/src/__tests__/followup-tools.test.ts +2 -2
  193. package/src/__tests__/get-skill-detail-audit.test.ts +1 -1
  194. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  195. package/src/__tests__/guardian-action-sweep.test.ts +3 -3
  196. package/src/__tests__/guardian-binding-drift-heal.test.ts +6 -3
  197. package/src/__tests__/guardian-card-withdrawal.test.ts +3 -3
  198. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +4 -4
  199. package/src/__tests__/guardian-dispatch.test.ts +14 -42
  200. package/src/__tests__/guardian-expiry-notifier.test.ts +4 -4
  201. package/src/__tests__/guardian-outbound-http.test.ts +3 -4
  202. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +3 -3
  203. package/src/__tests__/guardian-routing-invariants.test.ts +3 -3
  204. package/src/__tests__/guardian-routing-state.test.ts +6 -4
  205. package/src/__tests__/guardian-verification-voice-binding.test.ts +4 -4
  206. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
  207. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -3
  208. package/src/__tests__/heartbeat-disk-pressure.test.ts +7 -13
  209. package/src/__tests__/heartbeat-service.test.ts +31 -19
  210. package/src/__tests__/helpers/channel-test-adapter.ts +22 -48
  211. package/src/__tests__/helpers/create-guardian-binding.ts +1 -1
  212. package/src/__tests__/helpers/derive-guardian-delivery.ts +66 -0
  213. package/src/__tests__/helpers/gateway-acl-store.ts +81 -0
  214. package/src/__tests__/helpers/seed-contact-channel.ts +50 -29
  215. package/src/__tests__/history-repair-hook.test.ts +1 -1
  216. package/src/__tests__/home-state-routes.test.ts +1 -1
  217. package/src/__tests__/http-conversation-lineage.test.ts +4 -4
  218. package/src/__tests__/http-user-message-parity.test.ts +8 -12
  219. package/src/__tests__/identity-routes.test.ts +113 -25
  220. package/src/__tests__/image-recovery-hook.test.ts +3 -3
  221. package/src/__tests__/inbound-invite-redemption.test.ts +36 -38
  222. package/src/__tests__/inbound-slack-persistence.test.ts +5 -5
  223. package/src/__tests__/inbound-trust-verdict.test.ts +5 -4
  224. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +13 -6
  225. package/src/__tests__/inference-profile-reaper.test.ts +3 -3
  226. package/src/__tests__/inference-profile-session-handler.test.ts +3 -3
  227. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -3
  228. package/src/__tests__/init-feature-flag-overrides.test.ts +1 -4
  229. package/src/__tests__/injection-block.test.ts +5 -2
  230. package/src/__tests__/injector-background-turn.test.ts +3 -5
  231. package/src/__tests__/injector-chain.test.ts +25 -16
  232. package/src/__tests__/injector-config-quarantine-notice.test.ts +3 -5
  233. package/src/__tests__/injector-disk-pressure.test.ts +10 -8
  234. package/src/__tests__/injector-document-comments.test.ts +5 -3
  235. package/src/__tests__/injector-pkb-v2-silenced.test.ts +5 -2
  236. package/src/__tests__/injector-registry-order-guard.test.ts +132 -0
  237. package/src/__tests__/injector-v3-suppression.test.ts +15 -9
  238. package/src/__tests__/install-meta.test.ts +104 -0
  239. package/src/__tests__/install-skill-routing.test.ts +1 -1
  240. package/src/__tests__/internal-telemetry-routes.test.ts +4 -4
  241. package/src/__tests__/invite-redemption-service.test.ts +42 -45
  242. package/src/__tests__/invite-routes-http.test.ts +3 -3
  243. package/src/__tests__/invite-service-ipc.test.ts +3 -3
  244. package/src/__tests__/job-handler-registry-guard.test.ts +125 -0
  245. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +8 -8
  246. package/src/__tests__/jobs-store-upsert-debounced.test.ts +7 -4
  247. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +7 -6
  248. package/src/__tests__/list-messages-attachments.test.ts +7 -4
  249. package/src/__tests__/list-messages-client-message-id.test.ts +6 -3
  250. package/src/__tests__/list-messages-hidden-metadata.test.ts +5 -5
  251. package/src/__tests__/list-messages-page-latest.test.ts +5 -5
  252. package/src/__tests__/list-messages-queued.test.ts +223 -0
  253. package/src/__tests__/list-messages-tool-merge.test.ts +6 -3
  254. package/src/__tests__/llm-context-route-provider.test.ts +3 -3
  255. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +4 -4
  256. package/src/__tests__/llm-request-log-call-site.test.ts +5 -5
  257. package/src/__tests__/llm-request-log-error-payload.test.ts +1 -1
  258. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -1
  259. package/src/__tests__/llm-request-log-source-factory.test.ts +3 -3
  260. package/src/__tests__/llm-request-log-turn-query.test.ts +9 -6
  261. package/src/__tests__/llm-usage-store.test.ts +137 -3
  262. package/src/__tests__/log-export-routes.test.ts +3 -3
  263. package/src/__tests__/log-export-workspace.test.ts +3 -3
  264. package/src/__tests__/managed-profile-guard.test.ts +1 -1
  265. package/src/__tests__/managed-skill-lifecycle.test.ts +3 -3
  266. package/src/__tests__/managed-store.test.ts +307 -0
  267. package/src/__tests__/mcp-config-secret-boundary.test.ts +2 -1
  268. package/src/__tests__/media-stream-server-integration.test.ts +1 -1
  269. package/src/__tests__/memory-jobs-worker-backoff.test.ts +4 -4
  270. package/src/__tests__/memory-jobs-worker-lanes.test.ts +11 -9
  271. package/src/__tests__/memory-recall-log-store.test.ts +4 -4
  272. package/src/__tests__/memory-retrieval-budget.test.ts +1 -1
  273. package/src/__tests__/memory-retrieval-hook.test.ts +8 -8
  274. package/src/__tests__/memory-upsert-concurrency.test.ts +9 -5
  275. package/src/__tests__/memory-v2-static-injector.test.ts +3 -3
  276. package/src/__tests__/messages-after-tiebreaker.test.ts +4 -4
  277. package/src/__tests__/messaging-send-tool.test.ts +5 -5
  278. package/src/__tests__/mock-gateway-ipc.ts +1 -1
  279. package/src/__tests__/native-web-search.test.ts +11 -11
  280. package/src/__tests__/non-member-access-request.test.ts +9 -7
  281. package/src/__tests__/notification-candidate-guardian-context.test.ts +4 -4
  282. package/src/__tests__/notification-deep-link.test.ts +3 -3
  283. package/src/__tests__/notification-guardian-path.test.ts +3 -3
  284. package/src/__tests__/notification-schedule-notify-dedup.test.ts +3 -3
  285. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  286. package/src/__tests__/oauth-provider-visibility.test.ts +2 -2
  287. package/src/__tests__/oauth-store.test.ts +6 -6
  288. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  289. package/src/__tests__/persist-unsendable-image-downscale.test.ts +3 -3
  290. package/src/__tests__/persist-unsendable-image.test.ts +3 -3
  291. package/src/__tests__/persist-user-message-set-processing-failure.test.ts +70 -0
  292. package/src/__tests__/persistence-layering-guard.test.ts +207 -0
  293. package/src/__tests__/persistence-secret-redaction.test.ts +6 -6
  294. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  295. package/src/__tests__/platform-bash-auto-approve.test.ts +3 -3
  296. package/src/__tests__/playbook-execution.test.ts +4 -4
  297. package/src/__tests__/playbook-tools.test.ts +3 -3
  298. package/src/__tests__/plugin-bootstrap.test.ts +40 -3
  299. package/src/__tests__/plugin-config-data-migration.test.ts +263 -0
  300. package/src/__tests__/plugin-disabled-state.test.ts +137 -4
  301. package/src/__tests__/plugin-import-boundary-guard.test.ts +495 -0
  302. package/src/__tests__/plugin-injector-contribution.test.ts +149 -0
  303. package/src/__tests__/pointer-conversation-trust.test.ts +141 -0
  304. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +8 -1
  305. package/src/__tests__/process-message-background-slack.test.ts +6 -6
  306. package/src/__tests__/process-message-display-content.test.ts +5 -5
  307. package/src/__tests__/processing-flag-persist-failure.test.ts +280 -0
  308. package/src/__tests__/provider-usage-tracking.test.ts +3 -3
  309. package/src/__tests__/prune-jobs-changes-parser.test.ts +1 -1
  310. package/src/__tests__/prune-old-conversations-job.test.ts +5 -5
  311. package/src/__tests__/published-app-updater.test.ts +3 -3
  312. package/src/__tests__/qdrant-collection-migration.test.ts +5 -2
  313. package/src/__tests__/qdrant-manager.test.ts +1 -1
  314. package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +18 -12
  315. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +4 -4
  316. package/src/__tests__/reaction-persistence.test.ts +13 -10
  317. package/src/__tests__/rebuild-index-graph-nodes.test.ts +5 -5
  318. package/src/__tests__/recording-handler.test.ts +2 -2
  319. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +8 -8
  320. package/src/__tests__/relay-server.test.ts +140 -156
  321. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  322. package/src/__tests__/resolve-app-id.test.ts +3 -3
  323. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -7
  324. package/src/__tests__/runtime-events-sse-bilingual.test.ts +3 -3
  325. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -3
  326. package/src/__tests__/runtime-events-sse-reconnect.test.ts +3 -3
  327. package/src/__tests__/runtime-events-sse.test.ts +3 -3
  328. package/src/__tests__/scaffold-managed-skill-tool.test.ts +489 -2
  329. package/src/__tests__/schedule-retry.test.ts +53 -53
  330. package/src/__tests__/schedule-routes-workflow-validation.test.ts +47 -43
  331. package/src/__tests__/schedule-routes.test.ts +197 -187
  332. package/src/__tests__/schedule-store.test.ts +174 -172
  333. package/src/__tests__/schedule-tools.test.ts +2 -2
  334. package/src/__tests__/scheduler-disk-pressure.test.ts +3 -3
  335. package/src/__tests__/scheduler-recurrence.test.ts +15 -15
  336. package/src/__tests__/scheduler-reuse-conversation.test.ts +14 -14
  337. package/src/__tests__/scheduler-wake.test.ts +8 -8
  338. package/src/__tests__/scoped-approval-grants.test.ts +4 -4
  339. package/src/__tests__/scoped-grant-security-matrix.test.ts +4 -4
  340. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +2 -2
  341. package/src/__tests__/search-skills-unified.test.ts +1 -1
  342. package/src/__tests__/secret-ingress-channel.test.ts +3 -3
  343. package/src/__tests__/secret-ingress-http.test.ts +6 -6
  344. package/src/__tests__/secret-routes-platform-proxy.test.ts +8 -7
  345. package/src/__tests__/send-endpoint-busy.test.ts +6 -6
  346. package/src/__tests__/sequence-store.test.ts +3 -3
  347. package/src/__tests__/server-history-render.test.ts +7 -4
  348. package/src/__tests__/settings-routes.test.ts +2 -2
  349. package/src/__tests__/skill-docs-sync-guard.test.ts +34 -0
  350. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -1
  351. package/src/__tests__/skill-projection.benchmark.test.ts +2 -1
  352. package/src/__tests__/skill-version-hash.test.ts +32 -0
  353. package/src/__tests__/skills-file-content-endpoint.test.ts +1 -1
  354. package/src/__tests__/skills-files-catalog-fallback.test.ts +1 -1
  355. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  356. package/src/__tests__/slack-messaging-token-resolution.test.ts +2 -2
  357. package/src/__tests__/slack-reaction-canonical-approval.test.ts +4 -4
  358. package/src/__tests__/slack-share-routes.test.ts +1 -1
  359. package/src/__tests__/slim-skill-category.test.ts +34 -2
  360. package/src/__tests__/starter-task-flow.test.ts +1 -1
  361. package/src/__tests__/strip-memory-injections.test.ts +2 -2
  362. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  363. package/src/__tests__/subagent-detail.test.ts +1 -1
  364. package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
  365. package/src/__tests__/subagent-notify-parent.test.ts +3 -3
  366. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -1
  367. package/src/__tests__/subagent-spawn-tool-fork.test.ts +3 -3
  368. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  369. package/src/__tests__/subagent-tools.test.ts +2 -5
  370. package/src/__tests__/suggestion-routes.test.ts +4 -4
  371. package/src/__tests__/task-compiler.test.ts +2 -2
  372. package/src/__tests__/task-management-tools.test.ts +2 -2
  373. package/src/__tests__/task-memory-cleanup.test.ts +9 -7
  374. package/src/__tests__/task-progress-nudge-hook.test.ts +37 -94
  375. package/src/__tests__/task-scheduler.test.ts +26 -26
  376. package/src/__tests__/test-support/tool-invocation-seed.ts +5 -2
  377. package/src/__tests__/thread-backfill.test.ts +4 -4
  378. package/src/__tests__/title-generate-hook.test.ts +6 -6
  379. package/src/__tests__/tool-approval-handler.test.ts +4 -4
  380. package/src/__tests__/tool-audit-listener.test.ts +1 -1
  381. package/src/__tests__/tool-error-hook.test.ts +2 -0
  382. package/src/__tests__/tool-executor-lifecycle-events.test.ts +5 -5
  383. package/src/__tests__/tool-executor-redaction.test.ts +11 -0
  384. package/src/__tests__/tool-executor.test.ts +24 -2
  385. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -5
  386. package/src/__tests__/tool-preview-lifecycle.test.ts +77 -8
  387. package/src/__tests__/tool-result-metadata-plumbing.test.ts +4 -4
  388. package/src/__tests__/tool-result-truncate-hook.test.ts +2 -0
  389. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -1
  390. package/src/__tests__/tool-start-timestamp.test.ts +65 -2
  391. package/src/__tests__/tools-get-route.test.ts +44 -1
  392. package/src/__tests__/trace-emitter.test.ts +1 -1
  393. package/src/__tests__/trust-context-guards.test.ts +1 -1
  394. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +5 -5
  395. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +11 -5
  396. package/src/__tests__/trusted-contact-multichannel.test.ts +9 -9
  397. package/src/__tests__/trusted-contact-verification.test.ts +8 -30
  398. package/src/__tests__/turn-boundary-resolution.test.ts +7 -4
  399. package/src/__tests__/turn-call-site.test.ts +29 -0
  400. package/src/__tests__/turn-events-store.test.ts +8 -5
  401. package/src/__tests__/twilio-routes.test.ts +3 -3
  402. package/src/__tests__/usage-cache-backfill-migration.test.ts +4 -8
  403. package/src/__tests__/usage-grouped-buckets.test.ts +1 -1
  404. package/src/__tests__/usage-routes.test.ts +61 -3
  405. package/src/__tests__/verification-control-plane-policy.test.ts +6 -6
  406. package/src/__tests__/voice-invite-redemption.test.ts +41 -45
  407. package/src/__tests__/voice-quality.test.ts +38 -12
  408. package/src/__tests__/voice-scoped-grant-consumer.test.ts +22 -14
  409. package/src/__tests__/voice-session-bridge.test.ts +16 -10
  410. package/src/__tests__/web-search-backend-failure.test.ts +4 -4
  411. package/src/__tests__/workspace-lifecycle.test.ts +29 -18
  412. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
  413. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +5 -5
  414. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +3 -3
  415. package/src/__tests__/workspace-migration-113-swap-balanced-profile-to-glm-5p2.test.ts +241 -0
  416. package/src/__tests__/workspace-migration-114-swap-quality-profile-to-opus.test.ts +172 -0
  417. package/src/__tests__/workspace-migration-116-rename-memory-plugin-disabled-sentinel.test.ts +128 -0
  418. package/src/__tests__/workspace-migration-117-normalize-stale-lean-memory-v3-defaults.test.ts +221 -0
  419. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -1
  420. package/src/__tests__/workspace-migration-drop-user-md.test.ts +84 -7
  421. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +10 -6
  422. package/src/a2a/__tests__/task-store.test.ts +2 -2
  423. package/src/a2a/task-store.ts +4 -4
  424. package/src/acp/__tests__/client-handler.test.ts +680 -0
  425. package/src/acp/__tests__/helpers/acp-history-db.ts +32 -4
  426. package/src/acp/__tests__/session-manager-persistence.test.ts +215 -7
  427. package/src/acp/__tests__/session-manager-resume.test.ts +113 -2
  428. package/src/acp/__tests__/session-manager-startup.test.ts +3 -3
  429. package/src/acp/__tests__/session-manager-usage.test.ts +113 -0
  430. package/src/acp/client-handler.ts +140 -21
  431. package/src/acp/session-manager.ts +127 -4
  432. package/src/acp/types.ts +18 -0
  433. package/src/agent/loop.ts +200 -148
  434. package/src/api/events/acp-session-completed.ts +33 -0
  435. package/src/api/events/acp-session-error.ts +21 -0
  436. package/src/api/events/acp-session-spawned.ts +32 -0
  437. package/src/api/events/acp-session-update.test.ts +122 -0
  438. package/src/api/events/acp-session-update.ts +51 -0
  439. package/src/api/events/acp-session-usage.test.ts +49 -0
  440. package/src/api/events/acp-session-usage.ts +31 -0
  441. package/src/api/events/tool-use-preview-start.ts +11 -0
  442. package/src/api/events/tool-use-start.ts +14 -0
  443. package/src/api/index.ts +38 -0
  444. package/src/api/responses/conversation-message.ts +37 -1
  445. package/src/api/responses/llm-request-log-entry.ts +41 -0
  446. package/src/api/responses/memory-v3-selection-log.ts +5 -7
  447. package/src/approvals/approval-primitive.ts +1 -1
  448. package/src/approvals/guardian-card-withdrawal.ts +2 -2
  449. package/src/approvals/guardian-decision-primitive.ts +1 -1
  450. package/src/approvals/guardian-expiry-notifier.ts +1 -1
  451. package/src/approvals/guardian-request-resolvers.ts +4 -4
  452. package/src/approvals/scoped-approval-grants.ts +551 -0
  453. package/src/apps/app-store.ts +1058 -0
  454. package/src/apps/published-pages-store.ts +67 -0
  455. package/src/apps/shared-app-links-store.ts +130 -0
  456. package/src/background-wake/background-wake-routes.test.ts +53 -23
  457. package/src/background-wake/wake-intent-hooks.test.ts +18 -12
  458. package/src/backup/restore.ts +1 -1
  459. package/src/bundler/app-bundler.ts +1 -1
  460. package/src/calls/__tests__/relay-setup-router.test.ts +1 -1
  461. package/src/calls/call-controller.ts +5 -5
  462. package/src/calls/call-conversation-messages.ts +1 -1
  463. package/src/calls/call-domain.ts +5 -5
  464. package/src/calls/call-pointer-messages.ts +1 -1
  465. package/src/calls/call-store.ts +3 -3
  466. package/src/calls/guardian-action-sweep.ts +1 -1
  467. package/src/calls/guardian-dispatch.ts +5 -5
  468. package/src/calls/media-stream-server.ts +1 -1
  469. package/src/calls/relay-access-wait.ts +1 -1
  470. package/src/calls/relay-server.ts +3 -3
  471. package/src/calls/relay-setup-router.ts +1 -1
  472. package/src/calls/tts-call-strategy.ts +4 -3
  473. package/src/calls/voice-quality.ts +47 -59
  474. package/src/calls/voice-session-bridge.ts +2 -16
  475. package/src/channels/channel-verification-sessions.ts +557 -0
  476. package/src/cli/commands/__tests__/conversations-new.test.ts +186 -0
  477. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
  478. package/src/cli/commands/__tests__/conversations-wake.test.ts +147 -0
  479. package/src/cli/commands/__tests__/ps.test.ts +205 -0
  480. package/src/cli/commands/conversations.ts +90 -30
  481. package/src/cli/commands/db/__tests__/repair.test.ts +4 -3
  482. package/src/cli/commands/db/repair-step-conversation-backfill.ts +2 -2
  483. package/src/cli/commands/memory/__tests__/memory-v2-compare-render.test.ts +1 -1
  484. package/src/cli/commands/memory/__tests__/worker.test.ts +106 -307
  485. package/src/cli/commands/memory/memory-retrospective.ts +32 -28
  486. package/src/cli/commands/memory/memory-v2-compare-render.ts +1 -1
  487. package/src/cli/commands/memory/memory-v2.ts +2 -2
  488. package/src/cli/commands/memory/memory-v3.ts +2 -2
  489. package/src/cli/commands/memory/worker.ts +83 -160
  490. package/src/cli/commands/plugins.ts +147 -11
  491. package/src/cli/commands/ps.ts +90 -0
  492. package/src/cli/commands/tools-run.ts +114 -0
  493. package/src/cli/commands/tools.ts +19 -5
  494. package/src/cli/lib/__tests__/cli-colors.test.ts +30 -1
  495. package/src/cli/lib/__tests__/install-from-github.test.ts +168 -8
  496. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +9 -4
  497. package/src/cli/lib/__tests__/parse-github-plugin-spec.test.ts +121 -0
  498. package/src/cli/lib/__tests__/toggle-plugin.test.ts +10 -4
  499. package/src/cli/lib/cli-colors.ts +6 -0
  500. package/src/cli/lib/diff-plugin.ts +3 -7
  501. package/src/cli/lib/inspect-plugin.ts +2 -4
  502. package/src/cli/lib/install-from-github.ts +96 -24
  503. package/src/cli/lib/merge-plugin-tree.ts +5 -3
  504. package/src/cli/lib/parse-github-plugin-spec.ts +163 -0
  505. package/src/cli/lib/plugin-fingerprint.ts +22 -0
  506. package/src/cli/lib/upgrade-plugin.ts +6 -5
  507. package/src/cli/program.ts +4 -7
  508. package/src/cli.ts +6 -3
  509. package/src/config/__tests__/deployment-context-defaults.test.ts +228 -0
  510. package/src/config/__tests__/proc-to-skills.test.ts +21 -0
  511. package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
  512. package/src/config/bundled-skills/AGENTS.md +11 -0
  513. package/src/config/bundled-skills/app-builder/SKILL.md +2 -0
  514. package/src/config/bundled-skills/app-builder/tools/app-create.ts +2 -2
  515. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +2 -2
  516. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +2 -2
  517. package/src/config/bundled-skills/app-builder/tools/app-list.ts +1 -1
  518. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +2 -2
  519. package/src/config/bundled-skills/app-builder/tools/app-update.ts +2 -2
  520. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  521. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +1 -1
  522. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +1 -1
  523. package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
  524. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +1 -1
  525. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  526. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +1 -1
  527. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +1 -1
  528. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  529. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +2 -2
  530. package/src/config/bundled-skills/media-processing/tools/media-status.ts +1 -1
  531. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +5 -5
  532. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +6 -6
  533. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +8 -5
  534. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +4 -1
  535. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  536. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -4
  537. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +7 -7
  538. package/src/config/bundled-skills/skill-management/TOOLS.json +45 -0
  539. package/src/config/bundled-skills/skill-management/tools/find-similar.ts +12 -0
  540. package/src/config/bundled-tool-registry.ts +2 -0
  541. package/src/config/feature-flag-registry.json +8 -16
  542. package/src/config/llm-resolver.ts +17 -0
  543. package/src/config/loader.ts +38 -58
  544. package/src/config/memory-v3-gate.ts +16 -0
  545. package/src/config/schema.ts +2 -0
  546. package/src/config/schemas/__tests__/memory-v3.test.ts +16 -5
  547. package/src/config/schemas/conversations.ts +8 -0
  548. package/src/config/schemas/memory-lifecycle.ts +9 -0
  549. package/src/config/schemas/memory-v3.ts +56 -6
  550. package/src/config/schemas/migrations.ts +25 -0
  551. package/src/config/schemas/services.ts +0 -37
  552. package/src/config/seed-inference-profiles.ts +13 -50
  553. package/src/config/sync-gated-profiles.ts +6 -17
  554. package/src/contacts/__tests__/guardian-contact-reader.test.ts +89 -0
  555. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +3 -14
  556. package/src/contacts/canonical-guardian-store.ts +891 -0
  557. package/src/contacts/contact-store.ts +11 -9
  558. package/src/contacts/guardian-contact-reader.ts +52 -0
  559. package/src/contacts/guardian-delivery-reader.ts +21 -23
  560. package/src/contacts/guardian-rate-limits.ts +191 -0
  561. package/src/contacts/notify-contacts-changed.ts +17 -0
  562. package/src/context/compactor.ts +3 -3
  563. package/src/context/strip-injections.ts +1 -1
  564. package/src/conversations/__tests__/message-consolidation.test.ts +10 -26
  565. package/src/conversations/job-handlers/summarization.ts +246 -0
  566. package/src/conversations/message-consolidation.ts +1 -1
  567. package/src/credential-execution/ces-runtime.ts +285 -0
  568. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +25 -22
  569. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +5 -4
  570. package/src/daemon/__tests__/daemon-readiness.test.ts +51 -0
  571. package/src/daemon/__tests__/daemon-skill-host.test.ts +1 -1
  572. package/src/daemon/__tests__/embedding-reconcile.test.ts +456 -0
  573. package/src/daemon/__tests__/inference-profile-notification.test.ts +9 -6
  574. package/src/daemon/__tests__/lifecycle-embedding-reconcile.test.ts +119 -0
  575. package/src/daemon/__tests__/memory-v2-startup.test.ts +86 -0
  576. package/src/daemon/__tests__/native-web-search-metadata.test.ts +2 -2
  577. package/src/daemon/__tests__/web-search-status-text.test.ts +3 -5
  578. package/src/daemon/app-source-watcher.ts +71 -10
  579. package/src/daemon/channel-ui-capability.ts +25 -0
  580. package/src/daemon/config-watcher.ts +71 -47
  581. package/src/daemon/conversation-agent-loop-handlers.ts +150 -23
  582. package/src/daemon/conversation-agent-loop.ts +84 -28
  583. package/src/daemon/conversation-attachments.ts +2 -2
  584. package/src/daemon/conversation-evictor.ts +42 -9
  585. package/src/daemon/conversation-history.ts +6 -6
  586. package/src/daemon/conversation-launch.ts +2 -2
  587. package/src/daemon/conversation-lifecycle.ts +7 -4
  588. package/src/daemon/conversation-messaging.ts +25 -11
  589. package/src/daemon/conversation-notifiers.ts +1 -1
  590. package/src/daemon/conversation-process.ts +17 -15
  591. package/src/daemon/conversation-queue-manager.ts +6 -0
  592. package/src/daemon/conversation-registry.ts +6 -5
  593. package/src/daemon/conversation-runtime-assembly.ts +37 -31
  594. package/src/daemon/conversation-skill-tools.ts +26 -2
  595. package/src/daemon/conversation-slash.ts +1 -1
  596. package/src/daemon/conversation-store.ts +44 -39
  597. package/src/daemon/conversation-surfaces.ts +4 -4
  598. package/src/daemon/conversation-tool-setup.ts +2 -1
  599. package/src/daemon/conversation-usage.ts +4 -2
  600. package/src/daemon/conversation-workspace.ts +2 -2
  601. package/src/daemon/conversation.ts +45 -17
  602. package/src/daemon/daemon-readiness.ts +33 -0
  603. package/src/daemon/daemon-skill-host.ts +1 -1
  604. package/src/daemon/embedding-reconcile.ts +340 -0
  605. package/src/daemon/event-loop-watchdog.ts +1 -1
  606. package/src/daemon/external-plugins-bootstrap.ts +80 -14
  607. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +2 -2
  608. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +3 -3
  609. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +3 -3
  610. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +7 -11
  611. package/src/daemon/handlers/__tests__/config-a2a.test.ts +2 -2
  612. package/src/daemon/handlers/__tests__/config-channels.test.ts +17 -11
  613. package/src/daemon/handlers/config-a2a.ts +3 -3
  614. package/src/daemon/handlers/config-channels.ts +7 -4
  615. package/src/daemon/handlers/config-embeddings.ts +1 -1
  616. package/src/daemon/handlers/conversation-history.ts +2 -2
  617. package/src/daemon/handlers/conversations.ts +7 -4
  618. package/src/daemon/handlers/recording.ts +6 -3
  619. package/src/daemon/handlers/shared.ts +2 -0
  620. package/src/daemon/handlers/skills.ts +9 -1
  621. package/src/daemon/lifecycle.ts +890 -1208
  622. package/src/daemon/memory-v2-startup.test.ts +3 -3
  623. package/src/daemon/memory-v2-startup.ts +47 -12
  624. package/src/daemon/message-provenance.ts +1 -1
  625. package/src/daemon/message-types/acp.ts +27 -1
  626. package/src/daemon/message-types/bookmarks.ts +1 -1
  627. package/src/daemon/message-types/skills.ts +20 -2
  628. package/src/daemon/pointer-conversation-trust.ts +66 -0
  629. package/src/daemon/process-message.ts +24 -3
  630. package/src/daemon/providers-setup.ts +0 -14
  631. package/src/daemon/shutdown-handlers.ts +185 -165
  632. package/src/daemon/skill-memory-refresh.ts +1 -1
  633. package/src/daemon/status.ts +15 -0
  634. package/src/daemon/tool-setup-types.ts +17 -0
  635. package/src/daemon/tool-side-effects.ts +4 -4
  636. package/src/daemon/trace-emitter.ts +1 -1
  637. package/src/daemon/trust-context.ts +1 -1
  638. package/src/daemon/turn-call-site.ts +25 -0
  639. package/src/daemon/turn-latency-tracker.test.ts +137 -0
  640. package/src/daemon/turn-latency-tracker.ts +134 -0
  641. package/src/daemon/wake-conversation-ops.ts +11 -4
  642. package/src/documents/document-comments-store.test.ts +2 -2
  643. package/src/documents/document-comments-store.ts +1 -1
  644. package/src/documents/document-store.ts +1 -1
  645. package/src/events/tool-audit-listener.ts +4 -4
  646. package/src/events/tool-permission-telemetry-listener.ts +1 -1
  647. package/src/export/__tests__/transcript-formatter.test.ts +1 -1
  648. package/src/export/transcript-formatter.ts +1 -1
  649. package/src/followups/followup-store.ts +2 -2
  650. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +2 -2
  651. package/src/heartbeat/__tests__/heartbeat-service.test.ts +45 -39
  652. package/src/heartbeat/heartbeat-run-store.ts +3 -3
  653. package/src/heartbeat/heartbeat-service.ts +29 -11
  654. package/src/home/__tests__/relationship-state-writer.test.ts +1 -1
  655. package/src/home/__tests__/suggested-prompts.test.ts +1 -1
  656. package/src/home/conversation-starter-checkpoints.ts +64 -0
  657. package/src/home/feed-source-enrichment.ts +3 -3
  658. package/src/home/home-greeting-cache.ts +1 -1
  659. package/src/home/job-handlers/conversation-starters.ts +484 -0
  660. package/src/home/relationship-state-writer.ts +1 -1
  661. package/src/home/suggested-prompts.ts +1 -1
  662. package/src/hooks/hook-loader.ts +141 -6
  663. package/src/hooks/registry.ts +129 -0
  664. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  665. package/src/ipc/__tests__/cli-ipc.test.ts +1 -1
  666. package/src/ipc/__tests__/inject-local-actor-header.test.ts +33 -0
  667. package/src/ipc/__tests__/watcher-ipc.test.ts +1 -1
  668. package/src/ipc/assistant-server.ts +79 -33
  669. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +3 -3
  670. package/src/ipc/routes/db-proxy-transaction.ts +1 -1
  671. package/src/ipc/routes/db-proxy.ts +4 -2
  672. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -1
  673. package/src/ipc/skill-routes/memory.ts +1 -1
  674. package/src/ipc/skill-routes/registries.ts +8 -10
  675. package/src/ipc/skill-server.ts +42 -6
  676. package/src/jobs/register-job-handlers.ts +74 -0
  677. package/src/jobs/worker.ts +91 -0
  678. package/src/live-voice/__tests__/live-voice-archive.test.ts +5 -5
  679. package/src/live-voice/live-voice-archive.ts +2 -2
  680. package/src/mcp/manager.ts +11 -0
  681. package/src/media/app-icon-generator.ts +1 -1
  682. package/src/media/job-handlers/media-processing.ts +126 -0
  683. package/src/messaging/channel-binding-metadata.ts +1 -1
  684. package/src/messaging/content/parse.test.ts +34 -0
  685. package/src/messaging/content/parse.ts +23 -0
  686. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +1 -0
  687. package/src/messaging/providers/slack/binding-metadata.ts +1 -1
  688. package/src/messaging/providers/slack/render.test.ts +309 -0
  689. package/src/messaging/providers/slack/render.ts +459 -0
  690. package/src/messaging/providers/slack/send.test.ts +39 -0
  691. package/src/messaging/providers/slack/send.ts +38 -18
  692. package/src/messaging/providers/telegram-bot/adapter.ts +2 -2
  693. package/src/messaging/providers/telegram-bot/api.ts +17 -3
  694. package/src/messaging/providers/telegram-bot/render.test.ts +146 -0
  695. package/src/messaging/providers/telegram-bot/render.ts +292 -0
  696. package/src/messaging/providers/telegram-bot/send.test.ts +197 -0
  697. package/src/messaging/providers/telegram-bot/send.ts +70 -2
  698. package/src/messaging/providers/telegram-bot/transport.ts +10 -1
  699. package/src/messaging/providers/whatsapp/adapter.ts +2 -2
  700. package/src/messaging/providers/whatsapp/send.ts +1 -1
  701. package/src/notifications/__tests__/deterministic-checks.test.ts +3 -3
  702. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -1
  703. package/src/notifications/broadcaster.ts +1 -1
  704. package/src/notifications/canonical-delivery-recorder.ts +1 -1
  705. package/src/notifications/conversation-candidates.ts +3 -3
  706. package/src/notifications/conversation-pairing.ts +25 -16
  707. package/src/notifications/decisions-store.ts +2 -2
  708. package/src/notifications/deliveries-store.ts +3 -3
  709. package/src/notifications/deterministic-checks.ts +2 -2
  710. package/src/notifications/emit-signal.ts +1 -1
  711. package/src/notifications/events-store.ts +2 -2
  712. package/src/notifications/home-feed-side-effect.ts +2 -2
  713. package/src/notifications/preferences-store.ts +2 -2
  714. package/src/notifications/signal.ts +1 -1
  715. package/src/oauth/oauth-store.ts +3 -3
  716. package/src/onboarding/__tests__/onboarding-events-store.test.ts +80 -0
  717. package/src/onboarding/checkin-event.test.ts +5 -2
  718. package/src/onboarding/checkin-event.ts +7 -1
  719. package/src/onboarding/onboarding-events-store.ts +161 -0
  720. package/src/permissions/checker.test.ts +319 -1
  721. package/src/permissions/checker.ts +52 -0
  722. package/src/permissions/types.ts +21 -0
  723. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +20 -0
  724. package/src/persistence/__tests__/worker-control.test.ts +260 -0
  725. package/src/persistence/attachments-store.ts +1136 -0
  726. package/src/persistence/checkpoints.ts +65 -0
  727. package/src/persistence/compaction-ledger-store.ts +107 -0
  728. package/src/persistence/conversation-attention-store.ts +689 -0
  729. package/src/persistence/conversation-bootstrap.ts +59 -0
  730. package/src/persistence/conversation-crud.ts +3437 -0
  731. package/src/persistence/conversation-group-migration.test.ts +99 -0
  732. package/src/persistence/conversation-key-store.ts +274 -0
  733. package/src/persistence/conversation-queries.ts +768 -0
  734. package/src/persistence/conversation-row-batch-delete.ts +205 -0
  735. package/src/persistence/db-async-query.ts +329 -0
  736. package/src/persistence/db-connection.ts +242 -0
  737. package/src/persistence/db-init.ts +282 -0
  738. package/src/persistence/db-maintenance.ts +158 -0
  739. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +156 -0
  740. package/src/persistence/embeddings/__tests__/reconcile-decision.test.ts +95 -0
  741. package/src/persistence/embeddings/embed.ts +87 -0
  742. package/src/persistence/embeddings/embedding-backend.test.ts +355 -0
  743. package/src/persistence/embeddings/embedding-backend.ts +968 -0
  744. package/src/persistence/embeddings/embedding-billing-breaker.ts +96 -0
  745. package/src/persistence/embeddings/embedding-cache.ts +139 -0
  746. package/src/persistence/embeddings/embedding-identity.ts +88 -0
  747. package/src/persistence/embeddings/embedding-local.ts +587 -0
  748. package/src/persistence/embeddings/embedding-ollama.ts +79 -0
  749. package/src/persistence/embeddings/embedding-runtime-manager.ts +573 -0
  750. package/src/persistence/embeddings/embedding-types.ts +97 -0
  751. package/src/persistence/embeddings/qdrant-circuit-breaker.ts +119 -0
  752. package/src/persistence/embeddings/qdrant-client.test.ts +60 -0
  753. package/src/persistence/embeddings/qdrant-client.ts +842 -0
  754. package/src/persistence/embeddings/qdrant-manager.ts +450 -0
  755. package/src/persistence/embeddings/reconcile-decision.ts +53 -0
  756. package/src/persistence/embeddings/sparse-tokenize.ts +51 -0
  757. package/src/persistence/external-conversation-store.ts +315 -0
  758. package/src/persistence/fork-message-copy.ts +225 -0
  759. package/src/persistence/job-handlers/cleanup.ts +239 -0
  760. package/src/persistence/job-utils.ts +286 -0
  761. package/src/persistence/jobs-store.ts +813 -0
  762. package/src/persistence/jobs-worker.ts +833 -0
  763. package/src/persistence/llm-request-log-source-clickhouse.ts +525 -0
  764. package/src/persistence/llm-request-log-store.ts +740 -0
  765. package/src/persistence/llm-usage-store.ts +961 -0
  766. package/src/persistence/memory-lifecycle-hooks.test.ts +81 -0
  767. package/src/persistence/memory-lifecycle-hooks.ts +120 -0
  768. package/src/persistence/message-content.test.ts +35 -0
  769. package/src/persistence/migrations/126-backfill-guardian-principal-id.ts +300 -0
  770. package/src/persistence/migrations/140-backfill-usage-cache-accounting.ts +364 -0
  771. package/src/persistence/migrations/142-rename-verification-session-id-column.ts +55 -0
  772. package/src/persistence/migrations/182-oauth-providers-display-metadata.ts +22 -0
  773. package/src/persistence/migrations/196-strip-integration-prefix-from-provider-keys.ts +175 -0
  774. package/src/persistence/migrations/199-guardian-request-enrichment-columns.ts +50 -0
  775. package/src/persistence/migrations/202-memory-graph-tables.ts +128 -0
  776. package/src/persistence/migrations/203-drop-memory-items-tables.ts +53 -0
  777. package/src/persistence/migrations/206-scrub-corrupted-image-attachments.ts +121 -0
  778. package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +196 -0
  779. package/src/persistence/migrations/211-memory-recall-logs-query-context.ts +14 -0
  780. package/src/persistence/migrations/220-normalize-user-file-by-principal.ts +171 -0
  781. package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +179 -0
  782. package/src/persistence/migrations/236-tool-invocations-matched-rule-id.ts +23 -0
  783. package/src/persistence/migrations/243-provider-connections.ts +80 -0
  784. package/src/persistence/migrations/244-provider-connection-status-label.ts +29 -0
  785. package/src/persistence/migrations/246-backfill-provider-connection-label.ts +83 -0
  786. package/src/persistence/migrations/255-channel-inbound-delivery-attempts.ts +17 -0
  787. package/src/persistence/migrations/301-create-watchdog-events.ts +42 -0
  788. package/src/persistence/migrations/304-add-llm-usage-cron-run-id.ts +31 -0
  789. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +49 -0
  790. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +110 -0
  791. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.ts +65 -0
  792. package/src/persistence/migrations/307-acp-session-history-usage-columns.test.ts +124 -0
  793. package/src/persistence/migrations/307-acp-session-history-usage-columns.ts +36 -0
  794. package/src/persistence/migrations/308-acp-session-history-token-columns.test.ts +119 -0
  795. package/src/persistence/migrations/308-acp-session-history-token-columns.ts +32 -0
  796. package/src/persistence/migrations/309-drop-redundant-indexes.ts +60 -0
  797. package/src/persistence/migrations/310-llm-request-log-latency-breakdown.ts +37 -0
  798. package/src/persistence/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +328 -0
  799. package/src/persistence/migrations/__tests__/222-strip-placeholder-sentinels-from-messages.test.ts +273 -0
  800. package/src/persistence/migrations/__tests__/244-provider-connection-status-label.test.ts +90 -0
  801. package/src/persistence/migrations/__tests__/246-backfill-provider-connection-label.test.ts +250 -0
  802. package/src/persistence/migrations/__tests__/run-migrations.test.ts +380 -0
  803. package/src/persistence/migrations/helpers/relocation.ts +230 -0
  804. package/src/persistence/migrations/validate-migration-state.ts +279 -0
  805. package/src/persistence/schedule-attribution-sql.ts +106 -0
  806. package/src/persistence/schema/acp.ts +51 -0
  807. package/src/persistence/schema/contacts.ts +110 -0
  808. package/src/persistence/schema/conversations.ts +235 -0
  809. package/src/persistence/schema/infrastructure.ts +389 -0
  810. package/src/persistence/steps.ts +1310 -0
  811. package/src/persistence/worker-control.ts +277 -0
  812. package/src/platform/sync-identity.ts +24 -0
  813. package/src/playbooks/playbook-compiler.ts +2 -2
  814. package/src/plugin-api/index.ts +5 -0
  815. package/src/plugin-api/types.ts +40 -15
  816. package/src/plugins/defaults/channel/injectors.ts +101 -0
  817. package/src/plugins/defaults/channel/package.json +14 -0
  818. package/src/plugins/defaults/compaction/compact.ts +2 -1
  819. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +2 -1
  820. package/src/plugins/defaults/compaction/window-manager.ts +8 -7
  821. package/src/plugins/defaults/documents/injectors.ts +125 -0
  822. package/src/plugins/defaults/documents/package.json +14 -0
  823. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +6 -2
  824. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +10 -11
  825. package/src/plugins/defaults/history-repair/terminal.ts +1 -1
  826. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +23 -9
  827. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +2 -3
  828. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +7 -14
  829. package/src/plugins/defaults/image-fallback/src/vision-caption.ts +12 -4
  830. package/src/plugins/defaults/image-recovery/recover.ts +6 -3
  831. package/src/plugins/defaults/index.ts +235 -43
  832. package/src/plugins/defaults/injection-presence.ts +80 -0
  833. package/src/plugins/defaults/injector-order.ts +54 -0
  834. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +5 -2
  835. package/src/plugins/defaults/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  836. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +41 -0
  837. package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +264 -0
  838. package/src/plugins/defaults/memory/__tests__/bookmark-schema.test.ts +181 -0
  839. package/src/plugins/defaults/memory/__tests__/clear-stale-processing-flags.test.ts +52 -0
  840. package/src/plugins/defaults/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
  841. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +843 -0
  842. package/src/plugins/defaults/memory/__tests__/conversation-row-batch-delete.test.ts +199 -0
  843. package/src/plugins/defaults/memory/__tests__/conversation-types.test.ts +36 -0
  844. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +172 -0
  845. package/src/plugins/defaults/memory/__tests__/db-busy-timeout.test.ts +26 -0
  846. package/src/plugins/defaults/memory/__tests__/db-logs-attach.test.ts +113 -0
  847. package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +238 -0
  848. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +116 -0
  849. package/src/plugins/defaults/memory/__tests__/embedding-cache.test.ts +137 -0
  850. package/src/plugins/defaults/memory/__tests__/find-analysis-conversation.test.ts +197 -0
  851. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +140 -0
  852. package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +232 -0
  853. package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +245 -0
  854. package/src/plugins/defaults/memory/__tests__/jobs-store-job-classes.test.ts +52 -0
  855. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +115 -0
  856. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +508 -0
  857. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +160 -0
  858. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +1565 -0
  859. package/src/plugins/defaults/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +549 -0
  860. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +195 -0
  861. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +221 -0
  862. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +275 -0
  863. package/src/plugins/defaults/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
  864. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +192 -0
  865. package/src/plugins/defaults/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  866. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +130 -0
  867. package/src/plugins/defaults/memory/activation-session-store.ts +43 -0
  868. package/src/plugins/defaults/memory/anisotropy.ts +443 -0
  869. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +428 -0
  870. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1311 -0
  871. package/src/plugins/defaults/memory/context-search/search.ts +297 -0
  872. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +341 -0
  873. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +600 -0
  874. package/src/plugins/defaults/memory/context-search/sources/memory.ts +101 -0
  875. package/src/plugins/defaults/memory/context-search/types.ts +48 -0
  876. package/src/plugins/defaults/memory/filing-service.ts +430 -0
  877. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  878. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +663 -0
  879. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +321 -0
  880. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +287 -0
  881. package/src/plugins/defaults/memory/graph/bootstrap.ts +544 -0
  882. package/src/plugins/defaults/memory/graph/capability-seed.ts +454 -0
  883. package/src/plugins/defaults/memory/graph/consolidation.ts +712 -0
  884. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +1181 -0
  885. package/src/plugins/defaults/memory/graph/decay.ts +195 -0
  886. package/src/plugins/defaults/memory/graph/extraction-job.ts +77 -0
  887. package/src/plugins/defaults/memory/graph/extraction.ts +1462 -0
  888. package/src/plugins/defaults/memory/graph/graph-memory-state-store.ts +50 -0
  889. package/src/plugins/defaults/memory/graph/graph-search.test.ts +132 -0
  890. package/src/plugins/defaults/memory/graph/graph-search.ts +294 -0
  891. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +29 -0
  892. package/src/plugins/defaults/memory/graph/injection.ts +469 -0
  893. package/src/plugins/defaults/memory/graph/narrative.ts +267 -0
  894. package/src/plugins/defaults/memory/graph/pattern-scan.ts +269 -0
  895. package/src/plugins/defaults/memory/graph/retriever.test.ts +624 -0
  896. package/src/plugins/defaults/memory/graph/retriever.ts +1357 -0
  897. package/src/plugins/defaults/memory/graph/store.test.ts +1093 -0
  898. package/src/plugins/defaults/memory/graph/store.ts +923 -0
  899. package/src/plugins/defaults/memory/graph/tool-handlers.ts +195 -0
  900. package/src/plugins/defaults/memory/graph/tools.ts +95 -0
  901. package/src/plugins/defaults/memory/hooks/init.ts +26 -0
  902. package/src/plugins/defaults/memory/hooks/post-compact.ts +115 -0
  903. package/src/plugins/defaults/memory/hooks/shutdown.ts +14 -0
  904. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +371 -0
  905. package/src/plugins/defaults/memory/indexer.ts +409 -0
  906. package/src/plugins/defaults/memory/injectors.ts +388 -0
  907. package/src/plugins/defaults/memory/job-handlers/backfill.ts +107 -0
  908. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +236 -0
  909. package/src/plugins/defaults/memory/job-handlers/embedding.ts +133 -0
  910. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +117 -0
  911. package/src/plugins/defaults/memory/job-handlers.ts +203 -0
  912. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +565 -0
  913. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +424 -0
  914. package/src/plugins/defaults/memory/jobs/embed-pkb-file.test.ts +169 -0
  915. package/src/plugins/defaults/memory/jobs/embed-pkb-file.ts +59 -0
  916. package/src/plugins/defaults/memory/memory-recall-log-store.ts +172 -0
  917. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +60 -0
  918. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +131 -0
  919. package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +94 -0
  920. package/src/plugins/defaults/memory/memory-retrospective-job.ts +958 -0
  921. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +264 -0
  922. package/src/plugins/defaults/memory/memory-retrospective-state.ts +259 -0
  923. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +91 -0
  924. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +216 -0
  925. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +173 -0
  926. package/src/plugins/defaults/memory/package.json +14 -0
  927. package/src/plugins/defaults/memory/persistence-hooks.ts +119 -0
  928. package/src/plugins/defaults/memory/pkb/autoinject.ts +61 -0
  929. package/src/plugins/defaults/memory/pkb/context.ts +50 -0
  930. package/src/plugins/defaults/memory/pkb/pkb-index.test.ts +371 -0
  931. package/src/plugins/defaults/memory/pkb/pkb-index.ts +256 -0
  932. package/src/plugins/defaults/memory/pkb/pkb-reconcile.test.ts +254 -0
  933. package/src/plugins/defaults/memory/pkb/pkb-reconcile.ts +144 -0
  934. package/src/plugins/defaults/memory/pkb/pkb-search.test.ts +589 -0
  935. package/src/plugins/defaults/memory/pkb/pkb-search.ts +178 -0
  936. package/src/plugins/defaults/memory/pkb/types.ts +67 -0
  937. package/src/plugins/defaults/memory/rerank-local.ts +374 -0
  938. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-routes.test.ts +165 -0
  939. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +347 -0
  940. package/src/plugins/defaults/memory/routes/memory-eval-routes.ts +179 -0
  941. package/src/plugins/defaults/memory/routes/memory-item-routes.test.ts +922 -0
  942. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +814 -0
  943. package/src/plugins/defaults/memory/routes/memory-v2-routes.ts +850 -0
  944. package/src/plugins/defaults/memory/routes/memory-v3-routes.ts +125 -0
  945. package/src/plugins/defaults/memory/search/semantic.ts +241 -0
  946. package/src/plugins/defaults/memory/segmenter.ts +76 -0
  947. package/src/plugins/defaults/memory/tail-reinjection-strip.ts +65 -0
  948. package/src/plugins/defaults/memory/task-memory-cleanup.ts +241 -0
  949. package/src/plugins/defaults/memory/tools.test.ts +382 -0
  950. package/src/plugins/defaults/memory/tools.ts +87 -0
  951. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +207 -0
  952. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +1273 -0
  953. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +510 -0
  954. package/src/plugins/defaults/memory/v2/__tests__/cli-command-store.test.ts +432 -0
  955. package/src/plugins/defaults/memory/v2/__tests__/consolidation-job.test.ts +744 -0
  956. package/src/plugins/defaults/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +205 -0
  957. package/src/plugins/defaults/memory/v2/__tests__/frontmatter-sweep.test.ts +136 -0
  958. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +186 -0
  959. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  960. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
  961. package/src/plugins/defaults/memory/v2/__tests__/harness-runner.test.ts +135 -0
  962. package/src/plugins/defaults/memory/v2/__tests__/injection-events.test.ts +318 -0
  963. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +2308 -0
  964. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +940 -0
  965. package/src/plugins/defaults/memory/v2/__tests__/page-index.test.ts +760 -0
  966. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +332 -0
  967. package/src/plugins/defaults/memory/v2/__tests__/qdrant.test.ts +974 -0
  968. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +338 -0
  969. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1198 -0
  970. package/src/plugins/defaults/memory/v2/__tests__/sim.test.ts +704 -0
  971. package/src/plugins/defaults/memory/v2/__tests__/skill-content.test.ts +115 -0
  972. package/src/plugins/defaults/memory/v2/__tests__/skill-store.test.ts +986 -0
  973. package/src/plugins/defaults/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  974. package/src/plugins/defaults/memory/v2/__tests__/static-context.test.ts +223 -0
  975. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +530 -0
  976. package/src/plugins/defaults/memory/v2/activation-store.ts +185 -0
  977. package/src/plugins/defaults/memory/v2/activation.ts +560 -0
  978. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +296 -0
  979. package/src/plugins/defaults/memory/v2/cli-command-store.ts +341 -0
  980. package/src/plugins/defaults/memory/v2/consolidation-job.ts +550 -0
  981. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +98 -0
  982. package/src/plugins/defaults/memory/v2/harness/compare.ts +57 -0
  983. package/src/plugins/defaults/memory/v2/harness/oracle.ts +148 -0
  984. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +243 -0
  985. package/src/plugins/defaults/memory/v2/harness/retriever.ts +74 -0
  986. package/src/plugins/defaults/memory/v2/harness/router-retriever.ts +43 -0
  987. package/src/plugins/defaults/memory/v2/injected-block-slugs.ts +79 -0
  988. package/src/plugins/defaults/memory/v2/injection-events.ts +101 -0
  989. package/src/plugins/defaults/memory/v2/injection.ts +932 -0
  990. package/src/plugins/defaults/memory/v2/migration.ts +774 -0
  991. package/src/plugins/defaults/memory/v2/page-index.ts +459 -0
  992. package/src/plugins/defaults/memory/v2/page-store.ts +443 -0
  993. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +868 -0
  994. package/src/plugins/defaults/memory/v2/prompts/router.ts +148 -0
  995. package/src/plugins/defaults/memory/v2/qdrant.ts +939 -0
  996. package/src/plugins/defaults/memory/v2/reranker.ts +184 -0
  997. package/src/plugins/defaults/memory/v2/router.ts +602 -0
  998. package/src/plugins/defaults/memory/v2/sim.ts +310 -0
  999. package/src/plugins/defaults/memory/v2/skill-content.ts +61 -0
  1000. package/src/plugins/defaults/memory/v2/skill-store.ts +431 -0
  1001. package/src/plugins/defaults/memory/v2/sparse-bm25.ts +245 -0
  1002. package/src/plugins/defaults/memory/v2/static-context.ts +100 -0
  1003. package/src/plugins/defaults/memory/v2/sweep-job.ts +323 -0
  1004. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +316 -0
  1005. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +1163 -0
  1006. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +211 -0
  1007. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +247 -0
  1008. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +685 -0
  1009. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +365 -0
  1010. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +1012 -0
  1011. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +977 -0
  1012. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +599 -0
  1013. package/src/plugins/defaults/memory/v3/__tests__/render-injection.test.ts +128 -0
  1014. package/src/plugins/defaults/memory/v3/__tests__/section-dense-store.test.ts +756 -0
  1015. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +422 -0
  1016. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +501 -0
  1017. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +885 -0
  1018. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +96 -0
  1019. package/src/plugins/defaults/memory/v3/candidate-match.ts +197 -0
  1020. package/src/plugins/defaults/memory/v3/capabilities.ts +88 -0
  1021. package/src/plugins/defaults/memory/v3/card.ts +160 -0
  1022. package/src/plugins/defaults/memory/v3/dense.ts +108 -0
  1023. package/src/plugins/defaults/memory/v3/edge.ts +252 -0
  1024. package/src/plugins/defaults/memory/v3/entity-lane.test.ts +124 -0
  1025. package/src/plugins/defaults/memory/v3/entity-lane.ts +113 -0
  1026. package/src/plugins/defaults/memory/v3/ever-injected-store.test.ts +307 -0
  1027. package/src/plugins/defaults/memory/v3/ever-injected-store.ts +278 -0
  1028. package/src/plugins/defaults/memory/v3/hot-set.test.ts +143 -0
  1029. package/src/plugins/defaults/memory/v3/hot-set.ts +85 -0
  1030. package/src/plugins/defaults/memory/v3/injector.ts +423 -0
  1031. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +169 -0
  1032. package/src/plugins/defaults/memory/v3/learned-edges.ts +178 -0
  1033. package/src/plugins/defaults/memory/v3/maintain-job.ts +988 -0
  1034. package/src/plugins/defaults/memory/v3/orchestrate.ts +483 -0
  1035. package/src/plugins/defaults/memory/v3/page-content.ts +102 -0
  1036. package/src/plugins/defaults/memory/v3/pool-select.test.ts +147 -0
  1037. package/src/plugins/defaults/memory/v3/pool-select.ts +586 -0
  1038. package/src/plugins/defaults/memory/v3/prune.test.ts +760 -0
  1039. package/src/plugins/defaults/memory/v3/prune.ts +469 -0
  1040. package/src/plugins/defaults/memory/v3/render-injection.ts +92 -0
  1041. package/src/plugins/defaults/memory/v3/section-dense-store.ts +471 -0
  1042. package/src/plugins/defaults/memory/v3/section-needle.ts +215 -0
  1043. package/src/plugins/defaults/memory/v3/selection-log-store.ts +277 -0
  1044. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +656 -0
  1045. package/src/plugins/defaults/memory/v3/tuning-profile.ts +91 -0
  1046. package/src/plugins/defaults/memory/v3/types.ts +130 -0
  1047. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +731 -0
  1048. package/src/plugins/defaults/session/injectors.ts +84 -0
  1049. package/src/plugins/defaults/session/package.json +14 -0
  1050. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +6 -2
  1051. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +39 -45
  1052. package/src/plugins/defaults/title-generate/hooks/stop.ts +4 -5
  1053. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +3 -3
  1054. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +5 -3
  1055. package/src/plugins/defaults/turn-context/injectors.ts +52 -0
  1056. package/src/plugins/defaults/turn-context/package.json +14 -0
  1057. package/src/plugins/defaults/workspace/injectors.ts +295 -0
  1058. package/src/plugins/defaults/workspace/package.json +14 -0
  1059. package/src/plugins/injector-registry.ts +127 -0
  1060. package/src/plugins/job-handler-registry.ts +94 -0
  1061. package/src/plugins/mtime-cache.ts +1 -1
  1062. package/src/plugins/pipeline.ts +1 -1
  1063. package/src/plugins/registry.ts +37 -172
  1064. package/src/plugins/types.ts +36 -1
  1065. package/src/prompts/system-prompt.ts +1 -1
  1066. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  1067. package/src/providers/__tests__/dispatch-connection-routing.test.ts +1 -1
  1068. package/src/providers/__tests__/inference.test.ts +6 -6
  1069. package/src/providers/__tests__/placeholder-sentinels.test.ts +80 -0
  1070. package/src/providers/__tests__/retry-callsite.test.ts +31 -3
  1071. package/src/providers/__tests__/satellite-connection-routing.test.ts +1 -1
  1072. package/src/providers/anthropic/client.ts +23 -24
  1073. package/src/providers/call-site-routing.ts +1 -1
  1074. package/src/providers/connection-resolution.ts +7 -3
  1075. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +7 -8
  1076. package/src/providers/inference/__tests__/base-url-security.test.ts +8 -8
  1077. package/src/providers/inference/__tests__/connections-label.test.ts +5 -5
  1078. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +4 -4
  1079. package/src/providers/inference/backfill.ts +9 -5
  1080. package/src/providers/inference/connections.ts +2 -2
  1081. package/src/providers/inference/resolve-auth.ts +3 -3
  1082. package/src/providers/model-catalog.ts +38 -0
  1083. package/src/providers/placeholder-sentinels.ts +50 -15
  1084. package/src/providers/provider-send-message.ts +1 -1
  1085. package/src/providers/registry.ts +2 -0
  1086. package/src/providers/retry.ts +16 -0
  1087. package/src/providers/stop-reasons.ts +32 -0
  1088. package/src/providers/usage-tracking.ts +1 -1
  1089. package/src/runtime/__tests__/agent-wake.test.ts +100 -29
  1090. package/src/runtime/__tests__/background-job-runner.test.ts +19 -2
  1091. package/src/runtime/__tests__/channel-verification-service.test.ts +9 -5
  1092. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +7 -5
  1093. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +3 -3
  1094. package/src/runtime/__tests__/pre-first-message-gate.test.ts +1 -1
  1095. package/src/runtime/access-request-helper.ts +3 -3
  1096. package/src/runtime/agent-wake.ts +56 -11
  1097. package/src/runtime/assistant-event-hub.ts +1 -1
  1098. package/src/runtime/background-job-runner.ts +30 -10
  1099. package/src/runtime/channel-reply-delivery.ts +3 -3
  1100. package/src/runtime/channel-retry-sweep.ts +23 -3
  1101. package/src/runtime/channel-verification-service.ts +9 -9
  1102. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  1103. package/src/runtime/finalize-event-delivery.ts +2 -2
  1104. package/src/runtime/guardian-action-service.ts +1 -2
  1105. package/src/runtime/guardian-reply-router.ts +1 -1
  1106. package/src/runtime/http-server.ts +45 -1
  1107. package/src/runtime/invite-redemption-service.ts +11 -3
  1108. package/src/runtime/invite-service.ts +6 -4
  1109. package/src/runtime/migrations/vbundle-streaming-importer.ts +1 -1
  1110. package/src/runtime/pre-first-message-gate.ts +1 -1
  1111. package/src/runtime/routes/__tests__/acp-routes.test.ts +74 -8
  1112. package/src/runtime/routes/__tests__/backup-routes.test.ts +1 -1
  1113. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +3 -3
  1114. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +17 -23
  1115. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +3 -3
  1116. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +5 -5
  1117. package/src/runtime/routes/__tests__/contact-routes.test.ts +90 -9
  1118. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +5 -5
  1119. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +5 -5
  1120. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +3 -3
  1121. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +12 -12
  1122. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +4 -4
  1123. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +3 -3
  1124. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +3 -3
  1125. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +21 -7
  1126. package/src/runtime/routes/__tests__/memory-worker-routes.test.ts +306 -0
  1127. package/src/runtime/routes/__tests__/ps-routes.test.ts +114 -0
  1128. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +6 -6
  1129. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +4 -4
  1130. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
  1131. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  1132. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +125 -0
  1133. package/src/runtime/routes/acp-routes-event-log.test.ts +283 -0
  1134. package/src/runtime/routes/acp-routes-list.test.ts +24 -25
  1135. package/src/runtime/routes/acp-routes.test.ts +4 -4
  1136. package/src/runtime/routes/acp-routes.ts +31 -4
  1137. package/src/runtime/routes/app-management-routes.ts +9 -9
  1138. package/src/runtime/routes/app-routes.ts +3 -7
  1139. package/src/runtime/routes/approval-routes.ts +2 -4
  1140. package/src/runtime/routes/attachment-routes.ts +2 -2
  1141. package/src/runtime/routes/audit-routes.ts +2 -3
  1142. package/src/runtime/routes/background-wake-routes.ts +19 -5
  1143. package/src/runtime/routes/backup-routes.ts +1 -1
  1144. package/src/runtime/routes/bookmark-routes.ts +3 -3
  1145. package/src/runtime/routes/brain-graph-routes.ts +2 -2
  1146. package/src/runtime/routes/btw-routes.ts +1 -1
  1147. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1148. package/src/runtime/routes/channel-delivery-routes.ts +1 -1
  1149. package/src/runtime/routes/channel-readiness-routes.ts +7 -3
  1150. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +3 -8
  1151. package/src/runtime/routes/consolidation-routes.ts +6 -6
  1152. package/src/runtime/routes/contact-routes.ts +66 -15
  1153. package/src/runtime/routes/conversation-attention-routes.ts +2 -2
  1154. package/src/runtime/routes/conversation-cli-routes.ts +32 -7
  1155. package/src/runtime/routes/conversation-compaction-routes.ts +4 -4
  1156. package/src/runtime/routes/conversation-list-routes.ts +9 -9
  1157. package/src/runtime/routes/conversation-management-routes.ts +9 -9
  1158. package/src/runtime/routes/conversation-query-routes.ts +34 -11
  1159. package/src/runtime/routes/conversation-routes.ts +99 -16
  1160. package/src/runtime/routes/conversation-starter-routes.ts +11 -5
  1161. package/src/runtime/routes/conversations-import-routes.ts +10 -6
  1162. package/src/runtime/routes/debug-routes.ts +3 -3
  1163. package/src/runtime/routes/defer-routes.ts +4 -4
  1164. package/src/runtime/routes/documents-routes.ts +1 -1
  1165. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -1
  1166. package/src/runtime/routes/events-routes.ts +4 -4
  1167. package/src/runtime/routes/filing-routes.ts +1 -1
  1168. package/src/runtime/routes/global-search-routes.ts +4 -4
  1169. package/src/runtime/routes/group-routes.ts +1 -1
  1170. package/src/runtime/routes/guardian-action-routes.ts +1 -1
  1171. package/src/runtime/routes/heartbeat-routes.ts +2 -2
  1172. package/src/runtime/routes/home-feed-routes.ts +10 -5
  1173. package/src/runtime/routes/identity-routes.ts +33 -14
  1174. package/src/runtime/routes/inbound-conversation.ts +3 -3
  1175. package/src/runtime/routes/inbound-message-handler.ts +25 -25
  1176. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +8 -4
  1177. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +13 -6
  1178. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +5 -5
  1179. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -11
  1180. package/src/runtime/routes/inbound-stages/edit-intercept.ts +12 -12
  1181. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -2
  1182. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +1 -1
  1183. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +1 -1
  1184. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +8 -8
  1185. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +5 -2
  1186. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  1187. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
  1188. package/src/runtime/routes/index.ts +6 -4
  1189. package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
  1190. package/src/runtime/routes/inference-profile-session-reaper.ts +1 -1
  1191. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -2
  1192. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +3 -4
  1193. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  1194. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  1195. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
  1196. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1197. package/src/runtime/routes/log-export-routes.ts +2 -2
  1198. package/src/runtime/routes/memory-worker-routes.ts +227 -0
  1199. package/src/runtime/routes/migration-rollback-routes.ts +11 -12
  1200. package/src/runtime/routes/migration-routes.ts +143 -5
  1201. package/src/runtime/routes/notification-routes.ts +2 -2
  1202. package/src/runtime/routes/platform-routes.ts +3 -0
  1203. package/src/runtime/routes/playground/helpers.ts +3 -3
  1204. package/src/runtime/routes/ps-routes.ts +37 -66
  1205. package/src/runtime/routes/publish-routes.ts +3 -3
  1206. package/src/runtime/routes/rename-conversation-routes.ts +1 -1
  1207. package/src/runtime/routes/retrospective-routes.ts +5 -5
  1208. package/src/runtime/routes/schedule-routes.ts +42 -40
  1209. package/src/runtime/routes/secret-routes.ts +10 -9
  1210. package/src/runtime/routes/sequence-routes.ts +1 -1
  1211. package/src/runtime/routes/settings-routes.ts +18 -9
  1212. package/src/runtime/routes/skills-routes.ts +11 -1
  1213. package/src/runtime/routes/slack-channel-routes.ts +4 -4
  1214. package/src/runtime/routes/subagents-routes.ts +2 -2
  1215. package/src/runtime/routes/surface-conversation-resolver.ts +1 -1
  1216. package/src/runtime/routes/task-routes.ts +18 -29
  1217. package/src/runtime/routes/telemetry-routes.ts +1 -1
  1218. package/src/runtime/routes/trace-event-routes.ts +1 -1
  1219. package/src/runtime/routes/types.ts +7 -0
  1220. package/src/runtime/routes/usage-routes.ts +2 -2
  1221. package/src/runtime/routes/wake-conversation-routes.ts +44 -8
  1222. package/src/runtime/routes/wipe-conversation-routes.ts +3 -3
  1223. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  1224. package/src/runtime/routes/work-items-routes.ts +1 -1
  1225. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  1226. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +362 -0
  1227. package/src/runtime/services/__tests__/auto-analysis-guard.test.ts +57 -0
  1228. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +178 -0
  1229. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -1
  1230. package/src/runtime/services/analyze-conversation.ts +22 -13
  1231. package/src/runtime/services/auto-analysis-enqueue.ts +130 -0
  1232. package/src/runtime/services/auto-analysis-guard.ts +13 -0
  1233. package/src/runtime/services/conversation-analyze-job.ts +53 -0
  1234. package/src/runtime/services/conversation-serializer.ts +5 -5
  1235. package/src/runtime/tool-grant-request-helper.ts +1 -1
  1236. package/src/schedule/retry-policy.ts +8 -8
  1237. package/src/schedule/run-script.ts +7 -2
  1238. package/src/schedule/schedule-recovery.ts +8 -5
  1239. package/src/schedule/schedule-store.ts +270 -162
  1240. package/src/schedule/schedule-usage-store.ts +2 -2
  1241. package/src/schedule/scheduler-types.ts +6 -0
  1242. package/src/schedule/scheduler.ts +189 -59
  1243. package/src/security/auth-fallback-events-store.ts +94 -0
  1244. package/src/security/redaction.ts +18 -14
  1245. package/src/sequence/engine.ts +1 -1
  1246. package/src/sequence/store.ts +3 -3
  1247. package/src/services/published-app-updater.ts +2 -2
  1248. package/src/signals/cancel.ts +1 -1
  1249. package/src/signals/user-message.ts +2 -2
  1250. package/src/skills/catalog-install.ts +2 -1
  1251. package/src/skills/clawhub.ts +1 -0
  1252. package/src/skills/install-meta.ts +44 -0
  1253. package/src/skills/managed-store.ts +101 -3
  1254. package/src/skills/skillssh-registry.ts +1 -0
  1255. package/src/skills/version-hash.ts +20 -0
  1256. package/src/subagent/manager.ts +5 -4
  1257. package/src/tasks/task-compiler.ts +2 -2
  1258. package/src/tasks/task-runner.ts +3 -3
  1259. package/src/tasks/task-store.ts +2 -2
  1260. package/src/telemetry/__tests__/watchdog-events-store.test.ts +161 -0
  1261. package/src/telemetry/skill-loaded-events-store.test.ts +152 -0
  1262. package/src/telemetry/skill-loaded-events-store.ts +95 -0
  1263. package/src/telemetry/tool-executed-events-store.test.ts +219 -0
  1264. package/src/telemetry/tool-executed-events-store.ts +102 -0
  1265. package/src/telemetry/tool-usage-store.ts +114 -0
  1266. package/src/telemetry/trace-event-store.ts +133 -0
  1267. package/src/telemetry/turn-events-store.ts +173 -0
  1268. package/src/telemetry/turn-trace-store.test.ts +736 -0
  1269. package/src/telemetry/turn-trace-store.ts +364 -0
  1270. package/src/telemetry/usage-telemetry-reporter.test.ts +12 -12
  1271. package/src/telemetry/usage-telemetry-reporter.ts +46 -17
  1272. package/src/telemetry/watchdog-events-store.ts +87 -0
  1273. package/src/tools/__tests__/run-standalone.test.ts +19 -0
  1274. package/src/tools/acp/spawn.test.ts +18 -7
  1275. package/src/tools/acp/spawn.ts +1 -0
  1276. package/src/tools/apps/executors.ts +2 -2
  1277. package/src/tools/apps/resolve-app-id.ts +1 -1
  1278. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +3 -3
  1279. package/src/tools/document/document-comment-tool.test.ts +2 -2
  1280. package/src/tools/filesystem/write.ts +5 -4
  1281. package/src/tools/policy-context.ts +21 -0
  1282. package/src/tools/registry.ts +31 -1
  1283. package/src/tools/run-standalone.ts +101 -0
  1284. package/src/tools/schedule/create.ts +2 -2
  1285. package/src/tools/schedule/delete.ts +1 -1
  1286. package/src/tools/schedule/update.ts +1 -1
  1287. package/src/tools/skills/find-similar-skills.test.ts +277 -0
  1288. package/src/tools/skills/find-similar-skills.ts +120 -0
  1289. package/src/tools/skills/scaffold-managed.ts +123 -4
  1290. package/src/tools/subagent/read.ts +1 -1
  1291. package/src/tools/subagent/spawn.ts +1 -1
  1292. package/src/tools/tool-approval-handler.ts +1 -1
  1293. package/src/tools/tool-manifest.ts +1 -1
  1294. package/src/tools/types.ts +11 -0
  1295. package/src/usage/types.ts +7 -0
  1296. package/src/util/__tests__/process-tree.test.ts +123 -0
  1297. package/src/util/device-id.ts +52 -12
  1298. package/src/util/platform.ts +0 -14
  1299. package/src/util/process-tree.ts +203 -0
  1300. package/src/util/sqlite-retry.ts +90 -0
  1301. package/src/watcher/__tests__/telemetry.test.ts +2 -2
  1302. package/src/watcher/telemetry.ts +2 -2
  1303. package/src/watcher/watcher-store.ts +3 -3
  1304. package/src/work-items/work-item-store.ts +2 -2
  1305. package/src/workflows/engine-integration.test.ts +2 -2
  1306. package/src/workflows/engine.test.ts +2 -2
  1307. package/src/workflows/fanout-load.test.ts +2 -2
  1308. package/src/workflows/journal-store.test.ts +3 -3
  1309. package/src/workflows/journal-store.ts +1 -1
  1310. package/src/workflows/leaf-runner.test.ts +9 -6
  1311. package/src/workflows/leaf-runner.ts +1 -1
  1312. package/src/workspace/heartbeat-service.ts +29 -0
  1313. package/src/workspace/migrations/011-backfill-installation-id.ts +1 -1
  1314. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +5 -2
  1315. package/src/workspace/migrations/031-drop-user-md.ts +26 -0
  1316. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +1 -1
  1317. package/src/workspace/migrations/113-swap-balanced-profile-to-glm-5p2.ts +101 -0
  1318. package/src/workspace/migrations/114-swap-quality-profile-to-opus.ts +83 -0
  1319. package/src/workspace/migrations/115-drop-frontier-profile.ts +129 -0
  1320. package/src/workspace/migrations/116-rename-memory-plugin-disabled-sentinel.ts +53 -0
  1321. package/src/workspace/migrations/117-normalize-stale-lean-memory-v3-defaults.ts +116 -0
  1322. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +5 -2
  1323. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +4 -4
  1324. package/src/workspace/migrations/registry.ts +10 -0
  1325. package/src/__tests__/config-managed-gemini-defaults.test.ts +0 -277
  1326. package/src/__tests__/slack-block-formatting.test.ts +0 -173
  1327. package/src/background-wake/runtime-registry.ts +0 -24
  1328. package/src/contacts/contact-events.ts +0 -21
  1329. package/src/daemon/__tests__/meet-host-supervisor.test.ts +0 -587
  1330. package/src/daemon/__tests__/meet-manifest-loader.test.ts +0 -476
  1331. package/src/daemon/meet-host-startup.ts +0 -51
  1332. package/src/daemon/meet-host-supervisor.ts +0 -782
  1333. package/src/daemon/meet-manifest-loader.ts +0 -396
  1334. package/src/daemon/server.ts +0 -423
  1335. package/src/filing/filing-service.ts +0 -429
  1336. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  1337. package/src/memory/__tests__/activation-session-store.test.ts +0 -41
  1338. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +0 -359
  1339. package/src/memory/__tests__/auto-analysis-guard.test.ts +0 -57
  1340. package/src/memory/__tests__/bookmark-crud.test.ts +0 -264
  1341. package/src/memory/__tests__/bookmark-schema.test.ts +0 -181
  1342. package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +0 -432
  1343. package/src/memory/__tests__/conversation-analyze-job.test.ts +0 -178
  1344. package/src/memory/__tests__/conversation-group-migration.test.ts +0 -99
  1345. package/src/memory/__tests__/conversation-queries.test.ts +0 -843
  1346. package/src/memory/__tests__/conversation-types.test.ts +0 -36
  1347. package/src/memory/__tests__/db-async-query.test.ts +0 -165
  1348. package/src/memory/__tests__/db-logs-attach.test.ts +0 -110
  1349. package/src/memory/__tests__/db-maintenance.test.ts +0 -235
  1350. package/src/memory/__tests__/db-memory-attach.test.ts +0 -113
  1351. package/src/memory/__tests__/embedding-cache.test.ts +0 -136
  1352. package/src/memory/__tests__/find-analysis-conversation.test.ts +0 -197
  1353. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +0 -140
  1354. package/src/memory/__tests__/fork-message-copy.test.ts +0 -232
  1355. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +0 -241
  1356. package/src/memory/__tests__/jobs-store-job-classes.test.ts +0 -52
  1357. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +0 -113
  1358. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +0 -505
  1359. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +0 -160
  1360. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -1443
  1361. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +0 -544
  1362. package/src/memory/__tests__/memory-retrospective-state.test.ts +0 -195
  1363. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -221
  1364. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +0 -275
  1365. package/src/memory/__tests__/memory-v3-selections-migration.test.ts +0 -103
  1366. package/src/memory/__tests__/message-content.test.ts +0 -35
  1367. package/src/memory/__tests__/onboarding-events-store.test.ts +0 -80
  1368. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  1369. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +0 -49
  1370. package/src/memory/__tests__/table-relocation.test.ts +0 -129
  1371. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  1372. package/src/memory/activation-session-store.ts +0 -43
  1373. package/src/memory/anisotropy.ts +0 -443
  1374. package/src/memory/app-store.ts +0 -1058
  1375. package/src/memory/attachments-store.ts +0 -1136
  1376. package/src/memory/auth-fallback-events-store.ts +0 -94
  1377. package/src/memory/auto-analysis-enqueue.ts +0 -127
  1378. package/src/memory/auto-analysis-guard.ts +0 -17
  1379. package/src/memory/canonical-guardian-store.ts +0 -891
  1380. package/src/memory/channel-verification-sessions.ts +0 -557
  1381. package/src/memory/checkpoints.ts +0 -65
  1382. package/src/memory/compaction-ledger-store.ts +0 -107
  1383. package/src/memory/context-search/agent-protocol.ts +0 -428
  1384. package/src/memory/context-search/agent-runner.ts +0 -1310
  1385. package/src/memory/context-search/search.ts +0 -297
  1386. package/src/memory/context-search/sources/conversations.ts +0 -341
  1387. package/src/memory/context-search/sources/memory-v2.ts +0 -600
  1388. package/src/memory/context-search/sources/memory.ts +0 -101
  1389. package/src/memory/context-search/types.ts +0 -48
  1390. package/src/memory/conversation-analyze-job.ts +0 -53
  1391. package/src/memory/conversation-attention-store.ts +0 -689
  1392. package/src/memory/conversation-bootstrap.ts +0 -50
  1393. package/src/memory/conversation-crud.ts +0 -3436
  1394. package/src/memory/conversation-key-store.ts +0 -274
  1395. package/src/memory/conversation-queries.ts +0 -768
  1396. package/src/memory/conversation-starter-checkpoints.ts +0 -64
  1397. package/src/memory/db-async-query.ts +0 -298
  1398. package/src/memory/db-connection.ts +0 -228
  1399. package/src/memory/db-init.ts +0 -265
  1400. package/src/memory/db-maintenance.ts +0 -154
  1401. package/src/memory/embed.ts +0 -73
  1402. package/src/memory/embedding-backend.test.ts +0 -204
  1403. package/src/memory/embedding-backend.ts +0 -862
  1404. package/src/memory/embedding-billing-breaker.ts +0 -96
  1405. package/src/memory/embedding-cache.ts +0 -139
  1406. package/src/memory/embedding-local.ts +0 -587
  1407. package/src/memory/embedding-ollama.ts +0 -79
  1408. package/src/memory/embedding-runtime-manager.ts +0 -573
  1409. package/src/memory/embedding-types.ts +0 -90
  1410. package/src/memory/external-conversation-store.ts +0 -315
  1411. package/src/memory/fork-message-copy.ts +0 -170
  1412. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +0 -119
  1413. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +0 -655
  1414. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +0 -321
  1415. package/src/memory/graph/bootstrap.test.ts +0 -280
  1416. package/src/memory/graph/bootstrap.ts +0 -532
  1417. package/src/memory/graph/capability-seed.ts +0 -451
  1418. package/src/memory/graph/consolidation.ts +0 -712
  1419. package/src/memory/graph/conversation-graph-memory.ts +0 -1185
  1420. package/src/memory/graph/decay.ts +0 -195
  1421. package/src/memory/graph/extraction-job.ts +0 -74
  1422. package/src/memory/graph/extraction.ts +0 -1462
  1423. package/src/memory/graph/graph-memory-state-store.ts +0 -50
  1424. package/src/memory/graph/graph-search.test.ts +0 -129
  1425. package/src/memory/graph/graph-search.ts +0 -292
  1426. package/src/memory/graph/image-ref-utils.ts +0 -29
  1427. package/src/memory/graph/injection.ts +0 -469
  1428. package/src/memory/graph/narrative.ts +0 -267
  1429. package/src/memory/graph/pattern-scan.ts +0 -269
  1430. package/src/memory/graph/retriever.test.ts +0 -624
  1431. package/src/memory/graph/retriever.ts +0 -1356
  1432. package/src/memory/graph/store.test.ts +0 -1093
  1433. package/src/memory/graph/store.ts +0 -923
  1434. package/src/memory/graph/tool-handlers.ts +0 -195
  1435. package/src/memory/graph/tools.ts +0 -95
  1436. package/src/memory/guardian-rate-limits.ts +0 -191
  1437. package/src/memory/indexer.ts +0 -406
  1438. package/src/memory/job-handlers/backfill.ts +0 -104
  1439. package/src/memory/job-handlers/cleanup.ts +0 -237
  1440. package/src/memory/job-handlers/conversation-starters.ts +0 -481
  1441. package/src/memory/job-handlers/embedding.test.ts +0 -234
  1442. package/src/memory/job-handlers/embedding.ts +0 -133
  1443. package/src/memory/job-handlers/index-maintenance.ts +0 -111
  1444. package/src/memory/job-handlers/media-processing.ts +0 -120
  1445. package/src/memory/job-handlers/summarization.ts +0 -240
  1446. package/src/memory/job-utils.ts +0 -286
  1447. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +0 -559
  1448. package/src/memory/jobs/embed-concept-page.ts +0 -417
  1449. package/src/memory/jobs/embed-pkb-file.test.ts +0 -169
  1450. package/src/memory/jobs/embed-pkb-file.ts +0 -59
  1451. package/src/memory/jobs-store.ts +0 -813
  1452. package/src/memory/jobs-worker.ts +0 -1021
  1453. package/src/memory/llm-request-log-source-clickhouse.ts +0 -521
  1454. package/src/memory/llm-request-log-store.ts +0 -717
  1455. package/src/memory/llm-usage-store.ts +0 -900
  1456. package/src/memory/memory-recall-log-store.ts +0 -172
  1457. package/src/memory/memory-retrospective-constants.ts +0 -50
  1458. package/src/memory/memory-retrospective-enqueue.ts +0 -125
  1459. package/src/memory/memory-retrospective-fork-boundary.ts +0 -94
  1460. package/src/memory/memory-retrospective-job.ts +0 -884
  1461. package/src/memory/memory-retrospective-startup-cleanup.ts +0 -261
  1462. package/src/memory/memory-retrospective-state.ts +0 -245
  1463. package/src/memory/memory-retrospective-trigger-check.ts +0 -91
  1464. package/src/memory/memory-v2-activation-log-store.ts +0 -216
  1465. package/src/memory/memory-v2-concept-frequency.ts +0 -173
  1466. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +0 -303
  1467. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +0 -365
  1468. package/src/memory/migrations/142-rename-verification-session-id-column.ts +0 -55
  1469. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +0 -20
  1470. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +0 -179
  1471. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +0 -64
  1472. package/src/memory/migrations/202-memory-graph-tables.ts +0 -130
  1473. package/src/memory/migrations/203-drop-memory-items-tables.ts +0 -55
  1474. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +0 -124
  1475. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +0 -174
  1476. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +0 -16
  1477. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +0 -183
  1478. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +0 -76
  1479. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +0 -21
  1480. package/src/memory/migrations/243-provider-connections.ts +0 -68
  1481. package/src/memory/migrations/244-provider-connection-status-label.ts +0 -23
  1482. package/src/memory/migrations/246-backfill-provider-connection-label.ts +0 -81
  1483. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +0 -19
  1484. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  1485. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -297
  1486. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +0 -84
  1487. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +0 -192
  1488. package/src/memory/migrations/__tests__/run-migrations.test.ts +0 -378
  1489. package/src/memory/migrations/helpers/relocation.ts +0 -227
  1490. package/src/memory/migrations/validate-migration-state.ts +0 -277
  1491. package/src/memory/onboarding-events-store.ts +0 -161
  1492. package/src/memory/pkb/autoinject.ts +0 -61
  1493. package/src/memory/pkb/context.ts +0 -50
  1494. package/src/memory/pkb/pkb-index.test.ts +0 -368
  1495. package/src/memory/pkb/pkb-index.ts +0 -255
  1496. package/src/memory/pkb/pkb-reconcile.test.ts +0 -251
  1497. package/src/memory/pkb/pkb-reconcile.ts +0 -148
  1498. package/src/memory/pkb/pkb-search.test.ts +0 -586
  1499. package/src/memory/pkb/pkb-search.ts +0 -178
  1500. package/src/memory/pkb/types.ts +0 -67
  1501. package/src/memory/published-pages-store.ts +0 -67
  1502. package/src/memory/qdrant-circuit-breaker.ts +0 -119
  1503. package/src/memory/qdrant-client.test.ts +0 -60
  1504. package/src/memory/qdrant-client.ts +0 -834
  1505. package/src/memory/qdrant-manager.ts +0 -422
  1506. package/src/memory/rerank-local.ts +0 -374
  1507. package/src/memory/schedule-attribution-sql.ts +0 -104
  1508. package/src/memory/schema/acp.ts +0 -34
  1509. package/src/memory/schema/contacts.ts +0 -120
  1510. package/src/memory/schema/conversations.ts +0 -236
  1511. package/src/memory/schema/infrastructure.ts +0 -381
  1512. package/src/memory/scoped-approval-grants.ts +0 -551
  1513. package/src/memory/search/semantic.ts +0 -238
  1514. package/src/memory/segmenter.ts +0 -76
  1515. package/src/memory/shared-app-links-store.ts +0 -130
  1516. package/src/memory/skill-loaded-events-store.test.ts +0 -152
  1517. package/src/memory/skill-loaded-events-store.ts +0 -95
  1518. package/src/memory/sparse-tokenize.ts +0 -49
  1519. package/src/memory/steps.ts +0 -1296
  1520. package/src/memory/task-memory-cleanup.ts +0 -236
  1521. package/src/memory/tool-executed-events-store.test.ts +0 -219
  1522. package/src/memory/tool-executed-events-store.ts +0 -102
  1523. package/src/memory/tool-usage-store.ts +0 -113
  1524. package/src/memory/trace-event-store.ts +0 -133
  1525. package/src/memory/turn-events-store.ts +0 -173
  1526. package/src/memory/turn-trace-store.test.ts +0 -736
  1527. package/src/memory/turn-trace-store.ts +0 -364
  1528. package/src/memory/v2/__tests__/activation-store.test.ts +0 -204
  1529. package/src/memory/v2/__tests__/activation.test.ts +0 -1227
  1530. package/src/memory/v2/__tests__/backfill-jobs.test.ts +0 -504
  1531. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -429
  1532. package/src/memory/v2/__tests__/consolidation-job.test.ts +0 -747
  1533. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -189
  1534. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +0 -136
  1535. package/src/memory/v2/__tests__/harness-compare.test.ts +0 -186
  1536. package/src/memory/v2/__tests__/harness-oracle.test.ts +0 -257
  1537. package/src/memory/v2/__tests__/harness-replay-input.test.ts +0 -230
  1538. package/src/memory/v2/__tests__/harness-runner.test.ts +0 -135
  1539. package/src/memory/v2/__tests__/injection-events.test.ts +0 -318
  1540. package/src/memory/v2/__tests__/injection.test.ts +0 -2301
  1541. package/src/memory/v2/__tests__/migration.test.ts +0 -939
  1542. package/src/memory/v2/__tests__/page-index.test.ts +0 -760
  1543. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +0 -313
  1544. package/src/memory/v2/__tests__/qdrant.test.ts +0 -950
  1545. package/src/memory/v2/__tests__/reranker.test.ts +0 -338
  1546. package/src/memory/v2/__tests__/router.test.ts +0 -1197
  1547. package/src/memory/v2/__tests__/sim.test.ts +0 -670
  1548. package/src/memory/v2/__tests__/skill-content.test.ts +0 -115
  1549. package/src/memory/v2/__tests__/skill-store.test.ts +0 -983
  1550. package/src/memory/v2/__tests__/sparse-bm25.test.ts +0 -292
  1551. package/src/memory/v2/__tests__/static-context.test.ts +0 -223
  1552. package/src/memory/v2/__tests__/sweep-job.test.ts +0 -526
  1553. package/src/memory/v2/activation-store.ts +0 -185
  1554. package/src/memory/v2/activation.ts +0 -548
  1555. package/src/memory/v2/backfill-jobs.ts +0 -296
  1556. package/src/memory/v2/cli-command-store.ts +0 -341
  1557. package/src/memory/v2/consolidation-job.ts +0 -561
  1558. package/src/memory/v2/frontmatter-sweep.ts +0 -98
  1559. package/src/memory/v2/harness/compare.ts +0 -57
  1560. package/src/memory/v2/harness/oracle.ts +0 -145
  1561. package/src/memory/v2/harness/replay-input.ts +0 -240
  1562. package/src/memory/v2/harness/retriever.ts +0 -74
  1563. package/src/memory/v2/harness/router-retriever.ts +0 -43
  1564. package/src/memory/v2/injected-block-slugs.ts +0 -79
  1565. package/src/memory/v2/injection-events.ts +0 -101
  1566. package/src/memory/v2/injection.ts +0 -932
  1567. package/src/memory/v2/migration.ts +0 -776
  1568. package/src/memory/v2/page-index.ts +0 -459
  1569. package/src/memory/v2/page-store.ts +0 -443
  1570. package/src/memory/v2/prompts/consolidation.ts +0 -857
  1571. package/src/memory/v2/prompts/router.ts +0 -148
  1572. package/src/memory/v2/qdrant.ts +0 -892
  1573. package/src/memory/v2/reranker.ts +0 -184
  1574. package/src/memory/v2/router.ts +0 -601
  1575. package/src/memory/v2/sim.ts +0 -296
  1576. package/src/memory/v2/skill-content.ts +0 -61
  1577. package/src/memory/v2/skill-store.ts +0 -431
  1578. package/src/memory/v2/sparse-bm25.ts +0 -245
  1579. package/src/memory/v2/static-context.ts +0 -100
  1580. package/src/memory/v2/sweep-job.ts +0 -320
  1581. package/src/memory/v3-eval/eval-packets.ts +0 -731
  1582. package/src/memory/watchdog-events-store.ts +0 -87
  1583. package/src/memory/worker-control.ts +0 -204
  1584. package/src/memory/worker-process.ts +0 -89
  1585. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +0 -116
  1586. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +0 -370
  1587. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +0 -41
  1588. package/src/plugins/defaults/memory-retrieval/injectors.ts +0 -1061
  1589. package/src/plugins/defaults/memory-retrieval/package.json +0 -14
  1590. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +0 -64
  1591. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +0 -1164
  1592. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +0 -192
  1593. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +0 -247
  1594. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +0 -717
  1595. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +0 -365
  1596. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +0 -736
  1597. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +0 -839
  1598. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +0 -598
  1599. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +0 -128
  1600. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +0 -710
  1601. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +0 -425
  1602. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +0 -493
  1603. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +0 -856
  1604. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +0 -91
  1605. package/src/plugins/defaults/memory-v3-shadow/card.ts +0 -160
  1606. package/src/plugins/defaults/memory-v3-shadow/dense.ts +0 -97
  1607. package/src/plugins/defaults/memory-v3-shadow/edge.ts +0 -252
  1608. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +0 -305
  1609. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +0 -278
  1610. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
  1611. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
  1612. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +0 -138
  1613. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +0 -85
  1614. package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -453
  1615. package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +0 -169
  1616. package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +0 -178
  1617. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +0 -794
  1618. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +0 -431
  1619. package/src/plugins/defaults/memory-v3-shadow/package.json +0 -14
  1620. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +0 -102
  1621. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  1622. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +0 -578
  1623. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +0 -758
  1624. package/src/plugins/defaults/memory-v3-shadow/prune.ts +0 -471
  1625. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +0 -92
  1626. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +0 -422
  1627. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +0 -200
  1628. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +0 -281
  1629. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +0 -642
  1630. package/src/plugins/defaults/memory-v3-shadow/types.ts +0 -127
  1631. package/src/plugins/feature-gate.ts +0 -22
  1632. package/src/runtime/__tests__/slack-block-formatting.test.ts +0 -510
  1633. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +0 -165
  1634. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +0 -347
  1635. package/src/runtime/routes/memory-eval-routes.ts +0 -179
  1636. package/src/runtime/routes/memory-item-routes.test.ts +0 -912
  1637. package/src/runtime/routes/memory-item-routes.ts +0 -815
  1638. package/src/runtime/routes/memory-v2-routes.ts +0 -850
  1639. package/src/runtime/routes/memory-v3-routes.ts +0 -122
  1640. package/src/runtime/routes/secrets-deps.ts +0 -24
  1641. package/src/runtime/slack-block-formatting.ts +0 -586
  1642. package/src/tools/memory/register.test.ts +0 -382
  1643. package/src/tools/memory/register.ts +0 -81
  1644. /package/src/{memory → apps}/app-git-service.ts +0 -0
  1645. /package/src/{memory → channels}/slack-thread-store.ts +0 -0
  1646. /package/src/{memory → home}/conversation-starter-validation.ts +0 -0
  1647. /package/src/{memory → persistence}/auto-analysis-constants.ts +0 -0
  1648. /package/src/{memory → persistence}/bookmark-crud.ts +0 -0
  1649. /package/src/{memory → persistence}/cleanup-schedule-state.ts +0 -0
  1650. /package/src/{memory → persistence}/compaction-log-store-clickhouse.ts +0 -0
  1651. /package/src/{memory → persistence}/conversation-directories.ts +0 -0
  1652. /package/src/{memory → persistence}/conversation-disk-view.ts +0 -0
  1653. /package/src/{memory → persistence}/conversation-display-order-migration.ts +0 -0
  1654. /package/src/{memory → persistence}/conversation-group-migration.ts +0 -0
  1655. /package/src/{memory → persistence}/conversation-title-service.ts +0 -0
  1656. /package/src/{memory → persistence}/conversation-types.ts +0 -0
  1657. /package/src/{memory → persistence}/db-singleton.ts +0 -0
  1658. /package/src/{memory → persistence}/delivery-channels.ts +0 -0
  1659. /package/src/{memory → persistence}/delivery-crud.ts +0 -0
  1660. /package/src/{memory → persistence}/delivery-status.ts +0 -0
  1661. /package/src/{memory → persistence/embeddings}/__tests__/sparse-tokenize.test.ts +0 -0
  1662. /package/src/{memory → persistence/embeddings}/embedding-gemini.test.ts +0 -0
  1663. /package/src/{memory → persistence/embeddings}/embedding-gemini.ts +0 -0
  1664. /package/src/{memory → persistence/embeddings}/embedding-openai.ts +0 -0
  1665. /package/src/{memory → persistence/embeddings}/embedding-types.test.ts +0 -0
  1666. /package/src/{memory → persistence}/fingerprint.ts +0 -0
  1667. /package/src/{memory → persistence}/group-crud.ts +0 -0
  1668. /package/src/{memory → persistence}/invite-store.ts +0 -0
  1669. /package/src/{memory → persistence}/lifecycle-events-store.ts +0 -0
  1670. /package/src/{memory → persistence}/llm-request-log-source-local.ts +0 -0
  1671. /package/src/{memory → persistence}/llm-request-log-source.ts +0 -0
  1672. /package/src/{memory → persistence}/media-store.ts +0 -0
  1673. /package/src/{memory → persistence}/message-content.ts +0 -0
  1674. /package/src/{memory → persistence}/migrations/000-core-tables.ts +0 -0
  1675. /package/src/{memory → persistence}/migrations/001-job-deferrals.ts +0 -0
  1676. /package/src/{memory → persistence}/migrations/002-tool-invocations-fk.ts +0 -0
  1677. /package/src/{memory → persistence}/migrations/003-memory-fts-backfill.ts +0 -0
  1678. /package/src/{memory → persistence}/migrations/004-entity-relation-dedup.ts +0 -0
  1679. /package/src/{memory → persistence}/migrations/005-fingerprint-scope-unique.ts +0 -0
  1680. /package/src/{memory → persistence}/migrations/006-scope-salted-fingerprints.ts +0 -0
  1681. /package/src/{memory → persistence}/migrations/007-assistant-id-to-self.ts +0 -0
  1682. /package/src/{memory → persistence}/migrations/008-remove-assistant-id-columns.ts +0 -0
  1683. /package/src/{memory → persistence}/migrations/009-llm-usage-events-drop-assistant-id.ts +0 -0
  1684. /package/src/{memory → persistence}/migrations/011-call-sessions-provider-sid-dedup.ts +0 -0
  1685. /package/src/{memory → persistence}/migrations/012-call-sessions-add-initiated-from.ts +0 -0
  1686. /package/src/{memory → persistence}/migrations/013-guardian-action-tables.ts +0 -0
  1687. /package/src/{memory → persistence}/migrations/014-backfill-inbox-thread-state.ts +0 -0
  1688. /package/src/{memory → persistence}/migrations/015-drop-active-search-index.ts +0 -0
  1689. /package/src/{memory → persistence}/migrations/016-memory-segments-indexes.ts +0 -0
  1690. /package/src/{memory → persistence}/migrations/017-memory-items-indexes.ts +0 -0
  1691. /package/src/{memory → persistence}/migrations/018-remaining-table-indexes.ts +0 -0
  1692. /package/src/{memory → persistence}/migrations/019-notification-tables-schema-migration.ts +0 -0
  1693. /package/src/{memory → persistence}/migrations/020-rename-macos-ios-channel-to-vellum.ts +0 -0
  1694. /package/src/{memory → persistence}/migrations/021-conversation-status-indexes.ts +0 -0
  1695. /package/src/{memory → persistence}/migrations/022-add-origin-interface.ts +0 -0
  1696. /package/src/{memory → persistence}/migrations/023-memory-item-sources-indexes.ts +0 -0
  1697. /package/src/{memory → persistence}/migrations/024-embedding-vector-blob.ts +0 -0
  1698. /package/src/{memory → persistence}/migrations/025-messages-fts-backfill.ts +0 -0
  1699. /package/src/{memory → persistence}/migrations/026-guardian-verification-sessions.ts +0 -0
  1700. /package/src/{memory → persistence}/migrations/026a-embeddings-nullable-vector-json.ts +0 -0
  1701. /package/src/{memory → persistence}/migrations/027-notification-delivery-pairing-columns.ts +0 -0
  1702. /package/src/{memory → persistence}/migrations/027a-guardian-bootstrap-token.ts +0 -0
  1703. /package/src/{memory → persistence}/migrations/028-call-session-mode.ts +0 -0
  1704. /package/src/{memory → persistence}/migrations/028-notification-delivery-client-ack.ts +0 -0
  1705. /package/src/{memory → persistence}/migrations/029-channel-inbound-delivered-segments.ts +0 -0
  1706. /package/src/{memory → persistence}/migrations/030-guardian-action-followup.ts +0 -0
  1707. /package/src/{memory → persistence}/migrations/030-guardian-verification-purpose.ts +0 -0
  1708. /package/src/{memory → persistence}/migrations/031-conversations-thread-type-index.ts +0 -0
  1709. /package/src/{memory → persistence}/migrations/032-guardian-delivery-conversation-index.ts +0 -0
  1710. /package/src/{memory → persistence}/migrations/032-notification-delivery-thread-decision.ts +0 -0
  1711. /package/src/{memory → persistence}/migrations/033-scoped-approval-grants.ts +0 -0
  1712. /package/src/{memory → persistence}/migrations/034-guardian-action-tool-metadata.ts +0 -0
  1713. /package/src/{memory → persistence}/migrations/035-guardian-action-supersession.ts +0 -0
  1714. /package/src/{memory → persistence}/migrations/036-normalize-phone-identities.ts +0 -0
  1715. /package/src/{memory → persistence}/migrations/037-voice-invite-columns.ts +0 -0
  1716. /package/src/{memory → persistence}/migrations/040-invite-code-hash-column.ts +0 -0
  1717. /package/src/{memory → persistence}/migrations/041-approval-prompt-ts-tracker.ts +0 -0
  1718. /package/src/{memory → persistence}/migrations/101-watchers-and-logs.ts +0 -0
  1719. /package/src/{memory → persistence}/migrations/102-alter-table-columns.ts +0 -0
  1720. /package/src/{memory → persistence}/migrations/104-core-indexes.ts +0 -0
  1721. /package/src/{memory → persistence}/migrations/105-contacts-and-triage.ts +0 -0
  1722. /package/src/{memory → persistence}/migrations/106-call-sessions.ts +0 -0
  1723. /package/src/{memory → persistence}/migrations/107-followups.ts +0 -0
  1724. /package/src/{memory → persistence}/migrations/108-tasks-and-work-items.ts +0 -0
  1725. /package/src/{memory → persistence}/migrations/109-external-conversation-bindings.ts +0 -0
  1726. /package/src/{memory → persistence}/migrations/110-channel-guardian.ts +0 -0
  1727. /package/src/{memory → persistence}/migrations/111-media-assets.ts +0 -0
  1728. /package/src/{memory → persistence}/migrations/112-assistant-inbox.ts +0 -0
  1729. /package/src/{memory → persistence}/migrations/114-notifications.ts +0 -0
  1730. /package/src/{memory → persistence}/migrations/115-sequences.ts +0 -0
  1731. /package/src/{memory → persistence}/migrations/116-messages-fts.ts +0 -0
  1732. /package/src/{memory → persistence}/migrations/117-conversation-attention.ts +0 -0
  1733. /package/src/{memory → persistence}/migrations/118-reminder-routing-intent.ts +0 -0
  1734. /package/src/{memory → persistence}/migrations/119-schema-indexes-and-columns.ts +0 -0
  1735. /package/src/{memory → persistence}/migrations/120-fk-cascade-rebuilds.ts +0 -0
  1736. /package/src/{memory → persistence}/migrations/121-canonical-guardian-requests.ts +0 -0
  1737. /package/src/{memory → persistence}/migrations/122-canonical-guardian-requester-chat-id.ts +0 -0
  1738. /package/src/{memory → persistence}/migrations/123-canonical-guardian-deliveries-destination-index.ts +0 -0
  1739. /package/src/{memory → persistence}/migrations/124-voice-invite-display-metadata.ts +0 -0
  1740. /package/src/{memory → persistence}/migrations/125-guardian-principal-id-columns.ts +0 -0
  1741. /package/src/{memory → persistence}/migrations/127-guardian-principal-id-not-null.ts +0 -0
  1742. /package/src/{memory → persistence}/migrations/128-contacts-role-principal.ts +0 -0
  1743. /package/src/{memory → persistence}/migrations/129-contact-channels-access-fields.ts +0 -0
  1744. /package/src/{memory → persistence}/migrations/130-contact-channels-type-ext-chat-id-index.ts +0 -0
  1745. /package/src/{memory → persistence}/migrations/131-drop-legacy-member-guardian-tables.ts +0 -0
  1746. /package/src/{memory → persistence}/migrations/132-contacts-assistant-id.ts +0 -0
  1747. /package/src/{memory → persistence}/migrations/133-assistant-contact-metadata.ts +0 -0
  1748. /package/src/{memory → persistence}/migrations/134-contacts-notes-column.ts +0 -0
  1749. /package/src/{memory → persistence}/migrations/135-backfill-contact-interaction-stats.ts +0 -0
  1750. /package/src/{memory → persistence}/migrations/136-drop-assistant-id-columns.ts +0 -0
  1751. /package/src/{memory → persistence}/migrations/137-usage-dashboard-indexes.ts +0 -0
  1752. /package/src/{memory → persistence}/migrations/139-drop-usage-composite-indexes.ts +0 -0
  1753. /package/src/{memory → persistence}/migrations/141-rename-verification-table.ts +0 -0
  1754. /package/src/{memory → persistence}/migrations/143-rename-guardian-verification-values.ts +0 -0
  1755. /package/src/{memory → persistence}/migrations/144-rename-voice-to-phone.ts +0 -0
  1756. /package/src/{memory → persistence}/migrations/145-drop-accounts-table.ts +0 -0
  1757. /package/src/{memory → persistence}/migrations/146-schedule-oneshot-routing.ts +0 -0
  1758. /package/src/{memory → persistence}/migrations/147-migrate-reminders-to-schedules.ts +0 -0
  1759. /package/src/{memory → persistence}/migrations/148-drop-reminders-table.ts +0 -0
  1760. /package/src/{memory → persistence}/migrations/149-oauth-tables.ts +0 -0
  1761. /package/src/{memory → persistence}/migrations/150-oauth-apps-client-secret-path.ts +0 -0
  1762. /package/src/{memory → persistence}/migrations/151-oauth-providers-ping-url.ts +0 -0
  1763. /package/src/{memory → persistence}/migrations/152-memory-item-supersession.ts +0 -0
  1764. /package/src/{memory → persistence}/migrations/153-drop-entity-tables.ts +0 -0
  1765. /package/src/{memory → persistence}/migrations/154-drop-fts.ts +0 -0
  1766. /package/src/{memory → persistence}/migrations/155-drop-conflicts.ts +0 -0
  1767. /package/src/{memory → persistence}/migrations/156-call-session-invite-metadata.ts +0 -0
  1768. /package/src/{memory → persistence}/migrations/157-invite-contact-id.ts +0 -0
  1769. /package/src/{memory → persistence}/migrations/158-channel-interaction-columns.ts +0 -0
  1770. /package/src/{memory → persistence}/migrations/159-drop-contact-interaction-columns.ts +0 -0
  1771. /package/src/{memory → persistence}/migrations/160-drop-loopback-port-column.ts +0 -0
  1772. /package/src/{memory → persistence}/migrations/161-drop-orphaned-media-tables.ts +0 -0
  1773. /package/src/{memory → persistence}/migrations/162-guardian-timestamps-epoch-ms.ts +0 -0
  1774. /package/src/{memory → persistence}/migrations/163-rename-notification-thread-columns.ts +0 -0
  1775. /package/src/{memory → persistence}/migrations/164-rename-conversation-type-column.ts +0 -0
  1776. /package/src/{memory → persistence}/migrations/165-rename-inbox-thread-state-table.ts +0 -0
  1777. /package/src/{memory → persistence}/migrations/166-rename-followups-thread-id.ts +0 -0
  1778. /package/src/{memory → persistence}/migrations/167-rename-sequence-enrollments-thread-id.ts +0 -0
  1779. /package/src/{memory → persistence}/migrations/168-rename-sequence-steps-reply-key.ts +0 -0
  1780. /package/src/{memory → persistence}/migrations/169-rename-gmail-provider-key-to-google.ts +0 -0
  1781. /package/src/{memory → persistence}/migrations/170-thread-starters-table.ts +0 -0
  1782. /package/src/{memory → persistence}/migrations/171-capability-card-columns.ts +0 -0
  1783. /package/src/{memory → persistence}/migrations/172-rename-created-by-session-id.ts +0 -0
  1784. /package/src/{memory → persistence}/migrations/173-rename-source-session-id.ts +0 -0
  1785. /package/src/{memory → persistence}/migrations/174-rename-thread-starters-table.ts +0 -0
  1786. /package/src/{memory → persistence}/migrations/175-create-lifecycle-events.ts +0 -0
  1787. /package/src/{memory → persistence}/migrations/176-drop-capability-card-state.ts +0 -0
  1788. /package/src/{memory → persistence}/migrations/177-create-trace-events-table.ts +0 -0
  1789. /package/src/{memory → persistence}/migrations/178-oauth-providers-managed-service-config-key.ts +0 -0
  1790. /package/src/{memory → persistence}/migrations/179-llm-request-log-message-id.ts +0 -0
  1791. /package/src/{memory → persistence}/migrations/180-backfill-inline-attachments-to-disk.ts +0 -0
  1792. /package/src/{memory → persistence}/migrations/181-rename-thread-starters-checkpoints.ts +0 -0
  1793. /package/src/{memory → persistence}/migrations/183-add-conversation-fork-lineage.ts +0 -0
  1794. /package/src/{memory → persistence}/migrations/184-llm-request-log-provider.ts +0 -0
  1795. /package/src/{memory → persistence}/migrations/188-schedule-quiet-flag.ts +0 -0
  1796. /package/src/{memory → persistence}/migrations/189-drop-simplified-memory.ts +0 -0
  1797. /package/src/{memory → persistence}/migrations/190-call-session-skip-disclosure.ts +0 -0
  1798. /package/src/{memory → persistence}/migrations/191-backfill-audio-attachment-mime-types.ts +0 -0
  1799. /package/src/{memory → persistence}/migrations/192-contacts-user-file-column.ts +0 -0
  1800. /package/src/{memory → persistence}/migrations/193-add-source-type-columns.ts +0 -0
  1801. /package/src/{memory → persistence}/migrations/194-memory-recall-logs.ts +0 -0
  1802. /package/src/{memory → persistence}/migrations/195-oauth-providers-ping-config.ts +0 -0
  1803. /package/src/{memory → persistence}/migrations/196-messages-conversation-created-at-index.ts +0 -0
  1804. /package/src/{memory → persistence}/migrations/197-oauth-providers-behavior-columns.ts +0 -0
  1805. /package/src/{memory → persistence}/migrations/198-drop-setup-skill-id-column.ts +0 -0
  1806. /package/src/{memory → persistence}/migrations/200-usage-llm-call-count.ts +0 -0
  1807. /package/src/{memory → persistence}/migrations/201-oauth-providers-feature-flag.ts +0 -0
  1808. /package/src/{memory → persistence}/migrations/202-drop-callback-transport-column.ts +0 -0
  1809. /package/src/{memory → persistence}/migrations/204-rename-memory-graph-type-values.ts +0 -0
  1810. /package/src/{memory → persistence}/migrations/205-memory-graph-image-refs.ts +0 -0
  1811. /package/src/{memory → persistence}/migrations/206-memory-graph-node-edits.ts +0 -0
  1812. /package/src/{memory → persistence}/migrations/207-conversation-graph-memory-state.ts +0 -0
  1813. /package/src/{memory → persistence}/migrations/208-conversations-last-message-at.ts +0 -0
  1814. /package/src/{memory → persistence}/migrations/210-schedule-reuse-conversation.ts +0 -0
  1815. /package/src/{memory → persistence}/migrations/212-llm-request-logs-created-at-index.ts +0 -0
  1816. /package/src/{memory → persistence}/migrations/213-oauth-providers-scope-separator.ts +0 -0
  1817. /package/src/{memory → persistence}/migrations/214-oauth-providers-refresh-url.ts +0 -0
  1818. /package/src/{memory → persistence}/migrations/215-oauth-providers-revoke.ts +0 -0
  1819. /package/src/{memory → persistence}/migrations/216-oauth-providers-token-auth-method.ts +0 -0
  1820. /package/src/{memory → persistence}/migrations/217-conversation-host-access.ts +0 -0
  1821. /package/src/{memory → persistence}/migrations/218-oauth-providers-logo-url.ts +0 -0
  1822. /package/src/{memory → persistence}/migrations/219-oauth-providers-token-exchange-body-format.ts +0 -0
  1823. /package/src/{memory → persistence}/migrations/221-conversations-archived-at.ts +0 -0
  1824. /package/src/{memory → persistence}/migrations/223-schedule-script-column.ts +0 -0
  1825. /package/src/{memory → persistence}/migrations/224-oauth-providers-managed-service-is-paid.ts +0 -0
  1826. /package/src/{memory → persistence}/migrations/225-oauth-providers-available-scopes.ts +0 -0
  1827. /package/src/{memory → persistence}/migrations/226-schedule-wake-conversation-id.ts +0 -0
  1828. /package/src/{memory → persistence}/migrations/227-add-conversation-inference-profile.ts +0 -0
  1829. /package/src/{memory → persistence}/migrations/228-rename-inference-profile-snake-case.ts +0 -0
  1830. /package/src/{memory → persistence}/migrations/229-delete-private-conversations.test.ts +0 -0
  1831. /package/src/{memory → persistence}/migrations/229-delete-private-conversations.ts +0 -0
  1832. /package/src/{memory → persistence}/migrations/230-acp-session-history.ts +0 -0
  1833. /package/src/{memory → persistence}/migrations/231-repair-memory-graph-event-dates.ts +0 -0
  1834. /package/src/{memory → persistence}/migrations/232-activation-state.ts +0 -0
  1835. /package/src/{memory → persistence}/migrations/233-document-conversations.ts +0 -0
  1836. /package/src/{memory → persistence}/migrations/234-memory-v2-activation-logs.ts +0 -0
  1837. /package/src/{memory → persistence}/migrations/235-llm-usage-attribution.ts +0 -0
  1838. /package/src/{memory → persistence}/migrations/235-slack-compaction-watermark.ts +0 -0
  1839. /package/src/{memory → persistence}/migrations/237-heartbeat-runs.ts +0 -0
  1840. /package/src/{memory → persistence}/migrations/238-schedule-retry-policy.ts +0 -0
  1841. /package/src/{memory → persistence}/migrations/239-trace-events-created-at-index.ts +0 -0
  1842. /package/src/{memory → persistence}/migrations/240-conversation-inference-profile-session.ts +0 -0
  1843. /package/src/{memory → persistence}/migrations/241-activation-state-fk-cascade.ts +0 -0
  1844. /package/src/{memory → persistence}/migrations/242-message-bookmarks.ts +0 -0
  1845. /package/src/{memory → persistence}/migrations/245-memory-retrospective-state.ts +0 -0
  1846. /package/src/{memory → persistence}/migrations/247-external-conversation-binding-thread-id.ts +0 -0
  1847. /package/src/{memory → persistence}/migrations/248-create-onboarding-events.ts +0 -0
  1848. /package/src/{memory → persistence}/migrations/249-normalize-slack-external-content.ts +0 -0
  1849. /package/src/{memory → persistence}/migrations/250-provider-connection-base-url-and-models.ts +0 -0
  1850. /package/src/{memory → persistence}/migrations/251-a2a-tasks.ts +0 -0
  1851. /package/src/{memory → persistence}/migrations/252-llm-request-log-agent-loop-exit-reason.ts +0 -0
  1852. /package/src/{memory → persistence}/migrations/253-conversation-last-notified-profile.ts +0 -0
  1853. /package/src/{memory → persistence}/migrations/253-document-comments.ts +0 -0
  1854. /package/src/{memory → persistence}/migrations/254-external-conversation-binding-chat-name.ts +0 -0
  1855. /package/src/{memory → persistence}/migrations/256-memory-v2-injection-events.ts +0 -0
  1856. /package/src/{memory → persistence}/migrations/257-strip-base-url-non-openai-compatible.ts +0 -0
  1857. /package/src/{memory → persistence}/migrations/258-onboarding-events-prior-assistants.ts +0 -0
  1858. /package/src/{memory → persistence}/migrations/259-conversation-cleaned-at.ts +0 -0
  1859. /package/src/{memory → persistence}/migrations/260-rename-cleaned-at.ts +0 -0
  1860. /package/src/{memory → persistence}/migrations/261-llm-usage-add-raw-usage.ts +0 -0
  1861. /package/src/{memory → persistence}/migrations/262-memory-v3-coactivation.ts +0 -0
  1862. /package/src/{memory → persistence}/migrations/263-memory-v3-auto-edges.ts +0 -0
  1863. /package/src/{memory → persistence}/migrations/264-llm-request-log-call-site.ts +0 -0
  1864. /package/src/{memory → persistence}/migrations/265-drop-provider-connection-status.ts +0 -0
  1865. /package/src/{memory → persistence}/migrations/266-messages-client-message-id.ts +0 -0
  1866. /package/src/{memory → persistence}/migrations/267-llm-usage-events-add-assistant-version.ts +0 -0
  1867. /package/src/{memory → persistence}/migrations/268-add-memory-v3-selections.ts +0 -0
  1868. /package/src/{memory → persistence}/migrations/269-schedule-script-timeout.ts +0 -0
  1869. /package/src/{memory → persistence}/migrations/270-messages-role-created-at-index.ts +0 -0
  1870. /package/src/{memory → persistence}/migrations/270-schedule-description.ts +0 -0
  1871. /package/src/{memory → persistence}/migrations/270-schedule-source-conversation.ts +0 -0
  1872. /package/src/{memory → persistence}/migrations/271-create-auth-fallback-events.ts +0 -0
  1873. /package/src/{memory → persistence}/migrations/272-acp-session-history-cwd.ts +0 -0
  1874. /package/src/{memory → persistence}/migrations/273-onboarding-events-funnel-columns.ts +0 -0
  1875. /package/src/{memory → persistence}/migrations/274-create-activation-sessions.ts +0 -0
  1876. /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.test.ts +0 -0
  1877. /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.ts +0 -0
  1878. /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.test.ts +0 -0
  1879. /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.ts +0 -0
  1880. /package/src/{memory → persistence}/migrations/277-add-memory-v3-ever-injected.ts +0 -0
  1881. /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.test.ts +0 -0
  1882. /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.ts +0 -0
  1883. /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.test.ts +0 -0
  1884. /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.ts +0 -0
  1885. /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.test.ts +0 -0
  1886. /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.ts +0 -0
  1887. /package/src/{memory → persistence}/migrations/281-memory-retrospective-remembered-log.ts +0 -0
  1888. /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.test.ts +0 -0
  1889. /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.ts +0 -0
  1890. /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +0 -0
  1891. /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.ts +0 -0
  1892. /package/src/{memory → persistence}/migrations/284-workflow-runs.ts +0 -0
  1893. /package/src/{memory → persistence}/migrations/285-schedule-workflow-mode.ts +0 -0
  1894. /package/src/{memory → persistence}/migrations/286-workflow-run-trust.ts +0 -0
  1895. /package/src/{memory → persistence}/migrations/287-conversation-origin-channel-index.ts +0 -0
  1896. /package/src/{memory → persistence}/migrations/288-backfill-origin-channel-from-bindings.ts +0 -0
  1897. /package/src/{memory → persistence}/migrations/289-contact-channels-unique-ext-user.ts +0 -0
  1898. /package/src/{memory → persistence}/migrations/290-schedule-capabilities.test.ts +0 -0
  1899. /package/src/{memory → persistence}/migrations/290-schedule-capabilities.ts +0 -0
  1900. /package/src/{memory → persistence}/migrations/291-contact-channels-renormalize-addresses.ts +0 -0
  1901. /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.test.ts +0 -0
  1902. /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.ts +0 -0
  1903. /package/src/{memory → persistence}/migrations/293-workflow-journal-leaf-tokens.ts +0 -0
  1904. /package/src/{memory → persistence}/migrations/294-drop-external-user-id.ts +0 -0
  1905. /package/src/{memory → persistence}/migrations/295-drop-approval-prompt-ts-tracker.ts +0 -0
  1906. /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +0 -0
  1907. /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.ts +0 -0
  1908. /package/src/{memory → persistence}/migrations/297-move-llm-request-logs-to-logs-db.ts +0 -0
  1909. /package/src/{memory → persistence}/migrations/298-move-memory-jobs-to-memory-db.ts +0 -0
  1910. /package/src/{memory → persistence}/migrations/299-canonical-guardian-deliveries-conversation-index.ts +0 -0
  1911. /package/src/{memory → persistence}/migrations/300-add-processing-started-at.ts +0 -0
  1912. /package/src/{memory → persistence}/migrations/302-create-compaction-events.ts +0 -0
  1913. /package/src/{memory → persistence}/migrations/303-add-conversation-creation-seq.ts +0 -0
  1914. /package/src/{memory → persistence}/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +0 -0
  1915. /package/src/{memory → persistence}/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +0 -0
  1916. /package/src/{memory → persistence}/migrations/__tests__/136-drop-assistant-id-columns.test.ts +0 -0
  1917. /package/src/{memory → persistence}/migrations/__tests__/234-memory-v2-activation-logs.test.ts +0 -0
  1918. /package/src/{memory → persistence}/migrations/__tests__/245-memory-retrospective-state.test.ts +0 -0
  1919. /package/src/{memory → persistence}/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +0 -0
  1920. /package/src/{memory → persistence}/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +0 -0
  1921. /package/src/{memory → persistence}/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +0 -0
  1922. /package/src/{memory → persistence}/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +0 -0
  1923. /package/src/{memory → persistence}/migrations/__tests__/297-move-llm-request-logs.test.ts +0 -0
  1924. /package/src/{memory → persistence}/migrations/run-migrations.ts +0 -0
  1925. /package/src/{memory → persistence}/migrations/schema-introspection.ts +0 -0
  1926. /package/src/{memory → persistence}/raw-query.ts +0 -0
  1927. /package/src/{memory → persistence}/schema/a2a.ts +0 -0
  1928. /package/src/{memory → persistence}/schema/bookmarks.ts +0 -0
  1929. /package/src/{memory → persistence}/schema/calls.ts +0 -0
  1930. /package/src/{memory → persistence}/schema/guardian.ts +0 -0
  1931. /package/src/{memory → persistence}/schema/index.ts +0 -0
  1932. /package/src/{memory → persistence}/schema/inference.ts +0 -0
  1933. /package/src/{memory → persistence}/schema/memory-core.ts +0 -0
  1934. /package/src/{memory → persistence}/schema/memory-graph.ts +0 -0
  1935. /package/src/{memory → persistence}/schema/notifications.ts +0 -0
  1936. /package/src/{memory → persistence}/schema/oauth.ts +0 -0
  1937. /package/src/{memory → persistence}/schema/tasks.ts +0 -0
  1938. /package/src/{memory → persistence}/schema.ts +0 -0
  1939. /package/src/{memory → persistence}/usage-buckets.ts +0 -0
  1940. /package/src/{memory → persistence}/usage-grouped-buckets.ts +0 -0
  1941. /package/src/{memory → plugins/defaults/memory}/__tests__/fixtures/memory-v2-activation-fixtures.ts +0 -0
  1942. /package/src/{memory → plugins/defaults/memory}/__tests__/memory-retrospective-trigger-check.test.ts +0 -0
  1943. /package/src/{memory → plugins/defaults/memory}/anisotropy.test.ts +0 -0
  1944. /package/src/{memory → plugins/defaults/memory}/context-search/__tests__/agent-runner-redaction.test.ts +0 -0
  1945. /package/src/{memory → plugins/defaults/memory}/context-search/format.ts +0 -0
  1946. /package/src/{memory → plugins/defaults/memory}/context-search/limits.ts +0 -0
  1947. /package/src/{memory → plugins/defaults/memory}/context-search/sources/workspace.ts +0 -0
  1948. /package/src/{memory → plugins/defaults/memory}/graph/decay.test.ts +0 -0
  1949. /package/src/{memory → plugins/defaults/memory}/graph/extraction.test.ts +0 -0
  1950. /package/src/{memory → plugins/defaults/memory}/graph/injection.test.ts +0 -0
  1951. /package/src/{memory → plugins/defaults/memory}/graph/scoring.test.ts +0 -0
  1952. /package/src/{memory → plugins/defaults/memory}/graph/scoring.ts +0 -0
  1953. /package/src/{memory → plugins/defaults/memory}/graph/serendipity.ts +0 -0
  1954. /package/src/{memory → plugins/defaults/memory}/graph/triggers.test.ts +0 -0
  1955. /package/src/{memory → plugins/defaults/memory}/graph/triggers.ts +0 -0
  1956. /package/src/{memory → plugins/defaults/memory}/graph/types.ts +0 -0
  1957. /package/src/plugins/defaults/{memory-retrieval → memory}/hooks/__tests__/user-prompt-submit.test.ts +0 -0
  1958. /package/src/{memory → plugins/defaults/memory}/memory-marker.ts +0 -0
  1959. /package/src/{memory → plugins/defaults/memory}/prompt-override.ts +0 -0
  1960. /package/src/{memory → plugins/defaults/memory}/retrieval-budget.ts +0 -0
  1961. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +0 -0
  1962. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  1963. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/edge-index.test.ts +0 -0
  1964. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/harness-metrics.test.ts +0 -0
  1965. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/injected-block-slugs.test.ts +0 -0
  1966. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/page-store.test.ts +0 -0
  1967. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/prompts-router.test.ts +0 -0
  1968. /package/src/{memory → plugins/defaults/memory}/v2/cli-command-content.ts +0 -0
  1969. /package/src/{memory → plugins/defaults/memory}/v2/constants.ts +0 -0
  1970. /package/src/{memory → plugins/defaults/memory}/v2/edge-index.ts +0 -0
  1971. /package/src/{memory → plugins/defaults/memory}/v2/harness/metrics.ts +0 -0
  1972. /package/src/{memory → plugins/defaults/memory}/v2/harness/runner.ts +0 -0
  1973. /package/src/{memory → plugins/defaults/memory}/v2/harness/trace.ts +0 -0
  1974. /package/src/{memory → plugins/defaults/memory}/v2/now-text.ts +0 -0
  1975. /package/src/{memory → plugins/defaults/memory}/v2/prompts/sweep.ts +0 -0
  1976. /package/src/{memory → plugins/defaults/memory}/v2/types.ts +0 -0
  1977. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
  1978. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/card.test.ts +0 -0
  1979. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/fresh-set.test.ts +0 -0
  1980. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/section-needle.test.ts +0 -0
  1981. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/sections.test.ts +0 -0
  1982. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
  1983. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/card.test.ts +0 -0
  1984. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.test.ts +0 -0
  1985. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.ts +0 -0
  1986. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/README.md +0 -0
  1987. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
  1988. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/core.json +0 -0
  1989. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
  1990. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
  1991. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
  1992. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/fresh-set.ts +0 -0
  1993. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
  1994. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/sections.ts +0 -0
  1995. /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-packets.test.ts +0 -0
  1996. /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-tally.test.ts +0 -0
  1997. /package/src/{memory → plugins/defaults/memory}/v3-eval/eval-tally.ts +0 -0
  1998. /package/src/{memory → plugins/defaults/memory}/validation.ts +0 -0
  1999. /package/src/plugins/defaults/{memory-retrieval → turn-context}/unified-turn-context.ts +0 -0
@@ -0,0 +1,2308 @@
1
+ /**
2
+ * Tests for `assistant/src/memory/v2/injection.ts`.
3
+ *
4
+ * Coverage matrix:
5
+ * - Empty state seeds the first injection (initial conversation turn).
6
+ * - Second turn whose `topNow` overlaps prior `everInjected` returns
7
+ * `toInject = []` and `block = null` (cache-stable empty path).
8
+ * - A new topic appearing on a later turn injects only the new slug.
9
+ * - `evictCompactedTurns` re-enables a previously-injected slug —
10
+ * after eviction the same slug appears again in `toInject`.
11
+ * - Unified-pool skills: a `skills/<id>` slug ranked into the top-K is
12
+ * rendered under `### Skills You Can Use`, mixed concept-page+skill
13
+ * blocks render concept sections first then the skills suffix, both
14
+ * empty → null block, skills participate in `everInjected` so they
15
+ * deduplicate across turns just like concepts.
16
+ *
17
+ * Hermetic by design: the embedding backend, qdrant client, and `getConfig`
18
+ * are mocked at the module level so the suite never reaches a real backend.
19
+ * The skill-store cache (`getSkillCapability`, `isSkillSlug`) is mocked so
20
+ * each test can stage skill content without touching the real catalog.
21
+ * The activation-store uses an in-memory SQLite database so writes are
22
+ * real but contained.
23
+ *
24
+ * Tests use a temp workspace (mkdtemp) and never touch `~/.vellum/`. Sample
25
+ * page content uses generic placeholders (Alice, Bob, etc.) per the cross-
26
+ * cutting safety rules.
27
+ */
28
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
29
+ import { tmpdir } from "node:os";
30
+ import { join } from "node:path";
31
+ import { Database } from "bun:sqlite";
32
+ import {
33
+ afterAll,
34
+ afterEach,
35
+ beforeAll,
36
+ beforeEach,
37
+ describe,
38
+ expect,
39
+ mock,
40
+ test,
41
+ } from "bun:test";
42
+
43
+ import { drizzle } from "drizzle-orm/bun-sqlite";
44
+ import { z } from "zod";
45
+
46
+ import { makeMockLogger } from "../../../../../__tests__/helpers/mock-logger.js";
47
+ import type { AssistantConfig } from "../../../../../config/types.js";
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Module-level mocks
51
+ // ---------------------------------------------------------------------------
52
+
53
+ mock.module("../../../../../util/logger.js", () => ({
54
+ getLogger: () => makeMockLogger(),
55
+ }));
56
+
57
+ const STUB_QDRANT_CONFIG = {
58
+ memory: {
59
+ qdrant: {
60
+ url: "http://127.0.0.1:6333",
61
+ vectorSize: 384,
62
+ onDisk: true,
63
+ },
64
+ },
65
+ };
66
+ mock.module("../../../../../config/loader.js", () => ({
67
+ getConfig: () => STUB_QDRANT_CONFIG,
68
+ loadConfig: () => STUB_QDRANT_CONFIG,
69
+ }));
70
+
71
+ const realQdrantClient =
72
+ await import("../../../../../persistence/embeddings/qdrant-client.js");
73
+ mock.module("../../../../../persistence/embeddings/qdrant-client.js", () => ({
74
+ ...realQdrantClient,
75
+ resolveQdrantUrl: () => "http://127.0.0.1:6333",
76
+ }));
77
+
78
+ // Programmable embedding + Qdrant state — drives `selectCandidates`,
79
+ // `simBatch`, and friends without a live backend.
80
+ const state = {
81
+ embedReturn: [[0.1, 0.2, 0.3]] as number[][],
82
+ sparseReturn: { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] },
83
+ queryResponses: {
84
+ dense: [] as Array<{
85
+ points: Array<{ score?: number; payload: Record<string, unknown> }>;
86
+ }>,
87
+ sparse: [] as Array<{
88
+ points: Array<{ score?: number; payload: Record<string, unknown> }>;
89
+ }>,
90
+ },
91
+ };
92
+
93
+ const realEmbeddingBackend =
94
+ await import("../../../../../persistence/embeddings/embedding-backend.js");
95
+ mock.module(
96
+ "../../../../../persistence/embeddings/embedding-backend.js",
97
+ () => ({
98
+ ...realEmbeddingBackend,
99
+ isEmbeddingDimensionAvailable: async () => true,
100
+ embedWithBackend: async () => ({
101
+ provider: "local",
102
+ model: "test-model",
103
+ vectors: state.embedReturn,
104
+ }),
105
+ generateSparseEmbedding: () => state.sparseReturn,
106
+ }),
107
+ );
108
+
109
+ class MockQdrantClient {
110
+ constructor(_opts: unknown) {}
111
+ async collectionExists(_name: string) {
112
+ return { exists: true };
113
+ }
114
+ async createCollection() {
115
+ return {};
116
+ }
117
+ async createPayloadIndex() {
118
+ return {};
119
+ }
120
+ async query(
121
+ _name: string,
122
+ params: { using: string; limit: number; filter?: unknown },
123
+ ) {
124
+ // The four-channel hybrid query fires body-dense, body-sparse,
125
+ // summary-dense, summary-sparse in order; both dense channels share
126
+ // the dense queue and both sparse channels share the sparse queue.
127
+ const channel = params.using.endsWith("sparse") ? "sparse" : "dense";
128
+ return state.queryResponses[channel].shift() ?? { points: [] };
129
+ }
130
+ }
131
+
132
+ mock.module("@qdrant/js-client-rest", () => ({
133
+ QdrantClient: MockQdrantClient,
134
+ }));
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Skill-store mock
138
+ // ---------------------------------------------------------------------------
139
+ //
140
+ // Skills now flow through the unified pipeline under the `skills/<id>` slug
141
+ // prefix — they are scored by `simBatch` against the same Qdrant collection
142
+ // as concept pages, ranked by `selectInjections`, and rendered alongside
143
+ // concept sections. The render path branches on `isSkillSlug(slug)` to fetch
144
+ // content from the in-process cache via `getSkillCapability` instead of
145
+ // reading a page from disk. Tests stage that cache and rely on the regular
146
+ // `stageTurn` plumbing to land skill slugs in the candidate set.
147
+
148
+ const skillState = {
149
+ /** id → SkillEntry consulted by `getSkillCapability`. */
150
+ entries: new Map<string, SkillEntry>(),
151
+ };
152
+
153
+ mock.module("../skill-store.js", () => ({
154
+ getSkillCapability: (idOrSlug: string) => {
155
+ const id = idOrSlug.startsWith("skills/")
156
+ ? idOrSlug.slice("skills/".length)
157
+ : idOrSlug;
158
+ return skillState.entries.get(id) ?? null;
159
+ },
160
+ isSkillSlug: (slug: string) => slug.startsWith("skills/"),
161
+ SKILL_SLUG_PREFIX: "skills/",
162
+ skillSlugFor: (id: string) => `skills/${id}`,
163
+ // PR 4 added `listSkillEntries`; `page-index.ts` (transitively imported
164
+ // via `page-store.ts` and `skill-store.ts`) consumes it at module-init
165
+ // time. Tests stage skill content via `skillState.entries`; expose them
166
+ // here so the page-index loader sees a consistent view.
167
+ listSkillEntries: () => Array.from(skillState.entries.values()),
168
+ }));
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // CLI-command-store mock
172
+ // ---------------------------------------------------------------------------
173
+ //
174
+ // Mirrors the skill-store mock. CLI subcommand synthetic entries flow through
175
+ // the unified pipeline under the `cli-commands/<name>` slug prefix and render
176
+ // under `### CLI Commands You Can Use`. Tests stage `cliCommandState.entries`
177
+ // and rely on `stageTurn` plumbing to land slugs in the candidate set.
178
+
179
+ interface CliCommandEntryStub {
180
+ id: string;
181
+ description: string;
182
+ content: string;
183
+ }
184
+
185
+ const cliCommandState = {
186
+ entries: new Map<string, CliCommandEntryStub>(),
187
+ };
188
+
189
+ mock.module("../cli-command-store.js", () => ({
190
+ getCliCommandCapability: (idOrSlug: string) => {
191
+ const id = idOrSlug.startsWith("cli-commands/")
192
+ ? idOrSlug.slice("cli-commands/".length)
193
+ : idOrSlug;
194
+ return cliCommandState.entries.get(id) ?? null;
195
+ },
196
+ isCliCommandSlug: (slug: string) => slug.startsWith("cli-commands/"),
197
+ CLI_COMMAND_SLUG_PREFIX: "cli-commands/",
198
+ cliCommandSlugFor: (name: string) => `cli-commands/${name}`,
199
+ listCliCommandEntries: () => Array.from(cliCommandState.entries.values()),
200
+ }));
201
+
202
+ // ---------------------------------------------------------------------------
203
+ // Activation-log store mock
204
+ // ---------------------------------------------------------------------------
205
+ //
206
+ // The real `recordMemoryV2ActivationLog` writes to the singleton
207
+ // `getDb()` — but this test uses an isolated in-memory database, so we mock
208
+ // the writer to capture calls in-process. `recordCalls` is the captured log
209
+ // array; `recordShouldThrow` makes the next call throw to verify the caller
210
+ // swallows the failure.
211
+
212
+ const telemetryState = {
213
+ recordCalls: [] as Array<Record<string, unknown>>,
214
+ recordShouldThrow: false,
215
+ };
216
+
217
+ mock.module("../../memory-v2-activation-log-store.js", () => ({
218
+ recordMemoryV2ActivationLog: (params: Record<string, unknown>) => {
219
+ if (telemetryState.recordShouldThrow) {
220
+ throw new Error("simulated telemetry write failure");
221
+ }
222
+ telemetryState.recordCalls.push(params);
223
+ },
224
+ }));
225
+
226
+ // ---------------------------------------------------------------------------
227
+ // Page-store mock — pass-through with optional per-slug failure injection
228
+ // ---------------------------------------------------------------------------
229
+ //
230
+ // Most tests want the real `readPage` (it walks the temp workspace seeded in
231
+ // `beforeAll`). The error-isolation tests stage a slug whose `readPage` call
232
+ // must throw — typically a Zod validation error mimicking the real-world
233
+ // "unrecognized frontmatter key" failure that motivated this work. Tests
234
+ // stage entries via `pageStoreState.failingSlugs` and reset in `resetState`.
235
+ //
236
+ // Bun's `mock.module` mutates the module's exports object in place, so
237
+ // `realPageStore.readPage` AFTER the mock applies would resolve to the mock
238
+ // itself — calling it would recurse. We capture the original function value
239
+ // (not a property lookup) before installing the mock so the pass-through
240
+ // path has a real reference to the underlying implementation.
241
+
242
+ const realPageStoreModule = await import("../page-store.js");
243
+ const realReadPage = realPageStoreModule.readPage;
244
+ const pageStoreState = {
245
+ failingSlugs: new Map<string, Error>(),
246
+ };
247
+ mock.module("../page-store.js", () => ({
248
+ ...realPageStoreModule,
249
+ readPage: async (workspaceDir: string, slug: string) => {
250
+ const err = pageStoreState.failingSlugs.get(slug);
251
+ if (err) throw err;
252
+ return realReadPage(workspaceDir, slug);
253
+ },
254
+ }));
255
+
256
+ // ---------------------------------------------------------------------------
257
+ // Router mock — programmable per-call result
258
+ // ---------------------------------------------------------------------------
259
+ //
260
+ // PR 10 wires `runRouter` into `injectMemoryV2Block` behind the
261
+ // `memory.v2.router.enabled` flag. The activation-mode tests above never
262
+ // flip the flag, so the default mock returns a no-op result and the router
263
+ // branch is never exercised. Router-mode tests set `routerState.nextResult`
264
+ // to stage a deterministic outcome before each call.
265
+
266
+ interface RouterResultStub {
267
+ selectedSlugs: string[];
268
+ failureReason: string | null;
269
+ /** Tier provenance per slug. Defaults to `tier3:0` for any selected slug. */
270
+ sourceBySlug?: Map<string, string>;
271
+ }
272
+
273
+ const routerState = {
274
+ nextResult: null as RouterResultStub | null,
275
+ callCount: 0,
276
+ };
277
+
278
+ mock.module("../router.js", () => ({
279
+ runRouter: async () => {
280
+ routerState.callCount++;
281
+ const result = routerState.nextResult ?? {
282
+ selectedSlugs: [],
283
+ failureReason: null,
284
+ };
285
+ // Synthesize a default sourceBySlug for stubs that don't set one — pre-
286
+ // tier-provenance tests stage `selectedSlugs` only and expect every pick
287
+ // to flow through as a router selection. Treating them as `tier3:0` is
288
+ // the closest equivalent under the new model.
289
+ if (!result.sourceBySlug) {
290
+ const map = new Map<string, string>();
291
+ for (const slug of result.selectedSlugs) map.set(slug, "tier3:0");
292
+ result.sourceBySlug = map;
293
+ }
294
+ return result;
295
+ },
296
+ }));
297
+
298
+ // ---------------------------------------------------------------------------
299
+ // Activation-store mock — pass-through with optional `save` failure injection
300
+ // ---------------------------------------------------------------------------
301
+ //
302
+ // One regression test forces `save` to throw to exercise the
303
+ // `injectMemoryV2Block` outer try/finally — telemetry must still be flushed
304
+ // (with `mode: "errored"`) and the error must propagate. Default behavior
305
+ // delegates to the real activation-store so the rest of the suite stays
306
+ // untouched. Same pre-mock function-capture trick as `readPage` above.
307
+
308
+ const realActivationStoreModule = await import("../activation-store.js");
309
+ const realSave = realActivationStoreModule.save;
310
+ const activationStoreState = {
311
+ saveShouldThrow: false,
312
+ };
313
+ mock.module("../activation-store.js", () => ({
314
+ ...realActivationStoreModule,
315
+ save: async (...args: Parameters<typeof realSave>) => {
316
+ if (activationStoreState.saveShouldThrow) {
317
+ throw new Error("simulated activation-store save failure");
318
+ }
319
+ return realSave(...args);
320
+ },
321
+ }));
322
+
323
+ // ---------------------------------------------------------------------------
324
+ // Workspace + DB setup
325
+ // ---------------------------------------------------------------------------
326
+
327
+ let tmpWorkspace: string;
328
+ let previousWorkspaceEnv: string | undefined;
329
+
330
+ beforeAll(() => {
331
+ tmpWorkspace = mkdtempSync(join(tmpdir(), "memory-v2-injection-test-"));
332
+ previousWorkspaceEnv = process.env.VELLUM_WORKSPACE_DIR;
333
+ process.env.VELLUM_WORKSPACE_DIR = tmpWorkspace;
334
+
335
+ // Seed the v2 directory layout the migration would normally create.
336
+ mkdirSync(join(tmpWorkspace, "memory", "concepts"), { recursive: true });
337
+ // Three concept pages with generic, placeholder bodies. Outgoing edges
338
+ // live in each page's frontmatter `edges:` list — there is no separate
339
+ // edges-index file under the directed-edges model.
340
+ writeFileSync(
341
+ join(tmpWorkspace, "memory", "concepts", "alice-vscode.md"),
342
+ `---
343
+ edges: [bob-coffee]
344
+ ref_files: []
345
+ ---
346
+ Alice prefers VS Code as her editor.`,
347
+ );
348
+ writeFileSync(
349
+ join(tmpWorkspace, "memory", "concepts", "bob-coffee.md"),
350
+ `---
351
+ edges: [alice-vscode]
352
+ ref_files: []
353
+ ---
354
+ Bob takes his coffee black, no sugar.`,
355
+ );
356
+ writeFileSync(
357
+ join(tmpWorkspace, "memory", "concepts", "carol-jazz.md"),
358
+ `---
359
+ edges: []
360
+ ref_files: []
361
+ ---
362
+ Carol loves jazz music — Coltrane in particular.`,
363
+ );
364
+ // A page with both `edges` and `ref_files` populated so the frontmatter-
365
+ // injection test can assert the full canonical shape.
366
+ writeFileSync(
367
+ join(tmpWorkspace, "memory", "concepts", "frontmatter-demo.md"),
368
+ `---
369
+ edges:
370
+ - alice-vscode
371
+ ref_files:
372
+ - images/demo.jpg
373
+ ---
374
+ Demo body content.`,
375
+ );
376
+ // A page WITH a `summary` in its frontmatter — exercises the summary-only
377
+ // injection path. Body is intentionally longer than the summary so tests
378
+ // can assert that the body is *not* injected when the summary is present.
379
+ writeFileSync(
380
+ join(tmpWorkspace, "memory", "concepts", "summarized-page.md"),
381
+ `---
382
+ edges: []
383
+ ref_files: []
384
+ summary: A short prose description of the summarized page that retrieval injects in place of the full body.
385
+ ---
386
+ Long-form body content that should NOT appear in the injection block when the page has a summary in frontmatter — the agent reads the file on demand instead.`,
387
+ );
388
+ });
389
+
390
+ afterAll(() => {
391
+ if (previousWorkspaceEnv === undefined) {
392
+ delete process.env.VELLUM_WORKSPACE_DIR;
393
+ } else {
394
+ process.env.VELLUM_WORKSPACE_DIR = previousWorkspaceEnv;
395
+ }
396
+ rmSync(tmpWorkspace, { recursive: true, force: true });
397
+ });
398
+
399
+ // Static `import type` is fine — types erase, so they don't run module-init
400
+ // code that would race the mocks above.
401
+ import type { DrizzleDb } from "../../../../../persistence/db-connection.js";
402
+ import type { SkillEntry } from "../types.js";
403
+
404
+ const { getSqliteFrom } =
405
+ await import("../../../../../persistence/db-connection.js");
406
+ const { migrateActivationState } =
407
+ await import("../../../../../persistence/migrations/232-activation-state.js");
408
+ const { migrateMemoryV2InjectionEvents } =
409
+ await import("../../../../../persistence/migrations/256-memory-v2-injection-events.js");
410
+ const schema = await import("../../../../../persistence/schema/index.js");
411
+ const { clearEverInjected, hydrate, save } =
412
+ await import("../activation-store.js");
413
+ const { injectMemoryV2Block } = await import("../injection.js");
414
+ const { _resetMemoryV2QdrantForTests } = await import("../qdrant.js");
415
+
416
+ function createTestDb(): DrizzleDb {
417
+ const sqlite = new Database(":memory:");
418
+ sqlite.exec("PRAGMA journal_mode=WAL");
419
+ sqlite.exec("PRAGMA foreign_keys = ON");
420
+ const db = drizzle(sqlite, { schema });
421
+
422
+ // Migration uses the checkpoints table for crash recovery — bootstrap it.
423
+ getSqliteFrom(db).exec(/*sql*/ `
424
+ CREATE TABLE IF NOT EXISTS memory_checkpoints (
425
+ key TEXT PRIMARY KEY,
426
+ value TEXT NOT NULL,
427
+ updated_at INTEGER NOT NULL
428
+ )
429
+ `);
430
+ migrateActivationState(db);
431
+ migrateMemoryV2InjectionEvents(db);
432
+ return db;
433
+ }
434
+
435
+ function makeConfig(
436
+ overrides: Partial<{
437
+ d: number;
438
+ c_user: number;
439
+ c_assistant: number;
440
+ c_now: number;
441
+ k: number;
442
+ hops: number;
443
+ top_k: number;
444
+ epsilon: number;
445
+ dense_weight: number;
446
+ sparse_weight: number;
447
+ router: { enabled: boolean; max_page_ids?: number };
448
+ }> = {},
449
+ ): AssistantConfig {
450
+ const { router, ...rest } = overrides;
451
+ return {
452
+ memory: {
453
+ v2: {
454
+ d: 0.3,
455
+ c_user: 0.3,
456
+ c_assistant: 0.2,
457
+ c_now: 0.2,
458
+ k: 0.5,
459
+ hops: 2,
460
+ top_k: 25,
461
+ epsilon: 0.01,
462
+ dense_weight: 1.0,
463
+ sparse_weight: 0.0,
464
+ router: { enabled: false, max_page_ids: 25, ...(router ?? {}) },
465
+ ...rest,
466
+ },
467
+ },
468
+ } as unknown as AssistantConfig;
469
+ }
470
+
471
+ /**
472
+ * Stage one set of dense/sparse hits, used uniformly by every `simBatch`
473
+ * channel call (user/assistant/now) AND by the un-restricted ANN candidate
474
+ * query. The candidate query runs first, then three simBatch calls — that's
475
+ * `channels` (= 4) logical hybrid queries. Each logical hybrid query now
476
+ * fires a four-channel fan-out (body dense, body sparse, summary dense,
477
+ * summary sparse), so we push 2 dense + 2 sparse responses per logical
478
+ * call to match the post-summary-vector wire pattern.
479
+ *
480
+ * Each entry is mapped to a hit per channel; pass `denseScore`/`sparseScore`
481
+ * undefined to omit a slug from that channel. `summaryDenseScore` /
482
+ * `summarySparseScore` route to the summary-side channels — tests that
483
+ * don't care about summary scoring leave them undefined and the summary
484
+ * channel falls back to body-only behavior.
485
+ */
486
+ function stageTurn(
487
+ hits: Array<{
488
+ slug: string;
489
+ denseScore?: number;
490
+ sparseScore?: number;
491
+ summaryDenseScore?: number;
492
+ summarySparseScore?: number;
493
+ }>,
494
+ channels = 4,
495
+ ): void {
496
+ // Clear any leftovers from a prior turn before staging this one so unused
497
+ // staged responses can't bleed into the next injection. The activation
498
+ // pipeline now skips the embedding round-trip for empty texts (turn 1's
499
+ // assistantMessage), so consumed-channel counts vary per turn — staging
500
+ // exclusively is the only way multi-turn tests stay aligned.
501
+ state.queryResponses.dense.length = 0;
502
+ state.queryResponses.sparse.length = 0;
503
+ for (let i = 0; i < channels; i++) {
504
+ state.queryResponses.dense.push({
505
+ points: hits
506
+ .filter((h) => h.denseScore !== undefined)
507
+ .map((h) => ({ score: h.denseScore, payload: { slug: h.slug } })),
508
+ });
509
+ state.queryResponses.sparse.push({
510
+ points: hits
511
+ .filter((h) => h.sparseScore !== undefined)
512
+ .map((h) => ({ score: h.sparseScore, payload: { slug: h.slug } })),
513
+ });
514
+ state.queryResponses.dense.push({
515
+ points: hits
516
+ .filter((h) => h.summaryDenseScore !== undefined)
517
+ .map((h) => ({
518
+ score: h.summaryDenseScore,
519
+ payload: { slug: h.slug },
520
+ })),
521
+ });
522
+ state.queryResponses.sparse.push({
523
+ points: hits
524
+ .filter((h) => h.summarySparseScore !== undefined)
525
+ .map((h) => ({
526
+ score: h.summarySparseScore,
527
+ payload: { slug: h.slug },
528
+ })),
529
+ });
530
+ }
531
+ }
532
+
533
+ function resetState(): void {
534
+ state.embedReturn = [[0.1, 0.2, 0.3]];
535
+ state.sparseReturn = { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] };
536
+ state.queryResponses.dense.length = 0;
537
+ state.queryResponses.sparse.length = 0;
538
+ skillState.entries.clear();
539
+ cliCommandState.entries.clear();
540
+ telemetryState.recordCalls.length = 0;
541
+ telemetryState.recordShouldThrow = false;
542
+ pageStoreState.failingSlugs.clear();
543
+ activationStoreState.saveShouldThrow = false;
544
+ routerState.nextResult = null;
545
+ routerState.callCount = 0;
546
+ // The qdrant module caches its client; the cached client may be a
547
+ // MockQdrantClient instance from a sibling test file. Reset to force a
548
+ // fresh `new QdrantClient()` against this file's mock.
549
+ _resetMemoryV2QdrantForTests();
550
+ }
551
+
552
+ /** Stage skill-store cache entries for the upcoming render. */
553
+ function stageSkills(entries: SkillEntry[]): void {
554
+ for (const entry of entries) {
555
+ skillState.entries.set(entry.id, entry);
556
+ }
557
+ }
558
+
559
+ /** Stage cli-command-store cache entries for the upcoming render. */
560
+ function stageCliCommands(entries: CliCommandEntryStub[]): void {
561
+ for (const entry of entries) {
562
+ cliCommandState.entries.set(entry.id, entry);
563
+ }
564
+ }
565
+
566
+ let db: DrizzleDb;
567
+ beforeEach(() => {
568
+ db = createTestDb();
569
+ resetState();
570
+ });
571
+ afterEach(resetState);
572
+
573
+ // ---------------------------------------------------------------------------
574
+ // Tests
575
+ // ---------------------------------------------------------------------------
576
+
577
+ describe("injectMemoryV2Block", () => {
578
+ test("seeds first injection from an empty state", async () => {
579
+ // First turn: no prior state. The ANN candidate call surfaces alice; the
580
+ // three simBatch channels score her highly enough to dominate top-K.
581
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
582
+
583
+ const result = await injectMemoryV2Block({
584
+ database: db,
585
+ conversationId: "conv-1",
586
+ currentTurn: 1,
587
+ recentTurnPairs: [
588
+ { assistantMessage: "", userMessage: "Tell me about Alice's editor" },
589
+ ],
590
+ nowText: "Spring afternoon",
591
+ messageId: "msg-1",
592
+ config: makeConfig(),
593
+ });
594
+
595
+ expect(result.toInject).toEqual(["alice-vscode"]);
596
+ expect(result.block).not.toBeNull();
597
+ // `block` is the unwrapped inner content; the caller adds the
598
+ // `<memory>...</memory>` wrapper exactly once at injection time.
599
+ expect(result.block).not.toContain("<memory>");
600
+ expect(result.block).not.toContain("</memory>");
601
+ expect(result.block).not.toContain("## What I Remember Right Now");
602
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
603
+ expect(result.block).toContain("VS Code");
604
+
605
+ // State persisted: alice's activation is above epsilon and recorded;
606
+ // everInjected captured the new slug + currentTurn.
607
+ const persisted = await hydrate(db, "conv-1");
608
+ expect(persisted).not.toBeNull();
609
+ expect(persisted!.everInjected).toEqual([
610
+ { slug: "alice-vscode", turn: 1 },
611
+ ]);
612
+ expect(persisted!.state["alice-vscode"]).toBeGreaterThan(0.01);
613
+ expect(persisted!.currentTurn).toBe(1);
614
+ expect(persisted!.messageId).toBe("msg-1");
615
+ });
616
+
617
+ test("second turn with overlapping topNow returns null block + empty toInject", async () => {
618
+ // Turn 1 — seed alice as injected.
619
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
620
+ await injectMemoryV2Block({
621
+ database: db,
622
+ conversationId: "conv-1",
623
+ currentTurn: 1,
624
+ recentTurnPairs: [
625
+ { assistantMessage: "", userMessage: "Alice's editor" },
626
+ ],
627
+ nowText: "Now",
628
+ messageId: "msg-1",
629
+ config: makeConfig(),
630
+ });
631
+
632
+ // Turn 2 — the same slug is still top-of-mind. After subtracting
633
+ // everInjected, toInject is empty → block is null.
634
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
635
+ const result = await injectMemoryV2Block({
636
+ database: db,
637
+ conversationId: "conv-1",
638
+ currentTurn: 2,
639
+ recentTurnPairs: [
640
+ {
641
+ assistantMessage: "Alice loves it.",
642
+ userMessage: "And what about VS Code?",
643
+ },
644
+ ],
645
+ nowText: "Now",
646
+ messageId: "msg-2",
647
+ config: makeConfig(),
648
+ });
649
+
650
+ expect(result.toInject).toEqual([]);
651
+ expect(result.block).toBeNull();
652
+
653
+ // State still advanced (currentTurn moved forward) and the existing
654
+ // everInjected entry is preserved (no duplicate added).
655
+ const persisted = await hydrate(db, "conv-1");
656
+ expect(persisted!.currentTurn).toBe(2);
657
+ expect(persisted!.everInjected).toEqual([
658
+ { slug: "alice-vscode", turn: 1 },
659
+ ]);
660
+ expect(persisted!.messageId).toBe("msg-2");
661
+ });
662
+
663
+ test("new topic appears → only the new slug attaches", async () => {
664
+ // Turn 1 — seed alice.
665
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
666
+ await injectMemoryV2Block({
667
+ database: db,
668
+ conversationId: "conv-1",
669
+ currentTurn: 1,
670
+ recentTurnPairs: [
671
+ { assistantMessage: "", userMessage: "Editor preferences" },
672
+ ],
673
+ nowText: "Now",
674
+ messageId: "msg-1",
675
+ config: makeConfig(),
676
+ });
677
+
678
+ // Turn 2 — carol is now in the candidate pool with high relevance.
679
+ // Both alice (carry-forward) and carol should appear in topNow, but only
680
+ // carol should be in toInject (alice was already attached on turn 1).
681
+ stageTurn([
682
+ { slug: "alice-vscode", denseScore: 0.6 },
683
+ { slug: "carol-jazz", denseScore: 0.95 },
684
+ ]);
685
+ const result = await injectMemoryV2Block({
686
+ database: db,
687
+ conversationId: "conv-1",
688
+ currentTurn: 2,
689
+ recentTurnPairs: [
690
+ {
691
+ assistantMessage: "",
692
+ userMessage: "Tell me about Carol's music taste",
693
+ },
694
+ ],
695
+ nowText: "Now",
696
+ messageId: "msg-2",
697
+ config: makeConfig(),
698
+ });
699
+
700
+ expect(result.toInject).toEqual(["carol-jazz"]);
701
+ expect(result.block).toContain("# memory/concepts/carol-jazz.md");
702
+ // The block only shows the new slug — alice's attachment lives on the
703
+ // previous turn's user message.
704
+ expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
705
+
706
+ const persisted = await hydrate(db, "conv-1");
707
+ expect(persisted!.everInjected).toEqual([
708
+ { slug: "alice-vscode", turn: 1 },
709
+ { slug: "carol-jazz", turn: 2 },
710
+ ]);
711
+ });
712
+
713
+ test("compaction eviction makes a previously-injected slug eligible again", async () => {
714
+ // Turn 1 — seed alice.
715
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
716
+ await injectMemoryV2Block({
717
+ database: db,
718
+ conversationId: "conv-1",
719
+ currentTurn: 1,
720
+ recentTurnPairs: [
721
+ { assistantMessage: "", userMessage: "Alice's editor" },
722
+ ],
723
+ nowText: "Now",
724
+ messageId: "msg-1",
725
+ config: makeConfig(),
726
+ });
727
+
728
+ // Simulate compaction: clear the entire everInjected list.
729
+ const beforeEvict = await hydrate(db, "conv-1");
730
+ expect(beforeEvict).not.toBeNull();
731
+ const afterEvict = clearEverInjected(beforeEvict!);
732
+ expect(afterEvict.everInjected).toEqual([]);
733
+ await save(db, "conv-1", afterEvict);
734
+
735
+ // Turn 2 — alice should now be re-injectable since eviction cleared the
736
+ // everInjected entry. Same simulated relevance as before.
737
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
738
+ const result = await injectMemoryV2Block({
739
+ database: db,
740
+ conversationId: "conv-1",
741
+ currentTurn: 2,
742
+ recentTurnPairs: [
743
+ { assistantMessage: "", userMessage: "Alice's editor again" },
744
+ ],
745
+ nowText: "Now",
746
+ messageId: "msg-2",
747
+ config: makeConfig(),
748
+ });
749
+
750
+ expect(result.toInject).toEqual(["alice-vscode"]);
751
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
752
+
753
+ const persisted = await hydrate(db, "conv-1");
754
+ expect(persisted!.everInjected).toEqual([
755
+ { slug: "alice-vscode", turn: 2 },
756
+ ]);
757
+ });
758
+
759
+ test("page with summary renders as path + summary, no body, with the CRITICAL header", async () => {
760
+ // Pages whose frontmatter carries a `summary` should inject only the
761
+ // summary text behind the path header — the agent reads the full file
762
+ // on demand. The leading `**CRITICAL:**` line tells the agent how to
763
+ // read the block.
764
+ stageTurn([{ slug: "summarized-page", denseScore: 0.9 }]);
765
+
766
+ const result = await injectMemoryV2Block({
767
+ database: db,
768
+ conversationId: "conv-1",
769
+ currentTurn: 1,
770
+ recentTurnPairs: [
771
+ {
772
+ assistantMessage: "",
773
+ userMessage: "tell me about the summarized page",
774
+ },
775
+ ],
776
+ nowText: "Now",
777
+ messageId: "msg-1",
778
+ config: makeConfig(),
779
+ });
780
+
781
+ expect(result.block).not.toBeNull();
782
+ expect(result.block).toContain(
783
+ 'Use `file_read("memory/concepts/path/to/file.md")` to read the full pages for any of the injected memory summaries you want more information on.',
784
+ );
785
+ expect(result.block).toContain(
786
+ "# memory/concepts/summarized-page.md\nA short prose description",
787
+ );
788
+ // Body is NOT in the block — the agent must follow up with a read tool.
789
+ expect(result.block).not.toContain("Long-form body content");
790
+ // Frontmatter is also omitted; the path header carries the identifying
791
+ // information by itself, and edges flow through the activation graph.
792
+ expect(result.block).not.toContain("---\nedges:");
793
+ });
794
+
795
+ test("mixed batch — summary page renders short, fallback page renders full", async () => {
796
+ // Both pages rank into top-K. summarized-page has a summary → short
797
+ // form. frontmatter-demo has no summary → full-page fallback. The
798
+ // single CRITICAL header sits at the top regardless.
799
+ stageTurn([
800
+ { slug: "summarized-page", denseScore: 0.95 },
801
+ { slug: "frontmatter-demo", denseScore: 0.85 },
802
+ ]);
803
+
804
+ const result = await injectMemoryV2Block({
805
+ database: db,
806
+ conversationId: "conv-1",
807
+ currentTurn: 1,
808
+ recentTurnPairs: [
809
+ { assistantMessage: "", userMessage: "show me everything" },
810
+ ],
811
+ nowText: "Now",
812
+ messageId: "msg-1",
813
+ config: makeConfig(),
814
+ });
815
+
816
+ expect(result.block).not.toBeNull();
817
+ // Header appears exactly once.
818
+ const headerCount = (
819
+ result.block!.match(
820
+ /Use `file_read\("memory\/concepts\/path\/to\/file\.md"\)` to read/g,
821
+ ) ?? []
822
+ ).length;
823
+ expect(headerCount).toBe(1);
824
+ // summarized-page → short form (path + summary, no body, no frontmatter).
825
+ expect(result.block).toContain("# memory/concepts/summarized-page.md\nA");
826
+ expect(result.block).not.toContain("Long-form body content");
827
+ // frontmatter-demo → full-page fallback (path + frontmatter + body).
828
+ expect(result.block).toContain(
829
+ "# memory/concepts/frontmatter-demo.md\n---\n",
830
+ );
831
+ expect(result.block).toContain("Demo body content.");
832
+ });
833
+
834
+ test("includes the page frontmatter (edges, ref_files) in each rendered section", async () => {
835
+ // The frontmatter (`edges`, `ref_files`) lives on disk above the page
836
+ // body and is part of the page's content. Injection must reproduce both
837
+ // fields verbatim — bracketed by the canonical `---` delimiters — so the
838
+ // agent sees the page's edges and any referenced media paths alongside
839
+ // the prose body.
840
+ stageTurn([{ slug: "frontmatter-demo", denseScore: 0.9 }]);
841
+
842
+ const result = await injectMemoryV2Block({
843
+ database: db,
844
+ conversationId: "conv-1",
845
+ currentTurn: 1,
846
+ recentTurnPairs: [
847
+ { assistantMessage: "", userMessage: "show me the demo" },
848
+ ],
849
+ nowText: "Now",
850
+ messageId: "msg-1",
851
+ config: makeConfig(),
852
+ });
853
+
854
+ expect(result.block).not.toBeNull();
855
+ // Path header is immediately followed by the frontmatter open delimiter.
856
+ // The fallback path renders the full page (frontmatter + body) when the
857
+ // page has no `summary` field — `frontmatter-demo` predates the field.
858
+ expect(result.block).toContain(
859
+ "# memory/concepts/frontmatter-demo.md\n---\n",
860
+ );
861
+ // Both fields render in YAML block style with their populated values.
862
+ expect(result.block).toContain("edges:\n - alice-vscode");
863
+ expect(result.block).toContain("ref_files:\n - images/demo.jpg");
864
+ // Body still renders after the closing delimiter.
865
+ expect(result.block).toContain("Demo body content.");
866
+ });
867
+
868
+ test("renders pages in activation-descending order", async () => {
869
+ // Both slugs are fresh (no prior state). carol scores higher than alice
870
+ // on every channel — so carol should be ranked first in topNow and
871
+ // therefore appear first in the rendered block.
872
+ stageTurn([
873
+ { slug: "carol-jazz", denseScore: 0.95 },
874
+ { slug: "alice-vscode", denseScore: 0.5 },
875
+ ]);
876
+ const result = await injectMemoryV2Block({
877
+ database: db,
878
+ conversationId: "conv-1",
879
+ currentTurn: 1,
880
+ recentTurnPairs: [
881
+ { assistantMessage: "", userMessage: "music and editors" },
882
+ ],
883
+ nowText: "Now",
884
+ messageId: "msg-1",
885
+ config: makeConfig(),
886
+ });
887
+
888
+ expect(result.toInject).toEqual(["carol-jazz", "alice-vscode"]);
889
+ const carolIdx = result.block!.indexOf("# memory/concepts/carol-jazz.md");
890
+ const aliceIdx = result.block!.indexOf("# memory/concepts/alice-vscode.md");
891
+ expect(carolIdx).toBeGreaterThan(-1);
892
+ expect(aliceIdx).toBeGreaterThan(-1);
893
+ expect(carolIdx).toBeLessThan(aliceIdx);
894
+ });
895
+
896
+ test("persists sparse state — only slugs above epsilon survive", async () => {
897
+ // Carol scores high; alice essentially zero. After saving, only carol
898
+ // should appear in the persisted state map. denseScore is the raw
899
+ // Qdrant cosine in [-1, 1]; alice uses -1 so the post `(x+1)/2`
900
+ // unit-mapping pins her fused score to 0 — below epsilon.
901
+ stageTurn([
902
+ { slug: "carol-jazz", denseScore: 1.0 },
903
+ { slug: "alice-vscode", denseScore: -1.0 },
904
+ ]);
905
+ await injectMemoryV2Block({
906
+ database: db,
907
+ conversationId: "conv-1",
908
+ currentTurn: 1,
909
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "carol" }],
910
+ nowText: "",
911
+ messageId: "msg-1",
912
+ config: makeConfig({ epsilon: 0.05 }),
913
+ });
914
+
915
+ const persisted = await hydrate(db, "conv-1");
916
+ expect(persisted!.state["carol-jazz"]).toBeGreaterThan(0.05);
917
+ expect(persisted!.state["alice-vscode"]).toBeUndefined();
918
+ });
919
+
920
+ test("returns null block when toInject slugs all reference missing pages", async () => {
921
+ // The ANN response contains a slug that is NOT on disk. After ranking,
922
+ // toInject is non-empty (we don't pre-filter), but `renderInjectionBlock`
923
+ // discovers the page is missing and returns null. The state is still
924
+ // persisted so we don't keep re-attempting.
925
+ stageTurn([{ slug: "phantom-slug", denseScore: 0.99 }]);
926
+ const result = await injectMemoryV2Block({
927
+ database: db,
928
+ conversationId: "conv-1",
929
+ currentTurn: 1,
930
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "phantom" }],
931
+ nowText: "",
932
+ messageId: "msg-1",
933
+ config: makeConfig(),
934
+ });
935
+
936
+ expect(result.toInject).toEqual(["phantom-slug"]);
937
+ expect(result.block).toBeNull();
938
+
939
+ // everInjected still records the slug so future turns subtract it and
940
+ // we don't infinite-loop on a missing page.
941
+ const persisted = await hydrate(db, "conv-1");
942
+ expect(persisted!.everInjected).toEqual([
943
+ { slug: "phantom-slug", turn: 1 },
944
+ ]);
945
+
946
+ // Activation log marks the slug `page_missing` (not `injected`) so a
947
+ // stale Qdrant / edge-index entry pointing at a vanished page is
948
+ // visible in telemetry instead of masquerading as a successful inject.
949
+ expect(telemetryState.recordCalls.length).toBe(1);
950
+ const row = telemetryState.recordCalls[0] as {
951
+ concepts: Array<{ slug: string; status: string }>;
952
+ };
953
+ const phantom = row.concepts.find((c) => c.slug === "phantom-slug");
954
+ expect(phantom).toBeDefined();
955
+ expect(phantom!.status).toBe("page_missing");
956
+ });
957
+
958
+ // ---------------------------------------------------------------------------
959
+ // Unified pool — skills as `skills/<id>` slugs
960
+ // ---------------------------------------------------------------------------
961
+
962
+ test("renders a retrieved skills/<id> slug under Skills You Can Use", async () => {
963
+ // No concept-page candidates this turn — the only ANN hit is a skill
964
+ // slug. The render path branches on `skills/` prefix: it pulls the
965
+ // entry from the skill-store cache (mocked) and emits the bullet under
966
+ // the `### Skills You Can Use` subsection.
967
+ stageTurn([{ slug: "skills/retrieved-skill", denseScore: 0.9 }]);
968
+ stageSkills([
969
+ {
970
+ id: "retrieved-skill",
971
+ content:
972
+ 'The "Retrieved Skill" skill (retrieved-skill) is available. Helps with retrieved skills.',
973
+ },
974
+ ]);
975
+
976
+ const result = await injectMemoryV2Block({
977
+ database: db,
978
+ conversationId: "conv-1",
979
+ currentTurn: 1,
980
+ recentTurnPairs: [
981
+ { assistantMessage: "", userMessage: "Help me with examples" },
982
+ ],
983
+ nowText: "Now",
984
+ messageId: "msg-1",
985
+ config: makeConfig(),
986
+ });
987
+
988
+ expect(result.toInject).toEqual(["skills/retrieved-skill"]);
989
+ expect(result.block).not.toBeNull();
990
+ expect(result.block).not.toContain("<memory>");
991
+ expect(result.block).not.toContain("</memory>");
992
+ expect(result.block).not.toContain("## What I Remember Right Now");
993
+ expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
994
+ const headerIdx = result.block!.indexOf("### Skills You Can Use");
995
+ const skillIdx = result.block!.indexOf(
996
+ '- The "Retrieved Skill" skill (retrieved-skill) is available. Helps with retrieved skills. → use skill_load to activate',
997
+ );
998
+ expect(headerIdx).toBeGreaterThan(-1);
999
+ expect(skillIdx).toBeGreaterThan(headerIdx);
1000
+ });
1001
+
1002
+ test("renders concept-page sections before the skills subsection in mixed blocks", async () => {
1003
+ // Concept page hit AND a skill — concept-page sections come first, then
1004
+ // the skills subsection.
1005
+ stageTurn([
1006
+ { slug: "alice-vscode", denseScore: 0.9 },
1007
+ { slug: "skills/example-skill-a", denseScore: 0.7 },
1008
+ ]);
1009
+ stageSkills([
1010
+ {
1011
+ id: "example-skill-a",
1012
+ content:
1013
+ 'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
1014
+ },
1015
+ ]);
1016
+
1017
+ const result = await injectMemoryV2Block({
1018
+ database: db,
1019
+ conversationId: "conv-1",
1020
+ currentTurn: 1,
1021
+ recentTurnPairs: [
1022
+ { assistantMessage: "", userMessage: "Alice's editor" },
1023
+ ],
1024
+ nowText: "Now",
1025
+ messageId: "msg-1",
1026
+ config: makeConfig(),
1027
+ });
1028
+
1029
+ // Both slugs ranked into top-K and got freshly attached.
1030
+ expect(new Set(result.toInject)).toEqual(
1031
+ new Set(["alice-vscode", "skills/example-skill-a"]),
1032
+ );
1033
+ expect(result.block).not.toBeNull();
1034
+
1035
+ const aliceHeaderIdx = result.block!.indexOf(
1036
+ "# memory/concepts/alice-vscode.md",
1037
+ );
1038
+ const skillsIdx = result.block!.indexOf("### Skills You Can Use");
1039
+ expect(aliceHeaderIdx).toBeGreaterThan(-1);
1040
+ expect(skillsIdx).toBeGreaterThan(-1);
1041
+ expect(aliceHeaderIdx).toBeLessThan(skillsIdx);
1042
+
1043
+ expect(result.block).toContain(
1044
+ '- The "Example Skill A" skill (example-skill-a) is available. Helps with examples. → use skill_load to activate',
1045
+ );
1046
+ });
1047
+
1048
+ test("skills participate in everInjected — an attached skill is not re-attached on the next turn", async () => {
1049
+ // Turn 1: skill ranks high, gets attached.
1050
+ const skillEntry = {
1051
+ id: "example-skill-a",
1052
+ content:
1053
+ 'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
1054
+ };
1055
+ stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
1056
+ stageSkills([skillEntry]);
1057
+ const result1 = await injectMemoryV2Block({
1058
+ database: db,
1059
+ conversationId: "conv-1",
1060
+ currentTurn: 1,
1061
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "examples" }],
1062
+ nowText: "Now",
1063
+ messageId: "msg-1",
1064
+ config: makeConfig(),
1065
+ });
1066
+ expect(result1.toInject).toEqual(["skills/example-skill-a"]);
1067
+ expect(result1.block).toContain("### Skills You Can Use");
1068
+
1069
+ // Turn 2: same skill ranks top again. It is already in `everInjected`, so
1070
+ // `toInject` is empty and the block is null — the attachment from turn 1
1071
+ // remains visible to the agent via the cached prior user message.
1072
+ stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
1073
+ stageSkills([skillEntry]);
1074
+ const result2 = await injectMemoryV2Block({
1075
+ database: db,
1076
+ conversationId: "conv-1",
1077
+ currentTurn: 2,
1078
+ recentTurnPairs: [
1079
+ { assistantMessage: "ok", userMessage: "more examples" },
1080
+ ],
1081
+ nowText: "Now",
1082
+ messageId: "msg-2",
1083
+ config: makeConfig(),
1084
+ });
1085
+ expect(result2.toInject).toEqual([]);
1086
+ expect(result2.block).toBeNull();
1087
+
1088
+ const persisted = await hydrate(db, "conv-1");
1089
+ expect(persisted!.everInjected).toEqual([
1090
+ { slug: "skills/example-skill-a", turn: 1 },
1091
+ ]);
1092
+ });
1093
+
1094
+ test("skill slugs whose entry is missing from the cache are dropped silently", async () => {
1095
+ // The skill ranks into top-K but the in-process cache no longer knows
1096
+ // its content (skill uninstalled mid-run, or a startup race where the
1097
+ // Qdrant row landed before the skill cache was seeded). The render path
1098
+ // drops it without surfacing it as a `missingSlugs` page-missing event —
1099
+ // that status is reserved for on-disk concept pages, not catalog-derived
1100
+ // skill entries.
1101
+ stageTurn([{ slug: "skills/missing-skill", denseScore: 0.9 }]);
1102
+ // No `stageSkills` call — cache stays empty.
1103
+
1104
+ const result = await injectMemoryV2Block({
1105
+ database: db,
1106
+ conversationId: "conv-1",
1107
+ currentTurn: 1,
1108
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
1109
+ nowText: "Now",
1110
+ messageId: "msg-1",
1111
+ config: makeConfig(),
1112
+ });
1113
+
1114
+ // The skill is excluded from `toInject` (and `everInjected`) so future
1115
+ // per-turn runs re-attempt the attach once the cache is populated.
1116
+ // `block` collapses to null because the only candidate was a cache miss.
1117
+ expect(result.toInject).toEqual([]);
1118
+ expect(result.block).toBeNull();
1119
+
1120
+ // Persisted `everInjected` must not record the missing skill — that
1121
+ // would block retry on a later turn until compaction-driven eviction.
1122
+ const persisted = await hydrate(db, "conv-1");
1123
+ expect(persisted!.everInjected).toEqual([]);
1124
+ });
1125
+
1126
+ test("returns null when both concept pages and skills are empty", async () => {
1127
+ stageTurn([]);
1128
+
1129
+ const result = await injectMemoryV2Block({
1130
+ database: db,
1131
+ conversationId: "conv-1",
1132
+ currentTurn: 1,
1133
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
1134
+ nowText: "",
1135
+ messageId: "msg-1",
1136
+ config: makeConfig(),
1137
+ });
1138
+
1139
+ expect(result.toInject).toEqual([]);
1140
+ expect(result.block).toBeNull();
1141
+ });
1142
+
1143
+ // ---------------------------------------------------------------------------
1144
+ // CLI-command synthetic entries — same unified-pool plumbing as skills.
1145
+ // ---------------------------------------------------------------------------
1146
+
1147
+ test("renders a retrieved cli-commands/<name> slug under CLI Commands You Can Use", async () => {
1148
+ stageTurn([{ slug: "cli-commands/attachment", denseScore: 0.9 }]);
1149
+ stageCliCommands([
1150
+ {
1151
+ id: "attachment",
1152
+ description: "Manage file attachments for conversations",
1153
+ content: 'The "assistant attachment" CLI command is available...',
1154
+ },
1155
+ ]);
1156
+
1157
+ const result = await injectMemoryV2Block({
1158
+ database: db,
1159
+ conversationId: "conv-1",
1160
+ currentTurn: 1,
1161
+ recentTurnPairs: [
1162
+ { assistantMessage: "", userMessage: "How do I register a video?" },
1163
+ ],
1164
+ nowText: "Now",
1165
+ messageId: "msg-1",
1166
+ config: makeConfig(),
1167
+ });
1168
+
1169
+ expect(result.toInject).toEqual(["cli-commands/attachment"]);
1170
+ expect(result.block).not.toBeNull();
1171
+ const headerIdx = result.block!.indexOf("### CLI Commands You Can Use");
1172
+ const lineIdx = result.block!.indexOf(
1173
+ "- `assistant attachment`: Manage file attachments for conversations",
1174
+ );
1175
+ expect(headerIdx).toBeGreaterThan(-1);
1176
+ expect(lineIdx).toBeGreaterThan(headerIdx);
1177
+ });
1178
+
1179
+ test("renders concepts, skills, then cli-commands in that order in mixed blocks", async () => {
1180
+ stageTurn([
1181
+ { slug: "alice-vscode", denseScore: 0.95 },
1182
+ { slug: "skills/example-skill-a", denseScore: 0.85 },
1183
+ { slug: "cli-commands/config", denseScore: 0.75 },
1184
+ ]);
1185
+ stageSkills([
1186
+ {
1187
+ id: "example-skill-a",
1188
+ content:
1189
+ 'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
1190
+ },
1191
+ ]);
1192
+ stageCliCommands([
1193
+ {
1194
+ id: "config",
1195
+ description: "Manage configuration",
1196
+ content: 'The "assistant config" CLI command is available...',
1197
+ },
1198
+ ]);
1199
+
1200
+ const result = await injectMemoryV2Block({
1201
+ database: db,
1202
+ conversationId: "conv-1",
1203
+ currentTurn: 1,
1204
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "Help me" }],
1205
+ nowText: "Now",
1206
+ messageId: "msg-1",
1207
+ config: makeConfig(),
1208
+ });
1209
+
1210
+ expect(new Set(result.toInject)).toEqual(
1211
+ new Set([
1212
+ "alice-vscode",
1213
+ "skills/example-skill-a",
1214
+ "cli-commands/config",
1215
+ ]),
1216
+ );
1217
+ const conceptIdx = result.block!.indexOf(
1218
+ "# memory/concepts/alice-vscode.md",
1219
+ );
1220
+ const skillsIdx = result.block!.indexOf("### Skills You Can Use");
1221
+ const cliIdx = result.block!.indexOf("### CLI Commands You Can Use");
1222
+ expect(conceptIdx).toBeGreaterThan(-1);
1223
+ expect(skillsIdx).toBeGreaterThan(conceptIdx);
1224
+ expect(cliIdx).toBeGreaterThan(skillsIdx);
1225
+ });
1226
+
1227
+ test("cli-command slugs whose entry is missing from the cache are dropped silently", async () => {
1228
+ stageTurn([{ slug: "cli-commands/missing-command", denseScore: 0.9 }]);
1229
+
1230
+ const result = await injectMemoryV2Block({
1231
+ database: db,
1232
+ conversationId: "conv-1",
1233
+ currentTurn: 1,
1234
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "anything" }],
1235
+ nowText: "Now",
1236
+ messageId: "msg-1",
1237
+ config: makeConfig(),
1238
+ });
1239
+
1240
+ expect(result.toInject).toEqual([]);
1241
+ expect(result.block).toBeNull();
1242
+
1243
+ const persisted = await hydrate(db, "conv-1");
1244
+ expect(persisted!.everInjected).toEqual([]);
1245
+ });
1246
+
1247
+ test("cli-commands participate in everInjected so they dedupe across turns", async () => {
1248
+ const entry = {
1249
+ id: "config",
1250
+ description: "Manage configuration",
1251
+ content: 'The "assistant config" CLI command is available...',
1252
+ };
1253
+ stageTurn([{ slug: "cli-commands/config", denseScore: 0.9 }]);
1254
+ stageCliCommands([entry]);
1255
+ const result1 = await injectMemoryV2Block({
1256
+ database: db,
1257
+ conversationId: "conv-1",
1258
+ currentTurn: 1,
1259
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "config" }],
1260
+ nowText: "Now",
1261
+ messageId: "msg-1",
1262
+ config: makeConfig(),
1263
+ });
1264
+ expect(result1.toInject).toEqual(["cli-commands/config"]);
1265
+ expect(result1.block).toContain("### CLI Commands You Can Use");
1266
+
1267
+ stageTurn([{ slug: "cli-commands/config", denseScore: 0.9 }]);
1268
+ stageCliCommands([entry]);
1269
+ const result2 = await injectMemoryV2Block({
1270
+ database: db,
1271
+ conversationId: "conv-1",
1272
+ currentTurn: 2,
1273
+ recentTurnPairs: [{ assistantMessage: "ok", userMessage: "more config" }],
1274
+ nowText: "Now",
1275
+ messageId: "msg-2",
1276
+ config: makeConfig(),
1277
+ });
1278
+ expect(result2.toInject).toEqual([]);
1279
+ expect(result2.block).toBeNull();
1280
+
1281
+ const persisted = await hydrate(db, "conv-1");
1282
+ expect(persisted!.everInjected).toEqual([
1283
+ { slug: "cli-commands/config", turn: 1 },
1284
+ ]);
1285
+ });
1286
+
1287
+ test("context-load mode renders topNow even when every slug was previously injected", async () => {
1288
+ // Turn 1 (per-turn): seed alice as injected.
1289
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1290
+ await injectMemoryV2Block({
1291
+ database: db,
1292
+ conversationId: "conv-1",
1293
+ currentTurn: 1,
1294
+ recentTurnPairs: [
1295
+ { assistantMessage: "", userMessage: "Alice's editor" },
1296
+ ],
1297
+ nowText: "Now",
1298
+ messageId: "msg-1",
1299
+ config: makeConfig(),
1300
+ });
1301
+
1302
+ // Subsequent context-load (post-compaction or fresh load): alice is
1303
+ // back in the candidate pool. Per-turn would dedup against everInjected
1304
+ // and produce a null block; context-load must re-render the full top-K
1305
+ // because cached attachments don't exist on a fresh load.
1306
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1307
+ const result = await injectMemoryV2Block({
1308
+ database: db,
1309
+ conversationId: "conv-1",
1310
+ currentTurn: 2,
1311
+ recentTurnPairs: [
1312
+ { assistantMessage: "", userMessage: "Reload context" },
1313
+ ],
1314
+ nowText: "Now",
1315
+ messageId: "msg-2",
1316
+ mode: "context-load",
1317
+ config: makeConfig(),
1318
+ });
1319
+
1320
+ expect(result.block).not.toBeNull();
1321
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
1322
+ // No newly-injected slug — alice was already in everInjected.
1323
+ expect(result.toInject).toEqual([]);
1324
+
1325
+ // everInjected stays a single entry (alice was already there) — context-
1326
+ // load doesn't double-stamp.
1327
+ const persisted = await hydrate(db, "conv-1");
1328
+ expect(persisted!.everInjected).toEqual([
1329
+ { slug: "alice-vscode", turn: 1 },
1330
+ ]);
1331
+ });
1332
+
1333
+ test("context-load mode renders the full top-K on a fresh first turn", async () => {
1334
+ // Turn 1 with no prior state and three candidates. Per-turn and context-
1335
+ // load behave identically when everInjected is empty (toInject == topNow),
1336
+ // but this asserts the contract: a fresh first user message gets the
1337
+ // entire top-K rendered, not just a delta.
1338
+ stageTurn([
1339
+ { slug: "alice-vscode", denseScore: 0.9 },
1340
+ { slug: "bob-coffee", denseScore: 0.8 },
1341
+ { slug: "carol-jazz", denseScore: 0.7 },
1342
+ ]);
1343
+
1344
+ const result = await injectMemoryV2Block({
1345
+ database: db,
1346
+ conversationId: "conv-1",
1347
+ currentTurn: 1,
1348
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "hi" }],
1349
+ nowText: "",
1350
+ messageId: "msg-1",
1351
+ mode: "context-load",
1352
+ config: makeConfig({ top_k: 3 }),
1353
+ });
1354
+
1355
+ expect(result.block).not.toBeNull();
1356
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
1357
+ expect(result.block).toContain("# memory/concepts/bob-coffee.md");
1358
+ expect(result.block).toContain("# memory/concepts/carol-jazz.md");
1359
+ // The seeded directed edges (alice→bob, bob→alice, frontmatter-demo→alice)
1360
+ // mean alice has two incoming predecessors and bob has one, so directed
1361
+ // spread normalizes alice's activation more aggressively than bob's. The
1362
+ // resulting rank order is bob > carol (no predecessors) > alice.
1363
+ expect(new Set(result.toInject)).toEqual(
1364
+ new Set(["alice-vscode", "bob-coffee", "carol-jazz"]),
1365
+ );
1366
+ expect(result.toInject).toHaveLength(3);
1367
+
1368
+ // All three slugs persisted to everInjected so the next per-turn doesn't
1369
+ // re-attach the same content.
1370
+ const persisted = await hydrate(db, "conv-1");
1371
+ expect(new Set(persisted!.everInjected.map((e) => e.slug))).toEqual(
1372
+ new Set(["alice-vscode", "bob-coffee", "carol-jazz"]),
1373
+ );
1374
+ expect(persisted!.everInjected).toHaveLength(3);
1375
+ });
1376
+
1377
+ // ---------------------------------------------------------------------------
1378
+ // Activation-log telemetry
1379
+ // ---------------------------------------------------------------------------
1380
+
1381
+ test("writes one activation-log row per turn with concept rows partitioned and sorted", async () => {
1382
+ // Turn 1: seed alice as injected so turn 2 has an `in_context` candidate.
1383
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1384
+ await injectMemoryV2Block({
1385
+ database: db,
1386
+ conversationId: "conv-1",
1387
+ currentTurn: 1,
1388
+ recentTurnPairs: [
1389
+ { assistantMessage: "", userMessage: "Alice's editor" },
1390
+ ],
1391
+ nowText: "Now",
1392
+ messageId: "msg-1",
1393
+ config: makeConfig(),
1394
+ });
1395
+ expect(telemetryState.recordCalls.length).toBe(1);
1396
+
1397
+ // Turn 2: alice carries forward (now `in_context`); carol is freshly
1398
+ // surfaced (`injected`); bob would be a candidate only if it carried
1399
+ // forward, but with no prior bob entry it doesn't appear here.
1400
+ stageTurn([
1401
+ { slug: "alice-vscode", denseScore: 0.6 },
1402
+ { slug: "carol-jazz", denseScore: 0.95 },
1403
+ ]);
1404
+ await injectMemoryV2Block({
1405
+ database: db,
1406
+ conversationId: "conv-1",
1407
+ currentTurn: 2,
1408
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "Carol's music" }],
1409
+ nowText: "Now",
1410
+ messageId: "msg-2",
1411
+ config: makeConfig(),
1412
+ });
1413
+
1414
+ expect(telemetryState.recordCalls.length).toBe(2);
1415
+ const row = telemetryState.recordCalls[1] as {
1416
+ conversationId: string;
1417
+ turn: number;
1418
+ mode: string;
1419
+ concepts: Array<{
1420
+ slug: string;
1421
+ finalActivation: number;
1422
+ status: string;
1423
+ source: string;
1424
+ }>;
1425
+ config: { top_k: number };
1426
+ };
1427
+ expect(row.conversationId).toBe("conv-1");
1428
+ expect(row.turn).toBe(2);
1429
+ expect(row.mode).toBe("per-turn");
1430
+ expect(row.config.top_k).toBe(25);
1431
+
1432
+ // The candidate set is the union of fromPrior (alice) and fromAnn
1433
+ // (alice + carol) → two concept rows.
1434
+ expect(row.concepts.length).toBe(2);
1435
+ const slugs = row.concepts.map((c) => c.slug);
1436
+ expect(new Set(slugs)).toEqual(new Set(["alice-vscode", "carol-jazz"]));
1437
+
1438
+ // Sorted descending by finalActivation.
1439
+ for (let i = 1; i < row.concepts.length; i++) {
1440
+ expect(row.concepts[i - 1]!.finalActivation).toBeGreaterThanOrEqual(
1441
+ row.concepts[i]!.finalActivation,
1442
+ );
1443
+ }
1444
+
1445
+ const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
1446
+ // Alice was attached on turn 1 → status `in_context` on turn 2.
1447
+ expect(byslug.get("alice-vscode")!.status).toBe("in_context");
1448
+ // Carol is freshly injected on turn 2.
1449
+ expect(byslug.get("carol-jazz")!.status).toBe("injected");
1450
+ });
1451
+
1452
+ test("activation-log concepts include skill rows under the skills/ prefix", async () => {
1453
+ // Skills participate in the unified telemetry list — they live in the
1454
+ // same `concepts` array, identifiable by the `skills/` slug prefix.
1455
+ stageTurn([
1456
+ { slug: "alice-vscode", denseScore: 0.9 },
1457
+ { slug: "skills/example-skill-a", denseScore: 0.7 },
1458
+ ]);
1459
+ stageSkills([
1460
+ {
1461
+ id: "example-skill-a",
1462
+ content: "skill content",
1463
+ },
1464
+ ]);
1465
+
1466
+ await injectMemoryV2Block({
1467
+ database: db,
1468
+ conversationId: "conv-1",
1469
+ currentTurn: 1,
1470
+ recentTurnPairs: [
1471
+ { assistantMessage: "", userMessage: "Alice's editor" },
1472
+ ],
1473
+ nowText: "Now",
1474
+ messageId: "msg-1",
1475
+ config: makeConfig(),
1476
+ });
1477
+
1478
+ expect(telemetryState.recordCalls.length).toBe(1);
1479
+ const row = telemetryState.recordCalls[0] as {
1480
+ concepts: Array<{ slug: string; status: string }>;
1481
+ };
1482
+ const slugs = row.concepts.map((c) => c.slug);
1483
+ expect(new Set(slugs)).toEqual(
1484
+ new Set(["alice-vscode", "skills/example-skill-a"]),
1485
+ );
1486
+ });
1487
+
1488
+ test("context-load mode marks every rendered slug as `injected`, never `in_context`", async () => {
1489
+ // Turn 1 (per-turn): seed alice as injected so the next turn's prior
1490
+ // `everInjected` includes her — the same setup the per-turn telemetry
1491
+ // test uses, so the difference between modes is unambiguous.
1492
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1493
+ await injectMemoryV2Block({
1494
+ database: db,
1495
+ conversationId: "conv-1",
1496
+ currentTurn: 1,
1497
+ recentTurnPairs: [
1498
+ { assistantMessage: "", userMessage: "Alice's editor" },
1499
+ ],
1500
+ nowText: "Now",
1501
+ messageId: "msg-1",
1502
+ config: makeConfig(),
1503
+ });
1504
+ expect(telemetryState.recordCalls.length).toBe(1);
1505
+
1506
+ // Turn 2 in context-load mode (post-compaction or fresh load). Alice
1507
+ // carries forward AND ranks high again; carol is a brand-new candidate.
1508
+ // Both end up in `topNow` (and therefore in `slugsToRender` since
1509
+ // context-load renders the full top-K). The status field must reflect
1510
+ // that they were physically rendered into the new user message on this
1511
+ // turn — `injected` for both — rather than reading `in_context` for
1512
+ // alice based on stale prior `everInjected` state.
1513
+ stageTurn([
1514
+ { slug: "alice-vscode", denseScore: 0.6 },
1515
+ { slug: "carol-jazz", denseScore: 0.95 },
1516
+ ]);
1517
+ await injectMemoryV2Block({
1518
+ database: db,
1519
+ conversationId: "conv-1",
1520
+ currentTurn: 2,
1521
+ recentTurnPairs: [
1522
+ { assistantMessage: "", userMessage: "Reload context" },
1523
+ ],
1524
+ nowText: "Now",
1525
+ messageId: "msg-2",
1526
+ mode: "context-load",
1527
+ config: makeConfig(),
1528
+ });
1529
+
1530
+ expect(telemetryState.recordCalls.length).toBe(2);
1531
+ const row = telemetryState.recordCalls[1] as {
1532
+ mode: string;
1533
+ concepts: Array<{ slug: string; status: string }>;
1534
+ };
1535
+ expect(row.mode).toBe("context-load");
1536
+
1537
+ const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
1538
+ // Both rendered slugs read as `injected` — alice especially, even though
1539
+ // she's in prior `everInjected`, because context-load actually rendered
1540
+ // her into the fresh user message on this turn.
1541
+ expect(byslug.get("alice-vscode")!.status).toBe("injected");
1542
+ expect(byslug.get("carol-jazz")!.status).toBe("injected");
1543
+
1544
+ // No slug reads as `in_context` in context-load mode — the cache was
1545
+ // wiped, so there is no prior cached attachment to reference.
1546
+ for (const concept of row.concepts) {
1547
+ expect(concept.status).not.toBe("in_context");
1548
+ }
1549
+ });
1550
+
1551
+ test("context-load mode marks candidates outside `slugsToRender` as `not_injected`", async () => {
1552
+ // Turn 1 (per-turn): seed both alice and bob with positive activation
1553
+ // so they survive into turn 2's prior-state candidate pool.
1554
+ stageTurn([
1555
+ { slug: "alice-vscode", denseScore: 0.9 },
1556
+ { slug: "bob-coffee", denseScore: 0.8 },
1557
+ ]);
1558
+ await injectMemoryV2Block({
1559
+ database: db,
1560
+ conversationId: "conv-1",
1561
+ currentTurn: 1,
1562
+ recentTurnPairs: [
1563
+ {
1564
+ assistantMessage: "",
1565
+ userMessage: "Alice's editor and Bob's coffee",
1566
+ },
1567
+ ],
1568
+ nowText: "Now",
1569
+ messageId: "msg-1",
1570
+ config: makeConfig(),
1571
+ });
1572
+
1573
+ // Turn 2 (context-load) with `top_k: 1`: alice and bob both carry
1574
+ // forward as candidates, but only the top-ranked slug is rendered.
1575
+ // Whichever slug doesn't make the cut must read as `not_injected`.
1576
+ stageTurn([
1577
+ { slug: "alice-vscode", denseScore: 0.95 },
1578
+ { slug: "bob-coffee", denseScore: 0.05 },
1579
+ ]);
1580
+ await injectMemoryV2Block({
1581
+ database: db,
1582
+ conversationId: "conv-1",
1583
+ currentTurn: 2,
1584
+ recentTurnPairs: [
1585
+ { assistantMessage: "", userMessage: "Reload context" },
1586
+ ],
1587
+ nowText: "Now",
1588
+ messageId: "msg-2",
1589
+ mode: "context-load",
1590
+ config: makeConfig({ top_k: 1 }),
1591
+ });
1592
+
1593
+ expect(telemetryState.recordCalls.length).toBe(2);
1594
+ const row = telemetryState.recordCalls[1] as {
1595
+ mode: string;
1596
+ concepts: Array<{ slug: string; status: string }>;
1597
+ };
1598
+ expect(row.mode).toBe("context-load");
1599
+
1600
+ const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
1601
+ // Alice ranked first → she is in `slugsToRender` → `injected`.
1602
+ expect(byslug.get("alice-vscode")!.status).toBe("injected");
1603
+ // Bob was a candidate but didn't make `top_k: 1` → `not_injected`.
1604
+ expect(byslug.get("bob-coffee")!.status).toBe("not_injected");
1605
+ });
1606
+
1607
+ test("telemetry write failure is non-fatal — injection still returns a normal result", async () => {
1608
+ telemetryState.recordShouldThrow = true;
1609
+
1610
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1611
+ const result = await injectMemoryV2Block({
1612
+ database: db,
1613
+ conversationId: "conv-1",
1614
+ currentTurn: 1,
1615
+ recentTurnPairs: [
1616
+ { assistantMessage: "", userMessage: "Alice's editor" },
1617
+ ],
1618
+ nowText: "Now",
1619
+ messageId: "msg-1",
1620
+ config: makeConfig(),
1621
+ });
1622
+
1623
+ // No row captured (the throw aborted the push), but the caller still
1624
+ // produced a regular block + toInject result and persisted state.
1625
+ expect(telemetryState.recordCalls.length).toBe(0);
1626
+ expect(result.toInject).toEqual(["alice-vscode"]);
1627
+ expect(result.block).not.toBeNull();
1628
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
1629
+
1630
+ const persisted = await hydrate(db, "conv-1");
1631
+ expect(persisted!.everInjected).toEqual([
1632
+ { slug: "alice-vscode", turn: 1 },
1633
+ ]);
1634
+ });
1635
+
1636
+ // ---------------------------------------------------------------------------
1637
+ // Per-page error isolation + on-throw telemetry
1638
+ // ---------------------------------------------------------------------------
1639
+
1640
+ test("one slug's page-read failing isolates the error — other slugs still render and the corrupt slug records `status: corrupt`", async () => {
1641
+ // Two slugs rank into top-K together. Carol's page reads cleanly; alice's
1642
+ // `readPage` throws a ZodError mimicking the real "unrecognized
1643
+ // frontmatter key" failure that motivated this work. Before the fix, the
1644
+ // bare `Promise.all` rejected and the entire turn lost its block AND its
1645
+ // activation log row. With per-page isolation, carol still renders and
1646
+ // the activation log row marks alice as `corrupt` (telemetry remains
1647
+ // observable for triage).
1648
+ const zodErr = z.object({ x: z.string() }).safeParse({ x: 1 }).error!;
1649
+ pageStoreState.failingSlugs.set("alice-vscode", zodErr);
1650
+ stageTurn([
1651
+ { slug: "alice-vscode", denseScore: 0.95 },
1652
+ { slug: "carol-jazz", denseScore: 0.9 },
1653
+ ]);
1654
+
1655
+ const result = await injectMemoryV2Block({
1656
+ database: db,
1657
+ conversationId: "conv-1",
1658
+ currentTurn: 1,
1659
+ recentTurnPairs: [
1660
+ { assistantMessage: "", userMessage: "music and editors" },
1661
+ ],
1662
+ nowText: "Now",
1663
+ messageId: "msg-1",
1664
+ config: makeConfig(),
1665
+ });
1666
+
1667
+ // (a) Block is non-null and contains content from the OTHER slug; alice
1668
+ // is dropped from the rendered block but does not poison the batch.
1669
+ expect(result.block).not.toBeNull();
1670
+ expect(result.block).toContain("# memory/concepts/carol-jazz.md");
1671
+ expect(result.block).not.toContain("# memory/concepts/alice-vscode.md");
1672
+
1673
+ // (b) Activation log row exists with carol `injected` and alice
1674
+ // `corrupt`. Status `corrupt` is reserved for read-time throws and is
1675
+ // distinct from `page_missing` (which is null-return / file vanished).
1676
+ expect(telemetryState.recordCalls.length).toBe(1);
1677
+ const row = telemetryState.recordCalls[0] as {
1678
+ mode: string;
1679
+ concepts: Array<{ slug: string; status: string }>;
1680
+ };
1681
+ expect(row.mode).toBe("per-turn");
1682
+ const byslug = new Map(row.concepts.map((c) => [c.slug, c]));
1683
+ expect(byslug.get("alice-vscode")!.status).toBe("corrupt");
1684
+ expect(byslug.get("carol-jazz")!.status).toBe("injected");
1685
+
1686
+ // (c) Both slugs land in `toInject` and `everInjected` — same handling
1687
+ // as `page_missing` (see the phantom-slug test): the slug was attempted
1688
+ // this turn, telemetry records the outcome, and we don't keep re-trying
1689
+ // a stale Qdrant / edge-index entry on every subsequent turn.
1690
+ expect(new Set(result.toInject)).toEqual(
1691
+ new Set(["alice-vscode", "carol-jazz"]),
1692
+ );
1693
+ const persisted = await hydrate(db, "conv-1");
1694
+ const everInjectedSlugs = persisted!.everInjected.map((e) => e.slug);
1695
+ expect(new Set(everInjectedSlugs)).toEqual(
1696
+ new Set(["alice-vscode", "carol-jazz"]),
1697
+ );
1698
+ });
1699
+
1700
+ test("a throw before renderInjectionBlock still flushes telemetry as `mode: errored` and re-throws", async () => {
1701
+ // The activation-state save throws — the most realistic non-render
1702
+ // failure mode (transient SQLite write error mid-injection). The
1703
+ // `injectMemoryV2Block` outer try/finally must (a) flush an activation
1704
+ // log row tagged `mode: "errored"` so silent failures stay observable
1705
+ // in the database, and (b) re-throw so callers (e.g. `prepareMemory`'s
1706
+ // outer catch) see the original error and can degrade gracefully.
1707
+ activationStoreState.saveShouldThrow = true;
1708
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1709
+
1710
+ let threw: unknown = undefined;
1711
+ try {
1712
+ await injectMemoryV2Block({
1713
+ database: db,
1714
+ conversationId: "conv-1",
1715
+ currentTurn: 1,
1716
+ recentTurnPairs: [
1717
+ { assistantMessage: "", userMessage: "Alice's editor" },
1718
+ ],
1719
+ nowText: "Now",
1720
+ messageId: "msg-1",
1721
+ config: makeConfig(),
1722
+ });
1723
+ } catch (err) {
1724
+ threw = err;
1725
+ }
1726
+
1727
+ // The original error propagates to the caller.
1728
+ expect(threw).toBeInstanceOf(Error);
1729
+ expect((threw as Error).message).toContain(
1730
+ "simulated activation-store save failure",
1731
+ );
1732
+
1733
+ // A telemetry row was still written, tagged `errored`. `concepts` is
1734
+ // empty because the throw fired before the row-builder ran — that's
1735
+ // expected and documented as part of the contract.
1736
+ expect(telemetryState.recordCalls.length).toBe(1);
1737
+ const row = telemetryState.recordCalls[0] as {
1738
+ mode: string;
1739
+ conversationId: string;
1740
+ turn: number;
1741
+ concepts: unknown[];
1742
+ };
1743
+ expect(row.mode).toBe("errored");
1744
+ expect(row.conversationId).toBe("conv-1");
1745
+ expect(row.turn).toBe(1);
1746
+ expect(row.concepts).toEqual([]);
1747
+ });
1748
+
1749
+ test("activation pipeline routes through `finalizeInjection` — telemetry shape and config snapshot match the contract", async () => {
1750
+ // Pure-refactor regression check: `injectMemoryV2Block` now delegates the
1751
+ // tail (state save + render + telemetry finalization + log write) to a
1752
+ // private `finalizeInjection` helper. This test asserts the helper is
1753
+ // exercised by verifying `recordMemoryV2ActivationLog` is called with the
1754
+ // same arg shape as before — same conversationId/turn/mode, same config
1755
+ // snapshot, and a fully populated concept row whose status was finalized
1756
+ // to `"injected"` on the freshly-attached slug.
1757
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
1758
+
1759
+ const result = await injectMemoryV2Block({
1760
+ database: db,
1761
+ conversationId: "conv-finalize",
1762
+ currentTurn: 7,
1763
+ recentTurnPairs: [
1764
+ { assistantMessage: "", userMessage: "Alice's editor" },
1765
+ ],
1766
+ nowText: "Now",
1767
+ messageId: "msg-finalize",
1768
+ config: makeConfig(),
1769
+ });
1770
+
1771
+ // The helper rendered + persisted just like the original tail did.
1772
+ expect(result.block).toContain("alice-vscode");
1773
+ expect(result.toInject).toEqual(["alice-vscode"]);
1774
+
1775
+ expect(telemetryState.recordCalls.length).toBe(1);
1776
+ const row = telemetryState.recordCalls[0] as {
1777
+ conversationId: string;
1778
+ turn: number;
1779
+ mode: string;
1780
+ concepts: Array<{
1781
+ slug: string;
1782
+ status: string;
1783
+ finalActivation: number;
1784
+ }>;
1785
+ config: {
1786
+ d: number;
1787
+ c_user: number;
1788
+ c_assistant: number;
1789
+ c_now: number;
1790
+ k: number;
1791
+ hops: number;
1792
+ top_k: number;
1793
+ epsilon: number;
1794
+ };
1795
+ };
1796
+ expect(row.conversationId).toBe("conv-finalize");
1797
+ expect(row.turn).toBe(7);
1798
+ expect(row.mode).toBe("per-turn");
1799
+ // Config snapshot must include all eight tunables — proves the helper is
1800
+ // pulling from `config.memory.v2` rather than synthesizing a partial.
1801
+ expect(Object.keys(row.config).sort()).toEqual(
1802
+ [
1803
+ "c_assistant",
1804
+ "c_now",
1805
+ "c_user",
1806
+ "d",
1807
+ "epsilon",
1808
+ "hops",
1809
+ "k",
1810
+ "top_k",
1811
+ ].sort(),
1812
+ );
1813
+ // Status finalization ran inside the helper — alice was selected and
1814
+ // rendered, so its row reads `injected`.
1815
+ const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
1816
+ expect(aliceRow?.status).toBe("injected");
1817
+ });
1818
+
1819
+ // ---------------------------------------------------------------------------
1820
+ // Router mode (flag-gated)
1821
+ // ---------------------------------------------------------------------------
1822
+
1823
+ describe("router mode", () => {
1824
+ test("flag-on: router-selected slugs render and append to everInjected", async () => {
1825
+ // Router picks alice. The activation pipeline never runs — we don't
1826
+ // stage any qdrant responses here, and that's intentional. The
1827
+ // candidate set comes straight from the router's `selectedSlugs`.
1828
+ routerState.nextResult = {
1829
+ selectedSlugs: ["alice-vscode"],
1830
+ failureReason: null,
1831
+ };
1832
+
1833
+ const result = await injectMemoryV2Block({
1834
+ database: db,
1835
+ conversationId: "conv-router-1",
1836
+ currentTurn: 1,
1837
+ recentTurnPairs: [
1838
+ { assistantMessage: "", userMessage: "Tell me about Alice" },
1839
+ ],
1840
+ nowText: "Now",
1841
+ messageId: "msg-1",
1842
+ config: makeConfig({ router: { enabled: true } }),
1843
+ });
1844
+
1845
+ expect(routerState.callCount).toBe(1);
1846
+ expect(result.toInject).toEqual(["alice-vscode"]);
1847
+ expect(result.block).not.toBeNull();
1848
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
1849
+
1850
+ const persisted = await hydrate(db, "conv-router-1");
1851
+ expect(persisted!.everInjected).toEqual([
1852
+ { slug: "alice-vscode", turn: 1 },
1853
+ ]);
1854
+ // Router mode persists an empty sparse activation map — the router
1855
+ // does not compute spreading-activation scores.
1856
+ expect(persisted!.state).toEqual({});
1857
+
1858
+ // Telemetry: success rows get `mode: "router"` and `source: "router"`,
1859
+ // with all activation fields zeroed.
1860
+ expect(telemetryState.recordCalls.length).toBe(1);
1861
+ const row = telemetryState.recordCalls[0] as {
1862
+ mode: string;
1863
+ concepts: Array<{
1864
+ slug: string;
1865
+ source: string;
1866
+ status: string;
1867
+ finalActivation: number;
1868
+ ownActivation: number;
1869
+ }>;
1870
+ };
1871
+ expect(row.mode).toBe("router");
1872
+ const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
1873
+ expect(aliceRow).toBeDefined();
1874
+ // Default-stub provenance is `tier3:0` (single-batch path); see the
1875
+ // runRouter mock for the synthesis rule.
1876
+ expect(aliceRow!.source).toBe("tier3:0");
1877
+ expect(aliceRow!.status).toBe("injected");
1878
+ expect(aliceRow!.finalActivation).toBe(0);
1879
+ expect(aliceRow!.ownActivation).toBe(0);
1880
+ });
1881
+
1882
+ test("flag-on: saturated index (every page already injected) skips the router LLM call", async () => {
1883
+ // Turn 1 — normal router path injects alice.
1884
+ routerState.nextResult = {
1885
+ selectedSlugs: ["alice-vscode"],
1886
+ failureReason: null,
1887
+ };
1888
+ await injectMemoryV2Block({
1889
+ database: db,
1890
+ conversationId: "conv-router-saturated",
1891
+ currentTurn: 1,
1892
+ recentTurnPairs: [
1893
+ { assistantMessage: "", userMessage: "Tell me about Alice" },
1894
+ ],
1895
+ nowText: "Now",
1896
+ messageId: "msg-1",
1897
+ config: makeConfig({ router: { enabled: true } }),
1898
+ });
1899
+
1900
+ // Mark every page in the index as already injected — the state a
1901
+ // small workspace reaches a few turns into any conversation.
1902
+ const { getPageIndex } = await import("../page-index.js");
1903
+ const index = await getPageIndex(tmpWorkspace);
1904
+ const seeded = await hydrate(db, "conv-router-saturated");
1905
+ await save(db, "conv-router-saturated", {
1906
+ ...seeded!,
1907
+ everInjected: index.entries.map((e) => ({ slug: e.slug, turn: 1 })),
1908
+ });
1909
+
1910
+ // Turn 2 — the router must not be called: any selection would dedupe
1911
+ // against everInjected and render nothing.
1912
+ const callsBefore = routerState.callCount;
1913
+ routerState.nextResult = {
1914
+ selectedSlugs: ["bob-coffee"],
1915
+ failureReason: null,
1916
+ };
1917
+ const result = await injectMemoryV2Block({
1918
+ database: db,
1919
+ conversationId: "conv-router-saturated",
1920
+ currentTurn: 2,
1921
+ recentTurnPairs: [{ assistantMessage: "ok", userMessage: "and Bob?" }],
1922
+ nowText: "Now",
1923
+ messageId: "msg-2",
1924
+ config: makeConfig({ router: { enabled: true } }),
1925
+ });
1926
+
1927
+ expect(routerState.callCount).toBe(callsBefore);
1928
+ expect(result.block).toBeNull();
1929
+ expect(result.toInject).toEqual([]);
1930
+
1931
+ // State still advanced; everInjected preserved for future dedupe.
1932
+ const persisted = await hydrate(db, "conv-router-saturated");
1933
+ expect(persisted!.currentTurn).toBe(2);
1934
+ expect(persisted!.messageId).toBe("msg-2");
1935
+ expect(persisted!.everInjected.length).toBe(index.entries.length);
1936
+
1937
+ // Telemetry row stays in router mode with every slug carried over.
1938
+ const row = telemetryState.recordCalls.at(-1) as {
1939
+ mode: string;
1940
+ concepts: Array<{ source: string; status: string }>;
1941
+ };
1942
+ expect(row.mode).toBe("router");
1943
+ expect(row.concepts.length).toBe(index.entries.length);
1944
+ for (const concept of row.concepts) {
1945
+ expect(concept.source).toBe("carry_over");
1946
+ // `finalizeInjection` rewrites the placeholder status: slugs already
1947
+ // in everInjected are reported as in_context.
1948
+ expect(concept.status).toBe("in_context");
1949
+ }
1950
+ });
1951
+
1952
+ test("flag-on: router failure logs warn, writes mode:`errored` telemetry, returns null block", async () => {
1953
+ routerState.nextResult = {
1954
+ selectedSlugs: [],
1955
+ failureReason: "api_error",
1956
+ };
1957
+
1958
+ const result = await injectMemoryV2Block({
1959
+ database: db,
1960
+ conversationId: "conv-router-fail",
1961
+ currentTurn: 3,
1962
+ recentTurnPairs: [{ assistantMessage: "ok", userMessage: "anything" }],
1963
+ nowText: "Now",
1964
+ messageId: "msg-fail",
1965
+ config: makeConfig({ router: { enabled: true } }),
1966
+ });
1967
+
1968
+ expect(result.block).toBeNull();
1969
+ expect(result.toInject).toEqual([]);
1970
+
1971
+ // Stub state still advanced.
1972
+ const persisted = await hydrate(db, "conv-router-fail");
1973
+ expect(persisted).not.toBeNull();
1974
+ expect(persisted!.currentTurn).toBe(3);
1975
+ expect(persisted!.messageId).toBe("msg-fail");
1976
+ expect(persisted!.state).toEqual({});
1977
+ expect(persisted!.everInjected).toEqual([]);
1978
+
1979
+ // Single telemetry row with `mode: "errored"` (not `"router"`).
1980
+ expect(telemetryState.recordCalls.length).toBe(1);
1981
+ const row = telemetryState.recordCalls[0] as {
1982
+ mode: string;
1983
+ conversationId: string;
1984
+ turn: number;
1985
+ concepts: unknown[];
1986
+ };
1987
+ expect(row.mode).toBe("errored");
1988
+ expect(row.conversationId).toBe("conv-router-fail");
1989
+ expect(row.turn).toBe(3);
1990
+ expect(row.concepts).toEqual([]);
1991
+ });
1992
+
1993
+ test("flag-on: router-failure path swallows a save() error and returns block:null instead of throwing", async () => {
1994
+ // PR 30176 refactored router-failure handling to delegate to
1995
+ // `finalizeInjection`. That regressed the prior inline log-and-continue
1996
+ // semantics on the router-failure path: a transient SQLite write
1997
+ // throwing during the stub-state save now aborted the whole turn
1998
+ // because `finalizeInjection`'s try/catch re-threw caughtErr at the end.
1999
+ //
2000
+ // This test stages exactly that scenario — router returns
2001
+ // `failureReason: api_error` AND `save()` throws — and asserts the
2002
+ // turn completes with `{ block: null, toInject: [] }` rather than
2003
+ // propagating the SQLite error to `prepareMemory`.
2004
+ routerState.nextResult = {
2005
+ selectedSlugs: [],
2006
+ failureReason: "api_error",
2007
+ };
2008
+ activationStoreState.saveShouldThrow = true;
2009
+
2010
+ let threw: unknown = undefined;
2011
+ let result: Awaited<ReturnType<typeof injectMemoryV2Block>> | undefined;
2012
+ try {
2013
+ result = await injectMemoryV2Block({
2014
+ database: db,
2015
+ conversationId: "conv-router-fail-save-throws",
2016
+ currentTurn: 5,
2017
+ recentTurnPairs: [
2018
+ { assistantMessage: "ok", userMessage: "anything" },
2019
+ ],
2020
+ nowText: "Now",
2021
+ messageId: "msg-fail-save",
2022
+ config: makeConfig({ router: { enabled: true } }),
2023
+ });
2024
+ } catch (err) {
2025
+ threw = err;
2026
+ }
2027
+
2028
+ expect(threw).toBeUndefined();
2029
+ expect(result).toBeDefined();
2030
+ expect(result!.block).toBeNull();
2031
+ expect(result!.toInject).toEqual([]);
2032
+
2033
+ // Telemetry still flushes with `mode: "errored"` so the failure stays
2034
+ // observable — the same row the inline pre-refactor path emitted.
2035
+ expect(telemetryState.recordCalls.length).toBe(1);
2036
+ const row = telemetryState.recordCalls[0] as {
2037
+ mode: string;
2038
+ concepts: unknown[];
2039
+ };
2040
+ expect(row.mode).toBe("errored");
2041
+ expect(row.concepts).toEqual([]);
2042
+ });
2043
+
2044
+ test("flag-on: router abstention (empty selectedSlugs, no failure) writes mode:`router` row with no injected pages", async () => {
2045
+ routerState.nextResult = {
2046
+ selectedSlugs: [],
2047
+ failureReason: null,
2048
+ };
2049
+
2050
+ const result = await injectMemoryV2Block({
2051
+ database: db,
2052
+ conversationId: "conv-router-abstain",
2053
+ currentTurn: 1,
2054
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "small talk" }],
2055
+ nowText: "Now",
2056
+ messageId: "msg-abstain",
2057
+ config: makeConfig({ router: { enabled: true } }),
2058
+ });
2059
+
2060
+ expect(result.block).toBeNull();
2061
+ expect(result.toInject).toEqual([]);
2062
+
2063
+ // No prior everInjected to dedup against, so toInject is empty and
2064
+ // nothing renders. State still advanced.
2065
+ const persisted = await hydrate(db, "conv-router-abstain");
2066
+ expect(persisted!.everInjected).toEqual([]);
2067
+ expect(persisted!.currentTurn).toBe(1);
2068
+
2069
+ // Telemetry: `mode: "router"` row with zero injected pages.
2070
+ expect(telemetryState.recordCalls.length).toBe(1);
2071
+ const row = telemetryState.recordCalls[0] as {
2072
+ mode: string;
2073
+ concepts: Array<{ slug: string; status: string }>;
2074
+ };
2075
+ expect(row.mode).toBe("router");
2076
+ const injectedCount = row.concepts.filter(
2077
+ (c) => c.status === "injected",
2078
+ ).length;
2079
+ expect(injectedCount).toBe(0);
2080
+ });
2081
+
2082
+ test("flag-on: router-selected slug whose page is missing on disk records `page_missing` and is NOT added to everInjected", async () => {
2083
+ routerState.nextResult = {
2084
+ selectedSlugs: ["phantom-router-slug"],
2085
+ failureReason: null,
2086
+ };
2087
+
2088
+ const result = await injectMemoryV2Block({
2089
+ database: db,
2090
+ conversationId: "conv-router-missing",
2091
+ currentTurn: 1,
2092
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "phantom" }],
2093
+ nowText: "Now",
2094
+ messageId: "msg-missing",
2095
+ config: makeConfig({ router: { enabled: true } }),
2096
+ });
2097
+
2098
+ // No backing page → block collapses to null.
2099
+ expect(result.block).toBeNull();
2100
+ // toInject mirrors `newlyInjected` from `finalizeInjection` — the
2101
+ // missing slug still flowed through `slugsToRender` so it's recorded
2102
+ // here (matching the activation-mode phantom-slug contract).
2103
+ expect(result.toInject).toEqual(["phantom-router-slug"]);
2104
+
2105
+ // Activation-mode parity: the phantom slug DOES land in everInjected
2106
+ // so we don't infinite-retry it. (This matches the behavior the
2107
+ // existing `returns null block when toInject slugs all reference
2108
+ // missing pages` test asserts for activation mode.)
2109
+ const persisted = await hydrate(db, "conv-router-missing");
2110
+ expect(persisted!.everInjected).toEqual([
2111
+ { slug: "phantom-router-slug", turn: 1 },
2112
+ ]);
2113
+
2114
+ // Telemetry: `status: "page_missing"` for the phantom slug.
2115
+ expect(telemetryState.recordCalls.length).toBe(1);
2116
+ const row = telemetryState.recordCalls[0] as {
2117
+ mode: string;
2118
+ concepts: Array<{ slug: string; status: string; source: string }>;
2119
+ };
2120
+ expect(row.mode).toBe("router");
2121
+ const phantom = row.concepts.find(
2122
+ (c) => c.slug === "phantom-router-slug",
2123
+ );
2124
+ expect(phantom).toBeDefined();
2125
+ expect(phantom!.status).toBe("page_missing");
2126
+ expect(phantom!.source).toBe("tier3:0");
2127
+ });
2128
+
2129
+ test("flag-on: router re-picking a prior-everInjected slug does NOT re-render it; non-overlapping picks render and append to everInjected", async () => {
2130
+ // Turn 1: router picks alice. Standard append.
2131
+ routerState.nextResult = {
2132
+ selectedSlugs: ["alice-vscode"],
2133
+ failureReason: null,
2134
+ };
2135
+ const turn1 = await injectMemoryV2Block({
2136
+ database: db,
2137
+ conversationId: "conv-router-dedup",
2138
+ currentTurn: 1,
2139
+ recentTurnPairs: [
2140
+ { assistantMessage: "", userMessage: "Tell me about Alice" },
2141
+ ],
2142
+ nowText: "Now",
2143
+ messageId: "msg-1",
2144
+ config: makeConfig({ router: { enabled: true } }),
2145
+ });
2146
+ expect(turn1.toInject).toEqual(["alice-vscode"]);
2147
+
2148
+ // Turn 2: router re-picks alice (the "re-anchor" prompt branch) AND
2149
+ // adds bob. The block must NOT contain alice's body — her cached
2150
+ // attachment from turn 1 is still on the prior user message — but
2151
+ // must contain bob's.
2152
+ telemetryState.recordCalls.length = 0;
2153
+ routerState.nextResult = {
2154
+ selectedSlugs: ["alice-vscode", "bob-coffee"],
2155
+ failureReason: null,
2156
+ };
2157
+ const turn2 = await injectMemoryV2Block({
2158
+ database: db,
2159
+ conversationId: "conv-router-dedup",
2160
+ currentTurn: 2,
2161
+ recentTurnPairs: [
2162
+ { assistantMessage: "Sure", userMessage: "And Bob?" },
2163
+ ],
2164
+ nowText: "Now",
2165
+ messageId: "msg-2",
2166
+ config: makeConfig({ router: { enabled: true } }),
2167
+ });
2168
+
2169
+ // Re-picked alice was deduped; only bob is freshly injected.
2170
+ expect(turn2.toInject).toEqual(["bob-coffee"]);
2171
+ expect(turn2.block).not.toBeNull();
2172
+ expect(turn2.block).toContain("# memory/concepts/bob-coffee.md");
2173
+ expect(turn2.block).toContain("Bob takes his coffee");
2174
+ expect(turn2.block).not.toContain("VS Code");
2175
+ expect(turn2.block).not.toContain("# memory/concepts/alice-vscode.md");
2176
+
2177
+ // everInjected only gained bob — alice was already there.
2178
+ const persisted = await hydrate(db, "conv-router-dedup");
2179
+ expect(persisted!.everInjected).toEqual([
2180
+ { slug: "alice-vscode", turn: 1 },
2181
+ { slug: "bob-coffee", turn: 2 },
2182
+ ]);
2183
+ });
2184
+
2185
+ test("flag-on: telemetry distinguishes `source: router` (router picks) from `source: carry_over` (prior-everInjected slugs the router did not re-pick)", async () => {
2186
+ // Turn 1: seed everInjected with alice.
2187
+ routerState.nextResult = {
2188
+ selectedSlugs: ["alice-vscode"],
2189
+ failureReason: null,
2190
+ };
2191
+ await injectMemoryV2Block({
2192
+ database: db,
2193
+ conversationId: "conv-router-source",
2194
+ currentTurn: 1,
2195
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "Alice" }],
2196
+ nowText: "Now",
2197
+ messageId: "msg-1",
2198
+ config: makeConfig({ router: { enabled: true } }),
2199
+ });
2200
+ telemetryState.recordCalls.length = 0;
2201
+
2202
+ // Turn 2: router picks bob only. alice is still in everInjected but
2203
+ // not re-picked — her telemetry row must read `source: carry_over`,
2204
+ // not `source: router`.
2205
+ routerState.nextResult = {
2206
+ selectedSlugs: ["bob-coffee"],
2207
+ failureReason: null,
2208
+ };
2209
+ await injectMemoryV2Block({
2210
+ database: db,
2211
+ conversationId: "conv-router-source",
2212
+ currentTurn: 2,
2213
+ recentTurnPairs: [{ assistantMessage: "", userMessage: "Bob" }],
2214
+ nowText: "Now",
2215
+ messageId: "msg-2",
2216
+ config: makeConfig({ router: { enabled: true } }),
2217
+ });
2218
+
2219
+ expect(telemetryState.recordCalls.length).toBe(1);
2220
+ const row = telemetryState.recordCalls[0] as {
2221
+ mode: string;
2222
+ concepts: Array<{ slug: string; source: string; status: string }>;
2223
+ };
2224
+ expect(row.mode).toBe("router");
2225
+ const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
2226
+ const bobRow = row.concepts.find((c) => c.slug === "bob-coffee");
2227
+ expect(aliceRow).toBeDefined();
2228
+ expect(bobRow).toBeDefined();
2229
+ expect(aliceRow!.source).toBe("carry_over");
2230
+ expect(aliceRow!.status).toBe("in_context");
2231
+ expect(bobRow!.source).toBe("tier3:0");
2232
+ expect(bobRow!.status).toBe("injected");
2233
+ });
2234
+
2235
+ test("flag-off (default): activation pipeline still runs unchanged", async () => {
2236
+ // Regression check — with the router flag explicitly off (the
2237
+ // production default), `runRouter` must never be called and the
2238
+ // activation pipeline drives the selection just like before.
2239
+ stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
2240
+ routerState.nextResult = {
2241
+ selectedSlugs: ["should-not-be-used"],
2242
+ failureReason: null,
2243
+ };
2244
+
2245
+ const result = await injectMemoryV2Block({
2246
+ database: db,
2247
+ conversationId: "conv-flag-off",
2248
+ currentTurn: 1,
2249
+ recentTurnPairs: [
2250
+ { assistantMessage: "", userMessage: "Alice's editor" },
2251
+ ],
2252
+ nowText: "Now",
2253
+ messageId: "msg-1",
2254
+ config: makeConfig({ router: { enabled: false } }),
2255
+ });
2256
+
2257
+ // Router was not called.
2258
+ expect(routerState.callCount).toBe(0);
2259
+ // Activation pipeline produced its normal result.
2260
+ expect(result.toInject).toEqual(["alice-vscode"]);
2261
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
2262
+
2263
+ // Telemetry row carries the activation mode, not router.
2264
+ expect(telemetryState.recordCalls.length).toBe(1);
2265
+ const row = telemetryState.recordCalls[0] as { mode: string };
2266
+ expect(row.mode).toBe("per-turn");
2267
+ });
2268
+
2269
+ test("flag-on + mode='context-load': router runs (everInjected was cleared by onCompacted so dedupe is a no-op; abstention is accepted as the trade-off)", async () => {
2270
+ // Context-load is the full top-K bootstrap fired after compaction or
2271
+ // a fresh conversation reload. The earlier worry about the router's
2272
+ // `everInjected` dedupe filtering out post-compaction restorations
2273
+ // doesn't apply: `ConversationGraphMemory.onCompacted` calls
2274
+ // `evictCompactedTurnsV2` which empties the list before this code
2275
+ // runs. Router abstention here means no v2 pages this turn — that's
2276
+ // preferable to letting the activation graph pick something arbitrary.
2277
+ routerState.nextResult = {
2278
+ selectedSlugs: ["alice-vscode"],
2279
+ failureReason: null,
2280
+ };
2281
+
2282
+ const result = await injectMemoryV2Block({
2283
+ database: db,
2284
+ conversationId: "conv-context-load-router-on",
2285
+ currentTurn: 1,
2286
+ recentTurnPairs: [
2287
+ { assistantMessage: "", userMessage: "Tell me about Alice" },
2288
+ ],
2289
+ nowText: "Now",
2290
+ messageId: "msg-1",
2291
+ mode: "context-load",
2292
+ config: makeConfig({ router: { enabled: true } }),
2293
+ });
2294
+
2295
+ // Router was called on context-load too.
2296
+ expect(routerState.callCount).toBe(1);
2297
+
2298
+ // Router's picks were rendered.
2299
+ expect(result.toInject).toEqual(["alice-vscode"]);
2300
+ expect(result.block).toContain("# memory/concepts/alice-vscode.md");
2301
+
2302
+ // Telemetry row reflects the router mode, not the activation mode.
2303
+ expect(telemetryState.recordCalls.length).toBe(1);
2304
+ const row = telemetryState.recordCalls[0] as { mode: string };
2305
+ expect(row.mode).toBe("router");
2306
+ });
2307
+ });
2308
+ });