@vellumai/assistant 0.10.0 → 0.10.1-staging.1

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 (824) hide show
  1. package/ARCHITECTURE.md +36 -37
  2. package/bun.lock +3 -0
  3. package/docs/workflows.md +12 -7
  4. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  5. package/node_modules/@slack/types/LICENSE +23 -0
  6. package/node_modules/@slack/types/README.md +32 -0
  7. package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
  8. package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
  9. package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
  10. package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
  11. package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
  12. package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
  13. package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
  14. package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
  15. package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
  16. package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
  17. package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
  18. package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
  19. package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
  20. package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
  21. package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
  22. package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
  23. package/node_modules/@slack/types/dist/calls.d.ts +26 -0
  24. package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
  25. package/node_modules/@slack/types/dist/calls.js +6 -0
  26. package/node_modules/@slack/types/dist/calls.js.map +1 -0
  27. package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
  28. package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
  29. package/node_modules/@slack/types/dist/chunk.js +3 -0
  30. package/node_modules/@slack/types/dist/chunk.js.map +1 -0
  31. package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
  32. package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
  33. package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
  34. package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
  35. package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
  36. package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
  37. package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
  38. package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
  39. package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
  40. package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
  41. package/node_modules/@slack/types/dist/dialog.js +3 -0
  42. package/node_modules/@slack/types/dist/dialog.js.map +1 -0
  43. package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
  44. package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
  45. package/node_modules/@slack/types/dist/events/app.js +3 -0
  46. package/node_modules/@slack/types/dist/events/app.js.map +1 -0
  47. package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
  48. package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
  49. package/node_modules/@slack/types/dist/events/assistant.js +3 -0
  50. package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
  51. package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
  52. package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
  53. package/node_modules/@slack/types/dist/events/call.js +3 -0
  54. package/node_modules/@slack/types/dist/events/call.js.map +1 -0
  55. package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
  56. package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
  57. package/node_modules/@slack/types/dist/events/channel.js +3 -0
  58. package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
  59. package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
  60. package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
  61. package/node_modules/@slack/types/dist/events/dnd.js +3 -0
  62. package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
  63. package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
  64. package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
  65. package/node_modules/@slack/types/dist/events/email.js +3 -0
  66. package/node_modules/@slack/types/dist/events/email.js.map +1 -0
  67. package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
  68. package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
  69. package/node_modules/@slack/types/dist/events/emoji.js +3 -0
  70. package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
  71. package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
  72. package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
  73. package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
  74. package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
  75. package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
  76. package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
  77. package/node_modules/@slack/types/dist/events/file.js +4 -0
  78. package/node_modules/@slack/types/dist/events/file.js.map +1 -0
  79. package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
  80. package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
  81. package/node_modules/@slack/types/dist/events/function.js +3 -0
  82. package/node_modules/@slack/types/dist/events/function.js.map +1 -0
  83. package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
  84. package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
  85. package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
  86. package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
  87. package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
  88. package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
  89. package/node_modules/@slack/types/dist/events/group.js +3 -0
  90. package/node_modules/@slack/types/dist/events/group.js.map +1 -0
  91. package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
  92. package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
  93. package/node_modules/@slack/types/dist/events/im.js +3 -0
  94. package/node_modules/@slack/types/dist/events/im.js.map +1 -0
  95. package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
  96. package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
  97. package/node_modules/@slack/types/dist/events/index.js +43 -0
  98. package/node_modules/@slack/types/dist/events/index.js.map +1 -0
  99. package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
  100. package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
  101. package/node_modules/@slack/types/dist/events/invite.js +3 -0
  102. package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
  103. package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
  104. package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
  105. package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
  106. package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
  107. package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
  108. package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
  109. package/node_modules/@slack/types/dist/events/member.js +3 -0
  110. package/node_modules/@slack/types/dist/events/member.js.map +1 -0
  111. package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
  112. package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
  113. package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
  114. package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
  115. package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
  116. package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
  117. package/node_modules/@slack/types/dist/events/message.js +3 -0
  118. package/node_modules/@slack/types/dist/events/message.js.map +1 -0
  119. package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
  120. package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
  121. package/node_modules/@slack/types/dist/events/pin.js +3 -0
  122. package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
  123. package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
  124. package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
  125. package/node_modules/@slack/types/dist/events/reaction.js +3 -0
  126. package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
  127. package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
  128. package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
  129. package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
  130. package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
  131. package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
  132. package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
  133. package/node_modules/@slack/types/dist/events/star.js +3 -0
  134. package/node_modules/@slack/types/dist/events/star.js.map +1 -0
  135. package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
  136. package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
  137. package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
  138. package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
  139. package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
  140. package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
  141. package/node_modules/@slack/types/dist/events/subteam.js +3 -0
  142. package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
  143. package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
  144. package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
  145. package/node_modules/@slack/types/dist/events/team.js +3 -0
  146. package/node_modules/@slack/types/dist/events/team.js.map +1 -0
  147. package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
  148. package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
  149. package/node_modules/@slack/types/dist/events/token.js +3 -0
  150. package/node_modules/@slack/types/dist/events/token.js.map +1 -0
  151. package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
  152. package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
  153. package/node_modules/@slack/types/dist/events/user.js +3 -0
  154. package/node_modules/@slack/types/dist/events/user.js.map +1 -0
  155. package/node_modules/@slack/types/dist/index.d.ts +12 -0
  156. package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
  157. package/node_modules/@slack/types/dist/index.js +28 -0
  158. package/node_modules/@slack/types/dist/index.js.map +1 -0
  159. package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
  160. package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
  161. package/node_modules/@slack/types/dist/message-attachments.js +3 -0
  162. package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
  163. package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
  164. package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
  165. package/node_modules/@slack/types/dist/message-metadata.js +27 -0
  166. package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
  167. package/node_modules/@slack/types/dist/views.d.ts +71 -0
  168. package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
  169. package/node_modules/@slack/types/dist/views.js +3 -0
  170. package/node_modules/@slack/types/dist/views.js.map +1 -0
  171. package/node_modules/@slack/types/package.json +47 -0
  172. package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
  173. package/node_modules/@vellumai/gateway-client/package.json +1 -0
  174. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -0
  175. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +65 -0
  176. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
  177. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
  178. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  179. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
  180. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
  181. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +78 -0
  182. package/openapi.yaml +345 -18
  183. package/package.json +2 -1
  184. package/scripts/memory-inspect.ts +24 -14
  185. package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
  186. package/src/__tests__/activation-early-marking.test.ts +1 -1
  187. package/src/__tests__/actor-token-service.test.ts +3 -3
  188. package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
  189. package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
  190. package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
  191. package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
  192. package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
  193. package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
  194. package/src/__tests__/agent-loop.test.ts +3 -0
  195. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  196. package/src/__tests__/anthropic-provider.test.ts +143 -9
  197. package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
  198. package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
  199. package/src/__tests__/app-source-watcher.test.ts +30 -10
  200. package/src/__tests__/approval-cascade.test.ts +6 -0
  201. package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
  202. package/src/__tests__/approval-primitive.test.ts +1 -1
  203. package/src/__tests__/approval-routes-http.test.ts +1 -1
  204. package/src/__tests__/assistant-attachments.test.ts +155 -0
  205. package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
  206. package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
  207. package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
  208. package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
  209. package/src/__tests__/attachments-store.test.ts +1 -1
  210. package/src/__tests__/audit-log-rotation.test.ts +50 -54
  211. package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
  212. package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
  213. package/src/__tests__/background-shell-bash.test.ts +4 -1
  214. package/src/__tests__/background-shell-host-bash.test.ts +17 -3
  215. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  216. package/src/__tests__/call-controller.test.ts +1 -1
  217. package/src/__tests__/call-conversation-messages.test.ts +1 -1
  218. package/src/__tests__/call-domain.test.ts +1 -1
  219. package/src/__tests__/call-pointer-messages.test.ts +3 -4
  220. package/src/__tests__/call-recovery.test.ts +1 -1
  221. package/src/__tests__/call-routes-http.test.ts +1 -1
  222. package/src/__tests__/call-store.test.ts +1 -1
  223. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  224. package/src/__tests__/canonical-guardian-store.test.ts +24 -1
  225. package/src/__tests__/channel-approval-routes.test.ts +73 -1119
  226. package/src/__tests__/channel-delivery-store.test.ts +1 -1
  227. package/src/__tests__/channel-guardian.test.ts +265 -641
  228. package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
  229. package/src/__tests__/channel-retry-sweep.test.ts +1 -1
  230. package/src/__tests__/compaction-events.test.ts +6 -0
  231. package/src/__tests__/compaction-trail-store.test.ts +6 -5
  232. package/src/__tests__/compaction.benchmark.test.ts +0 -1
  233. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  234. package/src/__tests__/config-loader-backfill.test.ts +183 -51
  235. package/src/__tests__/config-schema.test.ts +34 -0
  236. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
  237. package/src/__tests__/contact-store-user-file.test.ts +2 -2
  238. package/src/__tests__/contacts-relay-reads.test.ts +409 -0
  239. package/src/__tests__/contacts-tools.test.ts +4 -4
  240. package/src/__tests__/contacts-write.test.ts +1 -2
  241. package/src/__tests__/context-search-conversations-source.test.ts +1 -1
  242. package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
  243. package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
  244. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  245. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
  246. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
  247. package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
  248. package/src/__tests__/conversation-agent-loop.test.ts +3 -0
  249. package/src/__tests__/conversation-attachments.test.ts +2 -5
  250. package/src/__tests__/conversation-attention-store.test.ts +1 -1
  251. package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
  252. package/src/__tests__/conversation-clear-safety.test.ts +1 -1
  253. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
  254. package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
  255. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
  256. package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
  257. package/src/__tests__/conversation-disk-view.test.ts +1 -1
  258. package/src/__tests__/conversation-fork-crud.test.ts +10 -8
  259. package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
  260. package/src/__tests__/conversation-fork-route.test.ts +1 -1
  261. package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
  262. package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
  263. package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
  264. package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
  265. package/src/__tests__/conversation-lifecycle.test.ts +117 -0
  266. package/src/__tests__/conversation-list-source.test.ts +3 -3
  267. package/src/__tests__/conversation-process-callsite.test.ts +6 -14
  268. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  269. package/src/__tests__/conversation-queue.test.ts +6 -0
  270. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
  271. package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
  272. package/src/__tests__/conversation-slash-queue.test.ts +6 -0
  273. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  274. package/src/__tests__/conversation-speed-override.test.ts +6 -0
  275. package/src/__tests__/conversation-starter-routes.test.ts +5 -5
  276. package/src/__tests__/conversation-store.test.ts +1 -1
  277. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -1
  278. package/src/__tests__/conversation-sync-tags.test.ts +1 -1
  279. package/src/__tests__/conversation-usage.test.ts +1 -1
  280. package/src/__tests__/conversation-wipe.test.ts +9 -8
  281. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
  282. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  283. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  284. package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
  285. package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
  286. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  287. package/src/__tests__/db-acp-history.test.ts +2 -2
  288. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
  289. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
  290. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
  291. package/src/__tests__/db-migration-rollback.test.ts +129 -39
  292. package/src/__tests__/db-proxy-transaction.test.ts +1 -1
  293. package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
  294. package/src/__tests__/db-test-helpers.ts +36 -19
  295. package/src/__tests__/delete-propagation.test.ts +1 -1
  296. package/src/__tests__/deterministic-verification-control-plane.test.ts +26 -8
  297. package/src/__tests__/disk-pressure-tools.test.ts +41 -1
  298. package/src/__tests__/dm-backfill.test.ts +1 -1
  299. package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
  300. package/src/__tests__/edit-propagation.test.ts +1 -1
  301. package/src/__tests__/emit-signal-routing-intent.test.ts +83 -0
  302. package/src/__tests__/empty-response-hook.test.ts +42 -0
  303. package/src/__tests__/events-client-registration.test.ts +1 -1
  304. package/src/__tests__/followup-tools.test.ts +1 -1
  305. package/src/__tests__/gemini-count-tokens.test.ts +70 -0
  306. package/src/__tests__/guardian-action-sweep.test.ts +9 -2
  307. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  308. package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
  309. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
  310. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  311. package/src/__tests__/guardian-outbound-http.test.ts +7 -12
  312. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
  313. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  314. package/src/__tests__/guardian-routing-state.test.ts +1 -2
  315. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  316. package/src/__tests__/headless-browser-mode.test.ts +2 -2
  317. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  318. package/src/__tests__/heartbeat-service.test.ts +6 -0
  319. package/src/__tests__/helpers/channel-test-adapter.ts +98 -0
  320. package/src/__tests__/http-conversation-lineage.test.ts +1 -1
  321. package/src/__tests__/image-recovery-hook.test.ts +1 -1
  322. package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
  323. package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
  324. package/src/__tests__/inference-profile-reaper.test.ts +1 -1
  325. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  326. package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
  327. package/src/__tests__/injector-chain.test.ts +1 -1
  328. package/src/__tests__/injector-disk-pressure.test.ts +11 -6
  329. package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
  330. package/src/__tests__/invite-redemption-service.test.ts +244 -43
  331. package/src/__tests__/invite-routes-http.test.ts +35 -186
  332. package/src/__tests__/invite-service-ipc.test.ts +287 -0
  333. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
  334. package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
  335. package/src/__tests__/list-messages-attachments.test.ts +42 -1
  336. package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
  337. package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
  338. package/src/__tests__/list-messages-page-latest.test.ts +1 -1
  339. package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
  340. package/src/__tests__/llm-context-route-provider.test.ts +69 -4
  341. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
  342. package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
  343. package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
  344. package/src/__tests__/llm-usage-store.test.ts +40 -1
  345. package/src/__tests__/log-export-routes.test.ts +1 -1
  346. package/src/__tests__/log-export-workspace.test.ts +3 -3
  347. package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
  348. package/src/__tests__/memory-recall-log-store.test.ts +1 -1
  349. package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
  350. package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
  351. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  352. package/src/__tests__/mtime-cache.test.ts +375 -0
  353. package/src/__tests__/non-member-access-request.test.ts +1 -2
  354. package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
  355. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  356. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  357. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  358. package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
  359. package/src/__tests__/oauth-store.test.ts +1 -1
  360. package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
  361. package/src/__tests__/persist-unsendable-image.test.ts +1 -1
  362. package/src/__tests__/persona-resolver.test.ts +39 -1
  363. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  364. package/src/__tests__/playbook-execution.test.ts +1 -1
  365. package/src/__tests__/playbook-tools.test.ts +1 -1
  366. package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
  367. package/src/__tests__/plugin-bootstrap.test.ts +78 -0
  368. package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
  369. package/src/__tests__/provider-usage-tracking.test.ts +1 -1
  370. package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
  371. package/src/__tests__/reaction-persistence.test.ts +1 -1
  372. package/src/__tests__/relay-server.test.ts +357 -56
  373. package/src/__tests__/runtime-attachment-metadata.test.ts +10 -1
  374. package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
  375. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  376. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  377. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  378. package/src/__tests__/schedule-retry.test.ts +1 -1
  379. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
  380. package/src/__tests__/schedule-routes.test.ts +1 -1
  381. package/src/__tests__/schedule-store.test.ts +1 -1
  382. package/src/__tests__/schedule-tools.test.ts +1 -1
  383. package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
  384. package/src/__tests__/scheduler-recurrence.test.ts +1 -1
  385. package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
  386. package/src/__tests__/scheduler-wake.test.ts +2 -1
  387. package/src/__tests__/scoped-approval-grants.test.ts +1 -1
  388. package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
  389. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
  390. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
  391. package/src/__tests__/send-endpoint-busy.test.ts +1 -1
  392. package/src/__tests__/sequence-store.test.ts +1 -1
  393. package/src/__tests__/server-history-render.test.ts +40 -1
  394. package/src/__tests__/settings-routes.test.ts +11 -10
  395. package/src/__tests__/skill-load-tool.test.ts +72 -0
  396. package/src/__tests__/slack-inbound-verification.test.ts +1 -3
  397. package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
  398. package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
  399. package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
  400. package/src/__tests__/subagent-tools.test.ts +1 -31
  401. package/src/__tests__/system-prompt.test.ts +1 -1
  402. package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
  403. package/src/__tests__/task-compiler.test.ts +1 -1
  404. package/src/__tests__/task-management-tools.test.ts +1 -1
  405. package/src/__tests__/task-memory-cleanup.test.ts +9 -6
  406. package/src/__tests__/task-scheduler.test.ts +1 -1
  407. package/src/__tests__/thread-backfill.test.ts +1 -1
  408. package/src/__tests__/tool-approval-handler.test.ts +1 -1
  409. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
  410. package/src/__tests__/tool-executor.test.ts +32 -1
  411. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
  412. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
  413. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
  414. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
  415. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  416. package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
  417. package/src/__tests__/turn-events-store.test.ts +1 -1
  418. package/src/__tests__/twilio-routes.test.ts +2 -3
  419. package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
  420. package/src/__tests__/usage-routes.test.ts +1 -1
  421. package/src/__tests__/user-plugin-loader.test.ts +34 -29
  422. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  423. package/src/__tests__/voice-invite-redemption.test.ts +134 -36
  424. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
  425. package/src/__tests__/voice-session-bridge.test.ts +1 -1
  426. package/src/__tests__/workspace-git-service.test.ts +114 -1
  427. package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
  428. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
  429. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
  430. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
  431. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
  432. package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
  433. package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
  434. package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
  435. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
  436. package/src/a2a/__tests__/task-store.test.ts +1 -1
  437. package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
  438. package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
  439. package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
  440. package/src/acp/__tests__/session-manager.test.ts +72 -1
  441. package/src/acp/index.ts +10 -0
  442. package/src/acp/session-manager.ts +35 -0
  443. package/src/agent/loop.ts +45 -27
  444. package/src/api/index.ts +0 -6
  445. package/src/approvals/AGENTS.md +1 -2
  446. package/src/approvals/guardian-decision-primitive.ts +13 -210
  447. package/src/approvals/guardian-request-resolvers.ts +104 -58
  448. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  449. package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
  450. package/src/calls/__tests__/relay-setup-router.test.ts +88 -62
  451. package/src/calls/inbound-trust-reader.ts +40 -0
  452. package/src/calls/relay-server.ts +65 -23
  453. package/src/calls/relay-setup-router.ts +20 -6
  454. package/src/calls/relay-verification.ts +7 -7
  455. package/src/cli/commands/contacts.ts +6 -24
  456. package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
  457. package/src/cli/commands/db/__tests__/status.test.ts +7 -3
  458. package/src/cli/commands/db/status.ts +212 -33
  459. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
  460. package/src/cli/commands/memory/index.ts +2 -0
  461. package/src/cli/commands/memory/memory-retrospective.ts +129 -0
  462. package/src/cli/commands/memory/memory-v3.ts +176 -4
  463. package/src/cli/commands/plugins.ts +268 -11
  464. package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
  465. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
  466. package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
  467. package/src/cli/lib/install-from-github.ts +47 -6
  468. package/src/cli/lib/plugin-marketplace.ts +11 -0
  469. package/src/cli/lib/plugin-pin-history.ts +257 -0
  470. package/src/cli/lib/toggle-plugin.ts +146 -0
  471. package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
  472. package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
  473. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
  474. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
  475. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
  476. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
  477. package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
  478. package/src/config/bundled-skills/contacts/SKILL.md +7 -12
  479. package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
  480. package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
  481. package/src/config/bundled-skills/workflows/SKILL.md +4 -3
  482. package/src/config/call-site-defaults.ts +11 -2
  483. package/src/config/feature-flag-registry.json +0 -8
  484. package/src/config/profile-dispatchability.ts +11 -0
  485. package/src/config/schemas/call-site-catalog.ts +7 -0
  486. package/src/config/schemas/llm.ts +2 -0
  487. package/src/config/schemas/memory-lifecycle.ts +5 -3
  488. package/src/config/schemas/timeouts.ts +24 -0
  489. package/src/config/seed-inference-profiles.ts +133 -45
  490. package/src/config/sync-gated-profiles.ts +13 -1
  491. package/src/contacts/contact-store.ts +21 -0
  492. package/src/contacts/member-status.ts +9 -0
  493. package/src/credential-health/credential-health-service.ts +1 -5
  494. package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
  495. package/src/daemon/app-source-watcher.ts +31 -18
  496. package/src/daemon/assistant-attachments.ts +94 -4
  497. package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
  498. package/src/daemon/conversation-agent-loop.ts +9 -36
  499. package/src/daemon/conversation-runtime-assembly.ts +91 -66
  500. package/src/daemon/conversation-tool-setup.ts +20 -63
  501. package/src/daemon/conversation.ts +144 -52
  502. package/src/daemon/event-loop-watchdog.test.ts +85 -0
  503. package/src/daemon/event-loop-watchdog.ts +133 -0
  504. package/src/daemon/external-plugins-bootstrap.ts +26 -80
  505. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  506. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
  507. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
  508. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
  509. package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
  510. package/src/daemon/handlers/config-channels.ts +32 -18
  511. package/src/daemon/handlers/conversations.ts +7 -0
  512. package/src/daemon/handlers/shared.ts +7 -0
  513. package/src/daemon/lifecycle.ts +16 -3
  514. package/src/daemon/message-types/inbox.ts +0 -6
  515. package/src/daemon/message-types/messages.ts +0 -4
  516. package/src/daemon/message-types/surfaces.ts +18 -8
  517. package/src/daemon/server.ts +0 -4
  518. package/src/daemon/tool-setup-types.ts +0 -7
  519. package/src/daemon/trust-context.ts +6 -0
  520. package/src/daemon/wake-conversation-ops.ts +70 -0
  521. package/src/daemon/workspace-tools-watcher.ts +7 -3
  522. package/src/documents/document-comments-store.test.ts +1 -1
  523. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
  524. package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
  525. package/src/heartbeat/heartbeat-service.ts +3 -4
  526. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  527. package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
  528. package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
  529. package/src/ipc/assistant-server.ts +8 -0
  530. package/src/ipc/gateway-client.ts +2 -1
  531. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
  532. package/src/ipc/routes/invite-ipc-routes.ts +66 -0
  533. package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
  534. package/src/memory/__tests__/activation-session-store.test.ts +1 -1
  535. package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
  536. package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
  537. package/src/memory/__tests__/conversation-queries.test.ts +1 -1
  538. package/src/memory/__tests__/db-async-query.test.ts +1 -1
  539. package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
  540. package/src/memory/__tests__/db-maintenance.test.ts +28 -36
  541. package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
  542. package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
  543. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
  544. package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
  545. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
  546. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
  547. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
  548. package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
  549. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
  550. package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
  551. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  552. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
  553. package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
  554. package/src/memory/__tests__/table-relocation.test.ts +129 -0
  555. package/src/memory/conversation-crud.ts +461 -152
  556. package/src/memory/db-async-query.ts +89 -5
  557. package/src/memory/db-connection.ts +101 -18
  558. package/src/memory/db-init.ts +409 -234
  559. package/src/memory/db-maintenance.ts +43 -38
  560. package/src/memory/db-singleton.ts +45 -19
  561. package/src/memory/fork-message-copy.ts +170 -0
  562. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
  563. package/src/memory/graph/bootstrap.test.ts +6 -3
  564. package/src/memory/graph/retriever.test.ts +12 -12
  565. package/src/memory/graph/store.test.ts +15 -25
  566. package/src/memory/graph/store.ts +23 -14
  567. package/src/memory/graph/tool-handlers.ts +34 -5
  568. package/src/memory/graph/tools.ts +5 -2
  569. package/src/memory/indexer.ts +21 -9
  570. package/src/memory/job-handlers/cleanup.ts +10 -3
  571. package/src/memory/job-handlers/embedding.test.ts +4 -4
  572. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
  573. package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
  574. package/src/memory/jobs-store.ts +36 -24
  575. package/src/memory/llm-request-log-store.ts +51 -19
  576. package/src/memory/llm-usage-store.ts +31 -1
  577. package/src/memory/memory-retrospective-job.ts +27 -19
  578. package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
  579. package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
  580. package/src/memory/migrations/104-core-indexes.ts +1 -1
  581. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
  582. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
  583. package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
  584. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
  585. package/src/memory/migrations/136-drop-assistant-id-columns.ts +227 -230
  586. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
  587. package/src/memory/migrations/141-rename-verification-table.ts +45 -48
  588. package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
  589. package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
  590. package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
  591. package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
  592. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
  593. package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
  594. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
  595. package/src/memory/migrations/157-invite-contact-id.ts +73 -76
  596. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
  597. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
  598. package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
  599. package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
  600. package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
  601. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
  602. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
  603. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
  604. package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
  605. package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
  606. package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
  607. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
  608. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
  609. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
  610. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
  611. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +50 -57
  612. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
  613. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
  614. package/src/memory/migrations/217-conversation-host-access.ts +13 -18
  615. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
  616. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
  617. package/src/memory/migrations/230-acp-session-history.ts +23 -28
  618. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
  619. package/src/memory/migrations/232-activation-state.ts +11 -16
  620. package/src/memory/migrations/233-document-conversations.ts +20 -25
  621. package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
  622. package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
  623. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
  624. package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
  625. package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
  626. package/src/memory/migrations/242-message-bookmarks.ts +17 -22
  627. package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
  628. package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
  629. package/src/memory/migrations/251-a2a-tasks.ts +27 -32
  630. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
  631. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
  632. package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
  633. package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
  634. package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
  635. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
  636. package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
  637. package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
  638. package/src/memory/migrations/270-schedule-description.ts +7 -12
  639. package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
  640. package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
  641. package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
  642. package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
  643. package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
  644. package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
  645. package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
  646. package/src/memory/migrations/helpers/relocation.ts +227 -0
  647. package/src/memory/migrations/registry.ts +63 -0
  648. package/src/memory/migrations/run-migrations.ts +187 -16
  649. package/src/memory/migrations/validate-migration-state.ts +50 -145
  650. package/src/memory/raw-query.ts +47 -2
  651. package/src/memory/skill-loaded-events-store.test.ts +1 -1
  652. package/src/memory/task-memory-cleanup.ts +62 -41
  653. package/src/memory/tool-executed-events-store.test.ts +1 -1
  654. package/src/memory/turn-trace-store.test.ts +1 -1
  655. package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
  656. package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
  657. package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  658. package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  659. package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
  660. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +38 -0
  661. package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
  662. package/src/memory/v3-eval/eval-packets.ts +197 -12
  663. package/src/memory/v3-eval/eval-tally.ts +234 -0
  664. package/src/messaging/provider.ts +10 -0
  665. package/src/messaging/providers/gmail/adapter.ts +1 -0
  666. package/src/messaging/providers/gmail/client.ts +14 -0
  667. package/src/messaging/providers/index.ts +1 -1
  668. package/src/messaging/providers/slack/send.test.ts +87 -39
  669. package/src/messaging/providers/slack/send.ts +84 -105
  670. package/src/notifications/README.md +9 -5
  671. package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
  672. package/src/notifications/adapters/slack.ts +12 -10
  673. package/src/notifications/approval-card-builder.ts +81 -20
  674. package/src/notifications/approval-card-data.ts +8 -5
  675. package/src/notifications/canonical-delivery-recorder.ts +7 -5
  676. package/src/notifications/conversation-candidates.ts +24 -59
  677. package/src/notifications/copy-composer.ts +48 -68
  678. package/src/notifications/deterministic-checks.ts +19 -16
  679. package/src/notifications/emit-signal.ts +29 -1
  680. package/src/notifications/trusted-contact-payloads.ts +70 -0
  681. package/src/oauth/byo-connection.test.ts +9 -0
  682. package/src/oauth/connection-resolver.test.ts +146 -6
  683. package/src/oauth/connection-resolver.ts +132 -5
  684. package/src/oauth/oauth-store.ts +16 -3
  685. package/src/oauth/scope-utils.ts +21 -0
  686. package/src/plugin-api/index.ts +9 -4
  687. package/src/plugin-api/model-profiles.test.ts +123 -0
  688. package/src/plugin-api/model-profiles.ts +5 -1
  689. package/src/plugin-api/vision-support.test.ts +149 -0
  690. package/src/plugin-api/vision-support.ts +78 -0
  691. package/src/plugins/defaults/compaction/window-manager.ts +45 -64
  692. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
  693. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +302 -0
  694. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +103 -0
  695. package/src/plugins/defaults/image-fallback/package.json +14 -0
  696. package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
  697. package/src/plugins/defaults/image-fallback/src/image-persist.ts +59 -0
  698. package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
  699. package/src/plugins/defaults/index.ts +23 -0
  700. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
  701. package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
  702. package/src/plugins/external-plugin-loader.ts +47 -6
  703. package/src/plugins/mtime-cache.ts +772 -0
  704. package/src/plugins/pipeline.ts +7 -2
  705. package/src/plugins/registry.ts +16 -5
  706. package/src/plugins/user-loader.ts +22 -76
  707. package/src/prompts/persona-resolver.ts +29 -11
  708. package/src/prompts/system-prompt.ts +1 -1
  709. package/src/prompts/templates/system-sections.ts +4 -4
  710. package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
  711. package/src/providers/anthropic/client.ts +254 -185
  712. package/src/providers/call-site-routing.ts +10 -0
  713. package/src/providers/gemini/client.ts +43 -0
  714. package/src/providers/inference/adapter-factory.ts +6 -0
  715. package/src/providers/inference/connections.ts +6 -1
  716. package/src/providers/model-catalog.ts +37 -0
  717. package/src/providers/platform-proxy/constants.ts +5 -0
  718. package/src/providers/ratelimit.ts +9 -0
  719. package/src/providers/retry.ts +10 -0
  720. package/src/providers/together/client.ts +35 -0
  721. package/src/providers/types.ts +16 -0
  722. package/src/providers/usage-tracking.ts +7 -0
  723. package/src/runtime/AGENTS.md +9 -1
  724. package/src/runtime/__tests__/agent-wake.test.ts +259 -4
  725. package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
  726. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +417 -0
  727. package/src/runtime/actor-trust-resolver.ts +8 -16
  728. package/src/runtime/agent-wake.ts +183 -60
  729. package/src/runtime/channel-reply-delivery.ts +6 -3
  730. package/src/runtime/guardian-decision-types.ts +3 -22
  731. package/src/runtime/http-server.ts +1 -15
  732. package/src/runtime/invite-redemption-service.ts +155 -6
  733. package/src/runtime/invite-service.ts +113 -62
  734. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
  735. package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
  736. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
  737. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
  738. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
  739. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
  740. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
  741. package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
  742. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  743. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
  744. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
  745. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
  746. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
  747. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
  748. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
  749. package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
  750. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
  751. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
  752. package/src/runtime/routes/acp-routes-list.test.ts +4 -0
  753. package/src/runtime/routes/acp-routes.test.ts +5 -6
  754. package/src/runtime/routes/attachment-routes.ts +21 -17
  755. package/src/runtime/routes/browser-routes.ts +19 -1
  756. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
  757. package/src/runtime/routes/channel-verification-routes.ts +12 -1
  758. package/src/runtime/routes/contact-routes.ts +275 -164
  759. package/src/runtime/routes/conversation-query-routes.ts +15 -5
  760. package/src/runtime/routes/conversation-routes.ts +24 -3
  761. package/src/runtime/routes/conversation-starter-routes.ts +7 -8
  762. package/src/runtime/routes/guardian-approval-interception.ts +13 -274
  763. package/src/runtime/routes/inbound-message-handler.ts +20 -15
  764. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +285 -0
  765. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +45 -34
  766. package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
  767. package/src/runtime/routes/log-export-routes.ts +2 -2
  768. package/src/runtime/routes/memory-eval-routes.ts +92 -0
  769. package/src/runtime/routes/memory-item-routes.test.ts +12 -11
  770. package/src/runtime/routes/migration-routes.ts +51 -40
  771. package/src/runtime/routes/plugins-routes.ts +164 -8
  772. package/src/runtime/routes/schedule-routes.ts +1 -0
  773. package/src/runtime/routes/usage-routes.ts +3 -0
  774. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  775. package/src/runtime/slack-block-formatting.ts +46 -48
  776. package/src/runtime/trust-verdict-consumer.ts +172 -0
  777. package/src/schedule/scheduler.ts +6 -9
  778. package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
  779. package/src/tools/ask-question/ask-question-tool.test.ts +60 -52
  780. package/src/tools/ask-question/ask-question-tool.ts +14 -73
  781. package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
  782. package/src/tools/browser/browser-execution.ts +16 -4
  783. package/src/tools/document/document-comment-tool.test.ts +1 -1
  784. package/src/tools/executor.ts +15 -3
  785. package/src/tools/host-terminal/host-shell.ts +28 -9
  786. package/src/tools/memory/register.test.ts +32 -0
  787. package/src/tools/skills/load.ts +43 -2
  788. package/src/tools/subagent/spawn.ts +4 -10
  789. package/src/tools/terminal/shell.ts +16 -5
  790. package/src/tools/types.ts +1 -0
  791. package/src/util/fs-watcher-error.ts +36 -0
  792. package/src/util/logs-db-path.ts +22 -0
  793. package/src/util/memory-db-path.ts +23 -0
  794. package/src/watcher/providers/gmail.ts +7 -2
  795. package/src/workflows/engine-integration.test.ts +1 -1
  796. package/src/workflows/engine.test.ts +1 -1
  797. package/src/workflows/engine.ts +22 -0
  798. package/src/workflows/fanout-load.test.ts +1 -1
  799. package/src/workflows/journal-store.test.ts +1 -1
  800. package/src/workflows/leaf-runner.test.ts +40 -1
  801. package/src/workflows/leaf-runner.ts +26 -1
  802. package/src/workspace/git-service.ts +144 -29
  803. package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
  804. package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
  805. package/src/workspace/migrations/registry.ts +4 -0
  806. package/src/workspace/migrations/runner.ts +32 -2
  807. package/src/__tests__/access-request-decision.test.ts +0 -375
  808. package/src/__tests__/guardian-grant-minting.test.ts +0 -607
  809. package/src/__tests__/plugin-source-watcher.test.ts +0 -302
  810. package/src/api/events/turn-profile-auto-routed.ts +0 -28
  811. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
  812. package/src/daemon/plugin-source-watcher.ts +0 -278
  813. package/src/daemon/switch-inference-profile-tool.ts +0 -62
  814. package/src/memory/guardian-approvals.ts +0 -361
  815. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
  816. package/src/memory/migrations/038-actor-token-records.ts +0 -45
  817. package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
  818. package/src/memory/migrations/103-complex-migrations.ts +0 -23
  819. package/src/memory/migrations/113-late-migrations.ts +0 -30
  820. package/src/memory/migrations/index.ts +0 -301
  821. package/src/runtime/routes/access-request-decision.ts +0 -297
  822. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
  823. package/src/runtime/routes/channel-guardian-routes.ts +0 -19
  824. package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
@@ -57,12 +57,27 @@ import {
57
57
  import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
58
58
  import { ensureGroupMigration } from "./conversation-group-migration.js";
59
59
  import { runAsyncSqlite } from "./db-async-query.js";
60
- import { getDb, getSqliteFrom } from "./db-connection.js";
60
+ import {
61
+ type DrizzleDb,
62
+ getDb,
63
+ getLogsDb,
64
+ getSqliteFrom,
65
+ } from "./db-connection.js";
66
+ import {
67
+ copyForkMessagesViaSubprocess,
68
+ type ForkIdPair,
69
+ } from "./fork-message-copy.js";
61
70
  import { forkGraphMemoryState } from "./graph/graph-memory-state-store.js";
62
71
  import { indexMessageNow } from "./indexer.js";
63
72
  import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
64
73
  import { forkRetrospectiveState } from "./memory-retrospective-state.js";
65
- import { rawExec, rawGet, rawRun } from "./raw-query.js";
74
+ import {
75
+ rawExec,
76
+ rawGet,
77
+ rawLogsRun,
78
+ rawMemoryRun,
79
+ rawRun,
80
+ } from "./raw-query.js";
66
81
  import {
67
82
  channelInboundEvents,
68
83
  conversations,
@@ -84,6 +99,19 @@ import { extractInjectedConceptSlugs } from "./v2/injected-block-slugs.js";
84
99
 
85
100
  const log = getLogger("conversation-store");
86
101
 
102
+ /**
103
+ * The logs connection (`assistant-logs.db`), where `llm_request_logs` lives.
104
+ * Throws if the file cannot be opened — the few call sites here that touch
105
+ * request logs (conversation deletes, turn-window anchoring) have no fallback.
106
+ */
107
+ function logsDb(): DrizzleDb {
108
+ const db = getLogsDb();
109
+ if (!db) {
110
+ throw new Error("logs database unavailable");
111
+ }
112
+ return db;
113
+ }
114
+
87
115
  // ── Message metadata Zod schema ──────────────────────────────────────
88
116
  // Validates the JSON stored in messages.metadata. Known fields are typed;
89
117
  // extra keys are allowed via passthrough so callers can attach ad-hoc data.
@@ -148,6 +176,13 @@ export const messageMetadataSchema = z
148
176
  nowScratchpadBlock: z.string().optional(),
149
177
  pkbContextBlock: z.string().optional(),
150
178
  memoryV2StaticBlock: z.string().optional(),
179
+ /** `<background_turn>` block (background/scheduled non-interactive turns),
180
+ * rehydrated by `loadFromDb` for reload/fork prefix-cache parity. */
181
+ backgroundTurnBlock: z.string().optional(),
182
+ /** `<channel_capabilities>` block, rehydrated for the same reason. */
183
+ channelCapabilitiesBlock: z.string().optional(),
184
+ /** `<non_interactive_context>` block, rehydrated for the same reason. */
185
+ nonInteractiveContextBlock: z.string().optional(),
151
186
  })
152
187
  .passthrough();
153
188
 
@@ -997,170 +1032,436 @@ export function forkConversation(params: {
997
1032
  }
998
1033
  }
999
1034
 
1000
- const attachmentIdMap = new Map<string, string>();
1001
- for (const message of messagesToCopy) {
1002
- const forkedMessageId = forkedMessageIds.get(message.id);
1003
- if (!forkedMessageId) continue;
1035
+ populateForkContentsInProcess({
1036
+ fork: fc,
1037
+ sourceConversationId: sourceConversation.id,
1038
+ messagesToCopy,
1039
+ forkedMessageIds,
1040
+ latestForkedAssistant,
1041
+ isFullHistoryFork: copyBoundaryIndex === sourceMessages.length - 1,
1042
+ preserveSourceCompactionState,
1043
+ visibleWindowStartIndex,
1044
+ diskSyncQueue,
1045
+ });
1004
1046
 
1005
- const attachmentLinks = db
1006
- .select({
1007
- attachmentId: messageAttachments.attachmentId,
1008
- position: messageAttachments.position,
1047
+ return fc;
1048
+ });
1049
+
1050
+ // Disk-view sync runs after commit — file I/O is idempotent and
1051
+ // conversation deletion cleans up orphaned directories.
1052
+ for (const entry of diskSyncQueue) {
1053
+ syncMessageToDisk(entry.conversationId, entry.messageId, entry.createdAt);
1054
+ }
1055
+
1056
+ const persistedFork = getConversation(forkedConversation.id);
1057
+ if (!persistedFork) {
1058
+ throw new Error(
1059
+ `Failed to load forked conversation ${forkedConversation.id} after creation`,
1060
+ );
1061
+ }
1062
+
1063
+ return persistedFork;
1064
+ }
1065
+
1066
+ interface PopulateForkContentsArgs {
1067
+ /** The freshly-created fork conversation row (needs `id` + `createdAt`). */
1068
+ fork: { id: string; createdAt: number };
1069
+ sourceConversationId: string;
1070
+ messagesToCopy: MessageRow[];
1071
+ /** Source→fork message-id map for every copied row. */
1072
+ forkedMessageIds: Map<string, string>;
1073
+ latestForkedAssistant: { messageId: string; messageAt: number } | null;
1074
+ /** `copyBoundaryIndex === sourceMessages.length - 1` for the source. */
1075
+ isFullHistoryFork: boolean;
1076
+ preserveSourceCompactionState: boolean;
1077
+ visibleWindowStartIndex: number;
1078
+ /**
1079
+ * When provided, a disk-sync entry is appended per copied message for the
1080
+ * caller to flush after commit. Omitted by the retrospective fork, whose
1081
+ * throwaway conversation needs no disk-view projection.
1082
+ */
1083
+ diskSyncQueue?: Array<{
1084
+ conversationId: string;
1085
+ messageId: string;
1086
+ createdAt: number;
1087
+ }>;
1088
+ }
1089
+
1090
+ /**
1091
+ * In-process tail of a conversation fork: relink each copied message's
1092
+ * attachments (scoped per-conversation), set `lastMessageAt`, seed attention,
1093
+ * and carry the parent's per-conversation memory state.
1094
+ *
1095
+ * Assumes the fork's message ROWS already exist — copied either in-process
1096
+ * (synchronous fork) or via the off-event-loop subprocess (retrospective
1097
+ * fork). Single source of truth shared by `forkConversation` and
1098
+ * `forkConversationForRetrospective`; must run inside a transaction on the
1099
+ * main connection.
1100
+ */
1101
+ function populateForkContentsInProcess(args: PopulateForkContentsArgs): void {
1102
+ const {
1103
+ fork,
1104
+ sourceConversationId,
1105
+ messagesToCopy,
1106
+ forkedMessageIds,
1107
+ latestForkedAssistant,
1108
+ isFullHistoryFork,
1109
+ preserveSourceCompactionState,
1110
+ visibleWindowStartIndex,
1111
+ diskSyncQueue,
1112
+ } = args;
1113
+ const db = getDb();
1114
+
1115
+ const attachmentIdMap = new Map<string, string>();
1116
+ for (const message of messagesToCopy) {
1117
+ const forkedMessageId = forkedMessageIds.get(message.id);
1118
+ if (!forkedMessageId) continue;
1119
+
1120
+ const attachmentLinks = db
1121
+ .select({
1122
+ attachmentId: messageAttachments.attachmentId,
1123
+ position: messageAttachments.position,
1124
+ })
1125
+ .from(messageAttachments)
1126
+ .where(eq(messageAttachments.messageId, message.id))
1127
+ .orderBy(messageAttachments.position)
1128
+ .all();
1129
+ const uncachedAttachmentLinks = attachmentLinks.filter(
1130
+ (link) => !attachmentIdMap.has(link.attachmentId),
1131
+ );
1132
+ const stagingMessageId = uncachedAttachmentLinks.length > 0 ? uuid() : null;
1133
+
1134
+ if (stagingMessageId) {
1135
+ db.insert(messages)
1136
+ .values({
1137
+ id: stagingMessageId,
1138
+ conversationId: fork.id,
1139
+ role: message.role,
1140
+ content: "",
1141
+ createdAt: message.createdAt,
1142
+ metadata: null,
1009
1143
  })
1010
- .from(messageAttachments)
1011
- .where(eq(messageAttachments.messageId, message.id))
1012
- .orderBy(messageAttachments.position)
1013
- .all();
1014
- const uncachedAttachmentLinks = attachmentLinks.filter(
1015
- (link) => !attachmentIdMap.has(link.attachmentId),
1016
- );
1017
- const stagingMessageId =
1018
- uncachedAttachmentLinks.length > 0 ? uuid() : null;
1144
+ .run();
1145
+ }
1019
1146
 
1020
- if (stagingMessageId) {
1021
- db.insert(messages)
1147
+ for (const link of attachmentLinks) {
1148
+ const cachedAttachmentId = attachmentIdMap.get(link.attachmentId);
1149
+ if (cachedAttachmentId) {
1150
+ db.insert(messageAttachments)
1022
1151
  .values({
1023
- id: stagingMessageId,
1024
- conversationId: fc.id,
1025
- role: message.role,
1026
- content: "",
1027
- createdAt: message.createdAt,
1028
- metadata: null,
1152
+ id: uuid(),
1153
+ messageId: forkedMessageId,
1154
+ attachmentId: cachedAttachmentId,
1155
+ position: link.position,
1156
+ createdAt: Date.now(),
1029
1157
  })
1030
1158
  .run();
1159
+ continue;
1031
1160
  }
1032
1161
 
1033
- for (const link of attachmentLinks) {
1034
- const cachedAttachmentId = attachmentIdMap.get(link.attachmentId);
1035
- if (cachedAttachmentId) {
1036
- db.insert(messageAttachments)
1037
- .values({
1038
- id: uuid(),
1039
- messageId: forkedMessageId,
1040
- attachmentId: cachedAttachmentId,
1041
- position: link.position,
1042
- createdAt: Date.now(),
1043
- })
1044
- .run();
1045
- continue;
1046
- }
1047
-
1048
- const scopedAttachmentId = linkAttachmentToMessage(
1049
- stagingMessageId ?? forkedMessageId,
1050
- link.attachmentId,
1051
- link.position,
1052
- );
1053
- attachmentIdMap.set(link.attachmentId, scopedAttachmentId);
1054
- }
1055
-
1056
- if (stagingMessageId) {
1057
- relinkAttachments([stagingMessageId], forkedMessageId);
1058
- db.delete(messages).where(eq(messages.id, stagingMessageId)).run();
1059
- }
1060
-
1061
- diskSyncQueue.push({
1062
- conversationId: fc.id,
1063
- messageId: forkedMessageId,
1064
- createdAt: fc.createdAt,
1065
- });
1162
+ const scopedAttachmentId = linkAttachmentToMessage(
1163
+ stagingMessageId ?? forkedMessageId,
1164
+ link.attachmentId,
1165
+ link.position,
1166
+ );
1167
+ attachmentIdMap.set(link.attachmentId, scopedAttachmentId);
1066
1168
  }
1067
1169
 
1068
- // Set lastMessageAt to the max createdAt of copied messages so the
1069
- // forked conversation sorts correctly by message recency.
1070
- const lastCopiedMessage = messagesToCopy.at(-1);
1071
- if (lastCopiedMessage) {
1072
- db.update(conversations)
1073
- .set({ lastMessageAt: lastCopiedMessage.createdAt })
1074
- .where(eq(conversations.id, fc.id))
1075
- .run();
1170
+ if (stagingMessageId) {
1171
+ relinkAttachments([stagingMessageId], forkedMessageId);
1172
+ db.delete(messages).where(eq(messages.id, stagingMessageId)).run();
1076
1173
  }
1077
1174
 
1078
- seedForkedConversationAttention({
1079
- conversationId: fc.id,
1080
- latestAssistantMessageId: latestForkedAssistant?.messageId ?? null,
1081
- latestAssistantMessageAt: latestForkedAssistant?.messageAt ?? null,
1175
+ diskSyncQueue?.push({
1176
+ conversationId: fork.id,
1177
+ messageId: forkedMessageId,
1178
+ createdAt: fork.createdAt,
1082
1179
  });
1180
+ }
1083
1181
 
1084
- // Carry the parent's per-conversation memory state into the child so the
1085
- // forked thread resumes with the same activation/injection log and
1086
- // in-context tracker the parent had at fork time. Only valid for
1087
- // full-history forks: a truncated fork would inherit activation/tracker
1088
- // entries for turns the child does not actually contain.
1089
- const isFullHistoryFork = copyBoundaryIndex === sourceMessages.length - 1;
1090
- if (isFullHistoryFork) {
1091
- forkActivationState(db, sourceConversation.id, fc.id);
1092
- forkEverInjected(db, sourceConversation.id, fc.id);
1093
- forkGraphMemoryState(sourceConversation.id, fc.id);
1094
- } else {
1095
- // Truncated fork: the wholesale copy above would over-claim, but
1096
- // seeding nothing makes the child re-select and re-attach every page
1097
- // whose `<memory>` attachment it already inherited (observed in
1098
- // production: 89 duplicate page injections on one fork). Derive
1099
- // `everInjected` from the inherited attachments themselves — scoped to
1100
- // the child's visible window, since attachments behind an inherited
1101
- // compaction boundary are not rendered and must stay re-injectable.
1102
- // The v2 and v3 layers persist under separate metadata keys with the
1103
- // same `# memory/concepts/<slug>.md` header convention, so each seeds
1104
- // its own dedup record from its own blocks.
1105
- const visibleStartIndex = preserveSourceCompactionState
1106
- ? visibleWindowStartIndex
1107
- : 0;
1108
- const inheritedSlugs = new Set<string>();
1109
- const inheritedV3Slugs = new Set<string>();
1110
- for (const message of messagesToCopy.slice(visibleStartIndex)) {
1111
- const block = readInjectedBlock(
1112
- message.metadata,
1113
- "memoryInjectedBlock",
1114
- );
1115
- if (block) {
1116
- for (const slug of extractInjectedConceptSlugs(block)) {
1117
- inheritedSlugs.add(slug);
1118
- }
1119
- }
1120
- const v3Block = readInjectedBlock(
1121
- message.metadata,
1122
- MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
1123
- );
1124
- if (v3Block) {
1125
- for (const slug of extractInjectedConceptSlugs(v3Block)) {
1126
- inheritedV3Slugs.add(slug);
1127
- }
1182
+ // Set lastMessageAt to the max createdAt of copied messages so the
1183
+ // forked conversation sorts correctly by message recency.
1184
+ const lastCopiedMessage = messagesToCopy.at(-1);
1185
+ if (lastCopiedMessage) {
1186
+ db.update(conversations)
1187
+ .set({ lastMessageAt: lastCopiedMessage.createdAt })
1188
+ .where(eq(conversations.id, fork.id))
1189
+ .run();
1190
+ }
1191
+
1192
+ seedForkedConversationAttention({
1193
+ conversationId: fork.id,
1194
+ latestAssistantMessageId: latestForkedAssistant?.messageId ?? null,
1195
+ latestAssistantMessageAt: latestForkedAssistant?.messageAt ?? null,
1196
+ });
1197
+
1198
+ // Carry the parent's per-conversation memory state into the child so the
1199
+ // forked thread resumes with the same activation/injection log and
1200
+ // in-context tracker the parent had at fork time. Only valid for
1201
+ // full-history forks: a truncated fork would inherit activation/tracker
1202
+ // entries for turns the child does not actually contain.
1203
+ if (isFullHistoryFork) {
1204
+ forkActivationState(db, sourceConversationId, fork.id);
1205
+ forkEverInjected(db, sourceConversationId, fork.id);
1206
+ forkGraphMemoryState(sourceConversationId, fork.id);
1207
+ } else {
1208
+ // Truncated fork: the wholesale copy above would over-claim, but
1209
+ // seeding nothing makes the child re-select and re-attach every page
1210
+ // whose `<memory>` attachment it already inherited (observed in
1211
+ // production: 89 duplicate page injections on one fork). Derive
1212
+ // `everInjected` from the inherited attachments themselves — scoped to
1213
+ // the child's visible window, since attachments behind an inherited
1214
+ // compaction boundary are not rendered and must stay re-injectable.
1215
+ // The v2 and v3 layers persist under separate metadata keys with the
1216
+ // same `# memory/concepts/<slug>.md` header convention, so each seeds
1217
+ // its own dedup record from its own blocks.
1218
+ const visibleStartIndex = preserveSourceCompactionState
1219
+ ? visibleWindowStartIndex
1220
+ : 0;
1221
+ const inheritedSlugs = new Set<string>();
1222
+ const inheritedV3Slugs = new Set<string>();
1223
+ for (const message of messagesToCopy.slice(visibleStartIndex)) {
1224
+ const block = readInjectedBlock(message.metadata, "memoryInjectedBlock");
1225
+ if (block) {
1226
+ for (const slug of extractInjectedConceptSlugs(block)) {
1227
+ inheritedSlugs.add(slug);
1128
1228
  }
1129
1229
  }
1130
- seedForkActivationState(db, fc.id, [...inheritedSlugs]);
1131
- seedEverInjectedFromSlugs(
1132
- db,
1133
- sourceConversation.id,
1134
- fc.id,
1135
- [...inheritedV3Slugs],
1136
- Date.now(),
1230
+ const v3Block = readInjectedBlock(
1231
+ message.metadata,
1232
+ MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
1137
1233
  );
1234
+ if (v3Block) {
1235
+ for (const slug of extractInjectedConceptSlugs(v3Block)) {
1236
+ inheritedV3Slugs.add(slug);
1237
+ }
1238
+ }
1138
1239
  }
1139
- forkRetrospectiveState({
1140
- database: db,
1141
- sourceConversationId: sourceConversation.id,
1142
- forkedConversationId: fc.id,
1143
- forkedMessageIds,
1144
- lastCopiedSourceMessageId: messagesToCopy.at(-1)?.id ?? null,
1145
- });
1146
-
1147
- return fc;
1240
+ seedForkActivationState(db, fork.id, [...inheritedSlugs]);
1241
+ seedEverInjectedFromSlugs(
1242
+ db,
1243
+ sourceConversationId,
1244
+ fork.id,
1245
+ [...inheritedV3Slugs],
1246
+ Date.now(),
1247
+ );
1248
+ }
1249
+ forkRetrospectiveState({
1250
+ database: db,
1251
+ sourceConversationId,
1252
+ forkedConversationId: fork.id,
1253
+ forkedMessageIds,
1254
+ lastCopiedSourceMessageId: messagesToCopy.at(-1)?.id ?? null,
1148
1255
  });
1256
+ }
1149
1257
 
1150
- // Disk-view sync runs after commit — file I/O is idempotent and
1151
- // conversation deletion cleans up orphaned directories.
1152
- for (const entry of diskSyncQueue) {
1153
- syncMessageToDisk(entry.conversationId, entry.messageId, entry.createdAt);
1258
+ /**
1259
+ * Resolve the fork id + timestamp of the LAST assistant message among the
1260
+ * copied rows. The synchronous copy loop tracks this inline; the off-loop
1261
+ * subprocess copy does not, so the async fork derives it from the id map.
1262
+ */
1263
+ function latestForkedAssistantFrom(
1264
+ messagesToCopy: MessageRow[],
1265
+ forkedMessageIds: Map<string, string>,
1266
+ ): { messageId: string; messageAt: number } | null {
1267
+ for (let i = messagesToCopy.length - 1; i >= 0; i--) {
1268
+ const message = messagesToCopy[i]!;
1269
+ if (message.role !== "assistant") continue;
1270
+ const forkedMessageId = forkedMessageIds.get(message.id);
1271
+ if (forkedMessageId) {
1272
+ return { messageId: forkedMessageId, messageAt: message.createdAt };
1273
+ }
1154
1274
  }
1275
+ return null;
1276
+ }
1155
1277
 
1156
- const persistedFork = getConversation(forkedConversation.id);
1157
- if (!persistedFork) {
1158
- throw new Error(
1159
- `Failed to load forked conversation ${forkedConversation.id} after creation`,
1278
+ /**
1279
+ * Async variant of {@link forkConversation} for the memory-retrospective job,
1280
+ * which forks the entire source conversation into a throwaway background
1281
+ * conversation on a hot path that must not stall the daemon.
1282
+ *
1283
+ * The dominant cost — copying every source message row — runs OFF the event
1284
+ * loop in a `sqlite3` subprocess (see {@link copyForkMessagesViaSubprocess}),
1285
+ * so `/healthz` and gateway IPC stay responsive during the copy. The cheap
1286
+ * tail (conversation row, attachment relink, memory-state seeding) runs
1287
+ * in-process and reuses {@link populateForkContentsInProcess}, the same helper
1288
+ * the synchronous fork uses, so the two paths cannot drift on that logic. The
1289
+ * boundary/compaction computation mirrors {@link forkConversation} and is
1290
+ * pinned by a parity test.
1291
+ *
1292
+ * The disk-view projection (`syncMessageToDisk`) is intentionally skipped: the
1293
+ * fork is GC'd after the retrospective pass and never browsed, and the agent
1294
+ * reads it from the database, not the on-disk JSONL.
1295
+ *
1296
+ * Atomicity spans two connections (the in-process row/tail and the subprocess
1297
+ * copy), so a mid-flight failure can leave a partial fork. The partial is
1298
+ * deleted best-effort on error; a crash between phases is reclaimed by the
1299
+ * worker's startup orphan sweep. Callers only ever observe a fully-built fork
1300
+ * because the returned promise resolves after every phase commits.
1301
+ */
1302
+ export async function forkConversationForRetrospective(params: {
1303
+ conversationId: string;
1304
+ throughMessageId?: string;
1305
+ source?: string;
1306
+ title?: string;
1307
+ conversationType?: ConversationCreateType;
1308
+ groupId?: string;
1309
+ }): Promise<ConversationRow> {
1310
+ const { conversationId, throughMessageId } = params;
1311
+ const db = getDb();
1312
+ const sourceConversation = getConversation(conversationId);
1313
+ if (!sourceConversation) {
1314
+ throw new UserError(`Conversation ${conversationId} not found`);
1315
+ }
1316
+
1317
+ const sourceMessages = getMessages(conversationId);
1318
+ if (throughMessageId != null) {
1319
+ // Re-sort on `(createdAt, id)` so the cutoff slice agrees with the cursor
1320
+ // the caller chose it from — see the matching note in `forkConversation`.
1321
+ sourceMessages.sort(
1322
+ (a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id),
1323
+ );
1324
+ }
1325
+ if (sourceMessages.length === 0) {
1326
+ throw new UserError(
1327
+ `Conversation ${conversationId} has no persisted messages to fork`,
1160
1328
  );
1161
1329
  }
1162
1330
 
1163
- return persistedFork;
1331
+ const initialBoundaryIndex =
1332
+ throughMessageId == null
1333
+ ? sourceMessages.length - 1
1334
+ : sourceMessages.findIndex((message) => message.id === throughMessageId);
1335
+ if (throughMessageId != null && initialBoundaryIndex === -1) {
1336
+ throw new UserError(
1337
+ `Message ${throughMessageId} does not belong to conversation ${conversationId}`,
1338
+ );
1339
+ }
1340
+
1341
+ const copyBoundaryIndex = findDisplayTurnEndIndex(
1342
+ sourceMessages,
1343
+ initialBoundaryIndex,
1344
+ );
1345
+ const visibleWindowStartIndex = Math.max(
1346
+ 0,
1347
+ Math.min(
1348
+ sourceConversation.contextCompactedMessageCount,
1349
+ sourceMessages.length,
1350
+ ),
1351
+ );
1352
+ const preserveSourceCompactionState =
1353
+ copyBoundaryIndex >= visibleWindowStartIndex;
1354
+ const messagesToCopy =
1355
+ copyBoundaryIndex >= 0
1356
+ ? sourceMessages.slice(0, copyBoundaryIndex + 1)
1357
+ : ([] as MessageRow[]);
1358
+
1359
+ const sourceHistoryStrippedAt = sourceConversation.historyStrippedAt ?? null;
1360
+ const boundaryMessageCreatedAt = messagesToCopy.at(-1)?.createdAt ?? null;
1361
+ const inheritsHistoryStrippedAt =
1362
+ sourceHistoryStrippedAt != null &&
1363
+ boundaryMessageCreatedAt != null &&
1364
+ boundaryMessageCreatedAt >= sourceHistoryStrippedAt;
1365
+ const forkParentMessageId = messagesToCopy.at(-1)?.id ?? null;
1366
+ const forkTitle =
1367
+ params.title ?? `${sourceConversation.title ?? "Untitled"} (Fork)`;
1368
+ const parentGroupId = getConversationGroupId(conversationId);
1369
+
1370
+ // Pre-generate the id map in JS so the same map drives the off-loop copy and
1371
+ // the in-process attachment relink that follows.
1372
+ const idPairs: ForkIdPair[] = messagesToCopy.map((message) => ({
1373
+ oldId: message.id,
1374
+ newId: uuid(),
1375
+ }));
1376
+ const forkedMessageIds = new Map<string, string>(
1377
+ idPairs.map((pair) => [pair.oldId, pair.newId]),
1378
+ );
1379
+
1380
+ // Phase 1 (in-process, tiny): create the fork conversation row + lineage so
1381
+ // the subprocess connection sees it before inserting messages.
1382
+ const fork = db.transaction(() => {
1383
+ const fc = createConversation({
1384
+ title: forkTitle,
1385
+ conversationType: params.conversationType ?? "standard",
1386
+ groupId: params.groupId ?? parentGroupId ?? "system:all",
1387
+ ...(params.source != null ? { source: params.source } : {}),
1388
+ });
1389
+ db.update(conversations)
1390
+ .set({
1391
+ forkParentConversationId: sourceConversation.id,
1392
+ forkParentMessageId,
1393
+ contextSummary: preserveSourceCompactionState
1394
+ ? sourceConversation.contextSummary
1395
+ : null,
1396
+ contextCompactedMessageCount: preserveSourceCompactionState
1397
+ ? sourceConversation.contextCompactedMessageCount
1398
+ : 0,
1399
+ contextCompactedAt: preserveSourceCompactionState
1400
+ ? sourceConversation.contextCompactedAt
1401
+ : null,
1402
+ slackContextCompactionWatermarkTs: preserveSourceCompactionState
1403
+ ? sourceConversation.slackContextCompactionWatermarkTs
1404
+ : null,
1405
+ slackContextCompactionWatermarkAt: preserveSourceCompactionState
1406
+ ? sourceConversation.slackContextCompactionWatermarkAt
1407
+ : null,
1408
+ historyStrippedAt: inheritsHistoryStrippedAt
1409
+ ? sourceHistoryStrippedAt
1410
+ : null,
1411
+ inferenceProfile: sourceConversation.inferenceProfile,
1412
+ })
1413
+ .where(eq(conversations.id, fc.id))
1414
+ .run();
1415
+ return fc;
1416
+ });
1417
+
1418
+ try {
1419
+ // Phase 2 (off the event loop): copy the message rows in a sqlite3
1420
+ // subprocess so the daemon stays responsive during the heavy copy.
1421
+ const copy = await copyForkMessagesViaSubprocess({
1422
+ forkConversationId: fork.id,
1423
+ idPairs,
1424
+ });
1425
+ if (!copy.ok) {
1426
+ throw new Error(
1427
+ `fork message copy failed (${copy.backend}): ${copy.error ?? "unknown"}`,
1428
+ );
1429
+ }
1430
+
1431
+ // Phase 3 (in-process): attachments + memory-state seeding, reusing the
1432
+ // same helper as the synchronous fork. Disk-view projection is skipped.
1433
+ const latestForkedAssistant = latestForkedAssistantFrom(
1434
+ messagesToCopy,
1435
+ forkedMessageIds,
1436
+ );
1437
+ db.transaction(() => {
1438
+ populateForkContentsInProcess({
1439
+ fork,
1440
+ sourceConversationId: sourceConversation.id,
1441
+ messagesToCopy,
1442
+ forkedMessageIds,
1443
+ latestForkedAssistant,
1444
+ isFullHistoryFork: copyBoundaryIndex === sourceMessages.length - 1,
1445
+ preserveSourceCompactionState,
1446
+ visibleWindowStartIndex,
1447
+ });
1448
+ });
1449
+
1450
+ const persistedFork = getConversation(fork.id);
1451
+ if (!persistedFork) {
1452
+ throw new Error(
1453
+ `Failed to load forked conversation ${fork.id} after creation`,
1454
+ );
1455
+ }
1456
+ return persistedFork;
1457
+ } catch (err) {
1458
+ try {
1459
+ deleteConversation(fork.id);
1460
+ } catch {
1461
+ // Best-effort cleanup; the worker's startup orphan sweep is the backstop.
1462
+ }
1463
+ throw err;
1464
+ }
1164
1465
  }
1165
1466
 
1166
1467
  /**
@@ -1180,6 +1481,13 @@ export function deleteConversation(id: string): DeletedMemoryIds {
1180
1481
  const convBeforeDelete = getConversation(id);
1181
1482
  const createdAtForDiskCleanup = convBeforeDelete?.createdAt;
1182
1483
 
1484
+ // llm_request_logs lives in the dedicated logs connection, so it is deleted
1485
+ // there — separately from the main-DB transaction below.
1486
+ logsDb()
1487
+ .delete(llmRequestLogs)
1488
+ .where(eq(llmRequestLogs.conversationId, id))
1489
+ .run();
1490
+
1183
1491
  db.transaction((tx) => {
1184
1492
  // Collect all message IDs for this conversation.
1185
1493
  const messageRows = tx
@@ -1199,9 +1507,6 @@ export function deleteConversation(id: string): DeletedMemoryIds {
1199
1507
  result.segmentIds = linkedSegments.map((r) => r.id);
1200
1508
 
1201
1509
  // Delete non-cascading tables first.
1202
- tx.delete(llmRequestLogs)
1203
- .where(eq(llmRequestLogs.conversationId, id))
1204
- .run();
1205
1510
  tx.delete(toolInvocations)
1206
1511
  .where(eq(toolInvocations.conversationId, id))
1207
1512
  .run();
@@ -1224,9 +1529,6 @@ export function deleteConversation(id: string): DeletedMemoryIds {
1224
1529
  }
1225
1530
  } else {
1226
1531
  // No messages — just clean up non-message tables.
1227
- tx.delete(llmRequestLogs)
1228
- .where(eq(llmRequestLogs.conversationId, id))
1229
- .run();
1230
1532
  tx.delete(toolInvocations)
1231
1533
  .where(eq(toolInvocations.conversationId, id))
1232
1534
  .run();
@@ -2133,8 +2435,11 @@ export async function clearAll(): Promise<{
2133
2435
  // Each DELETE goes through `runAsyncSqlite`. The original code threw
2134
2436
  // on rawExec failure; mirror that here by throwing when the async
2135
2437
  // result reports `ok: false`, so the route handler still returns 500.
2136
- const runOrThrow = async (sql: string): Promise<void> => {
2137
- const result = await runAsyncSqlite(sql);
2438
+ const runOrThrow = async (
2439
+ sql: string,
2440
+ options?: { dbPath?: string },
2441
+ ): Promise<void> => {
2442
+ const result = await runAsyncSqlite(sql, options);
2138
2443
  if (!result.ok) {
2139
2444
  throw new Error(
2140
2445
  `clearAll: \`${sql}\` failed (${result.backend}): ${result.error ?? "unknown"}`,
@@ -2154,9 +2459,12 @@ export async function clearAll(): Promise<{
2154
2459
  await runOrThrow("DELETE FROM memory_segments");
2155
2460
  await runOrThrow("DELETE FROM memory_summaries");
2156
2461
  await runOrThrow("DELETE FROM memory_embeddings");
2157
- await runOrThrow("DELETE FROM memory_jobs");
2462
+ // memory_jobs and llm_request_logs each live in their own dedicated
2463
+ // connection; clear them directly on those connections rather than through a
2464
+ // sqlite3 subprocess.
2465
+ rawMemoryRun("DELETE FROM memory_jobs");
2158
2466
  await runOrThrow("DELETE FROM memory_checkpoints");
2159
- await runOrThrow("DELETE FROM llm_request_logs");
2467
+ rawLogsRun("DELETE FROM llm_request_logs");
2160
2468
  await runOrThrow("DELETE FROM llm_usage_events");
2161
2469
  await runOrThrow("DELETE FROM message_attachments");
2162
2470
  await runOrThrow("DELETE FROM attachments");
@@ -2849,7 +3157,8 @@ export function getTurnTimeBounds(
2849
3157
  : startTime + MAX_TURN_DURATION_MS;
2850
3158
 
2851
3159
  if (hardCeiling > endTime) {
2852
- const latestLog = db
3160
+ // llm_request_logs lives in the dedicated logs connection.
3161
+ const latestLog = logsDb()
2853
3162
  .select({ createdAt: llmRequestLogs.createdAt })
2854
3163
  .from(llmRequestLogs)
2855
3164
  .where(