@vellumai/assistant 0.10.3-staging.2 → 0.10.4-dev.202607010028.1a4efcc

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 (2236) hide show
  1. package/ARCHITECTURE.md +13 -13
  2. package/Dockerfile +5 -15
  3. package/bun.lock +165 -3
  4. package/docs/architecture/memory.md +26 -0
  5. package/eslint-rules/cli-no-daemon-internals.js +9 -8
  6. package/knip.json +0 -1
  7. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +18 -0
  8. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
  9. package/openapi.yaml +1057 -88
  10. package/package.json +8 -3
  11. package/scripts/generate-openapi.ts +149 -62
  12. package/src/__tests__/acp-session.test.ts +2 -2
  13. package/src/__tests__/activation-early-marking.test.ts +4 -4
  14. package/src/__tests__/actor-token-service.test.ts +2 -3
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
  16. package/src/__tests__/agent-loop-compaction-events.test.ts +1 -0
  17. package/src/__tests__/agent-loop-compaction-strip.test.ts +2 -0
  18. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -1
  19. package/src/__tests__/agent-loop-override-profile.test.ts +2 -2
  20. package/src/__tests__/agent-loop-regrowth-guard.test.ts +8 -0
  21. package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
  22. package/src/__tests__/agent-loop.test.ts +1 -0
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +3 -3
  24. package/src/__tests__/agent-wake-override-profile.test.ts +3 -3
  25. package/src/__tests__/annotate-activity-metadata.test.ts +4 -4
  26. package/src/__tests__/annotate-risk-options.test.ts +4 -4
  27. package/src/__tests__/anthropic-provider.test.ts +53 -2
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +2 -2
  29. package/src/__tests__/app-bundler.test.ts +1 -1
  30. package/src/__tests__/app-conversation-ids-backfill.test.ts +4 -4
  31. package/src/__tests__/app-conversation-ids.test.ts +1 -1
  32. package/src/__tests__/app-dir-path-guard.test.ts +2 -2
  33. package/src/__tests__/app-executors.test.ts +1 -1
  34. package/src/__tests__/app-git-history.test.ts +2 -2
  35. package/src/__tests__/app-git-service.test.ts +2 -2
  36. package/src/__tests__/app-routes-csp.test.ts +2 -2
  37. package/src/__tests__/app-source-watcher.test.ts +1 -1
  38. package/src/__tests__/app-store-dir-names.test.ts +1 -1
  39. package/src/__tests__/approval-cascade.test.ts +7 -7
  40. package/src/__tests__/approval-interception-trust-gates.test.ts +1 -1
  41. package/src/__tests__/approval-primitive.test.ts +3 -3
  42. package/src/__tests__/approval-routes-http.test.ts +2 -2
  43. package/src/__tests__/assistant-event-hub-machine-name.test.ts +1 -1
  44. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -2
  45. package/src/__tests__/assistant-events-sse-shed.test.ts +2 -2
  46. package/src/__tests__/assistant-stream-state.test.ts +3 -76
  47. package/src/__tests__/attachment-upload-trusted-source.test.ts +4 -2
  48. package/src/__tests__/attachments-store.test.ts +9 -6
  49. package/src/__tests__/audit-log-rotation.test.ts +6 -4
  50. package/src/__tests__/auth-fallback-events-store.test.ts +4 -4
  51. package/src/__tests__/auto-analysis-end-to-end.test.ts +13 -9
  52. package/src/__tests__/background-shell-bash.test.ts +34 -0
  53. package/src/__tests__/background-shell-host-bash.test.ts +12 -0
  54. package/src/__tests__/background-tool-registry.test.ts +97 -0
  55. package/src/__tests__/background-tool-routes.test.ts +72 -1
  56. package/src/__tests__/background-workers-disk-pressure.test.ts +17 -10
  57. package/src/__tests__/btw-routes.test.ts +4 -5
  58. package/src/__tests__/build-persisted-content.test.ts +4 -4
  59. package/src/__tests__/call-controller.test.ts +6 -6
  60. package/src/__tests__/call-conversation-messages.test.ts +4 -4
  61. package/src/__tests__/call-domain.test.ts +5 -5
  62. package/src/__tests__/call-pointer-messages.test.ts +5 -5
  63. package/src/__tests__/call-recovery.test.ts +3 -3
  64. package/src/__tests__/call-routes-http.test.ts +3 -3
  65. package/src/__tests__/call-store.test.ts +3 -3
  66. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -3
  67. package/src/__tests__/canonical-guardian-store.test.ts +3 -3
  68. package/src/__tests__/channel-approval-routes.test.ts +30 -33
  69. package/src/__tests__/channel-delivery-store.test.ts +36 -8
  70. package/src/__tests__/channel-guardian.test.ts +62 -54
  71. package/src/__tests__/channel-inbound-disk-pressure.test.ts +15 -23
  72. package/src/__tests__/channel-reply-delivery.test.ts +8 -4
  73. package/src/__tests__/channel-retry-sweep.test.ts +49 -4
  74. package/src/__tests__/clawhub.test.ts +4 -0
  75. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  76. package/src/__tests__/compaction-events.test.ts +8 -8
  77. package/src/__tests__/compaction-ledger-store.test.ts +128 -0
  78. package/src/__tests__/compaction-trail-store.test.ts +5 -5
  79. package/src/__tests__/compaction.benchmark.test.ts +5 -5
  80. package/src/__tests__/compactor-call-site-logging.test.ts +5 -5
  81. package/src/__tests__/compactor-image-manifest-trust.test.ts +7 -4
  82. package/src/__tests__/compactor-low-watermark-cut.test.ts +5 -5
  83. package/src/__tests__/compactor-preserved-tail-count.test.ts +4 -4
  84. package/src/__tests__/compactor-summary-call-truncation.test.ts +5 -5
  85. package/src/__tests__/compactor-web-search-strip.test.ts +4 -4
  86. package/src/__tests__/config-get-vision-flag.test.ts +1 -1
  87. package/src/__tests__/config-loader-backfill.test.ts +230 -102
  88. package/src/__tests__/config-set-route.test.ts +5 -2
  89. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +3 -3
  90. package/src/__tests__/config-watcher-skill-reseed.test.ts +39 -112
  91. package/src/__tests__/config-watcher.test.ts +54 -31
  92. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -4
  93. package/src/__tests__/consult-deadline.test.ts +60 -0
  94. package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
  95. package/src/__tests__/contact-store-user-file.test.ts +98 -91
  96. package/src/__tests__/contacts-relay-reads.test.ts +27 -12
  97. package/src/__tests__/contacts-tools.test.ts +2 -2
  98. package/src/__tests__/contacts-write.test.ts +2 -4
  99. package/src/__tests__/context-search-agent-protocol.test.ts +2 -2
  100. package/src/__tests__/context-search-agent-runner.test.ts +2 -2
  101. package/src/__tests__/context-search-conversations-source.test.ts +5 -5
  102. package/src/__tests__/context-search-fanout.test.ts +3 -3
  103. package/src/__tests__/context-search-memory-source.test.ts +9 -8
  104. package/src/__tests__/context-search-memory-v2-source.test.ts +9 -8
  105. package/src/__tests__/context-search-types.test.ts +2 -2
  106. package/src/__tests__/context-search-workspace-source.test.ts +2 -2
  107. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -5
  108. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +4 -3
  109. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +40 -11
  110. package/src/__tests__/conversation-agent-loop-overflow.test.ts +11 -8
  111. package/src/__tests__/conversation-agent-loop.test.ts +150 -20
  112. package/src/__tests__/conversation-analysis-routes.test.ts +4 -4
  113. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -1
  114. package/src/__tests__/conversation-app-control-lifecycle.test.ts +7 -7
  115. package/src/__tests__/conversation-attachments.test.ts +7 -4
  116. package/src/__tests__/conversation-attention-store.test.ts +4 -4
  117. package/src/__tests__/conversation-attention-telegram.test.ts +17 -16
  118. package/src/__tests__/conversation-clear-safety.test.ts +3 -4
  119. package/src/__tests__/conversation-confirmation-signals.test.ts +7 -7
  120. package/src/__tests__/conversation-crud-inference-profile.test.ts +3 -3
  121. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +25 -26
  122. package/src/__tests__/conversation-directories-parse.test.ts +1 -1
  123. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -5
  124. package/src/__tests__/conversation-disk-view.test.ts +6 -6
  125. package/src/__tests__/conversation-error.test.ts +18 -18
  126. package/src/__tests__/conversation-evictor.test.ts +32 -7
  127. package/src/__tests__/conversation-fork-crud.test.ts +441 -44
  128. package/src/__tests__/conversation-fork-retrospective.test.ts +12 -10
  129. package/src/__tests__/conversation-fork-route.test.ts +6 -3
  130. package/src/__tests__/conversation-history-web-search.test.ts +8 -145
  131. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -3
  132. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -3
  133. package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
  134. package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
  135. package/src/__tests__/conversation-key-store-disk-view.test.ts +7 -4
  136. package/src/__tests__/conversation-lifecycle.test.ts +10 -13
  137. package/src/__tests__/conversation-list-source.test.ts +3 -3
  138. package/src/__tests__/conversation-load-history-repair.test.ts +4 -4
  139. package/src/__tests__/conversation-load-history-stripped.test.ts +4 -4
  140. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
  141. package/src/__tests__/conversation-pairing.test.ts +4 -4
  142. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +5 -5
  143. package/src/__tests__/conversation-process-callsite.test.ts +42 -5
  144. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -5
  145. package/src/__tests__/conversation-queue.test.ts +142 -9
  146. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -5
  147. package/src/__tests__/conversation-routes-guardian-reply.test.ts +6 -6
  148. package/src/__tests__/conversation-routes-slash-commands.test.ts +57 -10
  149. package/src/__tests__/conversation-runtime-assembly.test.ts +25 -19
  150. package/src/__tests__/conversation-runtime-workspace.test.ts +8 -1
  151. package/src/__tests__/conversation-skill-tools.test.ts +155 -2
  152. package/src/__tests__/conversation-slash-queue.test.ts +6 -6
  153. package/src/__tests__/conversation-slash-unknown.test.ts +6 -6
  154. package/src/__tests__/conversation-speed-override.test.ts +7 -7
  155. package/src/__tests__/conversation-starter-routes.test.ts +2 -2
  156. package/src/__tests__/conversation-store.test.ts +6 -6
  157. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +8 -5
  158. package/src/__tests__/conversation-surfaces-data-persist.test.ts +2 -2
  159. package/src/__tests__/conversation-sync-tags.test.ts +7 -4
  160. package/src/__tests__/conversation-title-service.test.ts +223 -203
  161. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
  162. package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
  163. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  164. package/src/__tests__/conversation-usage.test.ts +6 -6
  165. package/src/__tests__/conversation-wipe.test.ts +6 -4
  166. package/src/__tests__/conversation-workspace-cache-state.test.ts +9 -9
  167. package/src/__tests__/conversation-workspace-injection.test.ts +9 -9
  168. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +9 -9
  169. package/src/__tests__/conversations-import-system-filter.test.ts +5 -5
  170. package/src/__tests__/credential-security-invariants.test.ts +4 -7
  171. package/src/__tests__/db-acp-history.test.ts +4 -4
  172. package/src/__tests__/db-activation-state-fk-cascade.test.ts +4 -4
  173. package/src/__tests__/db-activation-state.test.ts +3 -3
  174. package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
  175. package/src/__tests__/db-connection-isolation.test.ts +1 -1
  176. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +3 -3
  177. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -6
  178. package/src/__tests__/db-drop-contact-acl-columns-migration.test.ts +159 -0
  179. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +3 -3
  180. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +3 -3
  181. package/src/__tests__/db-migration-rollback.test.ts +48 -43
  182. package/src/__tests__/db-proxy-transaction.test.ts +2 -2
  183. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +3 -3
  184. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -4
  185. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +3 -3
  186. package/src/__tests__/db-slack-external-content-normalization.test.ts +4 -4
  187. package/src/__tests__/db-test-helpers.ts +7 -0
  188. package/src/__tests__/delete-propagation.test.ts +9 -7
  189. package/src/__tests__/deterministic-verification-control-plane.test.ts +3 -3
  190. package/src/__tests__/device-id.test.ts +38 -1
  191. package/src/__tests__/dm-backfill.test.ts +9 -7
  192. package/src/__tests__/dm-persistence.test.ts +5 -5
  193. package/src/__tests__/document-conversations.test.ts +3 -3
  194. package/src/__tests__/document-create-dedupe.test.ts +1 -1
  195. package/src/__tests__/document-find-replace.test.ts +1 -1
  196. package/src/__tests__/document-tool-security.test.ts +1 -1
  197. package/src/__tests__/document-update-default-surface.test.ts +1 -1
  198. package/src/__tests__/drop-capability-card-state-migration.test.ts +3 -5
  199. package/src/__tests__/edit-propagation.test.ts +6 -6
  200. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  201. package/src/__tests__/emit-signal-routing-intent.test.ts +2 -6
  202. package/src/__tests__/empty-state-greeting-cache.test.ts +1 -1
  203. package/src/__tests__/events-client-registration.test.ts +1 -1
  204. package/src/__tests__/exploration-drift-hook.test.ts +7 -23
  205. package/src/__tests__/file-write-tool.test.ts +3 -3
  206. package/src/__tests__/filing-service.test.ts +6 -5
  207. package/src/__tests__/followup-tools.test.ts +2 -2
  208. package/src/__tests__/get-skill-detail-audit.test.ts +1 -1
  209. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  210. package/src/__tests__/guardian-action-sweep.test.ts +3 -3
  211. package/src/__tests__/guardian-binding-drift-heal.test.ts +48 -25
  212. package/src/__tests__/guardian-card-withdrawal.test.ts +3 -3
  213. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +4 -4
  214. package/src/__tests__/guardian-dispatch.test.ts +28 -11
  215. package/src/__tests__/guardian-expiry-notifier.test.ts +4 -4
  216. package/src/__tests__/guardian-outbound-http.test.ts +3 -4
  217. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +3 -3
  218. package/src/__tests__/guardian-routing-invariants.test.ts +3 -3
  219. package/src/__tests__/guardian-routing-state.test.ts +12 -14
  220. package/src/__tests__/guardian-verification-voice-binding.test.ts +4 -4
  221. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
  222. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -3
  223. package/src/__tests__/heartbeat-disk-pressure.test.ts +7 -13
  224. package/src/__tests__/heartbeat-service.test.ts +31 -19
  225. package/src/__tests__/helpers/channel-test-adapter.ts +25 -18
  226. package/src/__tests__/helpers/create-guardian-binding.ts +16 -24
  227. package/src/__tests__/helpers/derive-guardian-delivery.ts +66 -0
  228. package/src/__tests__/helpers/gateway-acl-store.ts +81 -0
  229. package/src/__tests__/helpers/mock-logger.ts +1 -0
  230. package/src/__tests__/helpers/seed-contact-channel.ts +117 -0
  231. package/src/__tests__/history-repair-hook.test.ts +1 -1
  232. package/src/__tests__/home-state-routes.test.ts +1 -1
  233. package/src/__tests__/http-conversation-lineage.test.ts +4 -4
  234. package/src/__tests__/http-user-message-parity.test.ts +8 -12
  235. package/src/__tests__/identity-routes.test.ts +113 -25
  236. package/src/__tests__/image-recovery-hook.test.ts +3 -3
  237. package/src/__tests__/inbound-invite-redemption.test.ts +87 -12
  238. package/src/__tests__/inbound-slack-persistence.test.ts +5 -5
  239. package/src/__tests__/inbound-trust-verdict.test.ts +5 -4
  240. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +13 -6
  241. package/src/__tests__/inference-profile-reaper.test.ts +3 -3
  242. package/src/__tests__/inference-profile-session-handler.test.ts +3 -3
  243. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -3
  244. package/src/__tests__/init-feature-flag-overrides.test.ts +1 -4
  245. package/src/__tests__/injection-block.test.ts +5 -2
  246. package/src/__tests__/injector-background-turn.test.ts +3 -5
  247. package/src/__tests__/injector-chain.test.ts +25 -16
  248. package/src/__tests__/injector-config-quarantine-notice.test.ts +3 -5
  249. package/src/__tests__/injector-disk-pressure.test.ts +10 -8
  250. package/src/__tests__/injector-document-comments.test.ts +5 -3
  251. package/src/__tests__/injector-pkb-v2-silenced.test.ts +5 -2
  252. package/src/__tests__/injector-registry-order-guard.test.ts +132 -0
  253. package/src/__tests__/injector-v3-suppression.test.ts +15 -9
  254. package/src/__tests__/install-meta.test.ts +104 -0
  255. package/src/__tests__/install-skill-routing.test.ts +1 -1
  256. package/src/__tests__/internal-telemetry-routes.test.ts +4 -4
  257. package/src/__tests__/invite-redemption-service.test.ts +274 -57
  258. package/src/__tests__/invite-routes-http.test.ts +37 -3
  259. package/src/__tests__/invite-service-ipc.test.ts +68 -5
  260. package/src/__tests__/job-handler-registry-guard.test.ts +129 -0
  261. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +8 -8
  262. package/src/__tests__/jobs-store-upsert-debounced.test.ts +7 -4
  263. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -8
  264. package/src/__tests__/list-messages-attachments.test.ts +7 -4
  265. package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
  266. package/src/__tests__/list-messages-client-message-id.test.ts +6 -3
  267. package/src/__tests__/list-messages-hidden-metadata.test.ts +5 -5
  268. package/src/__tests__/list-messages-page-latest.test.ts +176 -7
  269. package/src/__tests__/list-messages-queued.test.ts +223 -0
  270. package/src/__tests__/list-messages-tool-merge.test.ts +6 -3
  271. package/src/__tests__/llm-context-route-provider.test.ts +3 -3
  272. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +4 -4
  273. package/src/__tests__/llm-request-log-call-site.test.ts +5 -5
  274. package/src/__tests__/llm-request-log-error-payload.test.ts +1 -1
  275. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -1
  276. package/src/__tests__/llm-request-log-source-factory.test.ts +3 -3
  277. package/src/__tests__/llm-request-log-turn-query.test.ts +9 -6
  278. package/src/__tests__/llm-usage-store.test.ts +137 -3
  279. package/src/__tests__/log-export-routes.test.ts +3 -3
  280. package/src/__tests__/log-export-workspace.test.ts +3 -3
  281. package/src/__tests__/managed-profile-guard.test.ts +1 -1
  282. package/src/__tests__/managed-skill-lifecycle.test.ts +3 -3
  283. package/src/__tests__/managed-store.test.ts +381 -0
  284. package/src/__tests__/mcp-config-secret-boundary.test.ts +5 -1
  285. package/src/__tests__/media-stream-server-integration.test.ts +1 -1
  286. package/src/__tests__/memory-jobs-worker-backoff.test.ts +4 -4
  287. package/src/__tests__/memory-jobs-worker-lanes.test.ts +11 -9
  288. package/src/__tests__/memory-recall-log-store.test.ts +4 -4
  289. package/src/__tests__/memory-retrieval-budget.test.ts +1 -1
  290. package/src/__tests__/memory-retrieval-hook.test.ts +8 -8
  291. package/src/__tests__/memory-upsert-concurrency.test.ts +9 -5
  292. package/src/__tests__/memory-v2-static-injector.test.ts +3 -3
  293. package/src/__tests__/messages-after-tiebreaker.test.ts +4 -4
  294. package/src/__tests__/messaging-send-tool.test.ts +5 -5
  295. package/src/__tests__/mock-gateway-ipc.ts +1 -1
  296. package/src/__tests__/mtime-cache.test.ts +19 -0
  297. package/src/__tests__/native-web-search.test.ts +11 -11
  298. package/src/__tests__/non-member-access-request.test.ts +24 -20
  299. package/src/__tests__/notification-candidate-guardian-context.test.ts +4 -4
  300. package/src/__tests__/notification-deep-link.test.ts +3 -3
  301. package/src/__tests__/notification-guardian-path.test.ts +3 -3
  302. package/src/__tests__/notification-schedule-notify-dedup.test.ts +3 -3
  303. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  304. package/src/__tests__/oauth-provider-visibility.test.ts +2 -2
  305. package/src/__tests__/oauth-store.test.ts +6 -6
  306. package/src/__tests__/onboarding-persona-write.test.ts +52 -22
  307. package/src/__tests__/onboarding-template-contract.test.ts +27 -43
  308. package/src/__tests__/openai-provider.test.ts +33 -0
  309. package/src/__tests__/openai-responses-provider.test.ts +40 -0
  310. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  311. package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
  312. package/src/__tests__/persist-unsendable-image-downscale.test.ts +3 -3
  313. package/src/__tests__/persist-unsendable-image.test.ts +3 -3
  314. package/src/__tests__/persist-user-message-set-processing-failure.test.ts +70 -0
  315. package/src/__tests__/persistence-layering-guard.test.ts +222 -0
  316. package/src/__tests__/persistence-secret-redaction.test.ts +6 -6
  317. package/src/__tests__/persona-resolver.test.ts +75 -45
  318. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  319. package/src/__tests__/platform-bash-auto-approve.test.ts +3 -3
  320. package/src/__tests__/playbook-execution.test.ts +4 -4
  321. package/src/__tests__/playbook-tools.test.ts +3 -3
  322. package/src/__tests__/plugin-bootstrap.test.ts +78 -19
  323. package/src/__tests__/plugin-config-data-migration.test.ts +263 -0
  324. package/src/__tests__/plugin-disabled-state.test.ts +323 -0
  325. package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
  326. package/src/__tests__/plugin-import-boundary-guard.test.ts +506 -0
  327. package/src/__tests__/plugin-injector-contribution.test.ts +133 -0
  328. package/src/__tests__/plugin-route-contribution.test.ts +62 -115
  329. package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
  330. package/src/__tests__/pointer-conversation-trust.test.ts +141 -0
  331. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +8 -1
  332. package/src/__tests__/process-message-background-slack.test.ts +6 -6
  333. package/src/__tests__/process-message-display-content.test.ts +5 -5
  334. package/src/__tests__/processing-flag-persist-failure.test.ts +280 -0
  335. package/src/__tests__/provider-usage-tracking.test.ts +4 -4
  336. package/src/__tests__/prune-jobs-changes-parser.test.ts +1 -1
  337. package/src/__tests__/prune-old-conversations-job.test.ts +5 -5
  338. package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
  339. package/src/__tests__/published-app-updater.test.ts +3 -3
  340. package/src/__tests__/qdrant-collection-migration.test.ts +5 -2
  341. package/src/__tests__/qdrant-manager.test.ts +1 -1
  342. package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +141 -0
  343. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
  344. package/src/__tests__/reaction-persistence.test.ts +60 -10
  345. package/src/__tests__/rebuild-index-graph-nodes.test.ts +5 -5
  346. package/src/__tests__/recording-handler.test.ts +2 -2
  347. package/src/__tests__/relay-server.test.ts +183 -142
  348. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  349. package/src/__tests__/resolve-app-id.test.ts +3 -3
  350. package/src/__tests__/runtime-attachment-metadata.test.ts +16 -18
  351. package/src/__tests__/runtime-events-sse-bilingual.test.ts +3 -3
  352. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -3
  353. package/src/__tests__/runtime-events-sse-reconnect.test.ts +3 -3
  354. package/src/__tests__/runtime-events-sse.test.ts +3 -3
  355. package/src/__tests__/scaffold-managed-skill-tool.test.ts +489 -2
  356. package/src/__tests__/schedule-retry.test.ts +91 -67
  357. package/src/__tests__/schedule-routes-workflow-validation.test.ts +47 -43
  358. package/src/__tests__/schedule-routes.test.ts +199 -187
  359. package/src/__tests__/schedule-store.test.ts +174 -172
  360. package/src/__tests__/schedule-tools.test.ts +2 -2
  361. package/src/__tests__/scheduler-disk-pressure.test.ts +20 -9
  362. package/src/__tests__/scheduler-recurrence.test.ts +72 -122
  363. package/src/__tests__/scheduler-reuse-conversation.test.ts +65 -60
  364. package/src/__tests__/scheduler-wake.test.ts +21 -31
  365. package/src/__tests__/scoped-approval-grants.test.ts +4 -4
  366. package/src/__tests__/scoped-grant-security-matrix.test.ts +4 -4
  367. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +2 -2
  368. package/src/__tests__/search-skills-unified.test.ts +1 -1
  369. package/src/__tests__/secret-ingress-channel.test.ts +3 -3
  370. package/src/__tests__/secret-ingress-http.test.ts +6 -6
  371. package/src/__tests__/secret-routes-platform-proxy.test.ts +9 -8
  372. package/src/__tests__/send-endpoint-busy.test.ts +6 -6
  373. package/src/__tests__/sequence-store.test.ts +3 -3
  374. package/src/__tests__/server-history-render.test.ts +7 -4
  375. package/src/__tests__/settings-routes.test.ts +34 -2
  376. package/src/__tests__/shell-observability.test.ts +1 -0
  377. package/src/__tests__/skill-boundary-guard.test.ts +3 -4
  378. package/src/__tests__/skill-docs-sync-guard.test.ts +34 -0
  379. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -1
  380. package/src/__tests__/skill-projection.benchmark.test.ts +2 -1
  381. package/src/__tests__/skill-script-runner-host.test.ts +53 -0
  382. package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
  383. package/src/__tests__/skill-tool-factory.test.ts +20 -0
  384. package/src/__tests__/skill-version-hash.test.ts +32 -0
  385. package/src/__tests__/skills-file-content-endpoint.test.ts +1 -1
  386. package/src/__tests__/skills-files-catalog-fallback.test.ts +1 -1
  387. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  388. package/src/__tests__/slack-messaging-token-resolution.test.ts +2 -2
  389. package/src/__tests__/slack-reaction-canonical-approval.test.ts +4 -4
  390. package/src/__tests__/slack-share-routes.test.ts +1 -1
  391. package/src/__tests__/slim-skill-category.test.ts +34 -2
  392. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +13 -36
  393. package/src/__tests__/starter-task-flow.test.ts +1 -1
  394. package/src/__tests__/strip-memory-injections.test.ts +2 -2
  395. package/src/__tests__/stt-hints.test.ts +6 -3
  396. package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
  397. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  398. package/src/__tests__/subagent-detail.test.ts +1 -1
  399. package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
  400. package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
  401. package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
  402. package/src/__tests__/subagent-notify-parent.test.ts +3 -3
  403. package/src/__tests__/subagent-persistence.test.ts +122 -0
  404. package/src/__tests__/subagent-role-registry.test.ts +17 -4
  405. package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
  406. package/src/__tests__/subagent-spawn-tool-fork.test.ts +3 -3
  407. package/src/__tests__/subagent-terminal-message.test.ts +99 -0
  408. package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
  409. package/src/__tests__/subagent-tools.test.ts +396 -4
  410. package/src/__tests__/suggestion-routes.test.ts +4 -4
  411. package/src/__tests__/system-prompt.test.ts +4 -4
  412. package/src/__tests__/task-compiler.test.ts +2 -2
  413. package/src/__tests__/task-management-tools.test.ts +2 -2
  414. package/src/__tests__/task-memory-cleanup.test.ts +9 -7
  415. package/src/__tests__/task-progress-nudge-hook.test.ts +37 -94
  416. package/src/__tests__/task-scheduler.test.ts +94 -115
  417. package/src/__tests__/test-support/tool-invocation-seed.ts +5 -2
  418. package/src/__tests__/thread-backfill.test.ts +7 -7
  419. package/src/__tests__/title-generate-hook.test.ts +6 -6
  420. package/src/__tests__/tool-approval-handler.test.ts +4 -4
  421. package/src/__tests__/tool-audit-listener.test.ts +1 -1
  422. package/src/__tests__/tool-error-hook.test.ts +2 -0
  423. package/src/__tests__/tool-executor-lifecycle-events.test.ts +5 -5
  424. package/src/__tests__/tool-executor-redaction.test.ts +11 -0
  425. package/src/__tests__/tool-executor.test.ts +24 -2
  426. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -5
  427. package/src/__tests__/tool-preview-lifecycle.test.ts +102 -17
  428. package/src/__tests__/tool-result-metadata-plumbing.test.ts +4 -4
  429. package/src/__tests__/tool-result-truncate-hook.test.ts +2 -0
  430. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -1
  431. package/src/__tests__/tool-start-timestamp.test.ts +69 -5
  432. package/src/__tests__/tools-get-route.test.ts +44 -1
  433. package/src/__tests__/trace-emitter.test.ts +1 -1
  434. package/src/__tests__/trust-context-guards.test.ts +1 -1
  435. package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
  436. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -7
  437. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +20 -12
  438. package/src/__tests__/trusted-contact-multichannel.test.ts +17 -8
  439. package/src/__tests__/trusted-contact-verification.test.ts +60 -57
  440. package/src/__tests__/turn-boundary-resolution.test.ts +7 -4
  441. package/src/__tests__/turn-call-site.test.ts +29 -0
  442. package/src/__tests__/turn-events-store.test.ts +8 -5
  443. package/src/__tests__/twilio-routes.test.ts +3 -3
  444. package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
  445. package/src/__tests__/usage-cache-backfill-migration.test.ts +4 -8
  446. package/src/__tests__/usage-grouped-buckets.test.ts +1 -1
  447. package/src/__tests__/usage-routes.test.ts +61 -3
  448. package/src/__tests__/verification-control-plane-policy.test.ts +6 -6
  449. package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
  450. package/src/__tests__/voice-invite-redemption.test.ts +183 -24
  451. package/src/__tests__/voice-quality.test.ts +38 -12
  452. package/src/__tests__/voice-scoped-grant-consumer.test.ts +22 -14
  453. package/src/__tests__/voice-session-bridge.test.ts +16 -10
  454. package/src/__tests__/web-search-backend-failure.test.ts +4 -4
  455. package/src/__tests__/workspace-lifecycle.test.ts +29 -18
  456. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
  457. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +5 -5
  458. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +3 -3
  459. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
  460. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +2 -2
  461. package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
  462. package/src/__tests__/workspace-migration-113-swap-balanced-profile-to-glm-5p2.test.ts +241 -0
  463. package/src/__tests__/workspace-migration-114-swap-quality-profile-to-opus.test.ts +172 -0
  464. package/src/__tests__/workspace-migration-116-rename-memory-plugin-disabled-sentinel.test.ts +128 -0
  465. package/src/__tests__/workspace-migration-117-normalize-stale-lean-memory-v3-defaults.test.ts +221 -0
  466. package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
  467. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -1
  468. package/src/__tests__/workspace-migration-drop-user-md.test.ts +273 -238
  469. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +41 -49
  470. package/src/a2a/__tests__/task-store.test.ts +2 -2
  471. package/src/a2a/task-store.ts +4 -4
  472. package/src/acp/__tests__/client-handler.test.ts +680 -0
  473. package/src/acp/__tests__/helpers/acp-history-db.ts +32 -4
  474. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
  475. package/src/acp/__tests__/session-manager-persistence.test.ts +215 -7
  476. package/src/acp/__tests__/session-manager-resume.test.ts +113 -2
  477. package/src/acp/__tests__/session-manager-startup.test.ts +3 -3
  478. package/src/acp/__tests__/session-manager-usage.test.ts +113 -0
  479. package/src/acp/auto-install.ts +12 -8
  480. package/src/acp/client-handler.ts +140 -21
  481. package/src/acp/prepare-agent-env.ts +0 -12
  482. package/src/acp/resolve-agent.test.ts +6 -45
  483. package/src/acp/resolve-agent.ts +2 -4
  484. package/src/acp/session-manager.ts +127 -4
  485. package/src/acp/types.ts +18 -0
  486. package/src/agent/loop-exclusive-tool.test.ts +19 -15
  487. package/src/agent/loop-native-web-search.test.ts +200 -0
  488. package/src/agent/loop.ts +321 -149
  489. package/src/api/events/acp-session-completed.ts +33 -0
  490. package/src/api/events/acp-session-error.ts +21 -0
  491. package/src/api/events/acp-session-spawned.ts +32 -0
  492. package/src/api/events/acp-session-update.test.ts +122 -0
  493. package/src/api/events/acp-session-update.ts +51 -0
  494. package/src/api/events/acp-session-usage.test.ts +49 -0
  495. package/src/api/events/acp-session-usage.ts +31 -0
  496. package/src/api/events/background-tool-completed.test.ts +51 -0
  497. package/src/api/events/background-tool-completed.ts +29 -0
  498. package/src/api/events/background-tool-started.test.ts +36 -0
  499. package/src/api/events/background-tool-started.ts +28 -0
  500. package/src/api/events/conversation-error.ts +0 -1
  501. package/src/api/events/subagent-status-changed.ts +4 -1
  502. package/src/api/events/tool-use-preview-start.ts +11 -0
  503. package/src/api/events/tool-use-start.ts +14 -0
  504. package/src/api/index.ts +51 -0
  505. package/src/api/responses/conversation-message.ts +80 -1
  506. package/src/api/responses/llm-request-log-entry.ts +41 -0
  507. package/src/api/responses/memory-v3-selection-log.ts +5 -7
  508. package/src/approvals/approval-primitive.ts +1 -1
  509. package/src/approvals/guardian-card-withdrawal.ts +2 -2
  510. package/src/approvals/guardian-decision-primitive.ts +1 -1
  511. package/src/approvals/guardian-expiry-notifier.ts +1 -1
  512. package/src/approvals/guardian-request-resolvers.ts +19 -7
  513. package/src/approvals/scoped-approval-grants.ts +551 -0
  514. package/src/apps/app-store.ts +1058 -0
  515. package/src/apps/published-pages-store.ts +67 -0
  516. package/src/apps/shared-app-links-store.ts +130 -0
  517. package/src/background-wake/background-wake-routes.test.ts +53 -23
  518. package/src/background-wake/wake-intent-hooks.test.ts +18 -12
  519. package/src/backup/restore.ts +1 -1
  520. package/src/bundler/app-bundler.ts +1 -1
  521. package/src/calls/__tests__/relay-setup-router.test.ts +11 -19
  522. package/src/calls/call-controller.ts +5 -5
  523. package/src/calls/call-conversation-messages.ts +1 -1
  524. package/src/calls/call-domain.ts +5 -5
  525. package/src/calls/call-pointer-messages.ts +1 -1
  526. package/src/calls/call-store.ts +3 -3
  527. package/src/calls/guardian-action-sweep.ts +1 -1
  528. package/src/calls/guardian-dispatch.ts +15 -12
  529. package/src/calls/inbound-trust-reader.ts +7 -1
  530. package/src/calls/media-stream-server.ts +1 -1
  531. package/src/calls/relay-access-wait.ts +7 -7
  532. package/src/calls/relay-server.ts +25 -5
  533. package/src/calls/relay-setup-router.ts +11 -11
  534. package/src/calls/tts-call-strategy.ts +4 -3
  535. package/src/calls/voice-quality.ts +47 -59
  536. package/src/calls/voice-session-bridge.ts +2 -16
  537. package/src/channels/__tests__/types.test.ts +28 -0
  538. package/src/channels/channel-verification-sessions.ts +557 -0
  539. package/src/channels/types.ts +23 -0
  540. package/src/cli/commands/__tests__/conversations-new.test.ts +186 -0
  541. package/src/cli/commands/__tests__/conversations-slack.test.ts +2 -1
  542. package/src/cli/commands/__tests__/conversations-wake.test.ts +147 -0
  543. package/src/cli/commands/__tests__/ps.test.ts +205 -0
  544. package/src/cli/commands/__tests__/schedules.test.ts +52 -0
  545. package/src/cli/commands/contacts.ts +10 -7
  546. package/src/cli/commands/conversations.ts +90 -30
  547. package/src/cli/commands/db/__tests__/repair.test.ts +4 -3
  548. package/src/cli/commands/db/repair-step-conversation-backfill.ts +2 -2
  549. package/src/cli/commands/memory/__tests__/memory-v2-compare-render.test.ts +1 -1
  550. package/src/cli/commands/memory/__tests__/worker.test.ts +112 -183
  551. package/src/cli/commands/memory/memory-retrospective.ts +32 -28
  552. package/src/cli/commands/memory/memory-v2-compare-render.ts +1 -1
  553. package/src/cli/commands/memory/memory-v2.ts +2 -2
  554. package/src/cli/commands/memory/memory-v3.ts +2 -2
  555. package/src/cli/commands/memory/worker.ts +103 -113
  556. package/src/cli/commands/plugins.ts +150 -157
  557. package/src/cli/commands/ps.ts +90 -0
  558. package/src/cli/commands/schedules.ts +52 -8
  559. package/src/cli/commands/tools-run.ts +114 -0
  560. package/src/cli/commands/tools.ts +19 -5
  561. package/src/cli/lib/__tests__/cli-colors.test.ts +30 -1
  562. package/src/cli/lib/__tests__/install-from-github.test.ts +168 -8
  563. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +23 -18
  564. package/src/cli/lib/__tests__/parse-github-plugin-spec.test.ts +121 -0
  565. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
  566. package/src/cli/lib/__tests__/publish-plugin.test.ts +98 -0
  567. package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
  568. package/src/cli/lib/__tests__/toggle-plugin.test.ts +10 -4
  569. package/src/cli/lib/cli-colors.ts +6 -0
  570. package/src/cli/lib/diff-plugin.ts +3 -7
  571. package/src/cli/lib/inspect-plugin.ts +2 -4
  572. package/src/cli/lib/install-from-github.ts +96 -24
  573. package/src/cli/lib/merge-plugin-tree.ts +5 -3
  574. package/src/cli/lib/parse-github-plugin-spec.ts +163 -0
  575. package/src/cli/lib/plugin-fingerprint.ts +22 -0
  576. package/src/cli/lib/publish-plugin.ts +231 -1
  577. package/src/cli/lib/search-plugins.ts +6 -0
  578. package/src/cli/lib/upgrade-plugin.ts +6 -5
  579. package/src/cli/program.ts +5 -8
  580. package/src/cli.ts +6 -3
  581. package/src/config/__tests__/deployment-context-defaults.test.ts +228 -0
  582. package/src/config/__tests__/proc-to-skills.test.ts +21 -0
  583. package/src/config/__tests__/sync-gated-profiles.test.ts +7 -9
  584. package/src/config/acp-defaults.test.ts +0 -10
  585. package/src/config/acp-defaults.ts +0 -6
  586. package/src/config/bundled-skills/AGENTS.md +11 -0
  587. package/src/config/bundled-skills/acp/SKILL.md +13 -45
  588. package/src/config/bundled-skills/acp/TOOLS.json +3 -3
  589. package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
  590. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
  591. package/src/config/bundled-skills/app-builder/tools/app-create.ts +2 -2
  592. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +2 -2
  593. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +2 -2
  594. package/src/config/bundled-skills/app-builder/tools/app-list.ts +1 -1
  595. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +2 -2
  596. package/src/config/bundled-skills/app-builder/tools/app-update.ts +2 -2
  597. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  598. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +1 -1
  599. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +1 -1
  600. package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
  601. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +1 -1
  602. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  603. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +1 -1
  604. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +1 -1
  605. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  606. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +2 -2
  607. package/src/config/bundled-skills/media-processing/tools/media-status.ts +1 -1
  608. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +5 -5
  609. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +6 -6
  610. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +8 -5
  611. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +4 -1
  612. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  613. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -4
  614. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +7 -7
  615. package/src/config/bundled-skills/skill-management/TOOLS.json +45 -0
  616. package/src/config/bundled-skills/skill-management/tools/find-similar.ts +12 -0
  617. package/src/config/bundled-skills/subagent/SKILL.md +16 -1
  618. package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
  619. package/src/config/bundled-tool-registry.ts +2 -0
  620. package/src/config/call-site-defaults.ts +0 -8
  621. package/src/config/feature-flag-registry.json +16 -24
  622. package/src/config/llm-resolver.ts +17 -3
  623. package/src/config/loader.ts +38 -58
  624. package/src/config/memory-v3-gate.ts +16 -0
  625. package/src/config/schema.ts +2 -0
  626. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
  627. package/src/config/schemas/__tests__/memory-v3.test.ts +16 -5
  628. package/src/config/schemas/call-site-catalog.ts +0 -19
  629. package/src/config/schemas/conversations.ts +8 -0
  630. package/src/config/schemas/heartbeat.ts +2 -5
  631. package/src/config/schemas/llm.ts +3 -14
  632. package/src/config/schemas/memory-lifecycle.ts +10 -1
  633. package/src/config/schemas/memory-v2.ts +1 -1
  634. package/src/config/schemas/memory-v3.ts +56 -6
  635. package/src/config/schemas/migrations.ts +25 -0
  636. package/src/config/schemas/services.ts +0 -37
  637. package/src/config/seed-inference-profiles.ts +88 -84
  638. package/src/config/sync-gated-profiles.ts +6 -20
  639. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +7 -8
  640. package/src/contacts/__tests__/guardian-contact-reader.test.ts +89 -0
  641. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +3 -14
  642. package/src/contacts/__tests__/member-write-relay.test.ts +35 -11
  643. package/src/contacts/canonical-guardian-store.ts +891 -0
  644. package/src/contacts/contact-store.ts +37 -245
  645. package/src/contacts/contacts-write.ts +18 -58
  646. package/src/contacts/gateway-channel-read.ts +51 -0
  647. package/src/contacts/guardian-contact-reader.ts +52 -0
  648. package/src/contacts/guardian-delivery-reader.ts +21 -23
  649. package/src/contacts/guardian-rate-limits.ts +191 -0
  650. package/src/contacts/member-write-relay.ts +25 -31
  651. package/src/contacts/notify-contacts-changed.ts +17 -0
  652. package/src/contacts/types.ts +3 -15
  653. package/src/context/compactor.ts +3 -3
  654. package/src/context/strip-injections.ts +1 -1
  655. package/src/conversations/__tests__/message-consolidation.test.ts +10 -26
  656. package/src/conversations/job-handlers/summarization.ts +246 -0
  657. package/src/conversations/message-consolidation.ts +1 -1
  658. package/src/credential-execution/ces-runtime.ts +285 -0
  659. package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
  660. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +25 -22
  661. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +5 -4
  662. package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
  663. package/src/daemon/__tests__/daemon-readiness.test.ts +51 -0
  664. package/src/daemon/__tests__/embedding-reconcile.test.ts +456 -0
  665. package/src/daemon/__tests__/inference-profile-notification.test.ts +9 -6
  666. package/src/daemon/__tests__/lifecycle-embedding-reconcile.test.ts +119 -0
  667. package/src/daemon/__tests__/native-web-search-metadata.test.ts +2 -2
  668. package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
  669. package/src/daemon/__tests__/web-search-status-text.test.ts +3 -5
  670. package/src/daemon/app-source-watcher.ts +71 -10
  671. package/src/daemon/channel-ui-capability.ts +25 -0
  672. package/src/daemon/config-watcher.ts +71 -47
  673. package/src/daemon/conversation-agent-loop-handlers.ts +266 -49
  674. package/src/daemon/conversation-agent-loop.ts +166 -89
  675. package/src/daemon/conversation-attachments.ts +2 -2
  676. package/src/daemon/conversation-error.ts +8 -25
  677. package/src/daemon/conversation-evictor.ts +42 -9
  678. package/src/daemon/conversation-history.ts +8 -234
  679. package/src/daemon/conversation-initial-prompt.ts +77 -0
  680. package/src/daemon/conversation-launch.ts +2 -2
  681. package/src/daemon/conversation-lifecycle.ts +32 -5
  682. package/src/daemon/conversation-messaging.ts +25 -11
  683. package/src/daemon/conversation-notifiers.ts +1 -1
  684. package/src/daemon/conversation-process.ts +27 -15
  685. package/src/daemon/conversation-queue-manager.ts +6 -0
  686. package/src/daemon/conversation-registry.ts +6 -5
  687. package/src/daemon/conversation-runtime-assembly.ts +45 -31
  688. package/src/daemon/conversation-skill-tools.ts +26 -2
  689. package/src/daemon/conversation-slash.ts +1 -1
  690. package/src/daemon/conversation-store.ts +47 -42
  691. package/src/daemon/conversation-surfaces.ts +4 -4
  692. package/src/daemon/conversation-tool-setup.ts +2 -11
  693. package/src/daemon/conversation-usage.ts +4 -2
  694. package/src/daemon/conversation-workspace.ts +2 -2
  695. package/src/daemon/conversation.ts +104 -17
  696. package/src/daemon/daemon-readiness.ts +33 -0
  697. package/src/daemon/embedding-reconcile.ts +340 -0
  698. package/src/daemon/event-loop-watchdog.ts +1 -1
  699. package/src/daemon/external-plugins-bootstrap.ts +123 -92
  700. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +2 -3
  701. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +3 -5
  702. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +3 -3
  703. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +7 -13
  704. package/src/daemon/handlers/__tests__/config-a2a.test.ts +2 -2
  705. package/src/daemon/handlers/__tests__/config-channels.test.ts +22 -21
  706. package/src/daemon/handlers/config-a2a.ts +3 -3
  707. package/src/daemon/handlers/config-channels.ts +21 -33
  708. package/src/daemon/handlers/config-embeddings.ts +1 -1
  709. package/src/daemon/handlers/conversation-history.ts +2 -2
  710. package/src/daemon/handlers/conversations.ts +7 -56
  711. package/src/daemon/handlers/recording.ts +6 -3
  712. package/src/daemon/handlers/shared.ts +2 -0
  713. package/src/daemon/handlers/skills.ts +9 -1
  714. package/src/daemon/lifecycle.ts +714 -1242
  715. package/src/daemon/message-protocol.ts +3 -3
  716. package/src/daemon/message-provenance.ts +1 -1
  717. package/src/daemon/message-types/acp.ts +27 -1
  718. package/src/daemon/message-types/background-tools.ts +28 -0
  719. package/src/daemon/message-types/bookmarks.ts +1 -1
  720. package/src/daemon/message-types/conversations.ts +10 -0
  721. package/src/daemon/message-types/skills.ts +20 -2
  722. package/src/daemon/message-types/surfaces.ts +2 -0
  723. package/src/daemon/pointer-conversation-trust.ts +66 -0
  724. package/src/daemon/process-message.ts +24 -3
  725. package/src/daemon/providers-setup.ts +16 -14
  726. package/src/daemon/shutdown-handlers.ts +195 -166
  727. package/src/daemon/skill-memory-refresh.ts +3 -3
  728. package/src/daemon/status.ts +15 -0
  729. package/src/daemon/tool-setup-types.ts +17 -0
  730. package/src/daemon/tool-side-effects.ts +4 -4
  731. package/src/daemon/trace-emitter.ts +1 -1
  732. package/src/daemon/trust-context.ts +1 -1
  733. package/src/daemon/turn-call-site.ts +25 -0
  734. package/src/daemon/turn-latency-tracker.test.ts +137 -0
  735. package/src/daemon/turn-latency-tracker.ts +134 -0
  736. package/src/daemon/wake-conversation-ops.ts +14 -4
  737. package/src/documents/document-comments-store.test.ts +2 -2
  738. package/src/documents/document-comments-store.ts +1 -1
  739. package/src/documents/document-store.ts +1 -1
  740. package/src/events/tool-audit-listener.ts +4 -4
  741. package/src/events/tool-permission-telemetry-listener.ts +1 -1
  742. package/src/export/__tests__/transcript-formatter.test.ts +1 -1
  743. package/src/export/transcript-formatter.ts +1 -1
  744. package/src/followups/followup-store.ts +2 -2
  745. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +2 -2
  746. package/src/heartbeat/__tests__/heartbeat-service.test.ts +45 -39
  747. package/src/heartbeat/heartbeat-run-store.ts +3 -3
  748. package/src/heartbeat/heartbeat-service.ts +34 -11
  749. package/src/home/__tests__/relationship-state-writer.test.ts +1 -1
  750. package/src/home/__tests__/suggested-prompts.test.ts +1 -1
  751. package/src/home/conversation-starter-checkpoints.ts +64 -0
  752. package/src/home/feed-source-enrichment.ts +3 -3
  753. package/src/home/home-greeting-cache.ts +1 -1
  754. package/src/home/job-handlers/conversation-starters.ts +484 -0
  755. package/src/home/relationship-state-writer.ts +6 -1
  756. package/src/home/suggested-prompts.ts +1 -1
  757. package/src/hooks/hook-loader.ts +141 -6
  758. package/src/hooks/registry.ts +129 -0
  759. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  760. package/src/ipc/__tests__/cli-ipc.test.ts +1 -1
  761. package/src/ipc/__tests__/inject-local-actor-header.test.ts +33 -0
  762. package/src/ipc/__tests__/watcher-ipc.test.ts +1 -1
  763. package/src/ipc/assistant-server.ts +79 -33
  764. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +3 -3
  765. package/src/ipc/routes/db-proxy-transaction.ts +1 -1
  766. package/src/ipc/routes/db-proxy.ts +4 -2
  767. package/src/jobs/register-job-handlers.ts +78 -0
  768. package/src/jobs/worker.ts +91 -0
  769. package/src/live-voice/__tests__/live-voice-archive.test.ts +5 -5
  770. package/src/live-voice/live-voice-archive.ts +2 -2
  771. package/src/mcp/manager.ts +11 -0
  772. package/src/media/app-icon-generator.ts +1 -1
  773. package/src/media/job-handlers/media-processing.ts +126 -0
  774. package/src/messaging/channel-binding-metadata.ts +31 -0
  775. package/src/messaging/channel-binding-schema.ts +51 -0
  776. package/src/messaging/content/parse.test.ts +34 -0
  777. package/src/messaging/content/parse.ts +23 -0
  778. package/src/messaging/providers/__tests__/callback-routing.test.ts +45 -0
  779. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +196 -0
  780. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +11 -0
  781. package/src/messaging/providers/a2a/deliver.ts +5 -1
  782. package/src/messaging/providers/a2a/transport.ts +10 -0
  783. package/src/messaging/providers/callback-routing.ts +48 -0
  784. package/src/messaging/providers/channel-transport.ts +55 -0
  785. package/src/messaging/providers/index.ts +65 -241
  786. package/src/messaging/providers/slack/binding-metadata.ts +62 -0
  787. package/src/messaging/providers/slack/render.test.ts +309 -0
  788. package/src/messaging/providers/slack/render.ts +459 -0
  789. package/src/messaging/providers/slack/send.test.ts +39 -0
  790. package/src/messaging/providers/slack/send.ts +38 -18
  791. package/src/messaging/providers/slack/transport.ts +92 -0
  792. package/src/messaging/providers/telegram-bot/adapter.ts +2 -2
  793. package/src/messaging/providers/telegram-bot/api.ts +17 -3
  794. package/src/messaging/providers/telegram-bot/render.test.ts +146 -0
  795. package/src/messaging/providers/telegram-bot/render.ts +292 -0
  796. package/src/messaging/providers/telegram-bot/send.test.ts +197 -0
  797. package/src/messaging/providers/telegram-bot/send.ts +70 -2
  798. package/src/messaging/providers/telegram-bot/transport.ts +60 -0
  799. package/src/messaging/providers/whatsapp/adapter.ts +2 -2
  800. package/src/messaging/providers/whatsapp/send.ts +1 -1
  801. package/src/messaging/providers/whatsapp/transport.ts +38 -0
  802. package/src/notifications/__tests__/broadcaster.test.ts +0 -8
  803. package/src/notifications/__tests__/connected-channels.test.ts +8 -36
  804. package/src/notifications/__tests__/destination-resolver.test.ts +12 -117
  805. package/src/notifications/__tests__/deterministic-checks.test.ts +3 -3
  806. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -1
  807. package/src/notifications/broadcaster.ts +1 -1
  808. package/src/notifications/canonical-delivery-recorder.ts +1 -1
  809. package/src/notifications/conversation-candidates.ts +3 -3
  810. package/src/notifications/conversation-pairing.ts +25 -16
  811. package/src/notifications/decisions-store.ts +2 -2
  812. package/src/notifications/deliveries-store.ts +3 -3
  813. package/src/notifications/destination-resolver.ts +7 -23
  814. package/src/notifications/deterministic-checks.ts +2 -2
  815. package/src/notifications/emit-signal.ts +6 -12
  816. package/src/notifications/events-store.ts +2 -2
  817. package/src/notifications/home-feed-side-effect.ts +2 -2
  818. package/src/notifications/preferences-store.ts +2 -2
  819. package/src/notifications/signal.ts +1 -1
  820. package/src/oauth/oauth-store.ts +3 -3
  821. package/src/onboarding/__tests__/onboarding-events-store.test.ts +80 -0
  822. package/src/onboarding/checkin-event.test.ts +5 -2
  823. package/src/onboarding/checkin-event.ts +7 -1
  824. package/src/onboarding/onboarding-events-store.ts +161 -0
  825. package/src/permissions/checker.test.ts +319 -1
  826. package/src/permissions/checker.ts +52 -0
  827. package/src/permissions/types.ts +23 -2
  828. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +20 -0
  829. package/src/persistence/__tests__/worker-control.test.ts +260 -0
  830. package/src/persistence/attachments-store.ts +1136 -0
  831. package/src/persistence/checkpoints.ts +65 -0
  832. package/src/persistence/compaction-ledger-store.ts +107 -0
  833. package/src/persistence/conversation-attention-store.ts +689 -0
  834. package/src/persistence/conversation-bootstrap.ts +59 -0
  835. package/src/persistence/conversation-crud.ts +3404 -0
  836. package/src/persistence/conversation-group-migration.test.ts +99 -0
  837. package/src/persistence/conversation-key-store.ts +274 -0
  838. package/src/persistence/conversation-queries.ts +768 -0
  839. package/src/persistence/conversation-row-batch-delete.ts +212 -0
  840. package/src/persistence/conversation-title-service.ts +755 -0
  841. package/src/persistence/db-async-query.ts +329 -0
  842. package/src/persistence/db-connection.ts +242 -0
  843. package/src/persistence/db-init.ts +282 -0
  844. package/src/persistence/db-maintenance.ts +158 -0
  845. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +156 -0
  846. package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +307 -0
  847. package/src/persistence/embeddings/__tests__/reconcile-decision.test.ts +95 -0
  848. package/src/persistence/embeddings/embed.ts +87 -0
  849. package/src/persistence/embeddings/embedding-backend.test.ts +355 -0
  850. package/src/persistence/embeddings/embedding-backend.ts +968 -0
  851. package/src/persistence/embeddings/embedding-billing-breaker.ts +96 -0
  852. package/src/persistence/embeddings/embedding-cache.ts +139 -0
  853. package/src/persistence/embeddings/embedding-identity.ts +88 -0
  854. package/src/persistence/embeddings/embedding-local.ts +587 -0
  855. package/src/persistence/embeddings/embedding-ollama.ts +79 -0
  856. package/src/persistence/embeddings/embedding-runtime-manager.ts +573 -0
  857. package/src/persistence/embeddings/embedding-types.ts +97 -0
  858. package/src/persistence/embeddings/messages-lexical-index.ts +368 -0
  859. package/src/persistence/embeddings/qdrant-circuit-breaker.ts +119 -0
  860. package/src/persistence/embeddings/qdrant-client.test.ts +60 -0
  861. package/src/persistence/embeddings/qdrant-client.ts +842 -0
  862. package/src/persistence/embeddings/qdrant-manager.ts +450 -0
  863. package/src/persistence/embeddings/reconcile-decision.ts +53 -0
  864. package/src/persistence/embeddings/sparse-tokenize.ts +51 -0
  865. package/src/persistence/external-conversation-store.ts +315 -0
  866. package/src/persistence/fork-message-copy.ts +225 -0
  867. package/src/persistence/job-handlers/cleanup.ts +266 -0
  868. package/src/persistence/job-utils.ts +286 -0
  869. package/src/persistence/jobs-store.ts +866 -0
  870. package/src/persistence/jobs-worker.ts +842 -0
  871. package/src/persistence/llm-request-log-source-clickhouse.ts +525 -0
  872. package/src/persistence/llm-request-log-store.ts +740 -0
  873. package/src/persistence/llm-usage-store.ts +961 -0
  874. package/src/persistence/memory-lifecycle-hooks.test.ts +81 -0
  875. package/src/persistence/memory-lifecycle-hooks.ts +120 -0
  876. package/src/persistence/message-content.test.ts +35 -0
  877. package/src/persistence/migrations/126-backfill-guardian-principal-id.ts +300 -0
  878. package/src/persistence/migrations/140-backfill-usage-cache-accounting.ts +364 -0
  879. package/src/persistence/migrations/142-rename-verification-session-id-column.ts +55 -0
  880. package/src/persistence/migrations/182-oauth-providers-display-metadata.ts +22 -0
  881. package/src/persistence/migrations/196-strip-integration-prefix-from-provider-keys.ts +175 -0
  882. package/src/persistence/migrations/199-guardian-request-enrichment-columns.ts +50 -0
  883. package/src/persistence/migrations/202-memory-graph-tables.ts +128 -0
  884. package/src/persistence/migrations/203-drop-memory-items-tables.ts +53 -0
  885. package/src/persistence/migrations/206-scrub-corrupted-image-attachments.ts +121 -0
  886. package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +196 -0
  887. package/src/persistence/migrations/211-memory-recall-logs-query-context.ts +14 -0
  888. package/src/persistence/migrations/220-normalize-user-file-by-principal.ts +171 -0
  889. package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +179 -0
  890. package/src/persistence/migrations/236-tool-invocations-matched-rule-id.ts +23 -0
  891. package/src/persistence/migrations/243-provider-connections.ts +80 -0
  892. package/src/persistence/migrations/244-provider-connection-status-label.ts +29 -0
  893. package/src/persistence/migrations/246-backfill-provider-connection-label.ts +83 -0
  894. package/src/persistence/migrations/255-channel-inbound-delivery-attempts.ts +17 -0
  895. package/src/persistence/migrations/301-create-watchdog-events.ts +42 -0
  896. package/src/persistence/migrations/302-create-compaction-events.ts +107 -0
  897. package/src/persistence/migrations/303-add-conversation-creation-seq.ts +33 -0
  898. package/src/persistence/migrations/304-add-llm-usage-cron-run-id.ts +31 -0
  899. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +49 -0
  900. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +110 -0
  901. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.ts +65 -0
  902. package/src/persistence/migrations/307-acp-session-history-usage-columns.test.ts +124 -0
  903. package/src/persistence/migrations/307-acp-session-history-usage-columns.ts +36 -0
  904. package/src/persistence/migrations/308-acp-session-history-token-columns.test.ts +119 -0
  905. package/src/persistence/migrations/308-acp-session-history-token-columns.ts +32 -0
  906. package/src/persistence/migrations/309-drop-redundant-indexes.ts +60 -0
  907. package/src/persistence/migrations/310-llm-request-log-latency-breakdown.ts +37 -0
  908. package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
  909. package/src/persistence/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +328 -0
  910. package/src/persistence/migrations/__tests__/222-strip-placeholder-sentinels-from-messages.test.ts +273 -0
  911. package/src/persistence/migrations/__tests__/244-provider-connection-status-label.test.ts +90 -0
  912. package/src/persistence/migrations/__tests__/246-backfill-provider-connection-label.test.ts +250 -0
  913. package/src/persistence/migrations/__tests__/run-migrations.test.ts +380 -0
  914. package/src/persistence/migrations/helpers/relocation.ts +230 -0
  915. package/src/persistence/migrations/validate-migration-state.ts +279 -0
  916. package/src/persistence/schedule-attribution-sql.ts +106 -0
  917. package/src/persistence/schema/acp.ts +51 -0
  918. package/src/persistence/schema/contacts.ts +110 -0
  919. package/src/persistence/schema/conversations.ts +235 -0
  920. package/src/persistence/schema/infrastructure.ts +389 -0
  921. package/src/persistence/steps.ts +1312 -0
  922. package/src/persistence/subagent-store.ts +122 -0
  923. package/src/persistence/worker-control.ts +277 -0
  924. package/src/platform/sync-identity.ts +24 -0
  925. package/src/playbooks/playbook-compiler.ts +2 -2
  926. package/src/plugin-api/event-hub-facade.ts +172 -0
  927. package/src/plugin-api/index.ts +14 -1
  928. package/src/plugin-api/types.ts +61 -24
  929. package/src/plugins/defaults/channel/injectors.ts +101 -0
  930. package/src/plugins/defaults/channel/package.json +14 -0
  931. package/src/plugins/defaults/compaction/compact.ts +2 -1
  932. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +2 -1
  933. package/src/plugins/defaults/compaction/window-manager.ts +8 -7
  934. package/src/plugins/defaults/documents/injectors.ts +125 -0
  935. package/src/plugins/defaults/documents/package.json +14 -0
  936. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +6 -2
  937. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +10 -11
  938. package/src/plugins/defaults/history-repair/terminal.ts +1 -1
  939. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +23 -9
  940. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +2 -3
  941. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +7 -14
  942. package/src/plugins/defaults/image-fallback/src/vision-caption.ts +12 -4
  943. package/src/plugins/defaults/image-recovery/recover.ts +6 -3
  944. package/src/plugins/defaults/index.ts +235 -78
  945. package/src/plugins/defaults/injection-presence.ts +80 -0
  946. package/src/plugins/defaults/injector-order.ts +54 -0
  947. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +5 -2
  948. package/src/plugins/defaults/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  949. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +41 -0
  950. package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +264 -0
  951. package/src/plugins/defaults/memory/__tests__/bookmark-schema.test.ts +181 -0
  952. package/src/plugins/defaults/memory/__tests__/clear-stale-processing-flags.test.ts +52 -0
  953. package/src/plugins/defaults/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
  954. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +843 -0
  955. package/src/plugins/defaults/memory/__tests__/conversation-row-batch-delete.test.ts +199 -0
  956. package/src/plugins/defaults/memory/__tests__/conversation-types.test.ts +36 -0
  957. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +172 -0
  958. package/src/plugins/defaults/memory/__tests__/db-busy-timeout.test.ts +26 -0
  959. package/src/plugins/defaults/memory/__tests__/db-logs-attach.test.ts +113 -0
  960. package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +238 -0
  961. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +116 -0
  962. package/src/plugins/defaults/memory/__tests__/embedding-cache.test.ts +137 -0
  963. package/src/plugins/defaults/memory/__tests__/find-analysis-conversation.test.ts +197 -0
  964. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +138 -0
  965. package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +232 -0
  966. package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +245 -0
  967. package/src/plugins/defaults/memory/__tests__/jobs-store-job-classes.test.ts +52 -0
  968. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +115 -0
  969. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +508 -0
  970. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +160 -0
  971. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +1568 -0
  972. package/src/plugins/defaults/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +549 -0
  973. package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +195 -0
  974. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +221 -0
  975. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +275 -0
  976. package/src/plugins/defaults/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
  977. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +192 -0
  978. package/src/plugins/defaults/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  979. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +130 -0
  980. package/src/plugins/defaults/memory/activation-session-store.ts +43 -0
  981. package/src/plugins/defaults/memory/anisotropy.ts +443 -0
  982. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +428 -0
  983. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1311 -0
  984. package/src/plugins/defaults/memory/context-search/search.ts +297 -0
  985. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +341 -0
  986. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +600 -0
  987. package/src/plugins/defaults/memory/context-search/sources/memory.ts +101 -0
  988. package/src/plugins/defaults/memory/context-search/types.ts +48 -0
  989. package/src/plugins/defaults/memory/filing-service.ts +430 -0
  990. package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
  991. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
  992. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +663 -0
  993. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +321 -0
  994. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +287 -0
  995. package/src/plugins/defaults/memory/graph/bootstrap.ts +544 -0
  996. package/src/plugins/defaults/memory/graph/capability-seed.ts +454 -0
  997. package/src/plugins/defaults/memory/graph/consolidation.ts +712 -0
  998. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +1181 -0
  999. package/src/plugins/defaults/memory/graph/decay.ts +195 -0
  1000. package/src/plugins/defaults/memory/graph/extraction-job.ts +77 -0
  1001. package/src/plugins/defaults/memory/graph/extraction.ts +1462 -0
  1002. package/src/plugins/defaults/memory/graph/graph-memory-state-store.ts +50 -0
  1003. package/src/plugins/defaults/memory/graph/graph-search.test.ts +132 -0
  1004. package/src/plugins/defaults/memory/graph/graph-search.ts +294 -0
  1005. package/src/plugins/defaults/memory/graph/image-ref-utils.ts +29 -0
  1006. package/src/plugins/defaults/memory/graph/injection.ts +469 -0
  1007. package/src/plugins/defaults/memory/graph/narrative.ts +267 -0
  1008. package/src/plugins/defaults/memory/graph/pattern-scan.ts +269 -0
  1009. package/src/plugins/defaults/memory/graph/retriever.test.ts +624 -0
  1010. package/src/plugins/defaults/memory/graph/retriever.ts +1357 -0
  1011. package/src/plugins/defaults/memory/graph/store.test.ts +1093 -0
  1012. package/src/plugins/defaults/memory/graph/store.ts +923 -0
  1013. package/src/plugins/defaults/memory/graph/tool-handlers.ts +195 -0
  1014. package/src/plugins/defaults/memory/graph/tools.ts +95 -0
  1015. package/src/plugins/defaults/memory/hooks/init.ts +26 -0
  1016. package/src/plugins/defaults/memory/hooks/post-compact.ts +115 -0
  1017. package/src/plugins/defaults/memory/hooks/shutdown.ts +14 -0
  1018. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +371 -0
  1019. package/src/plugins/defaults/memory/indexer.ts +409 -0
  1020. package/src/plugins/defaults/memory/injectors.ts +388 -0
  1021. package/src/plugins/defaults/memory/job-handlers/__tests__/backfill-lexical-index.test.ts +310 -0
  1022. package/src/plugins/defaults/memory/job-handlers/__tests__/index-message-lexical.test.ts +265 -0
  1023. package/src/plugins/defaults/memory/job-handlers/backfill-lexical-index.ts +108 -0
  1024. package/src/plugins/defaults/memory/job-handlers/backfill.ts +107 -0
  1025. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +236 -0
  1026. package/src/plugins/defaults/memory/job-handlers/embedding.ts +133 -0
  1027. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +117 -0
  1028. package/src/plugins/defaults/memory/job-handlers/index-message-lexical.ts +106 -0
  1029. package/src/plugins/defaults/memory/job-handlers.ts +220 -0
  1030. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +565 -0
  1031. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +424 -0
  1032. package/src/plugins/defaults/memory/jobs/embed-pkb-file.test.ts +169 -0
  1033. package/src/plugins/defaults/memory/jobs/embed-pkb-file.ts +59 -0
  1034. package/src/plugins/defaults/memory/memory-recall-log-store.ts +172 -0
  1035. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +60 -0
  1036. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +131 -0
  1037. package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +94 -0
  1038. package/src/plugins/defaults/memory/memory-retrospective-job.ts +958 -0
  1039. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +264 -0
  1040. package/src/plugins/defaults/memory/memory-retrospective-state.ts +259 -0
  1041. package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +91 -0
  1042. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +216 -0
  1043. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +173 -0
  1044. package/src/plugins/defaults/memory/package.json +14 -0
  1045. package/src/plugins/defaults/memory/persistence-hooks.ts +119 -0
  1046. package/src/plugins/defaults/memory/pkb/autoinject.ts +61 -0
  1047. package/src/plugins/defaults/memory/pkb/context.ts +50 -0
  1048. package/src/plugins/defaults/memory/pkb/pkb-index.test.ts +371 -0
  1049. package/src/plugins/defaults/memory/pkb/pkb-index.ts +256 -0
  1050. package/src/plugins/defaults/memory/pkb/pkb-reconcile.test.ts +254 -0
  1051. package/src/plugins/defaults/memory/pkb/pkb-reconcile.ts +144 -0
  1052. package/src/plugins/defaults/memory/pkb/pkb-search.test.ts +589 -0
  1053. package/src/plugins/defaults/memory/pkb/pkb-search.ts +178 -0
  1054. package/src/plugins/defaults/memory/pkb/types.ts +67 -0
  1055. package/src/plugins/defaults/memory/rerank-local.ts +374 -0
  1056. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-routes.test.ts +165 -0
  1057. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +347 -0
  1058. package/src/plugins/defaults/memory/routes/memory-eval-routes.ts +179 -0
  1059. package/src/plugins/defaults/memory/routes/memory-item-routes.test.ts +922 -0
  1060. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +814 -0
  1061. package/src/plugins/defaults/memory/routes/memory-v2-routes.ts +850 -0
  1062. package/src/plugins/defaults/memory/routes/memory-v3-routes.ts +125 -0
  1063. package/src/plugins/defaults/memory/routes/messages-lexical-routes.ts +67 -0
  1064. package/src/plugins/defaults/memory/search/semantic.ts +241 -0
  1065. package/src/plugins/defaults/memory/segmenter.ts +76 -0
  1066. package/src/plugins/defaults/memory/startup.ts +234 -0
  1067. package/src/plugins/defaults/memory/tail-reinjection-strip.ts +65 -0
  1068. package/src/plugins/defaults/memory/task-memory-cleanup.ts +241 -0
  1069. package/src/plugins/defaults/memory/tools.test.ts +382 -0
  1070. package/src/plugins/defaults/memory/tools.ts +87 -0
  1071. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +207 -0
  1072. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +1273 -0
  1073. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +510 -0
  1074. package/src/plugins/defaults/memory/v2/__tests__/cli-command-store.test.ts +432 -0
  1075. package/src/plugins/defaults/memory/v2/__tests__/consolidation-job.test.ts +744 -0
  1076. package/src/plugins/defaults/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +205 -0
  1077. package/src/plugins/defaults/memory/v2/__tests__/frontmatter-sweep.test.ts +136 -0
  1078. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +186 -0
  1079. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  1080. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
  1081. package/src/plugins/defaults/memory/v2/__tests__/harness-runner.test.ts +135 -0
  1082. package/src/plugins/defaults/memory/v2/__tests__/injection-events.test.ts +318 -0
  1083. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +2308 -0
  1084. package/src/plugins/defaults/memory/v2/__tests__/memory-v2-startup.test.ts +86 -0
  1085. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +940 -0
  1086. package/src/plugins/defaults/memory/v2/__tests__/page-index.test.ts +760 -0
  1087. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +332 -0
  1088. package/src/plugins/defaults/memory/v2/__tests__/qdrant.test.ts +974 -0
  1089. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +338 -0
  1090. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1198 -0
  1091. package/src/plugins/defaults/memory/v2/__tests__/sim.test.ts +704 -0
  1092. package/src/plugins/defaults/memory/v2/__tests__/skill-content.test.ts +115 -0
  1093. package/src/plugins/defaults/memory/v2/__tests__/skill-store.test.ts +986 -0
  1094. package/src/plugins/defaults/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  1095. package/src/plugins/defaults/memory/v2/__tests__/static-context.test.ts +223 -0
  1096. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +530 -0
  1097. package/src/plugins/defaults/memory/v2/activation-store.ts +185 -0
  1098. package/src/plugins/defaults/memory/v2/activation.ts +560 -0
  1099. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +296 -0
  1100. package/src/plugins/defaults/memory/v2/cli-command-store.ts +341 -0
  1101. package/src/plugins/defaults/memory/v2/consolidation-job.ts +550 -0
  1102. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +98 -0
  1103. package/src/plugins/defaults/memory/v2/harness/compare.ts +57 -0
  1104. package/src/plugins/defaults/memory/v2/harness/oracle.ts +148 -0
  1105. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +243 -0
  1106. package/src/plugins/defaults/memory/v2/harness/retriever.ts +74 -0
  1107. package/src/plugins/defaults/memory/v2/harness/router-retriever.ts +43 -0
  1108. package/src/plugins/defaults/memory/v2/injected-block-slugs.ts +79 -0
  1109. package/src/plugins/defaults/memory/v2/injection-events.ts +101 -0
  1110. package/src/plugins/defaults/memory/v2/injection.ts +932 -0
  1111. package/src/plugins/defaults/memory/v2/memory-v2-startup.test.ts +203 -0
  1112. package/src/plugins/defaults/memory/v2/memory-v2-startup.ts +378 -0
  1113. package/src/plugins/defaults/memory/v2/migration.ts +774 -0
  1114. package/src/plugins/defaults/memory/v2/page-index.ts +459 -0
  1115. package/src/plugins/defaults/memory/v2/page-store.ts +443 -0
  1116. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +868 -0
  1117. package/src/plugins/defaults/memory/v2/prompts/router.ts +148 -0
  1118. package/src/plugins/defaults/memory/v2/qdrant.ts +939 -0
  1119. package/src/plugins/defaults/memory/v2/reranker.ts +184 -0
  1120. package/src/plugins/defaults/memory/v2/router.ts +602 -0
  1121. package/src/plugins/defaults/memory/v2/sim.ts +310 -0
  1122. package/src/plugins/defaults/memory/v2/skill-content.ts +61 -0
  1123. package/src/plugins/defaults/memory/v2/skill-store.ts +431 -0
  1124. package/src/plugins/defaults/memory/v2/sparse-bm25.ts +245 -0
  1125. package/src/plugins/defaults/memory/v2/static-context.ts +100 -0
  1126. package/src/plugins/defaults/memory/v2/sweep-job.ts +323 -0
  1127. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +316 -0
  1128. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +1163 -0
  1129. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +211 -0
  1130. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +247 -0
  1131. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +685 -0
  1132. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +365 -0
  1133. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +1012 -0
  1134. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +977 -0
  1135. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +599 -0
  1136. package/src/plugins/defaults/memory/v3/__tests__/render-injection.test.ts +128 -0
  1137. package/src/plugins/defaults/memory/v3/__tests__/section-dense-store.test.ts +756 -0
  1138. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +422 -0
  1139. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +501 -0
  1140. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +885 -0
  1141. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +96 -0
  1142. package/src/plugins/defaults/memory/v3/candidate-match.ts +197 -0
  1143. package/src/plugins/defaults/memory/v3/capabilities.ts +88 -0
  1144. package/src/plugins/defaults/memory/v3/card.ts +160 -0
  1145. package/src/plugins/defaults/memory/v3/dense.ts +108 -0
  1146. package/src/plugins/defaults/memory/v3/edge.ts +252 -0
  1147. package/src/plugins/defaults/memory/v3/entity-lane.test.ts +124 -0
  1148. package/src/plugins/defaults/memory/v3/entity-lane.ts +113 -0
  1149. package/src/plugins/defaults/memory/v3/ever-injected-store.test.ts +307 -0
  1150. package/src/plugins/defaults/memory/v3/ever-injected-store.ts +278 -0
  1151. package/src/plugins/defaults/memory/v3/hot-set.test.ts +143 -0
  1152. package/src/plugins/defaults/memory/v3/hot-set.ts +85 -0
  1153. package/src/plugins/defaults/memory/v3/injector.ts +423 -0
  1154. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +169 -0
  1155. package/src/plugins/defaults/memory/v3/learned-edges.ts +178 -0
  1156. package/src/plugins/defaults/memory/v3/maintain-job.ts +988 -0
  1157. package/src/plugins/defaults/memory/v3/orchestrate.ts +483 -0
  1158. package/src/plugins/defaults/memory/v3/page-content.ts +102 -0
  1159. package/src/plugins/defaults/memory/v3/pool-select.test.ts +147 -0
  1160. package/src/plugins/defaults/memory/v3/pool-select.ts +586 -0
  1161. package/src/plugins/defaults/memory/v3/prune.test.ts +760 -0
  1162. package/src/plugins/defaults/memory/v3/prune.ts +469 -0
  1163. package/src/plugins/defaults/memory/v3/render-injection.ts +92 -0
  1164. package/src/plugins/defaults/memory/v3/section-dense-store.ts +471 -0
  1165. package/src/plugins/defaults/memory/v3/section-needle.ts +215 -0
  1166. package/src/plugins/defaults/memory/v3/selection-log-store.ts +277 -0
  1167. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +656 -0
  1168. package/src/plugins/defaults/memory/v3/tuning-profile.ts +91 -0
  1169. package/src/plugins/defaults/memory/v3/types.ts +130 -0
  1170. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +731 -0
  1171. package/src/plugins/defaults/session/injectors.ts +84 -0
  1172. package/src/plugins/defaults/session/package.json +14 -0
  1173. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +6 -2
  1174. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +39 -45
  1175. package/src/plugins/defaults/title-generate/hooks/stop.ts +4 -5
  1176. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +3 -3
  1177. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +5 -3
  1178. package/src/plugins/defaults/turn-context/injectors.ts +53 -0
  1179. package/src/plugins/defaults/turn-context/package.json +14 -0
  1180. package/src/plugins/defaults/turn-context/unified-turn-context.ts +235 -0
  1181. package/src/plugins/defaults/workspace/injectors.ts +295 -0
  1182. package/src/plugins/defaults/workspace/package.json +14 -0
  1183. package/src/plugins/disabled-state.ts +31 -0
  1184. package/src/plugins/injector-registry.ts +127 -0
  1185. package/src/plugins/job-handler-registry.ts +94 -0
  1186. package/src/plugins/mtime-cache.ts +27 -47
  1187. package/src/plugins/pipeline.ts +1 -1
  1188. package/src/plugins/registry.ts +40 -132
  1189. package/src/plugins/types.ts +44 -1
  1190. package/src/prompts/persona-resolver.ts +43 -11
  1191. package/src/prompts/system-prompt.ts +1 -1
  1192. package/src/prompts/templates/BOOTSTRAP.md +16 -119
  1193. package/src/prompts/templates/SOUL.md +4 -0
  1194. package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
  1195. package/src/providers/__tests__/dispatch-connection-routing.test.ts +1 -1
  1196. package/src/providers/__tests__/inference.test.ts +6 -6
  1197. package/src/providers/__tests__/placeholder-sentinels.test.ts +80 -0
  1198. package/src/providers/__tests__/retry-callsite.test.ts +31 -3
  1199. package/src/providers/__tests__/satellite-connection-routing.test.ts +1 -1
  1200. package/src/providers/anthropic/client.ts +23 -24
  1201. package/src/providers/call-site-routing.ts +42 -1
  1202. package/src/providers/connection-resolution.ts +7 -3
  1203. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +7 -8
  1204. package/src/providers/inference/__tests__/base-url-security.test.ts +8 -8
  1205. package/src/providers/inference/__tests__/connections-label.test.ts +5 -5
  1206. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +4 -4
  1207. package/src/providers/inference/backfill.ts +9 -5
  1208. package/src/providers/inference/connections.ts +2 -2
  1209. package/src/providers/inference/resolve-auth.ts +3 -3
  1210. package/src/providers/model-catalog.ts +38 -0
  1211. package/src/providers/openai/chat-completions-provider.ts +14 -1
  1212. package/src/providers/openai/responses-provider.ts +18 -0
  1213. package/src/providers/placeholder-sentinels.ts +50 -15
  1214. package/src/providers/provider-send-message.ts +7 -1
  1215. package/src/providers/ratelimit.ts +6 -0
  1216. package/src/providers/registry.ts +3 -1
  1217. package/src/providers/retry.ts +22 -0
  1218. package/src/providers/stop-reasons.ts +32 -0
  1219. package/src/providers/tool-progress-events.test.ts +50 -0
  1220. package/src/providers/tool-progress-events.ts +99 -0
  1221. package/src/providers/types.ts +14 -1
  1222. package/src/providers/usage-tracking.ts +7 -1
  1223. package/src/runtime/__tests__/agent-wake.test.ts +100 -29
  1224. package/src/runtime/__tests__/background-job-runner.test.ts +19 -2
  1225. package/src/runtime/__tests__/channel-verification-service.test.ts +9 -5
  1226. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +37 -32
  1227. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +3 -3
  1228. package/src/runtime/__tests__/local-principal-trust.test.ts +16 -18
  1229. package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
  1230. package/src/runtime/__tests__/pre-first-message-gate.test.ts +1 -1
  1231. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +115 -168
  1232. package/src/runtime/access-request-helper.ts +4 -5
  1233. package/src/runtime/actor-trust-resolver.ts +44 -17
  1234. package/src/runtime/agent-wake.ts +69 -12
  1235. package/src/runtime/anchored-guardian.test.ts +7 -54
  1236. package/src/runtime/anchored-guardian.ts +4 -53
  1237. package/src/runtime/assistant-event-hub.ts +1 -1
  1238. package/src/runtime/assistant-event.ts +86 -12
  1239. package/src/runtime/assistant-stream-state.ts +12 -74
  1240. package/src/runtime/background-job-runner.ts +30 -10
  1241. package/src/runtime/channel-reply-delivery.ts +6 -11
  1242. package/src/runtime/channel-retry-sweep.ts +23 -3
  1243. package/src/runtime/channel-verification-service.ts +9 -9
  1244. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  1245. package/src/runtime/finalize-event-delivery.ts +2 -2
  1246. package/src/runtime/guardian-action-service.ts +1 -2
  1247. package/src/runtime/guardian-reply-router.ts +1 -1
  1248. package/src/runtime/guardian-vellum-migration.ts +18 -16
  1249. package/src/runtime/http-server.ts +45 -1
  1250. package/src/runtime/invite-redemption-service.ts +36 -13
  1251. package/src/runtime/invite-service.ts +6 -4
  1252. package/src/runtime/local-actor-identity.test.ts +108 -0
  1253. package/src/runtime/local-actor-identity.ts +27 -20
  1254. package/src/runtime/member-verdict-cache.ts +0 -0
  1255. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
  1256. package/src/runtime/migrations/vbundle-streaming-importer.ts +1 -1
  1257. package/src/runtime/pre-first-message-gate.ts +1 -1
  1258. package/src/runtime/routes/__tests__/acp-routes.test.ts +74 -8
  1259. package/src/runtime/routes/__tests__/backup-routes.test.ts +1 -1
  1260. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +3 -3
  1261. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +17 -23
  1262. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +3 -3
  1263. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +5 -5
  1264. package/src/runtime/routes/__tests__/contact-routes.test.ts +188 -14
  1265. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +5 -5
  1266. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +5 -5
  1267. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +3 -3
  1268. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +12 -12
  1269. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +4 -4
  1270. package/src/runtime/routes/__tests__/global-search-routes.test.ts +1 -2
  1271. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +3 -3
  1272. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +3 -3
  1273. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +21 -7
  1274. package/src/runtime/routes/__tests__/memory-worker-routes.test.ts +306 -0
  1275. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
  1276. package/src/runtime/routes/__tests__/plugins-routes.test.ts +395 -26
  1277. package/src/runtime/routes/__tests__/ps-routes.test.ts +114 -0
  1278. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +6 -6
  1279. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +72 -0
  1280. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +4 -4
  1281. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +3 -2
  1282. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  1283. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +125 -0
  1284. package/src/runtime/routes/acp-routes-event-log.test.ts +283 -0
  1285. package/src/runtime/routes/acp-routes-list.test.ts +24 -25
  1286. package/src/runtime/routes/acp-routes.test.ts +4 -4
  1287. package/src/runtime/routes/acp-routes.ts +31 -4
  1288. package/src/runtime/routes/app-management-routes.ts +9 -9
  1289. package/src/runtime/routes/app-routes.ts +3 -7
  1290. package/src/runtime/routes/approval-routes.ts +2 -4
  1291. package/src/runtime/routes/attachment-routes.ts +2 -2
  1292. package/src/runtime/routes/audit-routes.ts +2 -3
  1293. package/src/runtime/routes/background-tool-routes.ts +34 -5
  1294. package/src/runtime/routes/background-wake-routes.ts +19 -5
  1295. package/src/runtime/routes/backup-routes.ts +1 -1
  1296. package/src/runtime/routes/bookmark-routes.ts +3 -3
  1297. package/src/runtime/routes/brain-graph-routes.ts +2 -2
  1298. package/src/runtime/routes/btw-routes.ts +1 -1
  1299. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1300. package/src/runtime/routes/channel-delivery-routes.ts +1 -1
  1301. package/src/runtime/routes/channel-readiness-routes.ts +7 -3
  1302. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +3 -8
  1303. package/src/runtime/routes/consolidation-routes.ts +6 -6
  1304. package/src/runtime/routes/contact-routes.ts +98 -32
  1305. package/src/runtime/routes/conversation-attention-routes.ts +2 -2
  1306. package/src/runtime/routes/conversation-cli-routes.ts +32 -7
  1307. package/src/runtime/routes/conversation-compaction-routes.ts +4 -4
  1308. package/src/runtime/routes/conversation-list-routes.ts +9 -37
  1309. package/src/runtime/routes/conversation-management-routes.ts +9 -46
  1310. package/src/runtime/routes/conversation-query-routes.ts +35 -11
  1311. package/src/runtime/routes/conversation-routes.ts +174 -23
  1312. package/src/runtime/routes/conversation-starter-routes.ts +11 -5
  1313. package/src/runtime/routes/conversations-import-routes.ts +10 -6
  1314. package/src/runtime/routes/debug-routes.ts +3 -3
  1315. package/src/runtime/routes/defer-routes.ts +4 -4
  1316. package/src/runtime/routes/documents-routes.ts +1 -1
  1317. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -1
  1318. package/src/runtime/routes/events-routes.ts +4 -4
  1319. package/src/runtime/routes/filing-routes.ts +1 -1
  1320. package/src/runtime/routes/global-search-routes.ts +4 -4
  1321. package/src/runtime/routes/group-routes.ts +1 -1
  1322. package/src/runtime/routes/guardian-action-routes.ts +1 -1
  1323. package/src/runtime/routes/heartbeat-routes.ts +2 -2
  1324. package/src/runtime/routes/home-feed-routes.ts +10 -5
  1325. package/src/runtime/routes/identity-routes.ts +33 -14
  1326. package/src/runtime/routes/inbound-conversation.ts +3 -3
  1327. package/src/runtime/routes/inbound-message-handler.ts +25 -25
  1328. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +8 -4
  1329. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +13 -16
  1330. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +5 -5
  1331. package/src/runtime/routes/inbound-stages/background-dispatch.ts +15 -19
  1332. package/src/runtime/routes/inbound-stages/edit-intercept.ts +12 -12
  1333. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -2
  1334. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +1 -1
  1335. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +1 -1
  1336. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +27 -8
  1337. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +5 -2
  1338. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  1339. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
  1340. package/src/runtime/routes/index.ts +8 -4
  1341. package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
  1342. package/src/runtime/routes/inference-profile-session-reaper.ts +1 -1
  1343. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -2
  1344. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +3 -4
  1345. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  1346. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  1347. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
  1348. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1349. package/src/runtime/routes/log-export-routes.ts +2 -2
  1350. package/src/runtime/routes/memory-worker-routes.ts +227 -0
  1351. package/src/runtime/routes/migration-rollback-routes.ts +11 -12
  1352. package/src/runtime/routes/migration-routes.ts +211 -10
  1353. package/src/runtime/routes/notification-routes.ts +2 -2
  1354. package/src/runtime/routes/platform-routes.ts +3 -0
  1355. package/src/runtime/routes/playground/helpers.ts +3 -3
  1356. package/src/runtime/routes/plugins-routes.ts +180 -7
  1357. package/src/runtime/routes/ps-routes.ts +37 -66
  1358. package/src/runtime/routes/publish-routes.ts +3 -3
  1359. package/src/runtime/routes/rename-conversation-routes.ts +1 -1
  1360. package/src/runtime/routes/retrospective-routes.ts +5 -5
  1361. package/src/runtime/routes/schedule-routes.ts +88 -45
  1362. package/src/runtime/routes/secret-routes.ts +11 -10
  1363. package/src/runtime/routes/sequence-routes.ts +1 -1
  1364. package/src/runtime/routes/settings-routes.ts +26 -12
  1365. package/src/runtime/routes/skills-routes.ts +11 -1
  1366. package/src/runtime/routes/slack-channel-routes.ts +4 -4
  1367. package/src/runtime/routes/subagents-routes.ts +2 -2
  1368. package/src/runtime/routes/surface-conversation-resolver.ts +1 -1
  1369. package/src/runtime/routes/task-routes.ts +18 -29
  1370. package/src/runtime/routes/telemetry-routes.ts +1 -1
  1371. package/src/runtime/routes/trace-event-routes.ts +1 -1
  1372. package/src/runtime/routes/types.ts +7 -0
  1373. package/src/runtime/routes/usage-routes.ts +2 -2
  1374. package/src/runtime/routes/wake-conversation-routes.ts +44 -8
  1375. package/src/runtime/routes/wipe-conversation-routes.ts +3 -3
  1376. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  1377. package/src/runtime/routes/work-items-routes.ts +1 -1
  1378. package/src/runtime/runtime-mode.ts +5 -7
  1379. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  1380. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +362 -0
  1381. package/src/runtime/services/__tests__/auto-analysis-guard.test.ts +57 -0
  1382. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +178 -0
  1383. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -1
  1384. package/src/runtime/services/analyze-conversation.ts +22 -13
  1385. package/src/runtime/services/auto-analysis-enqueue.ts +130 -0
  1386. package/src/runtime/services/auto-analysis-guard.ts +13 -0
  1387. package/src/runtime/services/conversation-analyze-job.ts +53 -0
  1388. package/src/runtime/services/conversation-serializer.ts +10 -53
  1389. package/src/runtime/tool-grant-request-helper.ts +1 -1
  1390. package/src/runtime/trust-verdict-consumer.ts +36 -41
  1391. package/src/schedule/__tests__/run-script.test.ts +21 -0
  1392. package/src/schedule/retry-policy.ts +8 -8
  1393. package/src/schedule/run-script.ts +16 -4
  1394. package/src/schedule/schedule-recovery.ts +8 -5
  1395. package/src/schedule/schedule-store.ts +270 -162
  1396. package/src/schedule/schedule-usage-store.ts +2 -2
  1397. package/src/schedule/scheduler-types.ts +6 -0
  1398. package/src/schedule/scheduler.ts +218 -121
  1399. package/src/security/auth-fallback-events-store.ts +94 -0
  1400. package/src/security/redaction.ts +18 -14
  1401. package/src/sequence/engine.ts +1 -1
  1402. package/src/sequence/store.ts +3 -3
  1403. package/src/services/published-app-updater.ts +2 -2
  1404. package/src/signals/cancel.ts +1 -1
  1405. package/src/signals/user-message.ts +2 -2
  1406. package/src/skills/__tests__/categories-cache.test.ts +38 -0
  1407. package/src/skills/catalog-install.ts +2 -1
  1408. package/src/skills/categories-cache.ts +40 -5
  1409. package/src/skills/clawhub.ts +1 -0
  1410. package/src/skills/install-meta.ts +44 -0
  1411. package/src/skills/managed-store.ts +120 -3
  1412. package/src/skills/skillssh-registry.ts +1 -0
  1413. package/src/skills/version-hash.ts +20 -0
  1414. package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
  1415. package/src/subagent/__tests__/consult-transcript.test.ts +184 -0
  1416. package/src/subagent/consult-prompt.ts +57 -0
  1417. package/src/subagent/consult-transcript.ts +86 -0
  1418. package/src/subagent/index.ts +1 -1
  1419. package/src/subagent/manager.ts +502 -72
  1420. package/src/subagent/types.ts +14 -3
  1421. package/src/subagent/validate-allowlists.ts +65 -0
  1422. package/src/tasks/task-compiler.ts +2 -2
  1423. package/src/tasks/task-runner.ts +3 -3
  1424. package/src/tasks/task-store.ts +2 -2
  1425. package/src/telemetry/__tests__/watchdog-events-store.test.ts +161 -0
  1426. package/src/telemetry/skill-loaded-events-store.test.ts +152 -0
  1427. package/src/telemetry/skill-loaded-events-store.ts +95 -0
  1428. package/src/telemetry/tool-executed-events-store.test.ts +219 -0
  1429. package/src/telemetry/tool-executed-events-store.ts +102 -0
  1430. package/src/telemetry/tool-usage-store.ts +114 -0
  1431. package/src/telemetry/trace-event-store.ts +133 -0
  1432. package/src/telemetry/turn-events-store.ts +173 -0
  1433. package/src/telemetry/turn-trace-store.test.ts +736 -0
  1434. package/src/telemetry/turn-trace-store.ts +364 -0
  1435. package/src/telemetry/usage-telemetry-reporter.test.ts +12 -12
  1436. package/src/telemetry/usage-telemetry-reporter.ts +46 -17
  1437. package/src/telemetry/watchdog-events-store.ts +87 -0
  1438. package/src/tools/__tests__/run-standalone.test.ts +19 -0
  1439. package/src/tools/acp/list-agents.test.ts +0 -6
  1440. package/src/tools/acp/spawn.test.ts +18 -7
  1441. package/src/tools/acp/spawn.ts +1 -0
  1442. package/src/tools/apps/executors.ts +2 -2
  1443. package/src/tools/apps/resolve-app-id.ts +1 -1
  1444. package/src/tools/background-tool-registry.ts +61 -0
  1445. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +3 -3
  1446. package/src/tools/document/document-comment-tool.test.ts +2 -2
  1447. package/src/tools/filesystem/write.ts +5 -4
  1448. package/src/tools/host-terminal/host-shell.test.ts +397 -0
  1449. package/src/tools/host-terminal/host-shell.ts +203 -14
  1450. package/src/tools/policy-context.ts +21 -0
  1451. package/src/tools/registry.ts +41 -4
  1452. package/src/tools/run-standalone.ts +101 -0
  1453. package/src/tools/schedule/create.ts +2 -2
  1454. package/src/tools/schedule/delete.ts +1 -1
  1455. package/src/tools/schedule/update.ts +1 -1
  1456. package/src/tools/skills/find-similar-skills.test.ts +277 -0
  1457. package/src/tools/skills/find-similar-skills.ts +120 -0
  1458. package/src/tools/skills/scaffold-managed.ts +123 -4
  1459. package/src/tools/skills/skill-script-runner.ts +17 -0
  1460. package/src/tools/subagent/consult-deadline.ts +49 -0
  1461. package/src/tools/subagent/read.ts +1 -1
  1462. package/src/tools/subagent/spawn.ts +234 -5
  1463. package/src/tools/terminal/safe-env.ts +1 -0
  1464. package/src/tools/terminal/shell.test.ts +177 -0
  1465. package/src/tools/terminal/shell.ts +98 -4
  1466. package/src/tools/tool-approval-handler.ts +1 -1
  1467. package/src/tools/tool-manifest.ts +1 -1
  1468. package/src/tools/tool-types.ts +445 -0
  1469. package/src/tools/types.ts +28 -17
  1470. package/src/usage/types.ts +7 -0
  1471. package/src/util/__tests__/process-tree.test.ts +123 -0
  1472. package/src/util/device-id.ts +52 -12
  1473. package/src/util/logger.ts +9 -0
  1474. package/src/util/process-tree.ts +203 -0
  1475. package/src/util/sqlite-retry.ts +90 -0
  1476. package/src/watcher/__tests__/telemetry.test.ts +2 -2
  1477. package/src/watcher/telemetry.ts +2 -2
  1478. package/src/watcher/watcher-store.ts +3 -3
  1479. package/src/work-items/work-item-store.ts +2 -2
  1480. package/src/workflows/engine-integration.test.ts +2 -2
  1481. package/src/workflows/engine.test.ts +2 -2
  1482. package/src/workflows/fanout-load.test.ts +2 -2
  1483. package/src/workflows/journal-store.test.ts +3 -3
  1484. package/src/workflows/journal-store.ts +1 -1
  1485. package/src/workflows/leaf-runner.test.ts +9 -6
  1486. package/src/workflows/leaf-runner.ts +1 -1
  1487. package/src/workspace/heartbeat-service.ts +29 -0
  1488. package/src/workspace/migrations/011-backfill-installation-id.ts +1 -1
  1489. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +5 -2
  1490. package/src/workspace/migrations/031-drop-user-md.ts +258 -148
  1491. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +1 -1
  1492. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
  1493. package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
  1494. package/src/workspace/migrations/113-swap-balanced-profile-to-glm-5p2.ts +101 -0
  1495. package/src/workspace/migrations/114-swap-quality-profile-to-opus.ts +83 -0
  1496. package/src/workspace/migrations/115-drop-frontier-profile.ts +129 -0
  1497. package/src/workspace/migrations/116-rename-memory-plugin-disabled-sentinel.ts +53 -0
  1498. package/src/workspace/migrations/117-normalize-stale-lean-memory-v3-defaults.ts +116 -0
  1499. package/src/workspace/migrations/118-seed-now-md.ts +64 -0
  1500. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +5 -2
  1501. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +4 -4
  1502. package/src/workspace/migrations/registry.ts +14 -0
  1503. package/drizzle/0000_dizzy_maggott.sql +0 -301
  1504. package/drizzle/meta/0000_snapshot.json +0 -1933
  1505. package/drizzle/meta/_journal.json +0 -13
  1506. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
  1507. package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
  1508. package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
  1509. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
  1510. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
  1511. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
  1512. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
  1513. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
  1514. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
  1515. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +0 -446
  1516. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
  1517. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
  1518. package/src/__tests__/config-managed-gemini-defaults.test.ts +0 -277
  1519. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
  1520. package/src/__tests__/slack-block-formatting.test.ts +0 -210
  1521. package/src/background-wake/runtime-registry.ts +0 -24
  1522. package/src/contacts/contact-events.ts +0 -21
  1523. package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
  1524. package/src/daemon/__tests__/meet-host-supervisor.test.ts +0 -587
  1525. package/src/daemon/__tests__/meet-manifest-loader.test.ts +0 -476
  1526. package/src/daemon/daemon-skill-host.ts +0 -262
  1527. package/src/daemon/meet-host-startup.ts +0 -51
  1528. package/src/daemon/meet-host-supervisor.ts +0 -782
  1529. package/src/daemon/meet-manifest-loader.ts +0 -396
  1530. package/src/daemon/memory-v2-startup.test.ts +0 -203
  1531. package/src/daemon/memory-v2-startup.ts +0 -345
  1532. package/src/daemon/message-types/meet.ts +0 -143
  1533. package/src/daemon/server.ts +0 -423
  1534. package/src/daemon/shutdown-registry.ts +0 -40
  1535. package/src/filing/filing-service.ts +0 -429
  1536. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
  1537. package/src/ipc/__tests__/skill-server.test.ts +0 -182
  1538. package/src/ipc/skill-ipc-types.ts +0 -54
  1539. package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
  1540. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
  1541. package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
  1542. package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
  1543. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
  1544. package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
  1545. package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
  1546. package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
  1547. package/src/ipc/skill-routes/config.ts +0 -47
  1548. package/src/ipc/skill-routes/events.ts +0 -147
  1549. package/src/ipc/skill-routes/identity.ts +0 -21
  1550. package/src/ipc/skill-routes/index.ts +0 -37
  1551. package/src/ipc/skill-routes/log.ts +0 -40
  1552. package/src/ipc/skill-routes/memory.ts +0 -92
  1553. package/src/ipc/skill-routes/platform.ts +0 -39
  1554. package/src/ipc/skill-routes/providers.ts +0 -162
  1555. package/src/ipc/skill-routes/registries.ts +0 -340
  1556. package/src/ipc/skill-server.ts +0 -795
  1557. package/src/ipc/skill-socket-path.ts +0 -20
  1558. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  1559. package/src/memory/__tests__/activation-session-store.test.ts +0 -41
  1560. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +0 -359
  1561. package/src/memory/__tests__/auto-analysis-guard.test.ts +0 -57
  1562. package/src/memory/__tests__/bookmark-crud.test.ts +0 -264
  1563. package/src/memory/__tests__/bookmark-schema.test.ts +0 -181
  1564. package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +0 -432
  1565. package/src/memory/__tests__/conversation-analyze-job.test.ts +0 -178
  1566. package/src/memory/__tests__/conversation-group-migration.test.ts +0 -99
  1567. package/src/memory/__tests__/conversation-queries.test.ts +0 -843
  1568. package/src/memory/__tests__/conversation-types.test.ts +0 -36
  1569. package/src/memory/__tests__/db-async-query.test.ts +0 -165
  1570. package/src/memory/__tests__/db-logs-attach.test.ts +0 -110
  1571. package/src/memory/__tests__/db-maintenance.test.ts +0 -235
  1572. package/src/memory/__tests__/db-memory-attach.test.ts +0 -113
  1573. package/src/memory/__tests__/find-analysis-conversation.test.ts +0 -197
  1574. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +0 -140
  1575. package/src/memory/__tests__/fork-message-copy.test.ts +0 -232
  1576. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +0 -241
  1577. package/src/memory/__tests__/jobs-store-job-classes.test.ts +0 -52
  1578. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +0 -113
  1579. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +0 -505
  1580. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +0 -160
  1581. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -1443
  1582. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +0 -544
  1583. package/src/memory/__tests__/memory-retrospective-state.test.ts +0 -195
  1584. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -221
  1585. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +0 -275
  1586. package/src/memory/__tests__/memory-v3-selections-migration.test.ts +0 -103
  1587. package/src/memory/__tests__/message-content.test.ts +0 -35
  1588. package/src/memory/__tests__/onboarding-events-store.test.ts +0 -80
  1589. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  1590. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +0 -49
  1591. package/src/memory/__tests__/table-relocation.test.ts +0 -129
  1592. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  1593. package/src/memory/activation-session-store.ts +0 -43
  1594. package/src/memory/anisotropy.ts +0 -443
  1595. package/src/memory/app-store.ts +0 -1058
  1596. package/src/memory/attachments-store.ts +0 -1136
  1597. package/src/memory/auth-fallback-events-store.ts +0 -94
  1598. package/src/memory/auto-analysis-enqueue.ts +0 -127
  1599. package/src/memory/auto-analysis-guard.ts +0 -17
  1600. package/src/memory/canonical-guardian-store.ts +0 -891
  1601. package/src/memory/channel-verification-sessions.ts +0 -557
  1602. package/src/memory/checkpoints.ts +0 -65
  1603. package/src/memory/context-search/agent-protocol.ts +0 -428
  1604. package/src/memory/context-search/agent-runner.ts +0 -1310
  1605. package/src/memory/context-search/search.ts +0 -297
  1606. package/src/memory/context-search/sources/conversations.ts +0 -341
  1607. package/src/memory/context-search/sources/memory-v2.ts +0 -600
  1608. package/src/memory/context-search/sources/memory.ts +0 -101
  1609. package/src/memory/context-search/types.ts +0 -48
  1610. package/src/memory/conversation-analyze-job.ts +0 -53
  1611. package/src/memory/conversation-attention-store.ts +0 -689
  1612. package/src/memory/conversation-bootstrap.ts +0 -50
  1613. package/src/memory/conversation-crud.ts +0 -3361
  1614. package/src/memory/conversation-key-store.ts +0 -274
  1615. package/src/memory/conversation-queries.ts +0 -768
  1616. package/src/memory/conversation-starter-checkpoints.ts +0 -64
  1617. package/src/memory/conversation-title-service.ts +0 -606
  1618. package/src/memory/db-async-query.ts +0 -298
  1619. package/src/memory/db-connection.ts +0 -228
  1620. package/src/memory/db-init.ts +0 -265
  1621. package/src/memory/db-maintenance.ts +0 -154
  1622. package/src/memory/embed.ts +0 -73
  1623. package/src/memory/embedding-backend.test.ts +0 -204
  1624. package/src/memory/embedding-backend.ts +0 -855
  1625. package/src/memory/embedding-billing-breaker.ts +0 -96
  1626. package/src/memory/embedding-local.ts +0 -587
  1627. package/src/memory/embedding-ollama.ts +0 -79
  1628. package/src/memory/embedding-runtime-manager.ts +0 -573
  1629. package/src/memory/embedding-types.ts +0 -90
  1630. package/src/memory/external-conversation-store.ts +0 -315
  1631. package/src/memory/fork-message-copy.ts +0 -170
  1632. package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +0 -119
  1633. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +0 -655
  1634. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +0 -321
  1635. package/src/memory/graph/bootstrap.test.ts +0 -280
  1636. package/src/memory/graph/bootstrap.ts +0 -532
  1637. package/src/memory/graph/capability-seed.ts +0 -451
  1638. package/src/memory/graph/consolidation.ts +0 -712
  1639. package/src/memory/graph/conversation-graph-memory.ts +0 -1185
  1640. package/src/memory/graph/decay.ts +0 -195
  1641. package/src/memory/graph/extraction-job.ts +0 -74
  1642. package/src/memory/graph/extraction.ts +0 -1462
  1643. package/src/memory/graph/graph-memory-state-store.ts +0 -50
  1644. package/src/memory/graph/graph-search.test.ts +0 -129
  1645. package/src/memory/graph/graph-search.ts +0 -292
  1646. package/src/memory/graph/image-ref-utils.ts +0 -29
  1647. package/src/memory/graph/injection.ts +0 -469
  1648. package/src/memory/graph/narrative.ts +0 -267
  1649. package/src/memory/graph/pattern-scan.ts +0 -269
  1650. package/src/memory/graph/retriever.test.ts +0 -624
  1651. package/src/memory/graph/retriever.ts +0 -1356
  1652. package/src/memory/graph/store.test.ts +0 -1093
  1653. package/src/memory/graph/store.ts +0 -923
  1654. package/src/memory/graph/tool-handlers.ts +0 -195
  1655. package/src/memory/graph/tools.ts +0 -95
  1656. package/src/memory/guardian-rate-limits.ts +0 -191
  1657. package/src/memory/indexer.ts +0 -406
  1658. package/src/memory/job-handlers/backfill.ts +0 -104
  1659. package/src/memory/job-handlers/cleanup.ts +0 -237
  1660. package/src/memory/job-handlers/conversation-starters.ts +0 -481
  1661. package/src/memory/job-handlers/embedding.test.ts +0 -234
  1662. package/src/memory/job-handlers/embedding.ts +0 -133
  1663. package/src/memory/job-handlers/index-maintenance.ts +0 -111
  1664. package/src/memory/job-handlers/media-processing.ts +0 -120
  1665. package/src/memory/job-handlers/summarization.ts +0 -240
  1666. package/src/memory/job-utils.ts +0 -286
  1667. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +0 -559
  1668. package/src/memory/jobs/embed-concept-page.ts +0 -417
  1669. package/src/memory/jobs/embed-pkb-file.test.ts +0 -169
  1670. package/src/memory/jobs/embed-pkb-file.ts +0 -59
  1671. package/src/memory/jobs-store.ts +0 -813
  1672. package/src/memory/jobs-worker.ts +0 -975
  1673. package/src/memory/llm-request-log-source-clickhouse.ts +0 -521
  1674. package/src/memory/llm-request-log-store.ts +0 -717
  1675. package/src/memory/llm-usage-store.ts +0 -900
  1676. package/src/memory/memory-recall-log-store.ts +0 -172
  1677. package/src/memory/memory-retrospective-constants.ts +0 -50
  1678. package/src/memory/memory-retrospective-enqueue.ts +0 -125
  1679. package/src/memory/memory-retrospective-fork-boundary.ts +0 -94
  1680. package/src/memory/memory-retrospective-job.ts +0 -879
  1681. package/src/memory/memory-retrospective-startup-cleanup.ts +0 -261
  1682. package/src/memory/memory-retrospective-state.ts +0 -245
  1683. package/src/memory/memory-retrospective-trigger-check.ts +0 -91
  1684. package/src/memory/memory-v2-activation-log-store.ts +0 -216
  1685. package/src/memory/memory-v2-concept-frequency.ts +0 -173
  1686. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +0 -303
  1687. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +0 -365
  1688. package/src/memory/migrations/142-rename-verification-session-id-column.ts +0 -55
  1689. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +0 -20
  1690. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +0 -179
  1691. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +0 -64
  1692. package/src/memory/migrations/202-memory-graph-tables.ts +0 -130
  1693. package/src/memory/migrations/203-drop-memory-items-tables.ts +0 -55
  1694. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +0 -124
  1695. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +0 -152
  1696. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +0 -16
  1697. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +0 -183
  1698. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +0 -76
  1699. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +0 -21
  1700. package/src/memory/migrations/243-provider-connections.ts +0 -68
  1701. package/src/memory/migrations/244-provider-connection-status-label.ts +0 -23
  1702. package/src/memory/migrations/246-backfill-provider-connection-label.ts +0 -81
  1703. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +0 -19
  1704. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  1705. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  1706. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +0 -84
  1707. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +0 -192
  1708. package/src/memory/migrations/__tests__/run-migrations.test.ts +0 -378
  1709. package/src/memory/migrations/helpers/relocation.ts +0 -227
  1710. package/src/memory/migrations/validate-migration-state.ts +0 -277
  1711. package/src/memory/onboarding-events-store.ts +0 -161
  1712. package/src/memory/pkb/autoinject.ts +0 -61
  1713. package/src/memory/pkb/context.ts +0 -50
  1714. package/src/memory/pkb/pkb-index.test.ts +0 -368
  1715. package/src/memory/pkb/pkb-index.ts +0 -255
  1716. package/src/memory/pkb/pkb-reconcile.test.ts +0 -251
  1717. package/src/memory/pkb/pkb-reconcile.ts +0 -148
  1718. package/src/memory/pkb/pkb-search.test.ts +0 -586
  1719. package/src/memory/pkb/pkb-search.ts +0 -178
  1720. package/src/memory/pkb/types.ts +0 -67
  1721. package/src/memory/published-pages-store.ts +0 -67
  1722. package/src/memory/qdrant-circuit-breaker.ts +0 -119
  1723. package/src/memory/qdrant-client.test.ts +0 -60
  1724. package/src/memory/qdrant-client.ts +0 -834
  1725. package/src/memory/qdrant-manager.ts +0 -422
  1726. package/src/memory/rerank-local.ts +0 -374
  1727. package/src/memory/schedule-attribution-sql.ts +0 -104
  1728. package/src/memory/schema/acp.ts +0 -34
  1729. package/src/memory/schema/contacts.ts +0 -116
  1730. package/src/memory/schema/conversations.ts +0 -197
  1731. package/src/memory/schema/infrastructure.ts +0 -381
  1732. package/src/memory/scoped-approval-grants.ts +0 -551
  1733. package/src/memory/search/semantic.ts +0 -238
  1734. package/src/memory/segmenter.ts +0 -76
  1735. package/src/memory/shared-app-links-store.ts +0 -130
  1736. package/src/memory/skill-loaded-events-store.test.ts +0 -152
  1737. package/src/memory/skill-loaded-events-store.ts +0 -95
  1738. package/src/memory/sparse-tokenize.ts +0 -49
  1739. package/src/memory/steps.ts +0 -573
  1740. package/src/memory/task-memory-cleanup.ts +0 -236
  1741. package/src/memory/tool-executed-events-store.test.ts +0 -219
  1742. package/src/memory/tool-executed-events-store.ts +0 -102
  1743. package/src/memory/tool-usage-store.ts +0 -113
  1744. package/src/memory/trace-event-store.ts +0 -133
  1745. package/src/memory/turn-events-store.ts +0 -173
  1746. package/src/memory/turn-trace-store.test.ts +0 -736
  1747. package/src/memory/turn-trace-store.ts +0 -364
  1748. package/src/memory/v2/__tests__/activation-store.test.ts +0 -204
  1749. package/src/memory/v2/__tests__/activation.test.ts +0 -1227
  1750. package/src/memory/v2/__tests__/backfill-jobs.test.ts +0 -504
  1751. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -429
  1752. package/src/memory/v2/__tests__/consolidation-job.test.ts +0 -747
  1753. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -189
  1754. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +0 -136
  1755. package/src/memory/v2/__tests__/harness-compare.test.ts +0 -186
  1756. package/src/memory/v2/__tests__/harness-oracle.test.ts +0 -257
  1757. package/src/memory/v2/__tests__/harness-replay-input.test.ts +0 -230
  1758. package/src/memory/v2/__tests__/harness-runner.test.ts +0 -135
  1759. package/src/memory/v2/__tests__/injection-events.test.ts +0 -318
  1760. package/src/memory/v2/__tests__/injection.test.ts +0 -2301
  1761. package/src/memory/v2/__tests__/migration.test.ts +0 -939
  1762. package/src/memory/v2/__tests__/page-index.test.ts +0 -760
  1763. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +0 -313
  1764. package/src/memory/v2/__tests__/qdrant.test.ts +0 -950
  1765. package/src/memory/v2/__tests__/reranker.test.ts +0 -338
  1766. package/src/memory/v2/__tests__/router.test.ts +0 -1197
  1767. package/src/memory/v2/__tests__/sim.test.ts +0 -670
  1768. package/src/memory/v2/__tests__/skill-content.test.ts +0 -115
  1769. package/src/memory/v2/__tests__/skill-store.test.ts +0 -983
  1770. package/src/memory/v2/__tests__/sparse-bm25.test.ts +0 -292
  1771. package/src/memory/v2/__tests__/static-context.test.ts +0 -223
  1772. package/src/memory/v2/__tests__/sweep-job.test.ts +0 -526
  1773. package/src/memory/v2/activation-store.ts +0 -185
  1774. package/src/memory/v2/activation.ts +0 -548
  1775. package/src/memory/v2/backfill-jobs.ts +0 -296
  1776. package/src/memory/v2/cli-command-store.ts +0 -341
  1777. package/src/memory/v2/consolidation-job.ts +0 -561
  1778. package/src/memory/v2/frontmatter-sweep.ts +0 -98
  1779. package/src/memory/v2/harness/compare.ts +0 -57
  1780. package/src/memory/v2/harness/oracle.ts +0 -145
  1781. package/src/memory/v2/harness/replay-input.ts +0 -240
  1782. package/src/memory/v2/harness/retriever.ts +0 -74
  1783. package/src/memory/v2/harness/router-retriever.ts +0 -43
  1784. package/src/memory/v2/injected-block-slugs.ts +0 -79
  1785. package/src/memory/v2/injection-events.ts +0 -101
  1786. package/src/memory/v2/injection.ts +0 -932
  1787. package/src/memory/v2/migration.ts +0 -776
  1788. package/src/memory/v2/page-index.ts +0 -459
  1789. package/src/memory/v2/page-store.ts +0 -443
  1790. package/src/memory/v2/prompts/consolidation.ts +0 -857
  1791. package/src/memory/v2/prompts/router.ts +0 -148
  1792. package/src/memory/v2/qdrant.ts +0 -892
  1793. package/src/memory/v2/reranker.ts +0 -184
  1794. package/src/memory/v2/router.ts +0 -601
  1795. package/src/memory/v2/sim.ts +0 -296
  1796. package/src/memory/v2/skill-content.ts +0 -61
  1797. package/src/memory/v2/skill-store.ts +0 -431
  1798. package/src/memory/v2/sparse-bm25.ts +0 -245
  1799. package/src/memory/v2/static-context.ts +0 -100
  1800. package/src/memory/v2/sweep-job.ts +0 -320
  1801. package/src/memory/v3-eval/eval-packets.ts +0 -731
  1802. package/src/memory/watchdog-events-store.ts +0 -87
  1803. package/src/memory/worker-control.ts +0 -118
  1804. package/src/memory/worker-process.ts +0 -72
  1805. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
  1806. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
  1807. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
  1808. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -314
  1809. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  1810. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  1811. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
  1812. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +0 -147
  1813. package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
  1814. package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
  1815. package/src/plugins/defaults/advisor/config.ts +0 -21
  1816. package/src/plugins/defaults/advisor/consult.ts +0 -197
  1817. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  1818. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
  1819. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
  1820. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
  1821. package/src/plugins/defaults/advisor/package.json +0 -14
  1822. package/src/plugins/defaults/advisor/steering.ts +0 -79
  1823. package/src/plugins/defaults/advisor/tools/advisor.ts +0 -92
  1824. package/src/plugins/defaults/advisor/transcript.ts +0 -76
  1825. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +0 -116
  1826. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +0 -370
  1827. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +0 -41
  1828. package/src/plugins/defaults/memory-retrieval/injectors.ts +0 -1061
  1829. package/src/plugins/defaults/memory-retrieval/package.json +0 -14
  1830. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +0 -64
  1831. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +0 -231
  1832. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +0 -1164
  1833. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +0 -181
  1834. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +0 -247
  1835. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +0 -717
  1836. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +0 -365
  1837. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +0 -736
  1838. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +0 -839
  1839. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +0 -598
  1840. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +0 -128
  1841. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +0 -469
  1842. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +0 -425
  1843. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +0 -493
  1844. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +0 -856
  1845. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +0 -91
  1846. package/src/plugins/defaults/memory-v3-shadow/card.ts +0 -160
  1847. package/src/plugins/defaults/memory-v3-shadow/dense.ts +0 -97
  1848. package/src/plugins/defaults/memory-v3-shadow/edge.ts +0 -252
  1849. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +0 -305
  1850. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +0 -278
  1851. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
  1852. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
  1853. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +0 -138
  1854. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +0 -85
  1855. package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -453
  1856. package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +0 -169
  1857. package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +0 -178
  1858. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +0 -794
  1859. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +0 -431
  1860. package/src/plugins/defaults/memory-v3-shadow/package.json +0 -14
  1861. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +0 -102
  1862. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  1863. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +0 -578
  1864. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +0 -758
  1865. package/src/plugins/defaults/memory-v3-shadow/prune.ts +0 -471
  1866. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +0 -92
  1867. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +0 -269
  1868. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +0 -200
  1869. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +0 -281
  1870. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +0 -642
  1871. package/src/plugins/defaults/memory-v3-shadow/types.ts +0 -127
  1872. package/src/plugins/feature-gate.ts +0 -22
  1873. package/src/runtime/__tests__/slack-block-formatting.test.ts +0 -510
  1874. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +0 -165
  1875. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +0 -347
  1876. package/src/runtime/routes/memory-eval-routes.ts +0 -179
  1877. package/src/runtime/routes/memory-item-routes.test.ts +0 -912
  1878. package/src/runtime/routes/memory-item-routes.ts +0 -815
  1879. package/src/runtime/routes/memory-v2-routes.ts +0 -850
  1880. package/src/runtime/routes/memory-v3-routes.ts +0 -122
  1881. package/src/runtime/routes/secrets-deps.ts +0 -24
  1882. package/src/runtime/slack-block-formatting.ts +0 -601
  1883. package/src/tools/memory/register.test.ts +0 -382
  1884. package/src/tools/memory/register.ts +0 -81
  1885. /package/src/{memory → apps}/app-git-service.ts +0 -0
  1886. /package/src/{memory → channels}/slack-thread-store.ts +0 -0
  1887. /package/src/{memory → home}/conversation-starter-validation.ts +0 -0
  1888. /package/src/{memory → persistence}/auto-analysis-constants.ts +0 -0
  1889. /package/src/{memory → persistence}/bookmark-crud.ts +0 -0
  1890. /package/src/{memory → persistence}/cleanup-schedule-state.ts +0 -0
  1891. /package/src/{memory → persistence}/compaction-log-store-clickhouse.ts +0 -0
  1892. /package/src/{memory → persistence}/conversation-directories.ts +0 -0
  1893. /package/src/{memory → persistence}/conversation-disk-view.ts +0 -0
  1894. /package/src/{memory → persistence}/conversation-display-order-migration.ts +0 -0
  1895. /package/src/{memory → persistence}/conversation-group-migration.ts +0 -0
  1896. /package/src/{memory → persistence}/conversation-types.ts +0 -0
  1897. /package/src/{memory → persistence}/db-singleton.ts +0 -0
  1898. /package/src/{memory → persistence}/delivery-channels.ts +0 -0
  1899. /package/src/{memory → persistence}/delivery-crud.ts +0 -0
  1900. /package/src/{memory → persistence}/delivery-status.ts +0 -0
  1901. /package/src/{memory → persistence/embeddings}/__tests__/sparse-tokenize.test.ts +0 -0
  1902. /package/src/{memory → persistence/embeddings}/embedding-gemini.test.ts +0 -0
  1903. /package/src/{memory → persistence/embeddings}/embedding-gemini.ts +0 -0
  1904. /package/src/{memory → persistence/embeddings}/embedding-openai.ts +0 -0
  1905. /package/src/{memory → persistence/embeddings}/embedding-types.test.ts +0 -0
  1906. /package/src/{memory → persistence}/fingerprint.ts +0 -0
  1907. /package/src/{memory → persistence}/group-crud.ts +0 -0
  1908. /package/src/{memory → persistence}/invite-store.ts +0 -0
  1909. /package/src/{memory → persistence}/lifecycle-events-store.ts +0 -0
  1910. /package/src/{memory → persistence}/llm-request-log-source-local.ts +0 -0
  1911. /package/src/{memory → persistence}/llm-request-log-source.ts +0 -0
  1912. /package/src/{memory → persistence}/media-store.ts +0 -0
  1913. /package/src/{memory → persistence}/message-content.ts +0 -0
  1914. /package/src/{memory → persistence}/migrations/000-core-tables.ts +0 -0
  1915. /package/src/{memory → persistence}/migrations/001-job-deferrals.ts +0 -0
  1916. /package/src/{memory → persistence}/migrations/002-tool-invocations-fk.ts +0 -0
  1917. /package/src/{memory → persistence}/migrations/003-memory-fts-backfill.ts +0 -0
  1918. /package/src/{memory → persistence}/migrations/004-entity-relation-dedup.ts +0 -0
  1919. /package/src/{memory → persistence}/migrations/005-fingerprint-scope-unique.ts +0 -0
  1920. /package/src/{memory → persistence}/migrations/006-scope-salted-fingerprints.ts +0 -0
  1921. /package/src/{memory → persistence}/migrations/007-assistant-id-to-self.ts +0 -0
  1922. /package/src/{memory → persistence}/migrations/008-remove-assistant-id-columns.ts +0 -0
  1923. /package/src/{memory → persistence}/migrations/009-llm-usage-events-drop-assistant-id.ts +0 -0
  1924. /package/src/{memory → persistence}/migrations/011-call-sessions-provider-sid-dedup.ts +0 -0
  1925. /package/src/{memory → persistence}/migrations/012-call-sessions-add-initiated-from.ts +0 -0
  1926. /package/src/{memory → persistence}/migrations/013-guardian-action-tables.ts +0 -0
  1927. /package/src/{memory → persistence}/migrations/014-backfill-inbox-thread-state.ts +0 -0
  1928. /package/src/{memory → persistence}/migrations/015-drop-active-search-index.ts +0 -0
  1929. /package/src/{memory → persistence}/migrations/016-memory-segments-indexes.ts +0 -0
  1930. /package/src/{memory → persistence}/migrations/017-memory-items-indexes.ts +0 -0
  1931. /package/src/{memory → persistence}/migrations/018-remaining-table-indexes.ts +0 -0
  1932. /package/src/{memory → persistence}/migrations/019-notification-tables-schema-migration.ts +0 -0
  1933. /package/src/{memory → persistence}/migrations/020-rename-macos-ios-channel-to-vellum.ts +0 -0
  1934. /package/src/{memory → persistence}/migrations/021-conversation-status-indexes.ts +0 -0
  1935. /package/src/{memory → persistence}/migrations/022-add-origin-interface.ts +0 -0
  1936. /package/src/{memory → persistence}/migrations/023-memory-item-sources-indexes.ts +0 -0
  1937. /package/src/{memory → persistence}/migrations/024-embedding-vector-blob.ts +0 -0
  1938. /package/src/{memory → persistence}/migrations/025-messages-fts-backfill.ts +0 -0
  1939. /package/src/{memory → persistence}/migrations/026-guardian-verification-sessions.ts +0 -0
  1940. /package/src/{memory → persistence}/migrations/026a-embeddings-nullable-vector-json.ts +0 -0
  1941. /package/src/{memory → persistence}/migrations/027-notification-delivery-pairing-columns.ts +0 -0
  1942. /package/src/{memory → persistence}/migrations/027a-guardian-bootstrap-token.ts +0 -0
  1943. /package/src/{memory → persistence}/migrations/028-call-session-mode.ts +0 -0
  1944. /package/src/{memory → persistence}/migrations/028-notification-delivery-client-ack.ts +0 -0
  1945. /package/src/{memory → persistence}/migrations/029-channel-inbound-delivered-segments.ts +0 -0
  1946. /package/src/{memory → persistence}/migrations/030-guardian-action-followup.ts +0 -0
  1947. /package/src/{memory → persistence}/migrations/030-guardian-verification-purpose.ts +0 -0
  1948. /package/src/{memory → persistence}/migrations/031-conversations-thread-type-index.ts +0 -0
  1949. /package/src/{memory → persistence}/migrations/032-guardian-delivery-conversation-index.ts +0 -0
  1950. /package/src/{memory → persistence}/migrations/032-notification-delivery-thread-decision.ts +0 -0
  1951. /package/src/{memory → persistence}/migrations/033-scoped-approval-grants.ts +0 -0
  1952. /package/src/{memory → persistence}/migrations/034-guardian-action-tool-metadata.ts +0 -0
  1953. /package/src/{memory → persistence}/migrations/035-guardian-action-supersession.ts +0 -0
  1954. /package/src/{memory → persistence}/migrations/036-normalize-phone-identities.ts +0 -0
  1955. /package/src/{memory → persistence}/migrations/037-voice-invite-columns.ts +0 -0
  1956. /package/src/{memory → persistence}/migrations/040-invite-code-hash-column.ts +0 -0
  1957. /package/src/{memory → persistence}/migrations/041-approval-prompt-ts-tracker.ts +0 -0
  1958. /package/src/{memory → persistence}/migrations/101-watchers-and-logs.ts +0 -0
  1959. /package/src/{memory → persistence}/migrations/102-alter-table-columns.ts +0 -0
  1960. /package/src/{memory → persistence}/migrations/104-core-indexes.ts +0 -0
  1961. /package/src/{memory → persistence}/migrations/105-contacts-and-triage.ts +0 -0
  1962. /package/src/{memory → persistence}/migrations/106-call-sessions.ts +0 -0
  1963. /package/src/{memory → persistence}/migrations/107-followups.ts +0 -0
  1964. /package/src/{memory → persistence}/migrations/108-tasks-and-work-items.ts +0 -0
  1965. /package/src/{memory → persistence}/migrations/109-external-conversation-bindings.ts +0 -0
  1966. /package/src/{memory → persistence}/migrations/110-channel-guardian.ts +0 -0
  1967. /package/src/{memory → persistence}/migrations/111-media-assets.ts +0 -0
  1968. /package/src/{memory → persistence}/migrations/112-assistant-inbox.ts +0 -0
  1969. /package/src/{memory → persistence}/migrations/114-notifications.ts +0 -0
  1970. /package/src/{memory → persistence}/migrations/115-sequences.ts +0 -0
  1971. /package/src/{memory → persistence}/migrations/116-messages-fts.ts +0 -0
  1972. /package/src/{memory → persistence}/migrations/117-conversation-attention.ts +0 -0
  1973. /package/src/{memory → persistence}/migrations/118-reminder-routing-intent.ts +0 -0
  1974. /package/src/{memory → persistence}/migrations/119-schema-indexes-and-columns.ts +0 -0
  1975. /package/src/{memory → persistence}/migrations/120-fk-cascade-rebuilds.ts +0 -0
  1976. /package/src/{memory → persistence}/migrations/121-canonical-guardian-requests.ts +0 -0
  1977. /package/src/{memory → persistence}/migrations/122-canonical-guardian-requester-chat-id.ts +0 -0
  1978. /package/src/{memory → persistence}/migrations/123-canonical-guardian-deliveries-destination-index.ts +0 -0
  1979. /package/src/{memory → persistence}/migrations/124-voice-invite-display-metadata.ts +0 -0
  1980. /package/src/{memory → persistence}/migrations/125-guardian-principal-id-columns.ts +0 -0
  1981. /package/src/{memory → persistence}/migrations/127-guardian-principal-id-not-null.ts +0 -0
  1982. /package/src/{memory → persistence}/migrations/128-contacts-role-principal.ts +0 -0
  1983. /package/src/{memory → persistence}/migrations/129-contact-channels-access-fields.ts +0 -0
  1984. /package/src/{memory → persistence}/migrations/130-contact-channels-type-ext-chat-id-index.ts +0 -0
  1985. /package/src/{memory → persistence}/migrations/131-drop-legacy-member-guardian-tables.ts +0 -0
  1986. /package/src/{memory → persistence}/migrations/132-contacts-assistant-id.ts +0 -0
  1987. /package/src/{memory → persistence}/migrations/133-assistant-contact-metadata.ts +0 -0
  1988. /package/src/{memory → persistence}/migrations/134-contacts-notes-column.ts +0 -0
  1989. /package/src/{memory → persistence}/migrations/135-backfill-contact-interaction-stats.ts +0 -0
  1990. /package/src/{memory → persistence}/migrations/136-drop-assistant-id-columns.ts +0 -0
  1991. /package/src/{memory → persistence}/migrations/137-usage-dashboard-indexes.ts +0 -0
  1992. /package/src/{memory → persistence}/migrations/139-drop-usage-composite-indexes.ts +0 -0
  1993. /package/src/{memory → persistence}/migrations/141-rename-verification-table.ts +0 -0
  1994. /package/src/{memory → persistence}/migrations/143-rename-guardian-verification-values.ts +0 -0
  1995. /package/src/{memory → persistence}/migrations/144-rename-voice-to-phone.ts +0 -0
  1996. /package/src/{memory → persistence}/migrations/145-drop-accounts-table.ts +0 -0
  1997. /package/src/{memory → persistence}/migrations/146-schedule-oneshot-routing.ts +0 -0
  1998. /package/src/{memory → persistence}/migrations/147-migrate-reminders-to-schedules.ts +0 -0
  1999. /package/src/{memory → persistence}/migrations/148-drop-reminders-table.ts +0 -0
  2000. /package/src/{memory → persistence}/migrations/149-oauth-tables.ts +0 -0
  2001. /package/src/{memory → persistence}/migrations/150-oauth-apps-client-secret-path.ts +0 -0
  2002. /package/src/{memory → persistence}/migrations/151-oauth-providers-ping-url.ts +0 -0
  2003. /package/src/{memory → persistence}/migrations/152-memory-item-supersession.ts +0 -0
  2004. /package/src/{memory → persistence}/migrations/153-drop-entity-tables.ts +0 -0
  2005. /package/src/{memory → persistence}/migrations/154-drop-fts.ts +0 -0
  2006. /package/src/{memory → persistence}/migrations/155-drop-conflicts.ts +0 -0
  2007. /package/src/{memory → persistence}/migrations/156-call-session-invite-metadata.ts +0 -0
  2008. /package/src/{memory → persistence}/migrations/157-invite-contact-id.ts +0 -0
  2009. /package/src/{memory → persistence}/migrations/158-channel-interaction-columns.ts +0 -0
  2010. /package/src/{memory → persistence}/migrations/159-drop-contact-interaction-columns.ts +0 -0
  2011. /package/src/{memory → persistence}/migrations/160-drop-loopback-port-column.ts +0 -0
  2012. /package/src/{memory → persistence}/migrations/161-drop-orphaned-media-tables.ts +0 -0
  2013. /package/src/{memory → persistence}/migrations/162-guardian-timestamps-epoch-ms.ts +0 -0
  2014. /package/src/{memory → persistence}/migrations/163-rename-notification-thread-columns.ts +0 -0
  2015. /package/src/{memory → persistence}/migrations/164-rename-conversation-type-column.ts +0 -0
  2016. /package/src/{memory → persistence}/migrations/165-rename-inbox-thread-state-table.ts +0 -0
  2017. /package/src/{memory → persistence}/migrations/166-rename-followups-thread-id.ts +0 -0
  2018. /package/src/{memory → persistence}/migrations/167-rename-sequence-enrollments-thread-id.ts +0 -0
  2019. /package/src/{memory → persistence}/migrations/168-rename-sequence-steps-reply-key.ts +0 -0
  2020. /package/src/{memory → persistence}/migrations/169-rename-gmail-provider-key-to-google.ts +0 -0
  2021. /package/src/{memory → persistence}/migrations/170-thread-starters-table.ts +0 -0
  2022. /package/src/{memory → persistence}/migrations/171-capability-card-columns.ts +0 -0
  2023. /package/src/{memory → persistence}/migrations/172-rename-created-by-session-id.ts +0 -0
  2024. /package/src/{memory → persistence}/migrations/173-rename-source-session-id.ts +0 -0
  2025. /package/src/{memory → persistence}/migrations/174-rename-thread-starters-table.ts +0 -0
  2026. /package/src/{memory → persistence}/migrations/175-create-lifecycle-events.ts +0 -0
  2027. /package/src/{memory → persistence}/migrations/176-drop-capability-card-state.ts +0 -0
  2028. /package/src/{memory → persistence}/migrations/177-create-trace-events-table.ts +0 -0
  2029. /package/src/{memory → persistence}/migrations/178-oauth-providers-managed-service-config-key.ts +0 -0
  2030. /package/src/{memory → persistence}/migrations/179-llm-request-log-message-id.ts +0 -0
  2031. /package/src/{memory → persistence}/migrations/180-backfill-inline-attachments-to-disk.ts +0 -0
  2032. /package/src/{memory → persistence}/migrations/181-rename-thread-starters-checkpoints.ts +0 -0
  2033. /package/src/{memory → persistence}/migrations/183-add-conversation-fork-lineage.ts +0 -0
  2034. /package/src/{memory → persistence}/migrations/184-llm-request-log-provider.ts +0 -0
  2035. /package/src/{memory → persistence}/migrations/188-schedule-quiet-flag.ts +0 -0
  2036. /package/src/{memory → persistence}/migrations/189-drop-simplified-memory.ts +0 -0
  2037. /package/src/{memory → persistence}/migrations/190-call-session-skip-disclosure.ts +0 -0
  2038. /package/src/{memory → persistence}/migrations/191-backfill-audio-attachment-mime-types.ts +0 -0
  2039. /package/src/{memory → persistence}/migrations/192-contacts-user-file-column.ts +0 -0
  2040. /package/src/{memory → persistence}/migrations/193-add-source-type-columns.ts +0 -0
  2041. /package/src/{memory → persistence}/migrations/194-memory-recall-logs.ts +0 -0
  2042. /package/src/{memory → persistence}/migrations/195-oauth-providers-ping-config.ts +0 -0
  2043. /package/src/{memory → persistence}/migrations/196-messages-conversation-created-at-index.ts +0 -0
  2044. /package/src/{memory → persistence}/migrations/197-oauth-providers-behavior-columns.ts +0 -0
  2045. /package/src/{memory → persistence}/migrations/198-drop-setup-skill-id-column.ts +0 -0
  2046. /package/src/{memory → persistence}/migrations/200-usage-llm-call-count.ts +0 -0
  2047. /package/src/{memory → persistence}/migrations/201-oauth-providers-feature-flag.ts +0 -0
  2048. /package/src/{memory → persistence}/migrations/202-drop-callback-transport-column.ts +0 -0
  2049. /package/src/{memory → persistence}/migrations/204-rename-memory-graph-type-values.ts +0 -0
  2050. /package/src/{memory → persistence}/migrations/205-memory-graph-image-refs.ts +0 -0
  2051. /package/src/{memory → persistence}/migrations/206-memory-graph-node-edits.ts +0 -0
  2052. /package/src/{memory → persistence}/migrations/207-conversation-graph-memory-state.ts +0 -0
  2053. /package/src/{memory → persistence}/migrations/208-conversations-last-message-at.ts +0 -0
  2054. /package/src/{memory → persistence}/migrations/210-schedule-reuse-conversation.ts +0 -0
  2055. /package/src/{memory → persistence}/migrations/212-llm-request-logs-created-at-index.ts +0 -0
  2056. /package/src/{memory → persistence}/migrations/213-oauth-providers-scope-separator.ts +0 -0
  2057. /package/src/{memory → persistence}/migrations/214-oauth-providers-refresh-url.ts +0 -0
  2058. /package/src/{memory → persistence}/migrations/215-oauth-providers-revoke.ts +0 -0
  2059. /package/src/{memory → persistence}/migrations/216-oauth-providers-token-auth-method.ts +0 -0
  2060. /package/src/{memory → persistence}/migrations/217-conversation-host-access.ts +0 -0
  2061. /package/src/{memory → persistence}/migrations/218-oauth-providers-logo-url.ts +0 -0
  2062. /package/src/{memory → persistence}/migrations/219-oauth-providers-token-exchange-body-format.ts +0 -0
  2063. /package/src/{memory → persistence}/migrations/221-conversations-archived-at.ts +0 -0
  2064. /package/src/{memory → persistence}/migrations/223-schedule-script-column.ts +0 -0
  2065. /package/src/{memory → persistence}/migrations/224-oauth-providers-managed-service-is-paid.ts +0 -0
  2066. /package/src/{memory → persistence}/migrations/225-oauth-providers-available-scopes.ts +0 -0
  2067. /package/src/{memory → persistence}/migrations/226-schedule-wake-conversation-id.ts +0 -0
  2068. /package/src/{memory → persistence}/migrations/227-add-conversation-inference-profile.ts +0 -0
  2069. /package/src/{memory → persistence}/migrations/228-rename-inference-profile-snake-case.ts +0 -0
  2070. /package/src/{memory → persistence}/migrations/229-delete-private-conversations.test.ts +0 -0
  2071. /package/src/{memory → persistence}/migrations/229-delete-private-conversations.ts +0 -0
  2072. /package/src/{memory → persistence}/migrations/230-acp-session-history.ts +0 -0
  2073. /package/src/{memory → persistence}/migrations/231-repair-memory-graph-event-dates.ts +0 -0
  2074. /package/src/{memory → persistence}/migrations/232-activation-state.ts +0 -0
  2075. /package/src/{memory → persistence}/migrations/233-document-conversations.ts +0 -0
  2076. /package/src/{memory → persistence}/migrations/234-memory-v2-activation-logs.ts +0 -0
  2077. /package/src/{memory → persistence}/migrations/235-llm-usage-attribution.ts +0 -0
  2078. /package/src/{memory → persistence}/migrations/235-slack-compaction-watermark.ts +0 -0
  2079. /package/src/{memory → persistence}/migrations/237-heartbeat-runs.ts +0 -0
  2080. /package/src/{memory → persistence}/migrations/238-schedule-retry-policy.ts +0 -0
  2081. /package/src/{memory → persistence}/migrations/239-trace-events-created-at-index.ts +0 -0
  2082. /package/src/{memory → persistence}/migrations/240-conversation-inference-profile-session.ts +0 -0
  2083. /package/src/{memory → persistence}/migrations/241-activation-state-fk-cascade.ts +0 -0
  2084. /package/src/{memory → persistence}/migrations/242-message-bookmarks.ts +0 -0
  2085. /package/src/{memory → persistence}/migrations/245-memory-retrospective-state.ts +0 -0
  2086. /package/src/{memory → persistence}/migrations/247-external-conversation-binding-thread-id.ts +0 -0
  2087. /package/src/{memory → persistence}/migrations/248-create-onboarding-events.ts +0 -0
  2088. /package/src/{memory → persistence}/migrations/249-normalize-slack-external-content.ts +0 -0
  2089. /package/src/{memory → persistence}/migrations/250-provider-connection-base-url-and-models.ts +0 -0
  2090. /package/src/{memory → persistence}/migrations/251-a2a-tasks.ts +0 -0
  2091. /package/src/{memory → persistence}/migrations/252-llm-request-log-agent-loop-exit-reason.ts +0 -0
  2092. /package/src/{memory → persistence}/migrations/253-conversation-last-notified-profile.ts +0 -0
  2093. /package/src/{memory → persistence}/migrations/253-document-comments.ts +0 -0
  2094. /package/src/{memory → persistence}/migrations/254-external-conversation-binding-chat-name.ts +0 -0
  2095. /package/src/{memory → persistence}/migrations/256-memory-v2-injection-events.ts +0 -0
  2096. /package/src/{memory → persistence}/migrations/257-strip-base-url-non-openai-compatible.ts +0 -0
  2097. /package/src/{memory → persistence}/migrations/258-onboarding-events-prior-assistants.ts +0 -0
  2098. /package/src/{memory → persistence}/migrations/259-conversation-cleaned-at.ts +0 -0
  2099. /package/src/{memory → persistence}/migrations/260-rename-cleaned-at.ts +0 -0
  2100. /package/src/{memory → persistence}/migrations/261-llm-usage-add-raw-usage.ts +0 -0
  2101. /package/src/{memory → persistence}/migrations/262-memory-v3-coactivation.ts +0 -0
  2102. /package/src/{memory → persistence}/migrations/263-memory-v3-auto-edges.ts +0 -0
  2103. /package/src/{memory → persistence}/migrations/264-llm-request-log-call-site.ts +0 -0
  2104. /package/src/{memory → persistence}/migrations/265-drop-provider-connection-status.ts +0 -0
  2105. /package/src/{memory → persistence}/migrations/266-messages-client-message-id.ts +0 -0
  2106. /package/src/{memory → persistence}/migrations/267-llm-usage-events-add-assistant-version.ts +0 -0
  2107. /package/src/{memory → persistence}/migrations/268-add-memory-v3-selections.ts +0 -0
  2108. /package/src/{memory → persistence}/migrations/269-schedule-script-timeout.ts +0 -0
  2109. /package/src/{memory → persistence}/migrations/270-messages-role-created-at-index.ts +0 -0
  2110. /package/src/{memory → persistence}/migrations/270-schedule-description.ts +0 -0
  2111. /package/src/{memory → persistence}/migrations/270-schedule-source-conversation.ts +0 -0
  2112. /package/src/{memory → persistence}/migrations/271-create-auth-fallback-events.ts +0 -0
  2113. /package/src/{memory → persistence}/migrations/272-acp-session-history-cwd.ts +0 -0
  2114. /package/src/{memory → persistence}/migrations/273-onboarding-events-funnel-columns.ts +0 -0
  2115. /package/src/{memory → persistence}/migrations/274-create-activation-sessions.ts +0 -0
  2116. /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.test.ts +0 -0
  2117. /package/src/{memory → persistence}/migrations/275-tool-invocations-add-skill-id.ts +0 -0
  2118. /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.test.ts +0 -0
  2119. /package/src/{memory → persistence}/migrations/276-tool-invocations-created-at-id-index.ts +0 -0
  2120. /package/src/{memory → persistence}/migrations/277-add-memory-v3-ever-injected.ts +0 -0
  2121. /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.test.ts +0 -0
  2122. /package/src/{memory → persistence}/migrations/278-tool-invocations-telemetry-columns.ts +0 -0
  2123. /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.test.ts +0 -0
  2124. /package/src/{memory → persistence}/migrations/279-create-skill-loaded-events.ts +0 -0
  2125. /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.test.ts +0 -0
  2126. /package/src/{memory → persistence}/migrations/280-conversations-surfaced-at.ts +0 -0
  2127. /package/src/{memory → persistence}/migrations/281-memory-retrospective-remembered-log.ts +0 -0
  2128. /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.test.ts +0 -0
  2129. /package/src/{memory → persistence}/migrations/282-schedule-inference-profile.ts +0 -0
  2130. /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +0 -0
  2131. /package/src/{memory → persistence}/migrations/283-memory-v3-selections-message-id-and-sections.ts +0 -0
  2132. /package/src/{memory → persistence}/migrations/284-workflow-runs.ts +0 -0
  2133. /package/src/{memory → persistence}/migrations/285-schedule-workflow-mode.ts +0 -0
  2134. /package/src/{memory → persistence}/migrations/286-workflow-run-trust.ts +0 -0
  2135. /package/src/{memory → persistence}/migrations/287-conversation-origin-channel-index.ts +0 -0
  2136. /package/src/{memory → persistence}/migrations/288-backfill-origin-channel-from-bindings.ts +0 -0
  2137. /package/src/{memory → persistence}/migrations/289-contact-channels-unique-ext-user.ts +0 -0
  2138. /package/src/{memory → persistence}/migrations/290-schedule-capabilities.test.ts +0 -0
  2139. /package/src/{memory → persistence}/migrations/290-schedule-capabilities.ts +0 -0
  2140. /package/src/{memory → persistence}/migrations/291-contact-channels-renormalize-addresses.ts +0 -0
  2141. /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.test.ts +0 -0
  2142. /package/src/{memory → persistence}/migrations/292-schedule-default-no-reuse-conversation.ts +0 -0
  2143. /package/src/{memory → persistence}/migrations/293-workflow-journal-leaf-tokens.ts +0 -0
  2144. /package/src/{memory → persistence}/migrations/294-drop-external-user-id.ts +0 -0
  2145. /package/src/{memory → persistence}/migrations/295-drop-approval-prompt-ts-tracker.ts +0 -0
  2146. /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +0 -0
  2147. /package/src/{memory → persistence}/migrations/296-rewrite-balanced-economy-profile-pins.ts +0 -0
  2148. /package/src/{memory → persistence}/migrations/297-move-llm-request-logs-to-logs-db.ts +0 -0
  2149. /package/src/{memory → persistence}/migrations/298-move-memory-jobs-to-memory-db.ts +0 -0
  2150. /package/src/{memory → persistence}/migrations/299-canonical-guardian-deliveries-conversation-index.ts +0 -0
  2151. /package/src/{memory → persistence}/migrations/300-add-processing-started-at.ts +0 -0
  2152. /package/src/{memory → persistence}/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +0 -0
  2153. /package/src/{memory → persistence}/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +0 -0
  2154. /package/src/{memory → persistence}/migrations/__tests__/136-drop-assistant-id-columns.test.ts +0 -0
  2155. /package/src/{memory → persistence}/migrations/__tests__/234-memory-v2-activation-logs.test.ts +0 -0
  2156. /package/src/{memory → persistence}/migrations/__tests__/245-memory-retrospective-state.test.ts +0 -0
  2157. /package/src/{memory → persistence}/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +0 -0
  2158. /package/src/{memory → persistence}/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +0 -0
  2159. /package/src/{memory → persistence}/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +0 -0
  2160. /package/src/{memory → persistence}/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +0 -0
  2161. /package/src/{memory → persistence}/migrations/__tests__/297-move-llm-request-logs.test.ts +0 -0
  2162. /package/src/{memory → persistence}/migrations/run-migrations.ts +0 -0
  2163. /package/src/{memory → persistence}/migrations/schema-introspection.ts +0 -0
  2164. /package/src/{memory → persistence}/raw-query.ts +0 -0
  2165. /package/src/{memory → persistence}/schema/a2a.ts +0 -0
  2166. /package/src/{memory → persistence}/schema/bookmarks.ts +0 -0
  2167. /package/src/{memory → persistence}/schema/calls.ts +0 -0
  2168. /package/src/{memory → persistence}/schema/guardian.ts +0 -0
  2169. /package/src/{memory → persistence}/schema/index.ts +0 -0
  2170. /package/src/{memory → persistence}/schema/inference.ts +0 -0
  2171. /package/src/{memory → persistence}/schema/memory-core.ts +0 -0
  2172. /package/src/{memory → persistence}/schema/memory-graph.ts +0 -0
  2173. /package/src/{memory → persistence}/schema/notifications.ts +0 -0
  2174. /package/src/{memory → persistence}/schema/oauth.ts +0 -0
  2175. /package/src/{memory → persistence}/schema/tasks.ts +0 -0
  2176. /package/src/{memory → persistence}/schema.ts +0 -0
  2177. /package/src/{memory → persistence}/usage-buckets.ts +0 -0
  2178. /package/src/{memory → persistence}/usage-grouped-buckets.ts +0 -0
  2179. /package/src/{memory → plugins/defaults/memory}/__tests__/fixtures/memory-v2-activation-fixtures.ts +0 -0
  2180. /package/src/{memory → plugins/defaults/memory}/__tests__/memory-retrospective-trigger-check.test.ts +0 -0
  2181. /package/src/{memory → plugins/defaults/memory}/anisotropy.test.ts +0 -0
  2182. /package/src/{memory → plugins/defaults/memory}/context-search/__tests__/agent-runner-redaction.test.ts +0 -0
  2183. /package/src/{memory → plugins/defaults/memory}/context-search/format.ts +0 -0
  2184. /package/src/{memory → plugins/defaults/memory}/context-search/limits.ts +0 -0
  2185. /package/src/{memory → plugins/defaults/memory}/context-search/sources/workspace.ts +0 -0
  2186. /package/src/{memory → plugins/defaults/memory}/graph/decay.test.ts +0 -0
  2187. /package/src/{memory → plugins/defaults/memory}/graph/extraction.test.ts +0 -0
  2188. /package/src/{memory → plugins/defaults/memory}/graph/injection.test.ts +0 -0
  2189. /package/src/{memory → plugins/defaults/memory}/graph/scoring.test.ts +0 -0
  2190. /package/src/{memory → plugins/defaults/memory}/graph/scoring.ts +0 -0
  2191. /package/src/{memory → plugins/defaults/memory}/graph/serendipity.ts +0 -0
  2192. /package/src/{memory → plugins/defaults/memory}/graph/triggers.test.ts +0 -0
  2193. /package/src/{memory → plugins/defaults/memory}/graph/triggers.ts +0 -0
  2194. /package/src/{memory → plugins/defaults/memory}/graph/types.ts +0 -0
  2195. /package/src/plugins/defaults/{memory-retrieval → memory}/hooks/__tests__/user-prompt-submit.test.ts +0 -0
  2196. /package/src/{memory → plugins/defaults/memory}/memory-marker.ts +0 -0
  2197. /package/src/{memory → plugins/defaults/memory}/prompt-override.ts +0 -0
  2198. /package/src/{memory → plugins/defaults/memory}/retrieval-budget.ts +0 -0
  2199. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +0 -0
  2200. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  2201. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/edge-index.test.ts +0 -0
  2202. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/harness-metrics.test.ts +0 -0
  2203. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/injected-block-slugs.test.ts +0 -0
  2204. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/page-store.test.ts +0 -0
  2205. /package/src/{memory → plugins/defaults/memory}/v2/__tests__/prompts-router.test.ts +0 -0
  2206. /package/src/{memory → plugins/defaults/memory}/v2/cli-command-content.ts +0 -0
  2207. /package/src/{memory → plugins/defaults/memory}/v2/constants.ts +0 -0
  2208. /package/src/{memory → plugins/defaults/memory}/v2/edge-index.ts +0 -0
  2209. /package/src/{memory → plugins/defaults/memory}/v2/harness/metrics.ts +0 -0
  2210. /package/src/{memory → plugins/defaults/memory}/v2/harness/runner.ts +0 -0
  2211. /package/src/{memory → plugins/defaults/memory}/v2/harness/trace.ts +0 -0
  2212. /package/src/{memory → plugins/defaults/memory}/v2/now-text.ts +0 -0
  2213. /package/src/{memory → plugins/defaults/memory}/v2/prompts/sweep.ts +0 -0
  2214. /package/src/{memory → plugins/defaults/memory}/v2/types.ts +0 -0
  2215. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
  2216. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/card.test.ts +0 -0
  2217. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/fresh-set.test.ts +0 -0
  2218. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/section-needle.test.ts +0 -0
  2219. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/sections.test.ts +0 -0
  2220. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
  2221. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/card.test.ts +0 -0
  2222. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.test.ts +0 -0
  2223. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/core-set.ts +0 -0
  2224. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/README.md +0 -0
  2225. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
  2226. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/core.json +0 -0
  2227. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
  2228. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
  2229. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
  2230. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/fresh-set.ts +0 -0
  2231. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
  2232. /package/src/plugins/defaults/{memory-v3-shadow → memory/v3}/sections.ts +0 -0
  2233. /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-packets.test.ts +0 -0
  2234. /package/src/{memory → plugins/defaults/memory}/v3-eval/__tests__/eval-tally.test.ts +0 -0
  2235. /package/src/{memory → plugins/defaults/memory}/v3-eval/eval-tally.ts +0 -0
  2236. /package/src/{memory → plugins/defaults/memory}/validation.ts +0 -0
@@ -1,3361 +0,0 @@
1
- import { mkdirSync, rmSync } from "node:fs";
2
-
3
- import {
4
- and,
5
- asc,
6
- count,
7
- desc,
8
- eq,
9
- gt,
10
- gte,
11
- inArray,
12
- isNotNull,
13
- isNull,
14
- like,
15
- lt,
16
- lte,
17
- or,
18
- sql,
19
- } from "drizzle-orm";
20
- import { v4 as uuid } from "uuid";
21
- import { z } from "zod";
22
-
23
- import type { ChannelId, InterfaceId } from "../channels/types.js";
24
- import { parseChannelId, parseInterfaceId } from "../channels/types.js";
25
- import { CHANNEL_IDS, isChannelId } from "../channels/types.js";
26
- import { getConfig } from "../config/loader.js";
27
- import { findDisplayTurnEndIndex } from "../conversations/message-consolidation.js";
28
- import { findConversation } from "../daemon/conversation-registry.js";
29
- import { conversationMetadataSyncTag } from "../daemon/message-types/sync.js";
30
- import type { TrustContext } from "../daemon/trust-context.js";
31
- import { clearAllConversationIds } from "../home/feed-writer.js";
32
- import {
33
- forkEverInjected,
34
- MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
35
- seedEverInjectedFromSlugs,
36
- } from "../plugins/defaults/memory-v3-shadow/ever-injected-store.js";
37
- import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
38
- import { UserError } from "../util/errors.js";
39
- import { safeParseRecord } from "../util/json.js";
40
- import { getLogger } from "../util/logger.js";
41
- import { getConversationsDir } from "../util/platform.js";
42
- import { createRowMapper } from "../util/row-mapper.js";
43
- import {
44
- deleteOrphanAttachments,
45
- linkAttachmentToMessage,
46
- } from "./attachments-store.js";
47
- import { AUTO_ANALYSIS_SOURCE } from "./auto-analysis-constants.js";
48
- import {
49
- projectAssistantMessage,
50
- seedForkedConversationAttention,
51
- } from "./conversation-attention-store.js";
52
- import {
53
- initConversationDir,
54
- removeConversationDir,
55
- syncMessageToDisk,
56
- updateMetaFile,
57
- } from "./conversation-disk-view.js";
58
- import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
59
- import { ensureGroupMigration } from "./conversation-group-migration.js";
60
- import { runAsyncSqlite } from "./db-async-query.js";
61
- import {
62
- type DrizzleDb,
63
- getDb,
64
- getLogsDb,
65
- getSqliteFrom,
66
- } from "./db-connection.js";
67
- import {
68
- copyForkMessagesViaSubprocess,
69
- type ForkIdPair,
70
- } from "./fork-message-copy.js";
71
- import { forkGraphMemoryState } from "./graph/graph-memory-state-store.js";
72
- import { indexMessageNow } from "./indexer.js";
73
- import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
74
- import { forkRetrospectiveState } from "./memory-retrospective-state.js";
75
- import {
76
- rawExec,
77
- rawGet,
78
- rawLogsRun,
79
- rawMemoryRun,
80
- rawRun,
81
- } from "./raw-query.js";
82
- import {
83
- channelInboundEvents,
84
- conversations,
85
- llmRequestLogs,
86
- memoryEmbeddings,
87
- memorySegments,
88
- memorySummaries,
89
- messageAttachments,
90
- messages,
91
- skillLoadedEvents,
92
- toolInvocations,
93
- } from "./schema.js";
94
- import { cancelPendingJobsForConversation } from "./task-memory-cleanup.js";
95
- import {
96
- forkActivationState,
97
- seedForkActivationState,
98
- } from "./v2/activation-store.js";
99
- import { extractInjectedConceptSlugs } from "./v2/injected-block-slugs.js";
100
-
101
- const log = getLogger("conversation-store");
102
-
103
- /**
104
- * The logs connection (`assistant-logs.db`), where `llm_request_logs` lives.
105
- * Throws if the file cannot be opened — the few call sites here that touch
106
- * request logs (conversation deletes, turn-window anchoring) have no fallback.
107
- */
108
- function logsDb(): DrizzleDb {
109
- const db = getLogsDb();
110
- if (!db) {
111
- throw new Error("logs database unavailable");
112
- }
113
- return db;
114
- }
115
-
116
- // ── Message metadata Zod schema ──────────────────────────────────────
117
- // Validates the JSON stored in messages.metadata. Known fields are typed;
118
- // extra keys are allowed via passthrough so callers can attach ad-hoc data.
119
-
120
- const channelIdSchema = z.enum(CHANNEL_IDS);
121
- // Accept both canonical INTERFACE_IDS and the legacy "vellum" alias,
122
- // normalizing to "web" on read so downstream code only handles canonical IDs.
123
- const interfaceIdSchema = z
124
- .string()
125
- .transform((v) => parseInterfaceId(v))
126
- .refine((v): v is InterfaceId => v !== null);
127
-
128
- const subagentNotificationSchema = z.object({
129
- subagentId: z.string(),
130
- label: z.string(),
131
- status: z.enum(["running", "completed", "failed", "aborted"]),
132
- error: z.string().optional(),
133
- conversationId: z.string().optional(),
134
- objective: z.string().optional(),
135
- });
136
-
137
- export const messageMetadataSchema = z
138
- .object({
139
- userMessageChannel: channelIdSchema.optional(),
140
- assistantMessageChannel: channelIdSchema.optional(),
141
- userMessageInterface: interfaceIdSchema.optional(),
142
- assistantMessageInterface: interfaceIdSchema.optional(),
143
- /**
144
- * Optional client-side metadata bag attached to user messages by HTTP
145
- * header middleware (reads `x-vellum-browser-family`,
146
- * `x-vellum-browser-version`, `x-vellum-client-os`,
147
- * `x-vellum-interface-version`). Forwarded verbatim onto
148
- * `TurnTelemetryEvent.client` for downstream analytics. Kept as a
149
- * permissive `record` so adding a new client field doesn't require a
150
- * migration -- dbt can unpack later via JSON_VALUE.
151
- */
152
- client: z.record(z.string(), z.unknown()).optional(),
153
- subagentNotification: subagentNotificationSchema.optional(),
154
- /**
155
- * Trust class of the actor at the time this message was persisted.
156
- * This is a durable snapshot -- it does NOT change if the actor's
157
- * trust status changes later. Used by the memory write gate (indexer)
158
- * and read gate (conversation history loading) to enforce trust-aware access.
159
- */
160
- provenanceTrustClass: z
161
- .enum(["guardian", "trusted_contact", "unverified_contact", "unknown"])
162
- .optional(),
163
- provenanceSourceChannel: channelIdSchema.optional(),
164
- provenanceGuardianExternalUserId: z.string().optional(),
165
- provenanceRequesterIdentifier: z.string().optional(),
166
- automated: z.boolean().optional(),
167
- forkSourceMessageId: z.string().optional(),
168
- /** Image source paths from desktop attachments, keyed by filename. */
169
- imageSourcePaths: z.record(z.string(), z.string()).optional(),
170
- memoryInjectedBlock: z.string().optional(),
171
- /** Memory-v3 frozen net-new card block (unwrapped) — the v3 counterpart
172
- * of `memoryInjectedBlock`. A row carries at most one of the two. */
173
- [MEMORY_V3_INJECTED_BLOCK_METADATA_KEY]: z.string().optional(),
174
- turnContextBlock: z.string().optional(),
175
- pkbSystemReminderBlock: z.string().optional(),
176
- workspaceBlock: z.string().optional(),
177
- nowScratchpadBlock: z.string().optional(),
178
- pkbContextBlock: z.string().optional(),
179
- memoryV2StaticBlock: z.string().optional(),
180
- /** `<background_turn>` block (background/scheduled non-interactive turns),
181
- * rehydrated by `loadFromDb` for reload/fork prefix-cache parity. */
182
- backgroundTurnBlock: z.string().optional(),
183
- /** `<channel_capabilities>` block, rehydrated for the same reason. */
184
- channelCapabilitiesBlock: z.string().optional(),
185
- /** `<non_interactive_context>` block, rehydrated for the same reason. */
186
- nonInteractiveContextBlock: z.string().optional(),
187
- })
188
- .passthrough();
189
-
190
- function cloneForkMessageMetadata(
191
- metadata: string | null,
192
- sourceMessageId: string,
193
- ): string {
194
- if (!metadata) {
195
- return JSON.stringify({ forkSourceMessageId: sourceMessageId });
196
- }
197
-
198
- try {
199
- const parsed = JSON.parse(metadata);
200
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
201
- const sourceRecord = parsed as Record<string, unknown>;
202
- const forkSourceMessageId =
203
- typeof sourceRecord.forkSourceMessageId === "string"
204
- ? sourceRecord.forkSourceMessageId
205
- : sourceMessageId;
206
- return JSON.stringify({
207
- ...sourceRecord,
208
- forkSourceMessageId,
209
- });
210
- }
211
- } catch {
212
- // Fall through to source-only metadata.
213
- }
214
-
215
- return JSON.stringify({ forkSourceMessageId: sourceMessageId });
216
- }
217
-
218
- /**
219
- * Read a persisted memory-injection block off a message's metadata JSON, or
220
- * `null` when absent/malformed. `key` selects the injection layer: v2's
221
- * `memoryInjectedBlock` or memory-v3's card block
222
- * (`MEMORY_V3_INJECTED_BLOCK_METADATA_KEY`). The block is what the request
223
- * builder re-attaches as the message's `<memory>` content each turn.
224
- */
225
- function readInjectedBlock(
226
- metadata: string | null,
227
- key: string,
228
- ): string | null {
229
- if (!metadata) return null;
230
- try {
231
- const parsed: unknown = JSON.parse(metadata);
232
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
233
- const block = (parsed as Record<string, unknown>)[key];
234
- if (typeof block === "string") return block;
235
- }
236
- } catch {
237
- // Malformed metadata — treat as no block.
238
- }
239
- return null;
240
- }
241
-
242
- /**
243
- * Extract provenance metadata fields from a TrustContext.
244
- * When no guardian context is provided, defaults to 'unknown' because the
245
- * absence of trust context means we cannot verify trust —
246
- * callers with actual guardian trust should always supply a real context.
247
- */
248
- export function provenanceFromTrustContext(
249
- ctx: TrustContext | null | undefined,
250
- ): Record<string, unknown> {
251
- if (!ctx) return { provenanceTrustClass: "unknown" };
252
- return {
253
- provenanceTrustClass: ctx.trustClass,
254
- provenanceSourceChannel: ctx.sourceChannel,
255
- provenanceGuardianExternalUserId: ctx.guardianExternalUserId,
256
- provenanceRequesterIdentifier: ctx.requesterIdentifier,
257
- };
258
- }
259
-
260
- /** Extract image file paths from resolved attachments for message metadata. */
261
- export function extractImageSourcePaths(
262
- attachments: ReadonlyArray<{
263
- filename: string;
264
- mimeType: string;
265
- filePath?: string;
266
- }>,
267
- ): Record<string, string> | undefined {
268
- const paths: Record<string, string> = {};
269
- for (let i = 0; i < attachments.length; i++) {
270
- const a = attachments[i];
271
- if (a.filePath && a.mimeType.toLowerCase().startsWith("image/")) {
272
- paths[`${i}:${a.filename}`] = a.filePath;
273
- }
274
- }
275
- return Object.keys(paths).length > 0 ? paths : undefined;
276
- }
277
-
278
- export interface ConversationRow {
279
- id: string;
280
- title: string | null;
281
- createdAt: number;
282
- updatedAt: number;
283
- totalInputTokens: number;
284
- totalOutputTokens: number;
285
- totalEstimatedCost: number;
286
- contextSummary: string | null;
287
- contextCompactedMessageCount: number;
288
- contextCompactedAt: number | null;
289
- historyStrippedAt: number | null;
290
- slackContextCompactionWatermarkTs: string | null;
291
- slackContextCompactionWatermarkAt: number | null;
292
- conversationType: string;
293
- source: string;
294
- memoryScopeId: string;
295
- originChannel: string | null;
296
- originInterface: string | null;
297
- forkParentConversationId: string | null;
298
- forkParentMessageId: string | null;
299
- isAutoTitle: number;
300
- scheduleJobId: string | null;
301
- lastMessageAt: number | null;
302
- archivedAt: number | null;
303
- surfacedAt: number | null;
304
- inferenceProfile: string | null;
305
- inferenceProfileSessionId: string | null;
306
- inferenceProfileExpiresAt: number | null;
307
- lastNotifiedInferenceProfile: string | null;
308
- processingStartedAt: number | null;
309
- }
310
-
311
- export const parseConversation = createRowMapper<
312
- typeof conversations.$inferSelect,
313
- ConversationRow
314
- >({
315
- id: "id",
316
- title: "title",
317
- createdAt: "createdAt",
318
- updatedAt: "updatedAt",
319
- totalInputTokens: "totalInputTokens",
320
- totalOutputTokens: "totalOutputTokens",
321
- totalEstimatedCost: "totalEstimatedCost",
322
- contextSummary: "contextSummary",
323
- contextCompactedMessageCount: "contextCompactedMessageCount",
324
- contextCompactedAt: "contextCompactedAt",
325
- historyStrippedAt: "historyStrippedAt",
326
- slackContextCompactionWatermarkTs: "slackContextCompactionWatermarkTs",
327
- slackContextCompactionWatermarkAt: "slackContextCompactionWatermarkAt",
328
- conversationType: "conversationType",
329
- source: "source",
330
- memoryScopeId: "memoryScopeId",
331
- originChannel: "originChannel",
332
- originInterface: "originInterface",
333
- forkParentConversationId: "forkParentConversationId",
334
- forkParentMessageId: "forkParentMessageId",
335
- isAutoTitle: "isAutoTitle",
336
- scheduleJobId: "scheduleJobId",
337
- lastMessageAt: "lastMessageAt",
338
- archivedAt: "archivedAt",
339
- surfacedAt: "surfacedAt",
340
- inferenceProfile: "inferenceProfile",
341
- inferenceProfileSessionId: "inferenceProfileSessionId",
342
- inferenceProfileExpiresAt: "inferenceProfileExpiresAt",
343
- lastNotifiedInferenceProfile: "lastNotifiedInferenceProfile",
344
- processingStartedAt: "processingStartedAt",
345
- });
346
-
347
- /** Allowed values for the `role` column on `messages`. */
348
- export type MessageRole = "user" | "assistant" | "system";
349
-
350
- export interface MessageRow {
351
- id: string;
352
- conversationId: string;
353
- role: string;
354
- content: string;
355
- createdAt: number;
356
- metadata: string | null;
357
- clientMessageId: string | null;
358
- }
359
-
360
- const parseMessage = createRowMapper<typeof messages.$inferSelect, MessageRow>({
361
- id: "id",
362
- conversationId: "conversationId",
363
- role: "role",
364
- content: "content",
365
- createdAt: "createdAt",
366
- metadata: "metadata",
367
- clientMessageId: "clientMessageId",
368
- });
369
-
370
- export type ConversationCreateType = "standard" | "background" | "scheduled";
371
-
372
- /**
373
- * Monotonic timestamp source for message ordering. Two messages saved within
374
- * the same millisecond (e.g., tool_results user message + assistant message in
375
- * message_complete) would get the same Date.now(), making their reload order
376
- * non-deterministic. This counter ensures every call returns a strictly
377
- * increasing value so insertion order is always preserved.
378
- */
379
- let lastTimestamp = 0;
380
- function monotonicNow(): number {
381
- const now = Date.now();
382
- lastTimestamp = Math.max(now, lastTimestamp + 1);
383
- return lastTimestamp;
384
- }
385
-
386
- // ── insertMessageCore ─────────────────────────────────────────────────
387
-
388
- /** Shape returned by {@link insertMessageCore} and its public wrappers. */
389
- interface InsertedMessage {
390
- id: string;
391
- conversationId: string;
392
- role: MessageRole;
393
- content: string;
394
- createdAt: number;
395
- metadata?: string;
396
- clientMessageId?: string;
397
- deduplicated: boolean;
398
- }
399
-
400
- interface InsertMessageCoreParams {
401
- conversationId: string;
402
- role: MessageRole;
403
- content: string;
404
- metadata?: Record<string, unknown>;
405
- clientMessageId?: string;
406
- }
407
-
408
- /**
409
- * Core message persistence primitive shared by {@link addMessage} and
410
- * {@link reserveMessage}.
411
- *
412
- * Inserts a message row inside a transaction that atomically bumps the
413
- * parent conversation's `updatedAt` / `lastMessageAt` timestamps and
414
- * conditionally sets the conversation's `originChannel` when the first
415
- * channel-originated message arrives.
416
- *
417
- * When a `clientMessageId` is provided the insert runs inside a
418
- * SAVEPOINT. If the partial unique index on
419
- * `(conversation_id, client_message_id)` raises
420
- * `SQLITE_CONSTRAINT_UNIQUE`, the SAVEPOINT is rolled back, the
421
- * existing row is fetched, and returned with `deduplicated: true`.
422
- * This makes the operation idempotent for client-generated
423
- * correlation nonces.
424
- *
425
- * Retries up to 3 times on `SQLITE_BUSY*` / `SQLITE_IOERR*` to handle
426
- * WAL contention. The timestamp is recomputed each attempt so a late
427
- * retry doesn't persist a stale `updatedAt`.
428
- */
429
- async function insertMessageCore(
430
- params: InsertMessageCoreParams,
431
- ): Promise<InsertedMessage> {
432
- const { conversationId, role, content, metadata, clientMessageId } = params;
433
- const db = getDb();
434
- const messageId = uuid();
435
-
436
- if (metadata) {
437
- const result = messageMetadataSchema.safeParse(metadata);
438
- if (!result.success) {
439
- log.warn(
440
- { conversationId, messageId, issues: result.error.issues },
441
- "Invalid message metadata, storing as-is",
442
- );
443
- }
444
- }
445
-
446
- const metadataStr = metadata ? JSON.stringify(metadata) : undefined;
447
- const originChannelCandidate =
448
- metadata && isChannelId(metadata.userMessageChannel)
449
- ? metadata.userMessageChannel
450
- : null;
451
-
452
- const MAX_RETRIES = 3;
453
- let now!: number;
454
- for (let attempt = 0; ; attempt++) {
455
- now = monotonicNow();
456
- try {
457
- const values = {
458
- id: messageId,
459
- conversationId,
460
- role,
461
- content,
462
- createdAt: now,
463
- ...(metadataStr ? { metadata: metadataStr } : {}),
464
- ...(clientMessageId ? { clientMessageId } : {}),
465
- };
466
-
467
- if (clientMessageId) {
468
- // Idempotent insert: skip silently if this clientMessageId was
469
- // already persisted for the conversation.
470
- const raw = getSqliteFrom(db);
471
- raw.exec("SAVEPOINT insert_msg");
472
- try {
473
- db.insert(messages).values(values).run();
474
- if (originChannelCandidate) {
475
- db.update(conversations)
476
- .set({ originChannel: originChannelCandidate })
477
- .where(
478
- and(
479
- eq(conversations.id, conversationId),
480
- isNull(conversations.originChannel),
481
- ),
482
- )
483
- .run();
484
- }
485
- db.update(conversations)
486
- .set({ updatedAt: now, lastMessageAt: now })
487
- .where(eq(conversations.id, conversationId))
488
- .run();
489
- raw.exec("RELEASE insert_msg");
490
- } catch (insertErr) {
491
- raw.exec("ROLLBACK TO insert_msg");
492
- raw.exec("RELEASE insert_msg");
493
- const code = (insertErr as { code?: string }).code ?? "";
494
- if (code === "SQLITE_CONSTRAINT_UNIQUE") {
495
- // Duplicate clientMessageId — return the existing row.
496
- const existing = db
497
- .select()
498
- .from(messages)
499
- .where(
500
- and(
501
- eq(messages.conversationId, conversationId),
502
- eq(messages.clientMessageId, clientMessageId),
503
- ),
504
- )
505
- .get();
506
- if (existing) {
507
- return {
508
- id: existing.id,
509
- conversationId: existing.conversationId,
510
- role: existing.role as MessageRole,
511
- content: existing.content,
512
- createdAt: existing.createdAt,
513
- ...(existing.metadata ? { metadata: existing.metadata } : {}),
514
- clientMessageId: existing.clientMessageId ?? undefined,
515
- deduplicated: true,
516
- };
517
- }
518
- }
519
- throw insertErr;
520
- }
521
- } else {
522
- // No clientMessageId — standard insert inside a transaction.
523
- db.transaction((tx) => {
524
- tx.insert(messages).values(values).run();
525
- if (originChannelCandidate) {
526
- tx.update(conversations)
527
- .set({ originChannel: originChannelCandidate })
528
- .where(
529
- and(
530
- eq(conversations.id, conversationId),
531
- isNull(conversations.originChannel),
532
- ),
533
- )
534
- .run();
535
- }
536
- tx.update(conversations)
537
- .set({ updatedAt: now, lastMessageAt: now })
538
- .where(eq(conversations.id, conversationId))
539
- .run();
540
- });
541
- }
542
- break;
543
- } catch (err) {
544
- const errCode = (err as { code?: string }).code ?? "";
545
- if (
546
- attempt < MAX_RETRIES &&
547
- (errCode.startsWith("SQLITE_BUSY") ||
548
- errCode.startsWith("SQLITE_IOERR"))
549
- ) {
550
- log.warn(
551
- { attempt, conversationId, code: errCode },
552
- "insertMessageCore: transient SQLite error, retrying",
553
- );
554
- await Bun.sleep(50 * (attempt + 1));
555
- continue;
556
- }
557
- throw err;
558
- }
559
- }
560
-
561
- return {
562
- id: messageId,
563
- conversationId,
564
- role,
565
- content,
566
- createdAt: now,
567
- ...(metadataStr ? { metadata: metadataStr } : {}),
568
- ...(clientMessageId ? { clientMessageId } : {}),
569
- deduplicated: false,
570
- };
571
- }
572
-
573
- export function createConversation(
574
- titleOrOpts?:
575
- | string
576
- | {
577
- title?: string;
578
- /**
579
- * Override the `is_auto_title` column (schema default 1). Pass
580
- * `AUTO_TITLE_DETERMINISTIC` (2) when the title was derived
581
- * deterministically at bootstrap so later generation passes know
582
- * they may replace it.
583
- */
584
- isAutoTitle?: number;
585
- conversationType?: ConversationCreateType;
586
- source?: string;
587
- scheduleJobId?: string;
588
- groupId?: string;
589
- forkParentConversationId?: string;
590
- },
591
- ) {
592
- const db = getDb();
593
- const now = Date.now();
594
- const opts =
595
- typeof titleOrOpts === "string"
596
- ? { title: titleOrOpts }
597
- : (titleOrOpts ?? {});
598
- const requestedConversationType = opts.conversationType;
599
- const conversationType: ConversationCreateType =
600
- requestedConversationType ?? "standard";
601
- const source = opts.source ?? "user";
602
- const groupId = opts.groupId;
603
- const id = uuid();
604
- const memoryScopeId = "default";
605
-
606
- // Ensure group_id column exists for deterministic schema readiness,
607
- // even when this conversation has no groupId (a subsequent query or
608
- // reorder may reference the column).
609
- ensureGroupMigration();
610
-
611
- const conversation = {
612
- id,
613
- title: opts.title ?? null,
614
- ...(opts.isAutoTitle !== undefined
615
- ? { isAutoTitle: opts.isAutoTitle }
616
- : {}),
617
- createdAt: now,
618
- updatedAt: now,
619
- totalInputTokens: 0,
620
- totalOutputTokens: 0,
621
- totalEstimatedCost: 0,
622
- contextSummary: null as string | null,
623
- contextCompactedMessageCount: 0,
624
- contextCompactedAt: null as number | null,
625
- slackContextCompactionWatermarkTs: null as string | null,
626
- slackContextCompactionWatermarkAt: null as number | null,
627
- conversationType,
628
- source,
629
- memoryScopeId,
630
- scheduleJobId: opts.scheduleJobId ?? null,
631
- forkParentConversationId: opts.forkParentConversationId ?? null,
632
- };
633
-
634
- // Retry on SQLITE_BUSY and SQLITE_IOERR — transient disk I/O errors or WAL
635
- // contention can cause the first attempt to fail even under normal load.
636
- // INSERT and group_id UPDATE are retried independently so a transient failure
637
- // on the UPDATE doesn't re-execute the already-succeeded INSERT (which would
638
- // hit a unique constraint violation).
639
- // No explicit BEGIN/COMMIT here — callers that need atomicity (e.g.
640
- // forkConversation) wrap in their own transaction, and nesting raw BEGIN
641
- // inside Drizzle's db.transaction() would crash SQLite.
642
- const MAX_RETRIES = 3;
643
- for (let attempt = 0; ; attempt++) {
644
- try {
645
- db.insert(conversations).values(conversation).run();
646
- break;
647
- } catch (err) {
648
- const code = (err as { code?: string }).code ?? "";
649
- if (
650
- attempt < MAX_RETRIES &&
651
- (code.startsWith("SQLITE_BUSY") || code.startsWith("SQLITE_IOERR"))
652
- ) {
653
- log.warn(
654
- { attempt, conversationId: id, code },
655
- "createConversation: INSERT transient error, retrying",
656
- );
657
- Bun.sleepSync(50 * (attempt + 1));
658
- continue;
659
- }
660
- throw err;
661
- }
662
- }
663
-
664
- // group_id is NOT in the Drizzle schema (raw-query-only pattern).
665
- // Set via raw SQL after the INSERT succeeds.
666
- // Always set group_id — default to "system:all" when none provided.
667
- {
668
- const effectiveGroupId = groupId ?? "system:all";
669
- for (let attempt = 0; ; attempt++) {
670
- try {
671
- rawRun(
672
- "UPDATE conversations SET group_id = ?, is_pinned = ? WHERE id = ?",
673
- effectiveGroupId,
674
- effectiveGroupId === "system:pinned" ? 1 : 0,
675
- id,
676
- );
677
- break;
678
- } catch (err) {
679
- const code = (err as { code?: string }).code ?? "";
680
- if (
681
- attempt < MAX_RETRIES &&
682
- (code.startsWith("SQLITE_BUSY") || code.startsWith("SQLITE_IOERR"))
683
- ) {
684
- log.warn(
685
- { attempt, conversationId: id, code },
686
- "createConversation: group_id UPDATE transient error, retrying",
687
- );
688
- Bun.sleepSync(50 * (attempt + 1));
689
- continue;
690
- }
691
- throw err;
692
- }
693
- }
694
- }
695
-
696
- initConversationDir({ ...conversation, originChannel: null });
697
-
698
- return conversation;
699
- }
700
-
701
- export function getConversation(id: string): ConversationRow | null {
702
- const db = getDb();
703
- const row = db
704
- .select()
705
- .from(conversations)
706
- .where(eq(conversations.id, id))
707
- .get();
708
- return row ? parseConversation(row) : null;
709
- }
710
-
711
- /**
712
- * Count conversations that reference a given schedule job ID.
713
- * Useful for determining whether a schedule can be safely deleted
714
- * (i.e. no other conversations still reference it).
715
- */
716
- export function countConversationsByScheduleJobId(
717
- scheduleJobId: string,
718
- ): number {
719
- return (
720
- rawGet<{ c: number }>(
721
- "SELECT COUNT(*) AS c FROM conversations WHERE schedule_job_id = ?",
722
- scheduleJobId,
723
- )?.c ?? 0
724
- );
725
- }
726
-
727
- /**
728
- * Find the rolling analysis conversation for a given source conversation,
729
- * or null if none exists yet. Used by the auto-analyze loop to append
730
- * to an existing analysis conversation rather than creating a new one
731
- * each time the analyze job fires.
732
- *
733
- * Returns the most recently updated match if multiple exist (defensive —
734
- * shouldn't happen in normal operation but the contract is well-defined).
735
- *
736
- * Hits `idx_conversations_fork_parent_conversation_id` for the
737
- * `forkParentConversationId` lookup.
738
- */
739
- export function findAnalysisConversationFor(
740
- parentConversationId: string,
741
- ): { id: string } | null {
742
- const db = getDb();
743
- const row = db
744
- .select({ id: conversations.id })
745
- .from(conversations)
746
- .where(
747
- and(
748
- eq(conversations.source, AUTO_ANALYSIS_SOURCE),
749
- eq(conversations.forkParentConversationId, parentConversationId),
750
- ),
751
- )
752
- .orderBy(desc(conversations.updatedAt))
753
- .limit(1)
754
- .get();
755
- return row ? { id: row.id } : null;
756
- }
757
-
758
- /**
759
- * Find the most recent memory-retrospective background conversation rooted
760
- * at `parentConversationId`. Used by the memory-retrospective job handler
761
- * to load the prior retrospective's `remember` calls into the new run's
762
- * `<already_remembered>` block — bounded source-of-truth for "what the
763
- * prior pass already saved" that scales as the source conversation grows.
764
- *
765
- * Walks up `forkParentConversationId` when no retrospective exists at the
766
- * current level. This lets a forked conversation inherit dedup context from
767
- * its source's most recent retro on the fork's *first* retrospective —
768
- * otherwise the fork would re-save every fact the source already retro'd.
769
- * Once the fork accumulates its own retros, those are found at the first
770
- * iteration and we never walk up.
771
- *
772
- * The returned `forkParentConversationId` is the conversation the
773
- * retrospective row is rooted at — `parentConversationId` itself when it has
774
- * its own retros, or an ancestor when the chain walk found the row higher
775
- * up. Callers that mutate the prior (e.g. GC of superseded runs) must check
776
- * it against the source conversation: an ancestor's row is that ancestor's
777
- * dedup baseline, not the caller's to delete.
778
- *
779
- * Returns `null` when no prior retrospective exists anywhere in the fork
780
- * chain (true first-run case).
781
- *
782
- * Hits `idx_conversations_fork_parent_conversation_id` for the
783
- * `forkParentConversationId` lookup.
784
- */
785
- const MAX_FORK_CHAIN_DEPTH = 16;
786
-
787
- export function findMostRecentRetrospectiveFor(
788
- parentConversationId: string,
789
- ): { id: string; forkParentConversationId: string } | null {
790
- const db = getDb();
791
- let currentId: string | null = parentConversationId;
792
- for (let depth = 0; depth < MAX_FORK_CHAIN_DEPTH && currentId; depth++) {
793
- const row = db
794
- .select({ id: conversations.id })
795
- .from(conversations)
796
- .where(
797
- and(
798
- inArray(conversations.source, MEMORY_RETROSPECTIVE_SOURCES),
799
- eq(conversations.forkParentConversationId, currentId),
800
- ),
801
- )
802
- .orderBy(desc(conversations.createdAt))
803
- .limit(1)
804
- .get();
805
- if (row) return { id: row.id, forkParentConversationId: currentId };
806
-
807
- const parent = db
808
- .select({
809
- forkParentConversationId: conversations.forkParentConversationId,
810
- })
811
- .from(conversations)
812
- .where(eq(conversations.id, currentId))
813
- .get();
814
- currentId = parent?.forkParentConversationId ?? null;
815
- }
816
- return null;
817
- }
818
-
819
- /**
820
- * Returns the `source` column for the given conversation, or null if
821
- * not found. Tiny convenience used by the recursion guard in the
822
- * auto-analyze loop.
823
- */
824
- export function getConversationSource(conversationId: string): string | null {
825
- const db = getDb();
826
- const row = db
827
- .select({ source: conversations.source })
828
- .from(conversations)
829
- .where(eq(conversations.id, conversationId))
830
- .get();
831
- return row?.source ?? null;
832
- }
833
-
834
- /**
835
- * Fetch group_id for a conversation via raw SQL. group_id is NOT in the
836
- * Drizzle schema (raw-query-only pattern), so ConversationRow doesn't
837
- * include it. This helper is used by forkConversation to inherit group_id.
838
- */
839
- function getConversationGroupId(conversationId: string): string | null {
840
- ensureGroupMigration();
841
- const row = rawGet<{ group_id: string | null }>(
842
- "SELECT group_id FROM conversations WHERE id = ?",
843
- conversationId,
844
- );
845
- return row?.group_id ?? null;
846
- }
847
-
848
- export function forkConversation(params: {
849
- conversationId: string;
850
- throughMessageId?: string;
851
- /**
852
- * Override the fork's `source` column. Defaults to the standard
853
- * `createConversation` default (`"user"`). Used by fork-based memory
854
- * retrospectives to mark the fork as a retrospective artifact distinct
855
- * from a user-initiated fork, so dedup and cleanup queries can scope
856
- * correctly.
857
- */
858
- source?: string;
859
- /**
860
- * Optional title for the fork. Defaults to `<parent title> (Fork)`.
861
- */
862
- title?: string;
863
- /**
864
- * Override the fork's `conversationType` column. Defaults to `"standard"`.
865
- * Used by fork-based memory retrospectives to bucket the fork as a
866
- * `"background"` conversation so it doesn't surface in the user's
867
- * conversation list.
868
- */
869
- conversationType?: ConversationCreateType;
870
- /**
871
- * Override the fork's `groupId`. Defaults to the parent conversation's
872
- * group (or `"system:all"` when the parent has none). Used by fork-based
873
- * memory retrospectives to route the fork into a dedicated background
874
- * group.
875
- */
876
- groupId?: string;
877
- }): ConversationRow {
878
- const { conversationId, throughMessageId } = params;
879
- const db = getDb();
880
- const sourceConversation = getConversation(conversationId);
881
-
882
- if (!sourceConversation) {
883
- throw new UserError(`Conversation ${conversationId} not found`);
884
- }
885
- const sourceMessages = getMessages(conversationId);
886
- if (throughMessageId != null) {
887
- // `getMessages` orders by `createdAt` only; when rows share an identical
888
- // millisecond timestamp the tie order is unspecified. Callers that pin the
889
- // fork to a cutoff choose it from a `(createdAt, id)` cursor (e.g. the
890
- // memory-retrospective job, via `getMessagesAfter`), so slicing through
891
- // `throughMessageId` under the unstable order could include same-timestamp
892
- // siblings the cursor considers *after* the cutoff (reprocessed next run)
893
- // or exclude ones it considers *before* it (skipped forever). Re-sort on
894
- // `(createdAt, id)` so the slice agrees with the cutoff. The unpinned full
895
- // fork copies every row regardless of order, so it keeps source order.
896
- sourceMessages.sort(
897
- (a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id),
898
- );
899
- }
900
-
901
- if (sourceMessages.length === 0) {
902
- throw new UserError(
903
- `Conversation ${conversationId} has no persisted messages to fork`,
904
- );
905
- }
906
-
907
- const initialBoundaryIndex =
908
- throughMessageId == null
909
- ? sourceMessages.length - 1
910
- : sourceMessages.findIndex((message) => message.id === throughMessageId);
911
-
912
- if (throughMessageId != null && initialBoundaryIndex === -1) {
913
- throw new UserError(
914
- `Message ${throughMessageId} does not belong to conversation ${conversationId}`,
915
- );
916
- }
917
-
918
- // Extend the boundary to cover the full display turn the client
919
- // addressed. The read-path collapses each assistant turn across
920
- // multiple DB rows — consecutive assistant rows AND tool-result-only
921
- // user rows between them — so "fork through message X" semantically
922
- // means "fork through the entire display turn containing X" no matter
923
- // which DB row in the cluster the client supplied. Single source of
924
- // truth is `findDisplayTurnEndIndex`, shared with the read path so
925
- // both stay in sync.
926
- const copyBoundaryIndex = findDisplayTurnEndIndex(
927
- sourceMessages,
928
- initialBoundaryIndex,
929
- );
930
-
931
- const visibleWindowStartIndex = Math.max(
932
- 0,
933
- Math.min(
934
- sourceConversation.contextCompactedMessageCount,
935
- sourceMessages.length,
936
- ),
937
- );
938
- const preserveSourceCompactionState =
939
- copyBoundaryIndex >= visibleWindowStartIndex;
940
-
941
- const messagesToCopy =
942
- copyBoundaryIndex >= 0
943
- ? sourceMessages.slice(0, copyBoundaryIndex + 1)
944
- : ([] as MessageRow[]);
945
-
946
- // Inherit the history-strip marker only when the fork boundary is at-or-
947
- // after the strip event. Pre-strip forks branch from history that pre-
948
- // dates the strip, so the marker would be a no-op and is misleading to
949
- // copy.
950
- const sourceHistoryStrippedAt = sourceConversation.historyStrippedAt ?? null;
951
- const boundaryMessageCreatedAt = messagesToCopy.at(-1)?.createdAt ?? null;
952
- const inheritsHistoryStrippedAt =
953
- sourceHistoryStrippedAt != null &&
954
- boundaryMessageCreatedAt != null &&
955
- boundaryMessageCreatedAt >= sourceHistoryStrippedAt;
956
- const forkParentMessageId = messagesToCopy.at(-1)?.id ?? null;
957
- const forkTitle =
958
- params.title ?? `${sourceConversation.title ?? "Untitled"} (Fork)`;
959
-
960
- // Collect disk-sync work to run after the transaction commits.
961
- const diskSyncQueue: Array<{
962
- conversationId: string;
963
- messageId: string;
964
- createdAt: number;
965
- }> = [];
966
-
967
- // Wrap all DB mutations in a single transaction so a mid-flight failure
968
- // rolls back cleanly instead of leaving a partial fork. Helper functions
969
- // (linkAttachmentToMessage, relinkAttachments, seedForkedConversationAttention)
970
- // use the same underlying bun:sqlite connection, so their writes participate
971
- // in this transaction automatically.
972
- // Inherit group_id from parent via raw SQL helper (group_id is not in Drizzle schema)
973
- const parentGroupId = getConversationGroupId(conversationId);
974
-
975
- const forkedConversation = db.transaction(() => {
976
- const fc = createConversation({
977
- title: forkTitle,
978
- conversationType: params.conversationType ?? "standard",
979
- groupId: params.groupId ?? parentGroupId ?? "system:all",
980
- ...(params.source != null ? { source: params.source } : {}),
981
- });
982
-
983
- db.update(conversations)
984
- .set({
985
- forkParentConversationId: sourceConversation.id,
986
- forkParentMessageId,
987
- contextSummary: preserveSourceCompactionState
988
- ? sourceConversation.contextSummary
989
- : null,
990
- contextCompactedMessageCount: preserveSourceCompactionState
991
- ? sourceConversation.contextCompactedMessageCount
992
- : 0,
993
- contextCompactedAt: preserveSourceCompactionState
994
- ? sourceConversation.contextCompactedAt
995
- : null,
996
- slackContextCompactionWatermarkTs: preserveSourceCompactionState
997
- ? sourceConversation.slackContextCompactionWatermarkTs
998
- : null,
999
- slackContextCompactionWatermarkAt: preserveSourceCompactionState
1000
- ? sourceConversation.slackContextCompactionWatermarkAt
1001
- : null,
1002
- historyStrippedAt: inheritsHistoryStrippedAt
1003
- ? sourceHistoryStrippedAt
1004
- : null,
1005
- inferenceProfile: sourceConversation.inferenceProfile,
1006
- })
1007
- .where(eq(conversations.id, fc.id))
1008
- .run();
1009
-
1010
- const forkedMessageIds = new Map<string, string>();
1011
- let latestForkedAssistant: {
1012
- messageId: string;
1013
- messageAt: number;
1014
- } | null = null;
1015
-
1016
- for (const message of messagesToCopy) {
1017
- const forkedMessageId = uuid();
1018
- db.insert(messages)
1019
- .values({
1020
- id: forkedMessageId,
1021
- conversationId: fc.id,
1022
- role: message.role,
1023
- content: message.content,
1024
- createdAt: message.createdAt,
1025
- metadata: cloneForkMessageMetadata(message.metadata, message.id),
1026
- })
1027
- .run();
1028
- forkedMessageIds.set(message.id, forkedMessageId);
1029
-
1030
- if (message.role === "assistant") {
1031
- latestForkedAssistant = {
1032
- messageId: forkedMessageId,
1033
- messageAt: message.createdAt,
1034
- };
1035
- }
1036
- }
1037
-
1038
- populateForkContentsInProcess({
1039
- fork: fc,
1040
- sourceConversationId: sourceConversation.id,
1041
- messagesToCopy,
1042
- forkedMessageIds,
1043
- latestForkedAssistant,
1044
- isFullHistoryFork: copyBoundaryIndex === sourceMessages.length - 1,
1045
- preserveSourceCompactionState,
1046
- visibleWindowStartIndex,
1047
- diskSyncQueue,
1048
- });
1049
-
1050
- return fc;
1051
- });
1052
-
1053
- // Disk-view sync runs after commit — file I/O is idempotent and
1054
- // conversation deletion cleans up orphaned directories.
1055
- for (const entry of diskSyncQueue) {
1056
- syncMessageToDisk(entry.conversationId, entry.messageId, entry.createdAt);
1057
- }
1058
-
1059
- const persistedFork = getConversation(forkedConversation.id);
1060
- if (!persistedFork) {
1061
- throw new Error(
1062
- `Failed to load forked conversation ${forkedConversation.id} after creation`,
1063
- );
1064
- }
1065
-
1066
- return persistedFork;
1067
- }
1068
-
1069
- interface PopulateForkContentsArgs {
1070
- /** The freshly-created fork conversation row (needs `id` + `createdAt`). */
1071
- fork: { id: string; createdAt: number };
1072
- sourceConversationId: string;
1073
- messagesToCopy: MessageRow[];
1074
- /** Source→fork message-id map for every copied row. */
1075
- forkedMessageIds: Map<string, string>;
1076
- latestForkedAssistant: { messageId: string; messageAt: number } | null;
1077
- /** `copyBoundaryIndex === sourceMessages.length - 1` for the source. */
1078
- isFullHistoryFork: boolean;
1079
- preserveSourceCompactionState: boolean;
1080
- visibleWindowStartIndex: number;
1081
- /**
1082
- * When provided, a disk-sync entry is appended per copied message for the
1083
- * caller to flush after commit. Omitted by the retrospective fork, whose
1084
- * throwaway conversation needs no disk-view projection.
1085
- */
1086
- diskSyncQueue?: Array<{
1087
- conversationId: string;
1088
- messageId: string;
1089
- createdAt: number;
1090
- }>;
1091
- }
1092
-
1093
- /**
1094
- * In-process tail of a conversation fork: relink each copied message's
1095
- * attachments (scoped per-conversation), set `lastMessageAt`, seed attention,
1096
- * and carry the parent's per-conversation memory state.
1097
- *
1098
- * Assumes the fork's message ROWS already exist — copied either in-process
1099
- * (synchronous fork) or via the off-event-loop subprocess (retrospective
1100
- * fork). Single source of truth shared by `forkConversation` and
1101
- * `forkConversationForRetrospective`; must run inside a transaction on the
1102
- * main connection.
1103
- */
1104
- function populateForkContentsInProcess(args: PopulateForkContentsArgs): void {
1105
- const {
1106
- fork,
1107
- sourceConversationId,
1108
- messagesToCopy,
1109
- forkedMessageIds,
1110
- latestForkedAssistant,
1111
- isFullHistoryFork,
1112
- preserveSourceCompactionState,
1113
- visibleWindowStartIndex,
1114
- diskSyncQueue,
1115
- } = args;
1116
- const db = getDb();
1117
-
1118
- const attachmentIdMap = new Map<string, string>();
1119
- for (const message of messagesToCopy) {
1120
- const forkedMessageId = forkedMessageIds.get(message.id);
1121
- if (!forkedMessageId) continue;
1122
-
1123
- const attachmentLinks = db
1124
- .select({
1125
- attachmentId: messageAttachments.attachmentId,
1126
- position: messageAttachments.position,
1127
- })
1128
- .from(messageAttachments)
1129
- .where(eq(messageAttachments.messageId, message.id))
1130
- .orderBy(messageAttachments.position)
1131
- .all();
1132
- const uncachedAttachmentLinks = attachmentLinks.filter(
1133
- (link) => !attachmentIdMap.has(link.attachmentId),
1134
- );
1135
- const stagingMessageId = uncachedAttachmentLinks.length > 0 ? uuid() : null;
1136
-
1137
- if (stagingMessageId) {
1138
- db.insert(messages)
1139
- .values({
1140
- id: stagingMessageId,
1141
- conversationId: fork.id,
1142
- role: message.role,
1143
- content: "",
1144
- createdAt: message.createdAt,
1145
- metadata: null,
1146
- })
1147
- .run();
1148
- }
1149
-
1150
- for (const link of attachmentLinks) {
1151
- const cachedAttachmentId = attachmentIdMap.get(link.attachmentId);
1152
- if (cachedAttachmentId) {
1153
- db.insert(messageAttachments)
1154
- .values({
1155
- id: uuid(),
1156
- messageId: forkedMessageId,
1157
- attachmentId: cachedAttachmentId,
1158
- position: link.position,
1159
- createdAt: Date.now(),
1160
- })
1161
- .run();
1162
- continue;
1163
- }
1164
-
1165
- const scopedAttachmentId = linkAttachmentToMessage(
1166
- stagingMessageId ?? forkedMessageId,
1167
- link.attachmentId,
1168
- link.position,
1169
- );
1170
- attachmentIdMap.set(link.attachmentId, scopedAttachmentId);
1171
- }
1172
-
1173
- if (stagingMessageId) {
1174
- relinkAttachments([stagingMessageId], forkedMessageId);
1175
- db.delete(messages).where(eq(messages.id, stagingMessageId)).run();
1176
- }
1177
-
1178
- diskSyncQueue?.push({
1179
- conversationId: fork.id,
1180
- messageId: forkedMessageId,
1181
- createdAt: fork.createdAt,
1182
- });
1183
- }
1184
-
1185
- // Set lastMessageAt to the max createdAt of copied messages so the
1186
- // forked conversation sorts correctly by message recency.
1187
- const lastCopiedMessage = messagesToCopy.at(-1);
1188
- if (lastCopiedMessage) {
1189
- db.update(conversations)
1190
- .set({ lastMessageAt: lastCopiedMessage.createdAt })
1191
- .where(eq(conversations.id, fork.id))
1192
- .run();
1193
- }
1194
-
1195
- seedForkedConversationAttention({
1196
- conversationId: fork.id,
1197
- latestAssistantMessageId: latestForkedAssistant?.messageId ?? null,
1198
- latestAssistantMessageAt: latestForkedAssistant?.messageAt ?? null,
1199
- });
1200
-
1201
- // Carry the parent's per-conversation memory state into the child so the
1202
- // forked thread resumes with the same activation/injection log and
1203
- // in-context tracker the parent had at fork time. Only valid for
1204
- // full-history forks: a truncated fork would inherit activation/tracker
1205
- // entries for turns the child does not actually contain.
1206
- if (isFullHistoryFork) {
1207
- forkActivationState(db, sourceConversationId, fork.id);
1208
- forkEverInjected(db, sourceConversationId, fork.id);
1209
- forkGraphMemoryState(sourceConversationId, fork.id);
1210
- } else {
1211
- // Truncated fork: the wholesale copy above would over-claim, but
1212
- // seeding nothing makes the child re-select and re-attach every page
1213
- // whose `<memory>` attachment it already inherited (observed in
1214
- // production: 89 duplicate page injections on one fork). Derive
1215
- // `everInjected` from the inherited attachments themselves — scoped to
1216
- // the child's visible window, since attachments behind an inherited
1217
- // compaction boundary are not rendered and must stay re-injectable.
1218
- // The v2 and v3 layers persist under separate metadata keys with the
1219
- // same `# memory/concepts/<slug>.md` header convention, so each seeds
1220
- // its own dedup record from its own blocks.
1221
- const visibleStartIndex = preserveSourceCompactionState
1222
- ? visibleWindowStartIndex
1223
- : 0;
1224
- const inheritedSlugs = new Set<string>();
1225
- const inheritedV3Slugs = new Set<string>();
1226
- for (const message of messagesToCopy.slice(visibleStartIndex)) {
1227
- const block = readInjectedBlock(message.metadata, "memoryInjectedBlock");
1228
- if (block) {
1229
- for (const slug of extractInjectedConceptSlugs(block)) {
1230
- inheritedSlugs.add(slug);
1231
- }
1232
- }
1233
- const v3Block = readInjectedBlock(
1234
- message.metadata,
1235
- MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
1236
- );
1237
- if (v3Block) {
1238
- for (const slug of extractInjectedConceptSlugs(v3Block)) {
1239
- inheritedV3Slugs.add(slug);
1240
- }
1241
- }
1242
- }
1243
- seedForkActivationState(db, fork.id, [...inheritedSlugs]);
1244
- seedEverInjectedFromSlugs(
1245
- db,
1246
- sourceConversationId,
1247
- fork.id,
1248
- [...inheritedV3Slugs],
1249
- Date.now(),
1250
- );
1251
- }
1252
- forkRetrospectiveState({
1253
- database: db,
1254
- sourceConversationId,
1255
- forkedConversationId: fork.id,
1256
- forkedMessageIds,
1257
- lastCopiedSourceMessageId: messagesToCopy.at(-1)?.id ?? null,
1258
- });
1259
- }
1260
-
1261
- /**
1262
- * Resolve the fork id + timestamp of the LAST assistant message among the
1263
- * copied rows. The synchronous copy loop tracks this inline; the off-loop
1264
- * subprocess copy does not, so the async fork derives it from the id map.
1265
- */
1266
- function latestForkedAssistantFrom(
1267
- messagesToCopy: MessageRow[],
1268
- forkedMessageIds: Map<string, string>,
1269
- ): { messageId: string; messageAt: number } | null {
1270
- for (let i = messagesToCopy.length - 1; i >= 0; i--) {
1271
- const message = messagesToCopy[i]!;
1272
- if (message.role !== "assistant") continue;
1273
- const forkedMessageId = forkedMessageIds.get(message.id);
1274
- if (forkedMessageId) {
1275
- return { messageId: forkedMessageId, messageAt: message.createdAt };
1276
- }
1277
- }
1278
- return null;
1279
- }
1280
-
1281
- /**
1282
- * Async variant of {@link forkConversation} for the memory-retrospective job,
1283
- * which forks the entire source conversation into a throwaway background
1284
- * conversation on a hot path that must not stall the daemon.
1285
- *
1286
- * The dominant cost — copying every source message row — runs OFF the event
1287
- * loop in a `sqlite3` subprocess (see {@link copyForkMessagesViaSubprocess}),
1288
- * so `/healthz` and gateway IPC stay responsive during the copy. The cheap
1289
- * tail (conversation row, attachment relink, memory-state seeding) runs
1290
- * in-process and reuses {@link populateForkContentsInProcess}, the same helper
1291
- * the synchronous fork uses, so the two paths cannot drift on that logic. The
1292
- * boundary/compaction computation mirrors {@link forkConversation} and is
1293
- * pinned by a parity test.
1294
- *
1295
- * The disk-view projection (`syncMessageToDisk`) is intentionally skipped: the
1296
- * fork is GC'd after the retrospective pass and never browsed, and the agent
1297
- * reads it from the database, not the on-disk JSONL.
1298
- *
1299
- * Atomicity spans two connections (the in-process row/tail and the subprocess
1300
- * copy), so a mid-flight failure can leave a partial fork. The partial is
1301
- * deleted best-effort on error; a crash between phases is reclaimed by the
1302
- * worker's startup orphan sweep. Callers only ever observe a fully-built fork
1303
- * because the returned promise resolves after every phase commits.
1304
- */
1305
- export async function forkConversationForRetrospective(params: {
1306
- conversationId: string;
1307
- throughMessageId?: string;
1308
- source?: string;
1309
- title?: string;
1310
- conversationType?: ConversationCreateType;
1311
- groupId?: string;
1312
- }): Promise<ConversationRow> {
1313
- const { conversationId, throughMessageId } = params;
1314
- const db = getDb();
1315
- const sourceConversation = getConversation(conversationId);
1316
- if (!sourceConversation) {
1317
- throw new UserError(`Conversation ${conversationId} not found`);
1318
- }
1319
-
1320
- const sourceMessages = getMessages(conversationId);
1321
- if (throughMessageId != null) {
1322
- // Re-sort on `(createdAt, id)` so the cutoff slice agrees with the cursor
1323
- // the caller chose it from — see the matching note in `forkConversation`.
1324
- sourceMessages.sort(
1325
- (a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id),
1326
- );
1327
- }
1328
- if (sourceMessages.length === 0) {
1329
- throw new UserError(
1330
- `Conversation ${conversationId} has no persisted messages to fork`,
1331
- );
1332
- }
1333
-
1334
- const initialBoundaryIndex =
1335
- throughMessageId == null
1336
- ? sourceMessages.length - 1
1337
- : sourceMessages.findIndex((message) => message.id === throughMessageId);
1338
- if (throughMessageId != null && initialBoundaryIndex === -1) {
1339
- throw new UserError(
1340
- `Message ${throughMessageId} does not belong to conversation ${conversationId}`,
1341
- );
1342
- }
1343
-
1344
- const copyBoundaryIndex = findDisplayTurnEndIndex(
1345
- sourceMessages,
1346
- initialBoundaryIndex,
1347
- );
1348
- const visibleWindowStartIndex = Math.max(
1349
- 0,
1350
- Math.min(
1351
- sourceConversation.contextCompactedMessageCount,
1352
- sourceMessages.length,
1353
- ),
1354
- );
1355
- const preserveSourceCompactionState =
1356
- copyBoundaryIndex >= visibleWindowStartIndex;
1357
- const messagesToCopy =
1358
- copyBoundaryIndex >= 0
1359
- ? sourceMessages.slice(0, copyBoundaryIndex + 1)
1360
- : ([] as MessageRow[]);
1361
-
1362
- const sourceHistoryStrippedAt = sourceConversation.historyStrippedAt ?? null;
1363
- const boundaryMessageCreatedAt = messagesToCopy.at(-1)?.createdAt ?? null;
1364
- const inheritsHistoryStrippedAt =
1365
- sourceHistoryStrippedAt != null &&
1366
- boundaryMessageCreatedAt != null &&
1367
- boundaryMessageCreatedAt >= sourceHistoryStrippedAt;
1368
- const forkParentMessageId = messagesToCopy.at(-1)?.id ?? null;
1369
- const forkTitle =
1370
- params.title ?? `${sourceConversation.title ?? "Untitled"} (Fork)`;
1371
- const parentGroupId = getConversationGroupId(conversationId);
1372
-
1373
- // Pre-generate the id map in JS so the same map drives the off-loop copy and
1374
- // the in-process attachment relink that follows.
1375
- const idPairs: ForkIdPair[] = messagesToCopy.map((message) => ({
1376
- oldId: message.id,
1377
- newId: uuid(),
1378
- }));
1379
- const forkedMessageIds = new Map<string, string>(
1380
- idPairs.map((pair) => [pair.oldId, pair.newId]),
1381
- );
1382
-
1383
- // Phase 1 (in-process, tiny): create the fork conversation row + lineage so
1384
- // the subprocess connection sees it before inserting messages.
1385
- const fork = db.transaction(() => {
1386
- const fc = createConversation({
1387
- title: forkTitle,
1388
- conversationType: params.conversationType ?? "standard",
1389
- groupId: params.groupId ?? parentGroupId ?? "system:all",
1390
- ...(params.source != null ? { source: params.source } : {}),
1391
- });
1392
- db.update(conversations)
1393
- .set({
1394
- forkParentConversationId: sourceConversation.id,
1395
- forkParentMessageId,
1396
- contextSummary: preserveSourceCompactionState
1397
- ? sourceConversation.contextSummary
1398
- : null,
1399
- contextCompactedMessageCount: preserveSourceCompactionState
1400
- ? sourceConversation.contextCompactedMessageCount
1401
- : 0,
1402
- contextCompactedAt: preserveSourceCompactionState
1403
- ? sourceConversation.contextCompactedAt
1404
- : null,
1405
- slackContextCompactionWatermarkTs: preserveSourceCompactionState
1406
- ? sourceConversation.slackContextCompactionWatermarkTs
1407
- : null,
1408
- slackContextCompactionWatermarkAt: preserveSourceCompactionState
1409
- ? sourceConversation.slackContextCompactionWatermarkAt
1410
- : null,
1411
- historyStrippedAt: inheritsHistoryStrippedAt
1412
- ? sourceHistoryStrippedAt
1413
- : null,
1414
- inferenceProfile: sourceConversation.inferenceProfile,
1415
- })
1416
- .where(eq(conversations.id, fc.id))
1417
- .run();
1418
- return fc;
1419
- });
1420
-
1421
- try {
1422
- // Phase 2 (off the event loop): copy the message rows in a sqlite3
1423
- // subprocess so the daemon stays responsive during the heavy copy.
1424
- const copy = await copyForkMessagesViaSubprocess({
1425
- forkConversationId: fork.id,
1426
- idPairs,
1427
- });
1428
- if (!copy.ok) {
1429
- throw new Error(
1430
- `fork message copy failed (${copy.backend}): ${copy.error ?? "unknown"}`,
1431
- );
1432
- }
1433
-
1434
- // Phase 3 (in-process): attachments + memory-state seeding, reusing the
1435
- // same helper as the synchronous fork. Disk-view projection is skipped.
1436
- const latestForkedAssistant = latestForkedAssistantFrom(
1437
- messagesToCopy,
1438
- forkedMessageIds,
1439
- );
1440
- db.transaction(() => {
1441
- populateForkContentsInProcess({
1442
- fork,
1443
- sourceConversationId: sourceConversation.id,
1444
- messagesToCopy,
1445
- forkedMessageIds,
1446
- latestForkedAssistant,
1447
- isFullHistoryFork: copyBoundaryIndex === sourceMessages.length - 1,
1448
- preserveSourceCompactionState,
1449
- visibleWindowStartIndex,
1450
- });
1451
- });
1452
-
1453
- const persistedFork = getConversation(fork.id);
1454
- if (!persistedFork) {
1455
- throw new Error(
1456
- `Failed to load forked conversation ${fork.id} after creation`,
1457
- );
1458
- }
1459
- return persistedFork;
1460
- } catch (err) {
1461
- try {
1462
- deleteConversation(fork.id);
1463
- } catch {
1464
- // Best-effort cleanup; the worker's startup orphan sweep is the backstop.
1465
- }
1466
- throw err;
1467
- }
1468
- }
1469
-
1470
- /**
1471
- * Delete a conversation and all its messages, cleaning up orphaned memory
1472
- * artifacts (embeddings). Returns segment IDs so callers can clean up
1473
- * the corresponding Qdrant vector entries.
1474
- */
1475
- export function deleteConversation(id: string): DeletedMemoryIds {
1476
- const db = getDb();
1477
- const result: DeletedMemoryIds = {
1478
- segmentIds: [],
1479
- deletedSummaryIds: [],
1480
- };
1481
-
1482
- // Capture createdAt before the transaction deletes the row — needed to
1483
- // resolve the conversation's disk-view directory path after deletion.
1484
- const convBeforeDelete = getConversation(id);
1485
- const createdAtForDiskCleanup = convBeforeDelete?.createdAt;
1486
-
1487
- // llm_request_logs lives in the dedicated logs connection, so it is deleted
1488
- // there — separately from the main-DB transaction below.
1489
- logsDb()
1490
- .delete(llmRequestLogs)
1491
- .where(eq(llmRequestLogs.conversationId, id))
1492
- .run();
1493
-
1494
- db.transaction((tx) => {
1495
- // Collect all message IDs for this conversation.
1496
- const messageRows = tx
1497
- .select({ id: messages.id })
1498
- .from(messages)
1499
- .where(eq(messages.conversationId, id))
1500
- .all();
1501
- const messageIds = messageRows.map((r) => r.id);
1502
-
1503
- if (messageIds.length > 0) {
1504
- // Collect memory segment IDs linked to these messages before cascade.
1505
- const linkedSegments = tx
1506
- .select({ id: memorySegments.id })
1507
- .from(memorySegments)
1508
- .where(inArray(memorySegments.messageId, messageIds))
1509
- .all();
1510
- result.segmentIds = linkedSegments.map((r) => r.id);
1511
-
1512
- // Delete non-cascading tables first.
1513
- tx.delete(toolInvocations)
1514
- .where(eq(toolInvocations.conversationId, id))
1515
- .run();
1516
- tx.delete(skillLoadedEvents)
1517
- .where(eq(skillLoadedEvents.conversationId, id))
1518
- .run();
1519
- // Cascade deletes memory_segments, message_attachments.
1520
- tx.delete(messages).where(eq(messages.conversationId, id)).run();
1521
-
1522
- // Clean up segment embeddings.
1523
- if (result.segmentIds.length > 0) {
1524
- tx.delete(memoryEmbeddings)
1525
- .where(
1526
- and(
1527
- eq(memoryEmbeddings.targetType, "segment"),
1528
- inArray(memoryEmbeddings.targetId, result.segmentIds),
1529
- ),
1530
- )
1531
- .run();
1532
- }
1533
- } else {
1534
- // No messages — just clean up non-message tables.
1535
- tx.delete(toolInvocations)
1536
- .where(eq(toolInvocations.conversationId, id))
1537
- .run();
1538
- tx.delete(skillLoadedEvents)
1539
- .where(eq(skillLoadedEvents.conversationId, id))
1540
- .run();
1541
- }
1542
-
1543
- tx.delete(conversations).where(eq(conversations.id, id)).run();
1544
- });
1545
-
1546
- // Remove the conversation's disk-view directory after the DB transaction
1547
- if (createdAtForDiskCleanup != null) {
1548
- removeConversationDir(id, createdAtForDiskCleanup);
1549
- }
1550
-
1551
- return result;
1552
- }
1553
-
1554
- /**
1555
- * Wipe a conversation and revert all memory changes it caused.
1556
- *
1557
- * Extends `deleteConversation` with:
1558
- * - Cancelling pending memory jobs before deletion
1559
- * - Deleting conversation-scoped memory summaries and their embeddings
1560
- */
1561
- export function wipeConversation(id: string): WipeConversationResult {
1562
- const db = getDb();
1563
- const deletedSummaryIds: string[] = [];
1564
-
1565
- // Step A — Cancel pending memory jobs (before deleting messages, since
1566
- // the cancellation queries join on `messages`).
1567
- const cancelledJobCount = cancelPendingJobsForConversation(id);
1568
-
1569
- // Step C — Delete conversation-scoped memory summaries and their embeddings.
1570
- const summaryRows = db
1571
- .select({ id: memorySummaries.id })
1572
- .from(memorySummaries)
1573
- .where(
1574
- and(
1575
- eq(memorySummaries.scope, "conversation"),
1576
- eq(memorySummaries.scopeKey, id),
1577
- ),
1578
- )
1579
- .all();
1580
- const summaryIds = summaryRows.map((r) => r.id);
1581
- if (summaryIds.length > 0) {
1582
- db.delete(memoryEmbeddings)
1583
- .where(
1584
- and(
1585
- eq(memoryEmbeddings.targetType, "summary"),
1586
- inArray(memoryEmbeddings.targetId, summaryIds),
1587
- ),
1588
- )
1589
- .run();
1590
- db.delete(memorySummaries)
1591
- .where(inArray(memorySummaries.id, summaryIds))
1592
- .run();
1593
- }
1594
- deletedSummaryIds.push(...summaryIds);
1595
-
1596
- // Step D — Delegate to deleteConversation which handles messages (cascade
1597
- // segments, attachments), llmRequestLogs, toolInvocations,
1598
- // skillLoadedEvents, embeddings, and the conversation row.
1599
- const deletedMemoryIds = deleteConversation(id);
1600
-
1601
- // Step E — Return the combined result.
1602
- return {
1603
- ...deletedMemoryIds,
1604
- deletedSummaryIds: [
1605
- ...deletedSummaryIds,
1606
- ...deletedMemoryIds.deletedSummaryIds,
1607
- ],
1608
- cancelledJobCount,
1609
- };
1610
- }
1611
-
1612
- /** Options for {@link addMessage}. Only `skipIndexing` and `clientMessageId`
1613
- * have defaults; `metadata` is genuinely optional. */
1614
- export interface AddMessageOptions {
1615
- metadata?: Record<string, unknown>;
1616
- skipIndexing?: boolean;
1617
- /** Client-generated nonce for idempotent inserts. When provided,
1618
- * duplicate inserts for the same `(conversationId, clientMessageId)`
1619
- * pair are silently skipped. */
1620
- clientMessageId?: string;
1621
- }
1622
-
1623
- /**
1624
- * Persist a message and run post-insert side effects (memory indexing,
1625
- * attention projection). Delegates the core insert + retry logic to
1626
- * {@link insertMessageCore}.
1627
- */
1628
- export async function addMessage(
1629
- conversationId: string,
1630
- role: MessageRole,
1631
- content: string,
1632
- options?: AddMessageOptions,
1633
- ) {
1634
- const { metadata, skipIndexing, clientMessageId } = options ?? {};
1635
- const inserted = await insertMessageCore({
1636
- conversationId,
1637
- role,
1638
- content,
1639
- metadata,
1640
- clientMessageId,
1641
- });
1642
-
1643
- if (inserted.deduplicated) {
1644
- return inserted;
1645
- }
1646
-
1647
- const message = inserted;
1648
-
1649
- if (!skipIndexing) {
1650
- try {
1651
- const config = getConfig();
1652
- const parsed = metadata
1653
- ? messageMetadataSchema.safeParse(metadata)
1654
- : null;
1655
- const provenanceTrustClass = parsed?.success
1656
- ? parsed.data.provenanceTrustClass
1657
- : undefined;
1658
- const automated = parsed?.success ? parsed.data.automated : undefined;
1659
- await indexMessageNow(
1660
- {
1661
- messageId: message.id,
1662
- conversationId: message.conversationId,
1663
- role: message.role,
1664
- content: message.content,
1665
- createdAt: message.createdAt,
1666
- scopeId: "default",
1667
- provenanceTrustClass,
1668
- automated,
1669
- },
1670
- config.memory,
1671
- );
1672
- } catch (err) {
1673
- log.warn(
1674
- { err, conversationId, messageId: message.id },
1675
- "Failed to index message for memory",
1676
- );
1677
- }
1678
- }
1679
-
1680
- if (role === "assistant") {
1681
- try {
1682
- const attentionStateChanged = projectAssistantMessage({
1683
- conversationId,
1684
- messageId: message.id,
1685
- messageAt: message.createdAt,
1686
- });
1687
- if (attentionStateChanged) {
1688
- void publishSyncInvalidation([
1689
- conversationMetadataSyncTag(conversationId),
1690
- ]);
1691
- }
1692
- } catch (err) {
1693
- log.warn(
1694
- { err, conversationId, messageId: message.id },
1695
- "Failed to project assistant message for attention tracking",
1696
- );
1697
- }
1698
- }
1699
-
1700
- return message;
1701
- }
1702
-
1703
- export function getMessages(conversationId: string): MessageRow[] {
1704
- const db = getDb();
1705
- return db
1706
- .select()
1707
- .from(messages)
1708
- .where(eq(messages.conversationId, conversationId))
1709
- .orderBy(asc(messages.createdAt))
1710
- .all()
1711
- .map(parseMessage);
1712
- }
1713
-
1714
- /**
1715
- * Return raw `metadata` strings for messages whose metadata looks like it may
1716
- * contain Slack metadata, capped at `limit` and skipping the first `offset`
1717
- * matches. Pushes `LIKE` + `LIMIT`/`OFFSET` into SQL so warm Slack DM
1718
- * conversations don't require a full-table scan on the webhook critical path.
1719
- * The substring match is an indexable prefilter only — callers must parse and
1720
- * validate each returned string against the Slack metadata schema, because a
1721
- * malformed row (partial write, legacy format, unrelated key accidentally
1722
- * containing the literal) can still slip through the substring match. Callers
1723
- * that need a fixed number of *valid* rows should iterate with increasing
1724
- * offsets until the target is reached (capped at a reasonable maximum to bound
1725
- * scan cost).
1726
- */
1727
- export function selectSlackMetaCandidateMetadata(
1728
- conversationId: string,
1729
- limit: number,
1730
- offset = 0,
1731
- opts?: { includeFlatLegacy?: boolean },
1732
- ): string[] {
1733
- const db = getDb();
1734
- const rows = db
1735
- .select({ metadata: messages.metadata })
1736
- .from(messages)
1737
- .where(
1738
- and(
1739
- eq(messages.conversationId, conversationId),
1740
- opts?.includeFlatLegacy
1741
- ? or(
1742
- like(messages.metadata, '%"slackMeta"%'),
1743
- like(messages.metadata, '%"source":"slack"%'),
1744
- )
1745
- : like(messages.metadata, '%"slackMeta"%'),
1746
- ),
1747
- )
1748
- .orderBy(asc(messages.createdAt))
1749
- .limit(limit)
1750
- .offset(offset)
1751
- .all();
1752
- const out: string[] = [];
1753
- for (const r of rows) {
1754
- if (typeof r.metadata === "string" && r.metadata.length > 0) {
1755
- out.push(r.metadata);
1756
- }
1757
- }
1758
- return out;
1759
- }
1760
-
1761
- /**
1762
- * Count messages in a conversation that were created strictly after the
1763
- * `afterMessageId` reference message. If `afterMessageId` is `null` or empty,
1764
- * counts all messages in the conversation. If the referenced message no
1765
- * longer exists (e.g. deleted by a separate flow), returns 0 — callers
1766
- * decide how to react to a vanished reference, and the conservative answer
1767
- * here is "no new work."
1768
- *
1769
- * Used by the memory-retrospective trigger check to decide whether to fire
1770
- * the message-count trigger without loading message bodies.
1771
- */
1772
- export function countMessagesAfter(
1773
- conversationId: string,
1774
- afterMessageId: string | null,
1775
- ): number {
1776
- const db = getDb();
1777
- if (afterMessageId === null || afterMessageId === "") {
1778
- const row = db
1779
- .select({ c: count() })
1780
- .from(messages)
1781
- .where(eq(messages.conversationId, conversationId))
1782
- .get();
1783
- return row?.c ?? 0;
1784
- }
1785
- const ref = db
1786
- .select({ createdAt: messages.createdAt })
1787
- .from(messages)
1788
- .where(eq(messages.id, afterMessageId))
1789
- .get();
1790
- if (!ref) return 0;
1791
- // Tie-breaker on `messages.id` so rows that share a millisecond timestamp
1792
- // with the reference are not permanently skipped. Mirrors the
1793
- // `(createdAt, id)` cursor pattern used by the backfill job-handler and
1794
- // turn-events-store.
1795
- const row = db
1796
- .select({ c: count() })
1797
- .from(messages)
1798
- .where(
1799
- and(
1800
- eq(messages.conversationId, conversationId),
1801
- or(
1802
- gt(messages.createdAt, ref.createdAt),
1803
- and(
1804
- eq(messages.createdAt, ref.createdAt),
1805
- gt(messages.id, afterMessageId),
1806
- ),
1807
- ),
1808
- ),
1809
- )
1810
- .get();
1811
- return row?.c ?? 0;
1812
- }
1813
-
1814
- /**
1815
- * Return messages in a conversation created strictly after the
1816
- * `afterMessageId` reference. If the reference is `null`/empty, returns all
1817
- * messages. If the reference doesn't exist, returns an empty array (mirrors
1818
- * `countMessagesAfter`'s conservative semantics). Used by the
1819
- * memory-retrospective job handler to load the message slice it processes.
1820
- */
1821
- export function getMessagesAfter(
1822
- conversationId: string,
1823
- afterMessageId: string | null,
1824
- ): MessageRow[] {
1825
- const db = getDb();
1826
- if (afterMessageId === null || afterMessageId === "") {
1827
- // Secondary `asc(messages.id)` matches the non-null path's cursor
1828
- // ordering, so callers tracking `cutoffMessageId` across runs see a
1829
- // consistent ordering when multiple rows share a millisecond timestamp.
1830
- return db
1831
- .select()
1832
- .from(messages)
1833
- .where(eq(messages.conversationId, conversationId))
1834
- .orderBy(asc(messages.createdAt), asc(messages.id))
1835
- .all()
1836
- .map(parseMessage);
1837
- }
1838
- const ref = db
1839
- .select({ createdAt: messages.createdAt })
1840
- .from(messages)
1841
- .where(eq(messages.id, afterMessageId))
1842
- .get();
1843
- if (!ref) return [];
1844
- // Same `(createdAt, id)` cursor as `countMessagesAfter` — rows sharing
1845
- // the reference's millisecond timestamp would otherwise be skipped.
1846
- return db
1847
- .select()
1848
- .from(messages)
1849
- .where(
1850
- and(
1851
- eq(messages.conversationId, conversationId),
1852
- or(
1853
- gt(messages.createdAt, ref.createdAt),
1854
- and(
1855
- eq(messages.createdAt, ref.createdAt),
1856
- gt(messages.id, afterMessageId),
1857
- ),
1858
- ),
1859
- ),
1860
- )
1861
- .orderBy(asc(messages.createdAt), asc(messages.id))
1862
- .all()
1863
- .map(parseMessage);
1864
- }
1865
-
1866
- /**
1867
- * Efficient existence check — returns true if the conversation has at least
1868
- * one message row. Uses `LIMIT 1` + `select({ 1 })` to avoid loading and
1869
- * parsing any message content.
1870
- */
1871
- export function hasMessages(conversationId: string): boolean {
1872
- const db = getDb();
1873
- const row = db
1874
- .select({ one: sql`1` })
1875
- .from(messages)
1876
- .where(eq(messages.conversationId, conversationId))
1877
- .limit(1)
1878
- .get();
1879
- return row !== undefined;
1880
- }
1881
-
1882
- interface PaginatedMessagesResult {
1883
- messages: MessageRow[];
1884
- hasMore: boolean;
1885
- /**
1886
- * Position of the last row scanned when the loop stops on
1887
- * `PAGINATION_SCAN_CAP` rather than DB exhaustion. Callers derive their
1888
- * client cursor from the visible page's oldest row, but a cap-truncated
1889
- * page can be empty (a contiguous block of filtered-out rows longer than
1890
- * the cap), leaving nothing to resume from. Surfacing the last scanned
1891
- * `(createdAt, id)` lets the caller hand the client a cursor so it can
1892
- * request the next window and keep draining instead of stalling.
1893
- */
1894
- nextCursor?: { createdAt: number; id: string };
1895
- }
1896
-
1897
- const PAGINATION_CHUNK_MIN = 50;
1898
- const PAGINATION_SCAN_CAP = 10_000;
1899
-
1900
- // Test-only override for PAGINATION_SCAN_CAP so tests can exercise the
1901
- // cap-truncation branch with a small cap instead of seeding >10k rows (which
1902
- // makes the suite slow and the post-test DELETE flaky under parallel CI load).
1903
- // `undefined` restores the production cap.
1904
- let paginationScanCapOverride: number | undefined;
1905
- export function _setPaginationScanCapForTesting(cap: number | undefined): void {
1906
- paginationScanCapOverride = cap;
1907
- }
1908
-
1909
- export function getMessagesPaginated(
1910
- conversationId: string,
1911
- limit: number | undefined,
1912
- beforeTimestamp?: number,
1913
- filter?: (row: MessageRow) => boolean,
1914
- ): PaginatedMessagesResult {
1915
- const db = getDb();
1916
-
1917
- if (limit === undefined) {
1918
- const conditions = [eq(messages.conversationId, conversationId)];
1919
- if (beforeTimestamp !== undefined) {
1920
- conditions.push(lt(messages.createdAt, beforeTimestamp));
1921
- }
1922
- const rows = db
1923
- .select()
1924
- .from(messages)
1925
- .where(and(...conditions))
1926
- .orderBy(asc(messages.createdAt))
1927
- .all()
1928
- .map(parseMessage);
1929
- return {
1930
- messages: filter ? rows.filter(filter) : rows,
1931
- hasMore: false,
1932
- };
1933
- }
1934
-
1935
- // Walk pages newest→oldest, applying `filter` in TS (metadata parsing is
1936
- // JSON, not a structured column). Keep fetching until we have `limit + 1`
1937
- // visible rows or the DB is exhausted, so `hasMore` and the cursor reflect
1938
- // the visible page rather than the unfiltered row count. Without this loop,
1939
- // a fully-hidden page returns `{ messages: [], hasMore: true }` with no
1940
- // cursor, which stalls the web client's older-page fetch.
1941
- let cursorCreatedAt = beforeTimestamp;
1942
- let cursorMessageId: string | undefined;
1943
- const visible: MessageRow[] = [];
1944
- const chunkSize = Math.max(limit + 1, PAGINATION_CHUNK_MIN);
1945
- // Bound the work a single request can do when `filter` rejects nearly every
1946
- // row — otherwise a pathological filter against a huge conversation would
1947
- // tie up a connection for thousands of roundtrips.
1948
- let rowsScanned = 0;
1949
- // Distinguish "stopped because we hit the scan cap" from "stopped because the
1950
- // DB ran out of rows". On a cap-truncated stop there may be more visible rows
1951
- // past the scanned window, so `hasMore` must stay true and we record the last
1952
- // scanned position as a resume cursor (the visible page may be empty).
1953
- let scanCapTruncated = false;
1954
- let lastScanned: { createdAt: number; id: string } | undefined;
1955
- const scanCap = paginationScanCapOverride ?? PAGINATION_SCAN_CAP;
1956
-
1957
- while (visible.length < limit + 1) {
1958
- if (rowsScanned >= scanCap) {
1959
- scanCapTruncated = true;
1960
- break;
1961
- }
1962
- const cursorPredicate =
1963
- cursorCreatedAt === undefined
1964
- ? undefined
1965
- : cursorMessageId === undefined
1966
- ? lt(messages.createdAt, cursorCreatedAt)
1967
- : or(
1968
- lt(messages.createdAt, cursorCreatedAt),
1969
- and(
1970
- eq(messages.createdAt, cursorCreatedAt),
1971
- lt(messages.id, cursorMessageId),
1972
- ),
1973
- );
1974
-
1975
- const chunk = db
1976
- .select()
1977
- .from(messages)
1978
- .where(and(eq(messages.conversationId, conversationId), cursorPredicate))
1979
- .orderBy(desc(messages.createdAt), desc(messages.id))
1980
- .limit(chunkSize)
1981
- .all()
1982
- .map(parseMessage);
1983
-
1984
- if (chunk.length === 0) break;
1985
- rowsScanned += chunk.length;
1986
-
1987
- for (const row of chunk) {
1988
- if (!filter || filter(row)) visible.push(row);
1989
- if (visible.length >= limit + 1) break;
1990
- }
1991
-
1992
- if (chunk.length < chunkSize) break;
1993
- const lastRow = chunk[chunk.length - 1];
1994
- lastScanned = { createdAt: lastRow.createdAt, id: lastRow.id };
1995
- cursorCreatedAt = lastRow.createdAt;
1996
- cursorMessageId = lastRow.id;
1997
- }
1998
-
1999
- const filledPage = visible.length > limit;
2000
- // A cap-truncated stop means the DB may still hold older visible rows past
2001
- // the scanned window, so report `hasMore: true` to keep the client draining
2002
- // — returning `false` here is the stall this loop exists to prevent.
2003
- const hasMore = filledPage || scanCapTruncated;
2004
- if (filledPage) visible.splice(limit);
2005
- visible.reverse();
2006
-
2007
- // Only hand back a resume cursor when the cap (not DB exhaustion) cut the
2008
- // search short; callers fall back to it when the visible page came back
2009
- // empty and has no oldest row to anchor the next request.
2010
- const nextCursor = scanCapTruncated ? lastScanned : undefined;
2011
-
2012
- return { messages: visible, hasMore, nextCursor };
2013
- }
2014
-
2015
- export function getLastUserTimestampBefore(
2016
- conversationId: string,
2017
- beforeTimestamp: number,
2018
- ): number {
2019
- const db = getDb();
2020
- const row = db
2021
- .select({ createdAt: messages.createdAt })
2022
- .from(messages)
2023
- .where(
2024
- and(
2025
- eq(messages.conversationId, conversationId),
2026
- eq(messages.role, "user"),
2027
- lt(messages.createdAt, beforeTimestamp),
2028
- ),
2029
- )
2030
- .orderBy(desc(messages.createdAt))
2031
- .limit(1)
2032
- .get();
2033
- return row?.createdAt ?? 0;
2034
- }
2035
-
2036
- /**
2037
- * Most recent user-message timestamp (epoch ms) across all conversations, or
2038
- * `0` when no user message exists.
2039
- *
2040
- * Ordered by `created_at` rather than insertion order, because `forkConversation`
2041
- * copies a parent's messages into the fork while preserving their original
2042
- * `created_at`. Those copies receive fresh row ids, so an insertion-order scan
2043
- * could surface an old forked turn as if it were the latest activity and let
2044
- * maintenance run while the user is in fact active. The `(role, created_at)`
2045
- * index (`idx_messages_role_created_at`) makes this an indexed seek to the
2046
- * newest `role = "user"` row rather than a scan of the whole (potentially
2047
- * multi-GB) table.
2048
- */
2049
- export function getLastUserMessageTimestamp(): number {
2050
- const db = getDb();
2051
- const row = db
2052
- .select({ createdAt: messages.createdAt })
2053
- .from(messages)
2054
- .where(eq(messages.role, "user"))
2055
- .orderBy(desc(messages.createdAt))
2056
- .limit(1)
2057
- .get();
2058
- return row?.createdAt ?? 0;
2059
- }
2060
-
2061
- /** Fetch a single message by ID, optionally scoped to a specific conversation. */
2062
- export function getMessageById(
2063
- messageId: string,
2064
- conversationId?: string,
2065
- ): MessageRow | null {
2066
- const db = getDb();
2067
- const conditions = [eq(messages.id, messageId)];
2068
- if (conversationId) {
2069
- conditions.push(eq(messages.conversationId, conversationId));
2070
- }
2071
- const row = db
2072
- .select()
2073
- .from(messages)
2074
- .where(and(...conditions))
2075
- .get();
2076
- return row ? parseMessage(row) : null;
2077
- }
2078
-
2079
- export function updateConversationTitle(
2080
- id: string,
2081
- title: string,
2082
- isAutoTitle?: number,
2083
- ): void {
2084
- const db = getDb();
2085
- const set: Record<string, unknown> = { title, updatedAt: Date.now() };
2086
- if (isAutoTitle !== undefined) set.isAutoTitle = isAutoTitle;
2087
- db.update(conversations).set(set).where(eq(conversations.id, id)).run();
2088
-
2089
- // Update disk view meta.json with the new title
2090
- const conv = getConversation(id);
2091
- if (conv) {
2092
- updateMetaFile(conv);
2093
- }
2094
- }
2095
-
2096
- export function updateConversationUsage(
2097
- id: string,
2098
- totalInputTokens: number,
2099
- totalOutputTokens: number,
2100
- totalEstimatedCost: number,
2101
- ): void {
2102
- const db = getDb();
2103
- db.update(conversations)
2104
- .set({
2105
- totalInputTokens,
2106
- totalOutputTokens,
2107
- totalEstimatedCost,
2108
- updatedAt: Date.now(),
2109
- })
2110
- .where(eq(conversations.id, id))
2111
- .run();
2112
- }
2113
-
2114
- export function updateConversationContextWindow(
2115
- id: string,
2116
- contextSummary: string,
2117
- contextCompactedMessageCount: number,
2118
- ): void {
2119
- const db = getDb();
2120
- db.update(conversations)
2121
- .set({
2122
- contextSummary,
2123
- contextCompactedMessageCount,
2124
- contextCompactedAt: Date.now(),
2125
- updatedAt: Date.now(),
2126
- })
2127
- .where(eq(conversations.id, id))
2128
- .run();
2129
- }
2130
-
2131
- export function setConversationHistoryStrippedAt(
2132
- id: string,
2133
- historyStrippedAt: number | null,
2134
- ): void {
2135
- const db = getDb();
2136
- db.update(conversations)
2137
- .set({
2138
- historyStrippedAt,
2139
- updatedAt: Date.now(),
2140
- })
2141
- .where(eq(conversations.id, id))
2142
- .run();
2143
- }
2144
-
2145
- export function updateConversationSlackContextWatermark(
2146
- id: string,
2147
- watermarkTs: string,
2148
- compactedAt: number = Date.now(),
2149
- ): void {
2150
- const db = getDb();
2151
- db.update(conversations)
2152
- .set({
2153
- slackContextCompactionWatermarkTs: watermarkTs,
2154
- slackContextCompactionWatermarkAt: compactedAt,
2155
- updatedAt: Date.now(),
2156
- })
2157
- .where(eq(conversations.id, id))
2158
- .run();
2159
- }
2160
-
2161
- export function archiveConversation(id: string): boolean {
2162
- const conv = getConversation(id);
2163
- if (!conv) return false;
2164
- const now = Date.now();
2165
- rawRun(
2166
- "UPDATE conversations SET archived_at = ?, updated_at = ? WHERE id = ?",
2167
- now,
2168
- now,
2169
- id,
2170
- );
2171
- return true;
2172
- }
2173
-
2174
- export function unarchiveConversation(id: string): boolean {
2175
- const conv = getConversation(id);
2176
- if (!conv) return false;
2177
- const now = Date.now();
2178
- rawRun(
2179
- "UPDATE conversations SET archived_at = NULL, updated_at = ? WHERE id = ?",
2180
- now,
2181
- id,
2182
- );
2183
- return true;
2184
- }
2185
-
2186
- /**
2187
- * Persist the processing-start timestamp for a conversation. Called by
2188
- * `Conversation.setProcessing(true)` so out-of-process callers can detect
2189
- * mid-turn state by reading the `conversations` row directly. Pass `null`
2190
- * to clear (turn ended).
2191
- */
2192
- export function setConversationProcessingStartedAt(
2193
- id: string,
2194
- startedAt: number | null,
2195
- ): void {
2196
- rawRun(
2197
- "UPDATE conversations SET processing_started_at = ? WHERE id = ?",
2198
- startedAt,
2199
- id,
2200
- );
2201
- }
2202
-
2203
- /**
2204
- * Read whether a conversation is currently processing. Checks the in-memory
2205
- * `Conversation._processing` flag first (hot path for resident conversations),
2206
- * falling back to the persisted `processing_started_at` column for cold
2207
- * (evicted / never-loaded) conversations. This is the single entry point for
2208
- * processing state — callers don't need to layer `findConversation` themselves.
2209
- * Returns `false` when the conversation row doesn't exist.
2210
- */
2211
- export function isConversationProcessing(id: string): boolean {
2212
- const inMemory = findConversation(id)?.isProcessing();
2213
- if (inMemory != null) return inMemory;
2214
- const row = rawGet<{ processing_started_at: number | null }>(
2215
- "SELECT processing_started_at FROM conversations WHERE id = ?",
2216
- id,
2217
- );
2218
- return row?.processing_started_at != null;
2219
- }
2220
-
2221
- /**
2222
- * Set or clear the `surfaced_at` promotion marker for a conversation.
2223
- *
2224
- * A non-null `surfaced_at` promotes a background/scheduled conversation
2225
- * into the default ("standard") conversation listing so clients show it in
2226
- * the Recents sidebar grouping. Promotion is always explicit — callers are
2227
- * product flows that decide a background run deserves foreground visibility
2228
- * (e.g. the user sent a follow-up message in it). Nothing sets this
2229
- * automatically.
2230
- *
2231
- * Returns `null` when the conversation does not exist; otherwise the new
2232
- * `surfacedAt` value (`number` when surfacing, `null` when clearing).
2233
- */
2234
- export function setConversationSurfaced(
2235
- id: string,
2236
- surfaced: boolean,
2237
- ): { surfacedAt: number | null } | null {
2238
- const conv = getConversation(id);
2239
- if (!conv) return null;
2240
- const now = Date.now();
2241
- const surfacedAt = surfaced ? now : null;
2242
- rawRun(
2243
- "UPDATE conversations SET surfaced_at = ?, updated_at = ? WHERE id = ?",
2244
- surfacedAt,
2245
- now,
2246
- id,
2247
- );
2248
- return { surfacedAt };
2249
- }
2250
-
2251
- /**
2252
- * Set or clear the inference profile override for a conversation.
2253
- * Pass `null` to clear the override and fall back to the workspace
2254
- * `llm.activeProfile` resolution.
2255
- *
2256
- * Also clears any stale session columns (`inferenceProfileSessionId`,
2257
- * `inferenceProfileExpiresAt`) so that the reaper and lazy expiry check
2258
- * cannot later clobber the newly-set profile.
2259
- */
2260
- export function setConversationInferenceProfile(
2261
- conversationId: string,
2262
- profile: string | null,
2263
- ): void {
2264
- const db = getDb();
2265
- db.update(conversations)
2266
- .set({
2267
- inferenceProfile: profile,
2268
- inferenceProfileSessionId: null,
2269
- inferenceProfileExpiresAt: null,
2270
- updatedAt: Date.now(),
2271
- })
2272
- .where(eq(conversations.id, conversationId))
2273
- .run();
2274
- }
2275
-
2276
- /**
2277
- * Atomically set the inference profile, session id, and expiry timestamp for
2278
- * a conversation. Pass `null` for all three to clear the session-backed
2279
- * override and fall back to the workspace `llm.activeProfile` resolution.
2280
- */
2281
- export function setConversationInferenceProfileSession(
2282
- conversationId: string,
2283
- profile: string | null,
2284
- sessionId: string | null,
2285
- expiresAt: number | null,
2286
- ): void {
2287
- const db = getDb();
2288
- db.update(conversations)
2289
- .set({
2290
- inferenceProfile: profile,
2291
- inferenceProfileSessionId: sessionId,
2292
- inferenceProfileExpiresAt: expiresAt,
2293
- updatedAt: Date.now(),
2294
- })
2295
- .where(eq(conversations.id, conversationId))
2296
- .run();
2297
- }
2298
-
2299
- /**
2300
- * Clear all conversations whose session-backed inference profile has expired.
2301
- * Returns an array of `{ conversationId, sessionId }` for each cleared row so
2302
- * callers can emit the appropriate update events.
2303
- */
2304
- export function clearExpiredInferenceProfiles(
2305
- now: number,
2306
- ): Array<{ conversationId: string; sessionId: string | null }> {
2307
- const raw = getSqliteFrom(getDb());
2308
- // Two-step approach: SELECT to get pre-clear sessionIds, then UPDATE.
2309
- // The UPDATE re-applies the WHERE condition for CAS safety.
2310
- // RETURNING the id lets us know which rows were actually cleared.
2311
- const expired = raw
2312
- .prepare(
2313
- `
2314
- SELECT id AS conversationId, inference_profile_session_id AS sessionId
2315
- FROM conversations
2316
- WHERE inference_profile_expires_at IS NOT NULL AND inference_profile_expires_at <= ?
2317
- `,
2318
- )
2319
- .all(now) as Array<{ conversationId: string; sessionId: string | null }>;
2320
-
2321
- if (expired.length === 0) return [];
2322
-
2323
- const ids = expired.map((r) => r.conversationId);
2324
- const placeholders = ids.map(() => "?").join(", ");
2325
-
2326
- const actuallyCleared = raw
2327
- .prepare(
2328
- `
2329
- UPDATE conversations
2330
- SET inference_profile = NULL, inference_profile_session_id = NULL, inference_profile_expires_at = NULL
2331
- WHERE id IN (${placeholders}) AND inference_profile_expires_at IS NOT NULL AND inference_profile_expires_at <= ?
2332
- RETURNING id AS conversationId
2333
- `,
2334
- )
2335
- .all(...ids, now) as Array<{ conversationId: string }>;
2336
-
2337
- const clearedSet = new Set(actuallyCleared.map((r) => r.conversationId));
2338
- return expired.filter((r) => clearedSet.has(r.conversationId));
2339
- }
2340
-
2341
- /**
2342
- * List conversations with an active (non-expired) session-backed inference
2343
- * profile. Pass a `conversationId` to narrow to a single conversation.
2344
- */
2345
- export function listActiveInferenceProfileSessions(
2346
- conversationId?: string,
2347
- ): Array<{
2348
- conversationId: string;
2349
- conversationTitle: string | null;
2350
- profile: string;
2351
- sessionId: string;
2352
- expiresAt: number;
2353
- }> {
2354
- const db = getDb();
2355
- const now = Date.now();
2356
- const baseConditions = [
2357
- isNotNull(conversations.inferenceProfile),
2358
- isNotNull(conversations.inferenceProfileExpiresAt),
2359
- gt(conversations.inferenceProfileExpiresAt, now),
2360
- isNotNull(conversations.inferenceProfileSessionId),
2361
- ];
2362
- if (conversationId) {
2363
- baseConditions.push(eq(conversations.id, conversationId));
2364
- }
2365
- return db
2366
- .select({
2367
- conversationId: conversations.id,
2368
- conversationTitle: conversations.title,
2369
- profile: conversations.inferenceProfile,
2370
- sessionId: conversations.inferenceProfileSessionId,
2371
- expiresAt: conversations.inferenceProfileExpiresAt,
2372
- })
2373
- .from(conversations)
2374
- .where(and(...baseConditions))
2375
- .all() as Array<{
2376
- conversationId: string;
2377
- conversationTitle: string | null;
2378
- profile: string;
2379
- sessionId: string;
2380
- expiresAt: number;
2381
- }>;
2382
- }
2383
-
2384
- /**
2385
- * The conversation fields needed to resolve a per-turn inference-profile
2386
- * override. Satisfied by both the DB {@link ConversationRow} and the live
2387
- * in-memory `Conversation`, so callers can derive the override from whichever
2388
- * representation they already hold without a redundant row fetch.
2389
- */
2390
- export interface OverrideProfileFields {
2391
- conversationType?: string | null;
2392
- inferenceProfile?: string | null;
2393
- inferenceProfileExpiresAt?: number | null;
2394
- }
2395
-
2396
- /**
2397
- * Resolve the per-turn inference-profile override from a conversation's
2398
- * fields. Returns the `inferenceProfile` for interactive conversations,
2399
- * `undefined` for automation threads (subagent fan-out, scheduled
2400
- * tasks) so they run on the workspace defaults rather than
2401
- * inheriting an interactive override.
2402
- */
2403
- export function resolveOverrideProfile(
2404
- fields: OverrideProfileFields | null,
2405
- ): string | undefined {
2406
- if (
2407
- fields?.conversationType === "background" ||
2408
- fields?.conversationType === "scheduled"
2409
- ) {
2410
- return undefined;
2411
- }
2412
- // Treat an expired session as if the override is absent. The eager reaper
2413
- // clears the row and emits the update event; the lazy check here ensures
2414
- // correctness on read paths before the reaper fires.
2415
- //
2416
- // `<=` (not `<`) for boundary consistency with the rest of the session
2417
- // logic: the reaper SQL uses `expires_at <= ?`, and the active-session
2418
- // queries use `expiresAt > now` (i.e. treat exact-expiry as inactive).
2419
- // Without this, a session at the exact-expiry millisecond would be served
2420
- // for one extra turn here while being cleared by the reaper.
2421
- if (
2422
- fields?.inferenceProfileExpiresAt != null &&
2423
- fields.inferenceProfileExpiresAt <= Date.now()
2424
- ) {
2425
- return undefined;
2426
- }
2427
- return fields?.inferenceProfile ?? undefined;
2428
- }
2429
-
2430
- /**
2431
- * Resolve the per-turn inference-profile override by conversation id.
2432
- * Convenience wrapper for standalone callers (e.g. subagent spawn,
2433
- * opportunity-wake) that don't already have the conversation in hand.
2434
- */
2435
- export function getConversationOverrideProfile(
2436
- conversationId: string,
2437
- ): string | undefined {
2438
- return resolveOverrideProfile(getConversation(conversationId));
2439
- }
2440
-
2441
- export function setLastNotifiedInferenceProfile(
2442
- conversationId: string,
2443
- profileKey: string | null,
2444
- ): void {
2445
- rawRun(
2446
- "UPDATE conversations SET last_notified_inference_profile = ? WHERE id = ?",
2447
- profileKey,
2448
- conversationId,
2449
- );
2450
- }
2451
-
2452
- /**
2453
- * Delete all conversations, messages, and related data (tool invocations,
2454
- * memory segments, etc.) from the daemon database.
2455
- * Returns { conversations, messages } counts.
2456
- *
2457
- * Each bulk DELETE is dispatched through {@link runAsyncSqlite}: when
2458
- * the host has a `sqlite3` CLI it executes in a subprocess and the
2459
- * daemon's main event loop stays responsive while large tables
2460
- * (`llm_request_logs`, `tool_invocations`, etc.) are wiped. On hosts
2461
- * without the CLI the abstraction falls back to in-process blocking
2462
- * execution — the same behaviour the daemon had before.
2463
- */
2464
- export async function clearAll(): Promise<{
2465
- conversations: number;
2466
- messages: number;
2467
- }> {
2468
- const msgCount =
2469
- rawGet<{ c: number }>("SELECT COUNT(*) AS c FROM messages")?.c ?? 0;
2470
- const convCount =
2471
- rawGet<{ c: number }>("SELECT COUNT(*) AS c FROM conversations")?.c ?? 0;
2472
-
2473
- // Each DELETE goes through `runAsyncSqlite`. The original code threw
2474
- // on rawExec failure; mirror that here by throwing when the async
2475
- // result reports `ok: false`, so the route handler still returns 500.
2476
- const runOrThrow = async (
2477
- sql: string,
2478
- options?: { dbPath?: string },
2479
- ): Promise<void> => {
2480
- const result = await runAsyncSqlite(sql, options);
2481
- if (!result.ok) {
2482
- throw new Error(
2483
- `clearAll: \`${sql}\` failed (${result.backend}): ${result.error ?? "unknown"}`,
2484
- );
2485
- }
2486
- };
2487
-
2488
- // Delete in dependency order. Cascades handle memory_segments and
2489
- // tool_invocations, but we explicitly clear non-cascading memory
2490
- // tables too.
2491
- //
2492
- // FTS virtual tables are cleared before their base tables. If an FTS
2493
- // table is corrupted, the DELETE will fail — we drop the associated
2494
- // triggers so that the subsequent base-table DELETEs don't also fail
2495
- // (SQLite triggers are atomic with the triggering statement, so a
2496
- // corrupted FTS table would roll back every base-table DELETE).
2497
- await runOrThrow("DELETE FROM memory_segments");
2498
- await runOrThrow("DELETE FROM memory_summaries");
2499
- await runOrThrow("DELETE FROM memory_embeddings");
2500
- // memory_jobs and llm_request_logs each live in their own dedicated
2501
- // connection; clear them directly on those connections rather than through a
2502
- // sqlite3 subprocess.
2503
- rawMemoryRun("DELETE FROM memory_jobs");
2504
- await runOrThrow("DELETE FROM memory_checkpoints");
2505
- rawLogsRun("DELETE FROM llm_request_logs");
2506
- await runOrThrow("DELETE FROM llm_usage_events");
2507
- await runOrThrow("DELETE FROM message_attachments");
2508
- await runOrThrow("DELETE FROM attachments");
2509
- await runOrThrow("DELETE FROM tool_invocations");
2510
- await runOrThrow("DELETE FROM skill_loaded_events");
2511
- let messagesFtsCorrupted = false;
2512
- const ftsResult = await runAsyncSqlite("DELETE FROM messages_fts");
2513
- if (!ftsResult.ok) {
2514
- log.warn(
2515
- { error: ftsResult.error, backend: ftsResult.backend },
2516
- "clearAll: failed to clear messages_fts — dropping triggers so base-table cleanup can proceed",
2517
- );
2518
- rawExec("DROP TRIGGER IF EXISTS messages_fts_ai");
2519
- rawExec("DROP TRIGGER IF EXISTS messages_fts_ad");
2520
- rawExec("DROP TRIGGER IF EXISTS messages_fts_au");
2521
- messagesFtsCorrupted = true;
2522
- }
2523
- await runOrThrow("DELETE FROM messages");
2524
- await runOrThrow("DELETE FROM conversations");
2525
-
2526
- // Record audit event — lifecycle_events is NOT deleted by clearAll(),
2527
- // so this survives the wipe and provides a permanent trail.
2528
- rawRun(
2529
- `INSERT INTO lifecycle_events (id, event_name, created_at) VALUES (?, ?, ?)`,
2530
- uuid(),
2531
- "conversations_clear_all",
2532
- Date.now(),
2533
- );
2534
-
2535
- // Rebuild corrupted FTS tables and restore triggers after all base-table
2536
- // DELETEs have completed. Dropping the virtual table clears the corruption,
2537
- // and recreating it + triggers means subsequent writes maintain FTS
2538
- // consistency without requiring a daemon restart.
2539
- if (messagesFtsCorrupted) {
2540
- rawExec("DROP TABLE IF EXISTS messages_fts");
2541
- rawExec(
2542
- `CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(message_id UNINDEXED, content)`,
2543
- );
2544
- rawExec(
2545
- `CREATE TRIGGER IF NOT EXISTS messages_fts_ai AFTER INSERT ON messages BEGIN INSERT INTO messages_fts(message_id, content) VALUES (new.id, new.content); END`,
2546
- );
2547
- rawExec(
2548
- `CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages BEGIN DELETE FROM messages_fts WHERE message_id = old.id; END`,
2549
- );
2550
- rawExec(
2551
- `CREATE TRIGGER IF NOT EXISTS messages_fts_au AFTER UPDATE ON messages BEGIN DELETE FROM messages_fts WHERE message_id = old.id; INSERT INTO messages_fts(message_id, content) VALUES (new.id, new.content); END`,
2552
- );
2553
- }
2554
-
2555
- // Clear the disk-view conversations directory and recreate it empty
2556
- try {
2557
- rmSync(getConversationsDir(), { recursive: true, force: true });
2558
- mkdirSync(getConversationsDir(), { recursive: true });
2559
- } catch (err) {
2560
- log.warn({ err }, "clearAll: failed to reset conversations directory");
2561
- }
2562
-
2563
- void clearAllConversationIds();
2564
-
2565
- return { conversations: convCount, messages: msgCount };
2566
- }
2567
-
2568
- export function deleteLastExchange(conversationId: string): number {
2569
- const db = getDb();
2570
-
2571
- // Find the last user message's id
2572
- const lastUserMsg = db
2573
- .select({ id: messages.id })
2574
- .from(messages)
2575
- .where(
2576
- and(
2577
- eq(messages.conversationId, conversationId),
2578
- eq(messages.role, "user"),
2579
- ),
2580
- )
2581
- .orderBy(sql`rowid DESC`)
2582
- .limit(1)
2583
- .get();
2584
-
2585
- if (!lastUserMsg) return 0;
2586
-
2587
- // Use rowid to identify the last user message and everything after it.
2588
- // rowid is monotonically increasing for inserts, so this is safe even if
2589
- // multiple messages share the same millisecond timestamp.
2590
- const rowidSubquery = sql`(SELECT rowid FROM messages WHERE id = ${lastUserMsg.id})`;
2591
- const condition = and(
2592
- eq(messages.conversationId, conversationId),
2593
- sql`rowid >= ${rowidSubquery}`,
2594
- );
2595
-
2596
- const [{ deleted }] = db
2597
- .select({ deleted: count() })
2598
- .from(messages)
2599
- .where(condition)
2600
- .all();
2601
- if (deleted === 0) return 0;
2602
-
2603
- // Collect attachment IDs linked to the messages being deleted so we can
2604
- // scope orphan cleanup to only those candidates (not freshly uploaded ones).
2605
- const messageIds = db
2606
- .select({ id: messages.id })
2607
- .from(messages)
2608
- .where(condition)
2609
- .all()
2610
- .map((r) => r.id);
2611
- const candidateAttachmentIds =
2612
- messageIds.length > 0
2613
- ? db
2614
- .select({ attachmentId: messageAttachments.attachmentId })
2615
- .from(messageAttachments)
2616
- .where(inArray(messageAttachments.messageId, messageIds))
2617
- .all()
2618
- .map((r) => r.attachmentId)
2619
- .filter((id): id is string => id != null)
2620
- : [];
2621
-
2622
- db.transaction((tx) => {
2623
- tx.delete(messages).where(condition).run();
2624
- const maxResult = tx
2625
- .select({ maxCreatedAt: sql<number | null>`MAX(${messages.createdAt})` })
2626
- .from(messages)
2627
- .where(eq(messages.conversationId, conversationId))
2628
- .get();
2629
- tx.update(conversations)
2630
- .set({
2631
- updatedAt: Date.now(),
2632
- lastMessageAt: maxResult?.maxCreatedAt ?? null,
2633
- })
2634
- .where(eq(conversations.id, conversationId))
2635
- .run();
2636
- });
2637
-
2638
- deleteOrphanAttachments(candidateAttachmentIds);
2639
-
2640
- return deleted;
2641
- }
2642
-
2643
- /**
2644
- * IDs collected during message deletion for Qdrant vector cleanup.
2645
- * Callers must delete these from the Qdrant collection after the
2646
- * SQLite transaction commits.
2647
- */
2648
- interface DeletedMemoryIds {
2649
- segmentIds: string[];
2650
- deletedSummaryIds: string[];
2651
- }
2652
-
2653
- interface WipeConversationResult extends DeletedMemoryIds {
2654
- cancelledJobCount: number;
2655
- }
2656
-
2657
- /**
2658
- * Reserve an empty message row so the agent loop can stamp outbound
2659
- * streaming events with a stable identity before content is produced.
2660
- *
2661
- * Intentionally skips Qdrant indexing and attention projection — an empty
2662
- * placeholder is meaningless for either. The caller writes final content
2663
- * via {@link updateMessageContent} and handles indexing/projection itself.
2664
- *
2665
- * Delegates the core insert + retry logic to {@link insertMessageCore}.
2666
- */
2667
- export async function reserveMessage(
2668
- conversationId: string,
2669
- role: MessageRole,
2670
- metadata?: Record<string, unknown>,
2671
- ) {
2672
- return insertMessageCore({
2673
- conversationId,
2674
- role,
2675
- content: "[]",
2676
- metadata,
2677
- });
2678
- }
2679
-
2680
- /**
2681
- * Update the content of an existing message. Used when consolidating
2682
- * multiple assistant messages into one.
2683
- */
2684
- export function updateMessageContent(
2685
- messageId: string,
2686
- newContent: string,
2687
- ): void {
2688
- const db = getDb();
2689
- db.update(messages)
2690
- .set({ content: newContent })
2691
- .where(eq(messages.id, messageId))
2692
- .run();
2693
- }
2694
-
2695
- /**
2696
- * Merge `updates` into the metadata JSON of an existing message.
2697
- * Reads the current metadata, shallow-merges the new fields, and writes back.
2698
- */
2699
- export function updateMessageMetadata(
2700
- messageId: string,
2701
- updates: Record<string, unknown>,
2702
- ): void {
2703
- const db = getDb();
2704
- const row = db
2705
- .select({ metadata: messages.metadata })
2706
- .from(messages)
2707
- .where(eq(messages.id, messageId))
2708
- .get();
2709
- const existing = row?.metadata ? JSON.parse(row.metadata) : {};
2710
- db.update(messages)
2711
- .set({ metadata: JSON.stringify({ ...existing, ...updates }) })
2712
- .where(eq(messages.id, messageId))
2713
- .run();
2714
- }
2715
-
2716
- /**
2717
- * Atomically update both `content` and (shallow-merged) `metadata` for a
2718
- * message. Used by edit-propagation paths that need to update the message
2719
- * body and stamp metadata (e.g. `slackMeta.editedAt`) in a single
2720
- * transaction so a partial write cannot leak.
2721
- *
2722
- * `metadataUpdates` is shallow-merged into the existing top-level metadata
2723
- * object. To merge into a nested sub-key (e.g. `slackMeta`), the caller
2724
- * must compute the merged sub-value first and pass `{ slackMeta: merged }`.
2725
- */
2726
- export function updateMessageContentAndMetadata(
2727
- messageId: string,
2728
- newContent: string,
2729
- metadataUpdates: Record<string, unknown>,
2730
- ): void {
2731
- const db = getDb();
2732
- db.transaction((tx) => {
2733
- const row = tx
2734
- .select({ metadata: messages.metadata })
2735
- .from(messages)
2736
- .where(eq(messages.id, messageId))
2737
- .get();
2738
- const existing = row?.metadata ? safeParseRecord(row.metadata) : {};
2739
- tx.update(messages)
2740
- .set({
2741
- content: newContent,
2742
- metadata: JSON.stringify({ ...existing, ...metadataUpdates }),
2743
- })
2744
- .where(eq(messages.id, messageId))
2745
- .run();
2746
- });
2747
- }
2748
-
2749
- /**
2750
- * Re-link all attachments from a set of source messages to a target message.
2751
- * Used during message consolidation so that attachments linked to deleted
2752
- * messages survive the ON DELETE CASCADE on message_attachments.
2753
- */
2754
- export function relinkAttachments(
2755
- fromMessageIds: string[],
2756
- toMessageId: string,
2757
- ): number {
2758
- if (fromMessageIds.length === 0) return 0;
2759
- const db = getDb();
2760
-
2761
- // Count how many links will be moved before updating.
2762
- const [{ total }] = db
2763
- .select({ total: count() })
2764
- .from(messageAttachments)
2765
- .where(inArray(messageAttachments.messageId, fromMessageIds))
2766
- .all();
2767
-
2768
- if (total === 0) return 0;
2769
-
2770
- db.update(messageAttachments)
2771
- .set({ messageId: toMessageId })
2772
- .where(inArray(messageAttachments.messageId, fromMessageIds))
2773
- .run();
2774
-
2775
- return total;
2776
- }
2777
-
2778
- /**
2779
- * Delete a single message by ID without cascading to message_runs or
2780
- * channel_inbound_events. Nullable FK columns in those tables are set to
2781
- * NULL before the message row is removed, so associated run and event
2782
- * records survive.
2783
- *
2784
- * Returns segment IDs so the caller can clean up the corresponding
2785
- * Qdrant vector entries.
2786
- */
2787
- export function deleteMessageById(messageId: string): DeletedMemoryIds {
2788
- const db = getDb();
2789
- const result: DeletedMemoryIds = {
2790
- segmentIds: [],
2791
- deletedSummaryIds: [],
2792
- };
2793
-
2794
- // Collect attachment IDs linked to this message before cascade-delete
2795
- // so we can scope orphan cleanup to only those candidates.
2796
- const candidateAttachmentIds = db
2797
- .select({ attachmentId: messageAttachments.attachmentId })
2798
- .from(messageAttachments)
2799
- .where(eq(messageAttachments.messageId, messageId))
2800
- .all()
2801
- .map((r) => r.attachmentId)
2802
- .filter((id): id is string => id !== undefined);
2803
-
2804
- // Look up the conversation before the transaction so we can recalculate lastMessageAt.
2805
- const msgRow = db
2806
- .select({ conversationId: messages.conversationId })
2807
- .from(messages)
2808
- .where(eq(messages.id, messageId))
2809
- .get();
2810
-
2811
- db.transaction((tx) => {
2812
- // Collect memory segment IDs linked to this message before cascade.
2813
- const linkedSegments = tx
2814
- .select({ id: memorySegments.id })
2815
- .from(memorySegments)
2816
- .where(eq(memorySegments.messageId, messageId))
2817
- .all();
2818
- result.segmentIds = linkedSegments.map((r) => r.id);
2819
-
2820
- // Detach nullable FK references so the cascade doesn't destroy them.
2821
- tx.update(channelInboundEvents)
2822
- .set({ messageId: null })
2823
- .where(eq(channelInboundEvents.messageId, messageId))
2824
- .run();
2825
-
2826
- // Now safe to delete — NOT NULL cascades remove memory_segments
2827
- // and message_attachments.
2828
- tx.delete(messages).where(eq(messages.id, messageId)).run();
2829
-
2830
- // Recalculate lastMessageAt after deletion.
2831
- if (msgRow) {
2832
- const maxResult = tx
2833
- .select({
2834
- maxCreatedAt: sql<number | null>`MAX(${messages.createdAt})`,
2835
- })
2836
- .from(messages)
2837
- .where(eq(messages.conversationId, msgRow.conversationId))
2838
- .get();
2839
- tx.update(conversations)
2840
- .set({ lastMessageAt: maxResult?.maxCreatedAt ?? null })
2841
- .where(eq(conversations.id, msgRow.conversationId))
2842
- .run();
2843
- }
2844
-
2845
- // Clean up segment embeddings from SQLite (Qdrant cleanup is the caller's job).
2846
- if (result.segmentIds.length > 0) {
2847
- tx.delete(memoryEmbeddings)
2848
- .where(
2849
- and(
2850
- eq(memoryEmbeddings.targetType, "segment"),
2851
- inArray(memoryEmbeddings.targetId, result.segmentIds),
2852
- ),
2853
- )
2854
- .run();
2855
- }
2856
- });
2857
-
2858
- deleteOrphanAttachments(candidateAttachmentIds);
2859
-
2860
- return result;
2861
- }
2862
-
2863
- export function setConversationOriginChannelIfUnset(
2864
- conversationId: string,
2865
- channel: ChannelId,
2866
- ): void {
2867
- const db = getDb();
2868
- db.update(conversations)
2869
- .set({ originChannel: channel })
2870
- .where(
2871
- and(
2872
- eq(conversations.id, conversationId),
2873
- isNull(conversations.originChannel),
2874
- ),
2875
- )
2876
- .run();
2877
- }
2878
-
2879
- export function getConversationOriginChannel(
2880
- conversationId: string,
2881
- ): ChannelId | null {
2882
- const db = getDb();
2883
- const row = db
2884
- .select({ originChannel: conversations.originChannel })
2885
- .from(conversations)
2886
- .where(eq(conversations.id, conversationId))
2887
- .get();
2888
- return parseChannelId(row?.originChannel) ?? null;
2889
- }
2890
-
2891
- export function setConversationOriginInterfaceIfUnset(
2892
- conversationId: string,
2893
- interfaceId: InterfaceId,
2894
- ): void {
2895
- const db = getDb();
2896
- db.update(conversations)
2897
- .set({ originInterface: interfaceId })
2898
- .where(
2899
- and(
2900
- eq(conversations.id, conversationId),
2901
- isNull(conversations.originInterface),
2902
- ),
2903
- )
2904
- .run();
2905
- }
2906
-
2907
- export function getConversationOriginInterface(
2908
- conversationId: string,
2909
- ): InterfaceId | null {
2910
- const db = getDb();
2911
- const row = db
2912
- .select({ originInterface: conversations.originInterface })
2913
- .from(conversations)
2914
- .where(eq(conversations.id, conversationId))
2915
- .get();
2916
- return parseInterfaceId(row?.originInterface) ?? null;
2917
- }
2918
-
2919
- /**
2920
- * Return the most recent non-null provenanceTrustClass from user messages
2921
- * in the given conversation, or `undefined` if none is found.
2922
- *
2923
- * Used by the pointer message trust resolver to detect conversations
2924
- * whose audience is a guardian, trusted_contact, or unverified_contact
2925
- * outside desktop-origin conversations.
2926
- */
2927
- export function getConversationRecentProvenanceTrustClass(
2928
- conversationId: string,
2929
- ):
2930
- | "guardian"
2931
- | "trusted_contact"
2932
- | "unverified_contact"
2933
- | "unknown"
2934
- | undefined {
2935
- const row = rawGet<{ metadata: string | null }>(
2936
- `SELECT metadata FROM messages
2937
- WHERE conversation_id = ? AND role = 'user' AND metadata IS NOT NULL
2938
- ORDER BY created_at DESC LIMIT 1`,
2939
- conversationId,
2940
- );
2941
- if (!row?.metadata) return undefined;
2942
- try {
2943
- const parsed = messageMetadataSchema.safeParse(JSON.parse(row.metadata));
2944
- return parsed.success ? parsed.data.provenanceTrustClass : undefined;
2945
- } catch {
2946
- return undefined;
2947
- }
2948
- }
2949
-
2950
- // ---------------------------------------------------------------------------
2951
- // CRUD functions for display_order and is_pinned
2952
- // ---------------------------------------------------------------------------
2953
-
2954
- export function batchSetDisplayOrders(
2955
- updates: Array<{
2956
- id: string;
2957
- displayOrder: number | null;
2958
- isPinned?: boolean;
2959
- groupId?: string | null;
2960
- }>,
2961
- ): void {
2962
- ensureDisplayOrderMigration();
2963
- ensureGroupMigration();
2964
- rawExec("BEGIN");
2965
- try {
2966
- for (const update of updates) {
2967
- if (update.groupId !== undefined) {
2968
- // New client: groupId is authoritative.
2969
- // Derive is_pinned from groupId.
2970
- // Sanitize: if groupId is null or references a deleted/unknown group,
2971
- // fall back to "system:all" to avoid FK violation that would roll back
2972
- // the entire batch.
2973
- let safeGroupId = update.groupId;
2974
- if (safeGroupId === null) {
2975
- safeGroupId = "system:all";
2976
- } else if (
2977
- !rawGet<{ id: string }>(
2978
- "SELECT id FROM conversation_groups WHERE id = ?",
2979
- safeGroupId,
2980
- )
2981
- ) {
2982
- safeGroupId = "system:all";
2983
- }
2984
- // Moving a conversation into the Scheduled/Background system groups
2985
- // is an explicit demotion out of Recents, so clear any `surfaced_at`
2986
- // promotion in the same write — otherwise the surfaced marker would
2987
- // keep the row in the standard listing and the move would appear to
2988
- // do nothing.
2989
- const clearsSurfaced =
2990
- safeGroupId === "system:background" ||
2991
- safeGroupId === "system:scheduled";
2992
- rawRun(
2993
- `UPDATE conversations SET display_order = ?, is_pinned = ?, group_id = ?${
2994
- clearsSurfaced ? ", surfaced_at = NULL" : ""
2995
- } WHERE id = ?`,
2996
- update.displayOrder,
2997
- safeGroupId === "system:pinned" ? 1 : 0,
2998
- safeGroupId,
2999
- update.id,
3000
- );
3001
- } else if (update.isPinned === undefined) {
3002
- // Only displayOrder provided — preserve existing pin state and group.
3003
- rawRun(
3004
- "UPDATE conversations SET display_order = ? WHERE id = ?",
3005
- update.displayOrder,
3006
- update.id,
3007
- );
3008
- } else if (update.isPinned) {
3009
- rawRun(
3010
- "UPDATE conversations SET display_order = ?, is_pinned = 1, group_id = 'system:pinned' WHERE id = ?",
3011
- update.displayOrder,
3012
- update.id,
3013
- );
3014
- } else {
3015
- // Restore system group from source/conversationType when unpinning,
3016
- // instead of clearing to NULL (which would lose provenance).
3017
- rawRun(
3018
- `UPDATE conversations SET display_order = ?, is_pinned = 0,
3019
- group_id = CASE WHEN group_id = 'system:pinned' THEN
3020
- CASE
3021
- WHEN source IN ('schedule', 'reminder') THEN 'system:scheduled'
3022
- WHEN source IN ('heartbeat', 'task') THEN 'system:background'
3023
- WHEN conversation_type = 'background' AND COALESCE(source, '') != 'notification' THEN 'system:background'
3024
- ELSE 'system:all'
3025
- END
3026
- ELSE group_id END
3027
- WHERE id = ?`,
3028
- update.displayOrder,
3029
- update.id,
3030
- );
3031
- }
3032
- }
3033
- rawExec("COMMIT");
3034
- } catch (err) {
3035
- rawExec("ROLLBACK");
3036
- throw err;
3037
- }
3038
- }
3039
-
3040
- export function getDisplayMetaForConversations(
3041
- conversationIds: string[],
3042
- ): Map<
3043
- string,
3044
- { displayOrder: number | null; isPinned: boolean; groupId: string | null }
3045
- > {
3046
- ensureDisplayOrderMigration();
3047
- ensureGroupMigration();
3048
- const result = new Map<
3049
- string,
3050
- { displayOrder: number | null; isPinned: boolean; groupId: string | null }
3051
- >();
3052
- if (conversationIds.length === 0) return result;
3053
- for (const id of conversationIds) {
3054
- const row = rawGet<{
3055
- display_order: number | null;
3056
- is_pinned: number | null;
3057
- group_id: string | null;
3058
- }>(
3059
- "SELECT display_order, is_pinned, group_id FROM conversations WHERE id = ?",
3060
- id,
3061
- );
3062
- result.set(id, {
3063
- displayOrder: row?.display_order ?? null,
3064
- isPinned: (row?.is_pinned ?? 0) === 1,
3065
- groupId: row?.group_id ?? null,
3066
- });
3067
- }
3068
- return result;
3069
- }
3070
-
3071
- // ── Turn boundary resolution ─────────────────────────────────────────
3072
-
3073
- /**
3074
- * Returns `true` if a message is a tool-result user message — i.e. its
3075
- * role is "user" and its content is a JSON array where every block has
3076
- * `type === "tool_result"`. These synthetic user messages are injected
3077
- * between assistant messages within a single agent turn and should NOT
3078
- * be treated as turn boundaries.
3079
- */
3080
- function isToolResultMessage(role: string, content: string): boolean {
3081
- if (role !== "user") return false;
3082
- try {
3083
- const parsed = JSON.parse(content);
3084
- if (!Array.isArray(parsed) || parsed.length === 0) return false;
3085
- return parsed.every(
3086
- (block: unknown) =>
3087
- block != null &&
3088
- typeof block === "object" &&
3089
- (block as Record<string, unknown>).type === "tool_result",
3090
- );
3091
- } catch {
3092
- return false;
3093
- }
3094
- }
3095
-
3096
- /**
3097
- * Returns the time boundaries (start/end `createdAt` values) for the turn
3098
- * containing the given message. The bounds span from the real user message
3099
- * that started the turn to just before the real user message that starts the
3100
- * next turn (or to the end of the conversation if this is the last turn).
3101
- *
3102
- * Also extends the end boundary to capture orphaned LLM request logs from
3103
- * deleted intermediate messages (e.g. removed by retry/deleteLastExchange).
3104
- *
3105
- * Returns null if the message is the only one in the conversation.
3106
- */
3107
- export function getTurnTimeBounds(
3108
- conversationId: string,
3109
- messageCreatedAt: number,
3110
- ): { startTime: number; endTime: number } | null {
3111
- const db = getDb();
3112
-
3113
- // Walk backward (by rowid, not just createdAt) to find the real user
3114
- // message that starts this turn.
3115
- const rowidSubquery = sql`(
3116
- SELECT rowid FROM messages
3117
- WHERE conversation_id = ${conversationId}
3118
- AND created_at <= ${messageCreatedAt}
3119
- ORDER BY rowid DESC LIMIT 1
3120
- )`;
3121
- const backwardRows = db
3122
- .select({
3123
- role: messages.role,
3124
- content: messages.content,
3125
- createdAt: messages.createdAt,
3126
- })
3127
- .from(messages)
3128
- .where(
3129
- and(
3130
- eq(messages.conversationId, conversationId),
3131
- sql`rowid <= ${rowidSubquery}`,
3132
- ),
3133
- )
3134
- .orderBy(sql`rowid DESC`)
3135
- .limit(50)
3136
- .all();
3137
-
3138
- let startTime = messageCreatedAt;
3139
- for (const row of backwardRows) {
3140
- if (row.role === "user" && !isToolResultMessage(row.role, row.content)) {
3141
- startTime = row.createdAt;
3142
- break;
3143
- }
3144
- }
3145
-
3146
- // Walk forward (by rowid) to find the next real user message.
3147
- const forwardRowidSubquery = sql`(
3148
- SELECT rowid FROM messages
3149
- WHERE conversation_id = ${conversationId}
3150
- AND created_at >= ${messageCreatedAt}
3151
- ORDER BY rowid DESC LIMIT 1
3152
- )`;
3153
- const forwardRows = db
3154
- .select({
3155
- role: messages.role,
3156
- content: messages.content,
3157
- createdAt: messages.createdAt,
3158
- })
3159
- .from(messages)
3160
- .where(
3161
- and(
3162
- eq(messages.conversationId, conversationId),
3163
- sql`rowid > ${forwardRowidSubquery}`,
3164
- ),
3165
- )
3166
- .orderBy(sql`rowid ASC`)
3167
- .limit(50)
3168
- .all();
3169
-
3170
- let endTime = messageCreatedAt;
3171
- let nextTurnStart: number | null = null;
3172
- for (const row of forwardRows) {
3173
- if (row.role === "user" && !isToolResultMessage(row.role, row.content)) {
3174
- nextTurnStart = row.createdAt;
3175
- break;
3176
- }
3177
- endTime = row.createdAt;
3178
- }
3179
-
3180
- // When the next turn start has a strictly greater timestamp, use it minus
3181
- // 1ms as the hard upper bound. When timestamps collide (e.g. in tests),
3182
- // don't extend — the message-ID-based query is authoritative.
3183
- if (nextTurnStart != null && nextTurnStart > endTime) {
3184
- endTime = nextTurnStart - 1;
3185
- }
3186
-
3187
- // Extend end boundary to the latest log that falls within the turn window.
3188
- // Orphaned logs from deleted intermediate messages may have timestamps
3189
- // beyond any surviving message. Cap at 30 minutes to avoid sweeping in
3190
- // logs from a much later turn.
3191
- const MAX_TURN_DURATION_MS = 30 * 60 * 1000;
3192
- const hardCeiling =
3193
- nextTurnStart != null && nextTurnStart > startTime
3194
- ? nextTurnStart - 1
3195
- : startTime + MAX_TURN_DURATION_MS;
3196
-
3197
- if (hardCeiling > endTime) {
3198
- // llm_request_logs lives in the dedicated logs connection.
3199
- const latestLog = logsDb()
3200
- .select({ createdAt: llmRequestLogs.createdAt })
3201
- .from(llmRequestLogs)
3202
- .where(
3203
- and(
3204
- eq(llmRequestLogs.conversationId, conversationId),
3205
- gte(llmRequestLogs.createdAt, startTime),
3206
- lte(llmRequestLogs.createdAt, hardCeiling),
3207
- ),
3208
- )
3209
- .orderBy(desc(llmRequestLogs.createdAt))
3210
- .limit(1)
3211
- .get();
3212
-
3213
- if (latestLog && latestLog.createdAt > endTime) {
3214
- endTime = latestLog.createdAt;
3215
- }
3216
- }
3217
-
3218
- return { startTime, endTime };
3219
- }
3220
-
3221
- /**
3222
- * Resolve all assistant message IDs that belong to the same agent turn
3223
- * as the given `messageId`. A "turn" is bounded by:
3224
- * - The start of the conversation, or
3225
- * - A user message whose content is NOT a tool_result array.
3226
- *
3227
- * Within a multi-step agent loop, the pattern is:
3228
- * user msg → assistant A1 → user (tool_result) → assistant A2 → ...
3229
- * All assistant messages from A1 through the queried message (and beyond,
3230
- * up to the next real user message) are part of the same turn.
3231
- *
3232
- * Returns `[messageId]` as a fallback if the message is not found,
3233
- * preserving backward compatibility for callers.
3234
- */
3235
- export function getAssistantMessageIdsInTurn(messageId: string): string[] {
3236
- const db = getDb();
3237
-
3238
- // Look up the target message to get its conversationId and createdAt.
3239
- const target = getMessageById(messageId);
3240
- if (!target) return [messageId];
3241
-
3242
- // Walk backward from the target message to find the turn boundary.
3243
- // Limit to 50 rows — sufficient for even aggressive tool-use loops.
3244
- const backwardRows = db
3245
- .select({
3246
- id: messages.id,
3247
- role: messages.role,
3248
- content: messages.content,
3249
- createdAt: messages.createdAt,
3250
- })
3251
- .from(messages)
3252
- .where(
3253
- and(
3254
- eq(messages.conversationId, target.conversationId),
3255
- lte(messages.createdAt, target.createdAt),
3256
- ),
3257
- )
3258
- .orderBy(desc(messages.createdAt))
3259
- .limit(50)
3260
- .all();
3261
-
3262
- const assistantIds: string[] = [];
3263
- let boundaryCreatedAt: number | null = null;
3264
-
3265
- for (const row of backwardRows) {
3266
- if (row.role === "assistant") {
3267
- assistantIds.push(row.id);
3268
- } else if (row.role === "user") {
3269
- if (isToolResultMessage(row.role, row.content)) {
3270
- // Tool-result user message — still within the same turn, continue.
3271
- continue;
3272
- }
3273
- // Real user message — this is the turn boundary.
3274
- boundaryCreatedAt = row.createdAt;
3275
- break;
3276
- }
3277
- }
3278
-
3279
- // Walk forward from the target to collect any later assistant messages
3280
- // still within the same turn (e.g. when querying an intermediate
3281
- // message like A1 in a multi-step turn A1 → tool_result → A2).
3282
- const forwardRows = db
3283
- .select({
3284
- id: messages.id,
3285
- role: messages.role,
3286
- content: messages.content,
3287
- createdAt: messages.createdAt,
3288
- })
3289
- .from(messages)
3290
- .where(
3291
- and(
3292
- eq(messages.conversationId, target.conversationId),
3293
- gt(messages.createdAt, target.createdAt),
3294
- ),
3295
- )
3296
- .orderBy(asc(messages.createdAt))
3297
- .limit(50)
3298
- .all();
3299
-
3300
- for (const row of forwardRows) {
3301
- if (row.role === "assistant") {
3302
- if (!assistantIds.includes(row.id)) {
3303
- assistantIds.push(row.id);
3304
- }
3305
- } else if (row.role === "user") {
3306
- if (isToolResultMessage(row.role, row.content)) {
3307
- // Tool-result user message — still within the same turn.
3308
- continue;
3309
- }
3310
- // Real user message — end of the turn.
3311
- break;
3312
- }
3313
- }
3314
-
3315
- // Also query forward from the backward-walk boundary to pick up any
3316
- // assistant messages between the boundary and the target that may have
3317
- // been missed (e.g. due to the 50-row limit in the backward walk).
3318
- if (boundaryCreatedAt != null) {
3319
- const gapRows = db
3320
- .select({
3321
- id: messages.id,
3322
- role: messages.role,
3323
- createdAt: messages.createdAt,
3324
- })
3325
- .from(messages)
3326
- .where(
3327
- and(
3328
- eq(messages.conversationId, target.conversationId),
3329
- gt(messages.createdAt, boundaryCreatedAt),
3330
- lte(messages.createdAt, target.createdAt),
3331
- ),
3332
- )
3333
- .orderBy(asc(messages.createdAt))
3334
- .all();
3335
-
3336
- for (const row of gapRows) {
3337
- if (row.role === "assistant" && !assistantIds.includes(row.id)) {
3338
- assistantIds.push(row.id);
3339
- }
3340
- }
3341
- }
3342
-
3343
- // Sort by createdAt to ensure stable ordering.
3344
- // Re-fetch createdAt for all collected IDs so the sort is accurate.
3345
- if (assistantIds.length <= 1) return assistantIds;
3346
-
3347
- const idSet = new Set(assistantIds);
3348
- const sorted = db
3349
- .select({ id: messages.id, createdAt: messages.createdAt })
3350
- .from(messages)
3351
- .where(
3352
- and(
3353
- eq(messages.conversationId, target.conversationId),
3354
- inArray(messages.id, [...idSet]),
3355
- ),
3356
- )
3357
- .orderBy(asc(messages.createdAt))
3358
- .all();
3359
-
3360
- return sorted.map((r) => r.id);
3361
- }