@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -32,7 +32,9 @@
32
32
  // conversations left by a mid-run crash are swept by
33
33
  // `memory-retrospective-startup-cleanup.ts`.
34
34
 
35
+ import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
35
36
  import type { AssistantConfig } from "../config/types.js";
37
+ import { extractTurnContextTimestamp } from "../context/compactor.js";
36
38
  import { resolveTurnTimezoneContext } from "../daemon/date-context.js";
37
39
  import {
38
40
  getAssistantName,
@@ -40,13 +42,17 @@ import {
40
42
  } from "../daemon/identity-helpers.js";
41
43
  import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../daemon/trust-context.js";
42
44
  import { formatMessageSliceForTranscript } from "../export/transcript-formatter.js";
45
+ import type { Message } from "../providers/types.js";
43
46
  import { wakeAgentForOpportunity } from "../runtime/agent-wake.js";
44
47
  import { getLogger } from "../util/logger.js";
45
48
  import { getWorkspaceDir } from "../util/platform.js";
46
49
  import { bootstrapConversation } from "./conversation-bootstrap.js";
47
50
  import {
51
+ addMessage,
48
52
  deleteConversation,
49
53
  findMostRecentRetrospectiveFor,
54
+ forkConversation,
55
+ getConversation,
50
56
  getMessages,
51
57
  getMessagesAfter,
52
58
  } from "./conversation-crud.js";
@@ -56,7 +62,9 @@ import {
56
62
  type MemoryJobType,
57
63
  } from "./jobs-store.js";
58
64
  import {
65
+ MEMORY_RETROSPECTIVE_FORK_SOURCE,
59
66
  MEMORY_RETROSPECTIVE_GROUP_ID,
67
+ MEMORY_RETROSPECTIVE_INSTRUCTION_KIND,
60
68
  MEMORY_RETROSPECTIVE_SOURCE,
61
69
  } from "./memory-retrospective-constants.js";
62
70
  import {
@@ -65,6 +73,17 @@ import {
65
73
  upsertRetrospectiveState,
66
74
  } from "./memory-retrospective-state.js";
67
75
 
76
+ /**
77
+ * Feature flag that switches the retrospective handler between the legacy
78
+ * transcript-based path (renders the new-message slice into a `<transcript>`
79
+ * block and wakes an empty background conversation) and the new fork-based
80
+ * path (forks the source through its latest message, persists a user-role
81
+ * instruction, and wakes the fork). The fork path lets the retrospective hit
82
+ * the provider prompt cache and read compaction summary + tail messages
83
+ * natively.
84
+ */
85
+ const MEMORY_RETROSPECTIVE_FORK_FLAG = "memory-retrospective-fork" as const;
86
+
68
87
  const log = getLogger("memory-retrospective-job");
69
88
 
70
89
  /**
@@ -96,6 +115,24 @@ export async function memoryRetrospectiveJob(
96
115
  return { kind: "no_new_messages" };
97
116
  }
98
117
 
118
+ const useFork = isAssistantFeatureFlagEnabled(
119
+ MEMORY_RETROSPECTIVE_FORK_FLAG,
120
+ config,
121
+ );
122
+ return useFork
123
+ ? runForkBasedRetrospective(sourceConversationId, config)
124
+ : runLegacyRetrospective(sourceConversationId, config);
125
+ }
126
+
127
+ // ---------------------------------------------------------------------------
128
+ // Legacy path — transcript-rendered slice + empty background conversation.
129
+ // Kept behind the `memory-retrospective-fork` flag for safe rollback.
130
+ // ---------------------------------------------------------------------------
131
+
132
+ async function runLegacyRetrospective(
133
+ sourceConversationId: string,
134
+ config: AssistantConfig,
135
+ ): Promise<MemoryRetrospectiveOutcome> {
99
136
  // 1. Load state + compute the message slice.
100
137
  const state = getRetrospectiveState(sourceConversationId);
101
138
  const lastProcessedMessageId = state?.lastProcessedMessageId ?? null;
@@ -142,7 +179,7 @@ export async function memoryRetrospectiveJob(
142
179
  assistantName: getAssistantName(),
143
180
  userName: resolveUserName(getWorkspaceDir()),
144
181
  });
145
- const prompt = buildPrompt({
182
+ const prompt = buildLegacyPrompt({
146
183
  transcript,
147
184
  priorRemembers,
148
185
  timeZone: timezoneContext.effectiveTimezone,
@@ -171,6 +208,11 @@ export async function memoryRetrospectiveJob(
171
208
  source: MEMORY_RETROSPECTIVE_SOURCE,
172
209
  trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
173
210
  callSite: "memoryRetrospective",
211
+ // The background conversation's title already reads "Memory
212
+ // Retrospective", and `hint` is the full retrospective prompt — surfacing
213
+ // it verbatim as a "Conversation Woke" card body is noisy internal
214
+ // scaffolding for the user. Suppress it, matching the fork-based path.
215
+ suppressWakeSurface: true,
174
216
  });
175
217
  wakeSucceeded = result.invoked;
176
218
  failureReason = result.reason;
@@ -191,17 +233,7 @@ export async function memoryRetrospectiveJob(
191
233
  lastRunAt: Date.now(),
192
234
  });
193
235
 
194
- const followUpJobIds: string[] = [];
195
- for (const jobType of FOLLOW_UP_JOB_TYPES) {
196
- try {
197
- followUpJobIds.push(enqueueMemoryJob(jobType, {}));
198
- } catch (err) {
199
- log.warn(
200
- { err, jobType },
201
- "memory-retrospective: failed to enqueue follow-up job; continuing",
202
- );
203
- }
204
- }
236
+ const followUpJobIds = enqueueFollowUpJobs();
205
237
 
206
238
  log.info(
207
239
  {
@@ -210,6 +242,7 @@ export async function memoryRetrospectiveJob(
210
242
  cutoffMessageId,
211
243
  newMessageCount: newMessages.length,
212
244
  priorRememberCount: priorRemembers.length,
245
+ kind: "legacy",
213
246
  },
214
247
  "memory-retrospective invoked",
215
248
  );
@@ -251,6 +284,243 @@ export async function memoryRetrospectiveJob(
251
284
  };
252
285
  }
253
286
 
287
+ // ---------------------------------------------------------------------------
288
+ // Fork-based path — fork the source through its latest message, persist a
289
+ // user-role retrospective instruction at the tail, and wake the fork. The
290
+ // fork inherits compaction state (summary + tail messages) via the existing
291
+ // `forkConversation` machinery, and its prefix matches the source's prefix
292
+ // so provider prompt caching hits.
293
+ // ---------------------------------------------------------------------------
294
+
295
+ async function runForkBasedRetrospective(
296
+ sourceConversationId: string,
297
+ config: AssistantConfig,
298
+ ): Promise<MemoryRetrospectiveOutcome> {
299
+ const sourceConversation = getConversation(sourceConversationId);
300
+ if (!sourceConversation) {
301
+ log.warn(
302
+ { sourceConversationId },
303
+ "memory-retrospective (fork): source conversation not found; skipping",
304
+ );
305
+ return { kind: "no_new_messages" };
306
+ }
307
+
308
+ const state = getRetrospectiveState(sourceConversationId);
309
+ const lastProcessedMessageId = state?.lastProcessedMessageId ?? null;
310
+ const newMessages = getMessagesAfter(
311
+ sourceConversationId,
312
+ lastProcessedMessageId,
313
+ );
314
+
315
+ if (newMessages.length === 0) {
316
+ return { kind: "no_new_messages" };
317
+ }
318
+
319
+ const cutoffMessage = newMessages[newMessages.length - 1];
320
+ if (!cutoffMessage) {
321
+ return { kind: "no_new_messages" };
322
+ }
323
+ const cutoffMessageId = cutoffMessage.id;
324
+
325
+ // The fork carries the full conversation, so the agent needs an explicit
326
+ // anchor telling it where the review window begins. Prefer the user
327
+ // turn's `<turn_context>` `current_time:` (matches the conversation's
328
+ // own clock); fall back to ISO-formatted `createdAt` when the slice
329
+ // begins with an assistant turn or tool_result-only user message.
330
+ const windowStartTimestamp =
331
+ findFirstTurnContextTimestamp(newMessages) ??
332
+ new Date(newMessages[0]!.createdAt).toISOString();
333
+
334
+ // Pull prior `remember` calls BEFORE forking — otherwise
335
+ // `findMostRecentRetrospectiveFor` could locate this run's own fork.
336
+ const priorRemembers =
337
+ collectPriorRetrospectiveRemembers(sourceConversationId);
338
+
339
+ // Pin the fork to `cutoffMessageId` so messages arriving between the slice
340
+ // read above and this call don't sneak into the fork. Without
341
+ // `throughMessageId`, the fork snapshots the latest source message at fork
342
+ // time and this run would process turns past the cutoff while state only
343
+ // advances to `cutoffMessageId`, causing the next retrospective to
344
+ // reprocess (and potentially re-`remember`) those same turns.
345
+ //
346
+ // `forkConversation` inherits `contextSummary` /
347
+ // `contextCompactedMessageCount` / `contextCompactedAt` when the fork
348
+ // point sits within the visible window. Compacted source ⇒ compacted
349
+ // fork ⇒ summary + tail visible to the agent natively.
350
+ let forkConversationRow: ReturnType<typeof forkConversation>;
351
+ try {
352
+ forkConversationRow = forkConversation({
353
+ conversationId: sourceConversationId,
354
+ throughMessageId: cutoffMessageId,
355
+ source: MEMORY_RETROSPECTIVE_FORK_SOURCE,
356
+ title: `${sourceConversation.title ?? "Untitled"} (Retrospective)`,
357
+ conversationType: "background",
358
+ groupId: MEMORY_RETROSPECTIVE_GROUP_ID,
359
+ });
360
+ } catch (err) {
361
+ bumpRetrospectiveLastRunAt(sourceConversationId, Date.now());
362
+ log.error(
363
+ { err, sourceConversationId },
364
+ "memory-retrospective (fork): forkConversation failed",
365
+ );
366
+ throw err;
367
+ }
368
+ const forkId = forkConversationRow.id;
369
+
370
+ const timezoneContext = resolveTurnTimezoneContext({
371
+ configuredUserTimeZone: config.ui.userTimezone ?? null,
372
+ detectedTimezone: config.ui.detectedTimezone ?? null,
373
+ });
374
+ const instruction = buildForkInstruction({
375
+ windowStartTimestamp,
376
+ priorRemembers,
377
+ timeZone: timezoneContext.effectiveTimezone,
378
+ isFirstPass: lastProcessedMessageId == null,
379
+ });
380
+ try {
381
+ await addMessage(
382
+ forkId,
383
+ "user",
384
+ JSON.stringify([{ type: "text", text: instruction }]),
385
+ { kind: MEMORY_RETROSPECTIVE_INSTRUCTION_KIND, hidden: true },
386
+ { skipIndexing: true },
387
+ );
388
+ } catch (err) {
389
+ log.error(
390
+ { err, forkId, sourceConversationId },
391
+ "memory-retrospective (fork): failed to persist instruction message",
392
+ );
393
+ safeDeleteForkOnFailure(forkId);
394
+ bumpRetrospectiveLastRunAt(sourceConversationId, Date.now());
395
+ throw err;
396
+ }
397
+
398
+ // `skipHintInjection: true` because the instruction is already a
399
+ // persisted message — the wake's hint sandwich would only duplicate it.
400
+ let wakeSucceeded = false;
401
+ let failureReason: string | undefined;
402
+ let threw: unknown;
403
+ try {
404
+ const result = await wakeAgentForOpportunity({
405
+ conversationId: forkId,
406
+ hint: "",
407
+ source: MEMORY_RETROSPECTIVE_SOURCE,
408
+ trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
409
+ callSite: "memoryRetrospective",
410
+ hintRole: "user",
411
+ skipHintInjection: true,
412
+ suppressAutoCompaction: true,
413
+ // The fork's title already reads "(Retrospective)", so an empty-body
414
+ // "Conversation Woke" surface card on top of it would be noise. Suppress
415
+ // it — clients should display the fork as a normal background conv.
416
+ suppressWakeSurface: true,
417
+ });
418
+ wakeSucceeded = result.invoked;
419
+ failureReason = result.reason;
420
+ } catch (err) {
421
+ threw = err;
422
+ failureReason = err instanceof Error ? err.message : String(err);
423
+ log.error(
424
+ { err, forkId, sourceConversationId },
425
+ "memory-retrospective (fork): wake threw",
426
+ );
427
+ }
428
+
429
+ if (wakeSucceeded) {
430
+ upsertRetrospectiveState({
431
+ conversationId: sourceConversationId,
432
+ lastProcessedMessageId: cutoffMessageId,
433
+ lastRunAt: Date.now(),
434
+ });
435
+
436
+ const followUpJobIds = enqueueFollowUpJobs();
437
+
438
+ log.info(
439
+ {
440
+ sourceConversationId,
441
+ backgroundConversationId: forkId,
442
+ cutoffMessageId,
443
+ newMessageCount: newMessages.length,
444
+ priorRememberCount: priorRemembers.length,
445
+ windowStartTimestamp,
446
+ kind: "fork",
447
+ },
448
+ "memory-retrospective invoked",
449
+ );
450
+ return {
451
+ kind: "invoked",
452
+ backgroundConversationId: forkId,
453
+ cutoffMessageId,
454
+ newMessageCount: newMessages.length,
455
+ followUpJobIds,
456
+ };
457
+ }
458
+
459
+ bumpRetrospectiveLastRunAt(sourceConversationId, Date.now());
460
+ safeDeleteForkOnFailure(forkId);
461
+
462
+ if (threw !== undefined) {
463
+ throw threw;
464
+ }
465
+
466
+ return {
467
+ kind: "wake_failed",
468
+ reason: failureReason,
469
+ conversationId: forkId,
470
+ };
471
+ }
472
+
473
+ function enqueueFollowUpJobs(): string[] {
474
+ const followUpJobIds: string[] = [];
475
+ for (const jobType of FOLLOW_UP_JOB_TYPES) {
476
+ try {
477
+ followUpJobIds.push(enqueueMemoryJob(jobType, {}));
478
+ } catch (err) {
479
+ log.warn(
480
+ { err, jobType },
481
+ "memory-retrospective: failed to enqueue follow-up job; continuing",
482
+ );
483
+ }
484
+ }
485
+ return followUpJobIds;
486
+ }
487
+
488
+ function safeDeleteForkOnFailure(forkId: string): void {
489
+ try {
490
+ deleteConversation(forkId);
491
+ } catch (err) {
492
+ log.warn(
493
+ { err, forkId },
494
+ "memory-retrospective (fork): failed to delete fork on wake failure; continuing",
495
+ );
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Walk the slice and return the `<turn_context>` `current_time:` value from
501
+ * the first message that has one (typically the first user message). The
502
+ * agent uses this as the explicit anchor for the review window inside its
503
+ * forked history.
504
+ */
505
+ function findFirstTurnContextTimestamp(
506
+ messages: Array<{ role: string; content: string }>,
507
+ ): string | null {
508
+ for (const row of messages) {
509
+ if (row.role !== "user") continue;
510
+ let blocks: unknown;
511
+ try {
512
+ blocks = JSON.parse(row.content);
513
+ } catch {
514
+ continue;
515
+ }
516
+ if (!Array.isArray(blocks)) continue;
517
+ const message = { role: "user", content: blocks } as Message;
518
+ const ts = extractTurnContextTimestamp(message);
519
+ if (ts) return ts;
520
+ }
521
+ return null;
522
+ }
523
+
254
524
  // ---------------------------------------------------------------------------
255
525
  // Prior-retrospective remember extraction
256
526
  // ---------------------------------------------------------------------------
@@ -261,9 +531,23 @@ export async function memoryRetrospectiveJob(
261
531
  * array on first run (no prior retrospective) or when the prior run had no
262
532
  * `remember` calls (it found nothing to save).
263
533
  *
264
- * This is bounded a single retrospective conversation, however long the
265
- * source conversation has grown. Older retrospectives' saves are already
266
- * baked into the most recent one's `<already_remembered>` block transitively.
534
+ * Two artifact shapes exist depending on which path produced the prior
535
+ * retrospective:
536
+ *
537
+ * - **Legacy** (`source === MEMORY_RETROSPECTIVE_SOURCE`): empty bg
538
+ * conversation containing only the wake's tail (`remember` tool_use
539
+ * blocks). Scan everything.
540
+ * - **Fork** (`source === MEMORY_RETROSPECTIVE_FORK_SOURCE`): full source
541
+ * prefix forked in, followed by the retrospective's post-fork tail.
542
+ * The forked prefix contains the source conversation's own inline
543
+ * `remember` calls — scanning the whole row would dump source-inline
544
+ * saves into the dedup baseline and inflate it dramatically. Restrict
545
+ * to messages created **after** `forkParentMessageId` (the last copied
546
+ * message); only messages after that boundary came from this
547
+ * retrospective's own work.
548
+ *
549
+ * Older retrospectives' saves remain reflected transitively because each
550
+ * retrospective dedups against the one before it.
267
551
  */
268
552
  function collectPriorRetrospectiveRemembers(
269
553
  sourceConversationId: string,
@@ -280,9 +564,67 @@ function collectPriorRetrospectiveRemembers(
280
564
  );
281
565
  return [];
282
566
  }
567
+
568
+ const priorConv = getConversation(prior.id);
569
+ if (priorConv?.source === MEMORY_RETROSPECTIVE_FORK_SOURCE) {
570
+ // For fork-kind rows, prior `remember` calls live in the post-fork
571
+ // tail. `cloneForkMessageMetadata` stamps every copied message with
572
+ // `forkSourceMessageId` (preserving any existing value when the source
573
+ // was itself a fork), so the LAST message in the fork carrying
574
+ // `forkSourceMessageId` is the boundary — its value can point to any
575
+ // ancestor when the source was a nested fork, so we can't match it
576
+ // against `forkParentMessageId`. Everything strictly past that
577
+ // timestamp is post-fork.
578
+ const boundaryCreatedAt = findForkBoundaryCreatedAt(messages);
579
+ if (boundaryCreatedAt == null) {
580
+ log.warn(
581
+ { priorConversationId: prior.id },
582
+ "memory-retrospective: fork-kind prior has no message with forkSourceMessageId metadata; treating dedup as empty",
583
+ );
584
+ return [];
585
+ }
586
+ return extractRememberContents(
587
+ messages.filter((m) => m.createdAt > boundaryCreatedAt),
588
+ );
589
+ }
590
+
283
591
  return extractRememberContents(messages);
284
592
  }
285
593
 
594
+ /**
595
+ * Locate the boundary timestamp between the fork's prefix and its post-fork
596
+ * tail. Scans from the end for the last message whose metadata carries a
597
+ * `forkSourceMessageId` stamp (the last copied source message); its
598
+ * `createdAt` is the boundary. The stamp's value may point at any ancestor
599
+ * when the source was itself a fork (`cloneForkMessageMetadata` preserves
600
+ * pre-existing values), so we only check for presence, not equality.
601
+ * Returns `null` only if no copied messages remain (corrupted fork metadata
602
+ * or empty fork — caller logs + degrades).
603
+ */
604
+ function findForkBoundaryCreatedAt(
605
+ forkMessages: Array<{
606
+ id: string;
607
+ createdAt: number;
608
+ metadata: string | null;
609
+ }>,
610
+ ): number | null {
611
+ for (let i = forkMessages.length - 1; i >= 0; i--) {
612
+ const row = forkMessages[i]!;
613
+ if (!row.metadata) continue;
614
+ try {
615
+ const parsed = JSON.parse(row.metadata) as {
616
+ forkSourceMessageId?: unknown;
617
+ };
618
+ if (typeof parsed.forkSourceMessageId === "string") {
619
+ return row.createdAt;
620
+ }
621
+ } catch {
622
+ continue;
623
+ }
624
+ }
625
+ return null;
626
+ }
627
+
286
628
  interface MessageLike {
287
629
  role: string;
288
630
  content: string;
@@ -339,17 +681,17 @@ function neutralizeSentinels(s: string): string {
339
681
  );
340
682
  }
341
683
 
342
- interface PromptArgs {
684
+ interface LegacyPromptArgs {
343
685
  transcript: string;
344
686
  priorRemembers: string[];
345
687
  timeZone: string;
346
688
  }
347
689
 
348
- function buildPrompt({
690
+ function buildLegacyPrompt({
349
691
  transcript,
350
692
  priorRemembers,
351
693
  timeZone,
352
- }: PromptArgs): string {
694
+ }: LegacyPromptArgs): string {
353
695
  const safeTranscript = neutralizeSentinels(transcript);
354
696
  const renderedPrior =
355
697
  priorRemembers.length === 0
@@ -376,3 +718,56 @@ Two dedup sources to skip:
376
718
  For everything else, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. One \`remember\` call per fact. If nothing new is worth saving, say "Nothing new to save." and stop.
377
719
  `;
378
720
  }
721
+
722
+ // ---------------------------------------------------------------------------
723
+ // Fork-based retrospective instruction
724
+ // ---------------------------------------------------------------------------
725
+
726
+ interface ForkInstructionArgs {
727
+ windowStartTimestamp: string;
728
+ priorRemembers: string[];
729
+ timeZone: string;
730
+ /** True when this is the first retrospective pass over the source conversation. */
731
+ isFirstPass: boolean;
732
+ }
733
+
734
+ /**
735
+ * Build the user-role instruction message appended to the forked conversation.
736
+ * The agent reads the conversation natively (including any inherited compaction
737
+ * summary + tail messages), so the prompt is short — it just anchors the
738
+ * review window by `<turn_context>` timestamp and lists the prior
739
+ * retrospective's saves for cross-kind dedup (a legacy-kind prior's
740
+ * `remember` calls aren't visible inside the forked conversation history).
741
+ */
742
+ function buildForkInstruction({
743
+ windowStartTimestamp,
744
+ priorRemembers,
745
+ timeZone,
746
+ isFirstPass,
747
+ }: ForkInstructionArgs): string {
748
+ const renderedPrior =
749
+ priorRemembers.length === 0
750
+ ? "(none — this is your first retrospective over this conversation)"
751
+ : priorRemembers.map((c) => `- ${neutralizeSentinels(c)}`).join("\n");
752
+
753
+ const windowAnchor = isFirstPass
754
+ ? "Your review window is the full conversation above."
755
+ : `Your review window starts at the user turn with \`current_time: ${neutralizeSentinels(windowStartTimestamp)}\` (timezone: ${timeZone}) and ends at the most recent message.`;
756
+
757
+ return `This is a memory retrospective pass over the conversation above.
758
+
759
+ ${windowAnchor}
760
+
761
+ Here are the facts you saved in your previous retrospective pass over this conversation (so you don't restate them):
762
+
763
+ <already_remembered>
764
+ ${renderedPrior}
765
+ </already_remembered>
766
+
767
+ Two dedup sources to skip:
768
+ 1. Anything semantically captured in <already_remembered> above (from your prior retrospective pass).
769
+ 2. Anything you already called \`remember\` on inline within your review window — those appear as \`tool_use\` blocks with \`name: "remember"\` in your history.
770
+
771
+ For everything else in your review window, use the \`remember\` tool on facts, plans, decisions, preferences, names, dates, felt moments, corrections, commitments, or anything else concrete and worth carrying forward. One \`remember\` call per fact. If nothing new is worth saving, say "Nothing new to save." and stop.
772
+ `;
773
+ }
@@ -45,7 +45,7 @@ import {
45
45
  import { getLogger } from "../util/logger.js";
46
46
  import { deleteConversation } from "./conversation-crud.js";
47
47
  import { getDb } from "./db-connection.js";
48
- import { MEMORY_RETROSPECTIVE_SOURCE } from "./memory-retrospective-constants.js";
48
+ import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
49
49
  import { conversations, memoryJobs } from "./schema.js";
50
50
 
51
51
  const log = getLogger("memory-retrospective-startup-cleanup");
@@ -103,7 +103,7 @@ export function sweepOrphanMemoryRetrospectiveConversations(
103
103
  .from(conversations)
104
104
  .where(
105
105
  and(
106
- eq(conversations.source, MEMORY_RETROSPECTIVE_SOURCE),
106
+ inArray(conversations.source, MEMORY_RETROSPECTIVE_SOURCES),
107
107
  isNotNull(conversations.forkParentConversationId),
108
108
  ),
109
109
  )
@@ -129,7 +129,7 @@ export function sweepOrphanMemoryRetrospectiveConversations(
129
129
  .from(conversations)
130
130
  .where(
131
131
  and(
132
- eq(conversations.source, MEMORY_RETROSPECTIVE_SOURCE),
132
+ inArray(conversations.source, MEMORY_RETROSPECTIVE_SOURCES),
133
133
  // Conservative: only sweep rows that have had at least one message
134
134
  // AND haven't seen activity recently. Conversations without a
135
135
  // last_message_at value are too fresh to assess.
@@ -44,19 +44,37 @@ export interface MemoryV2ConceptRowRecord {
44
44
  * - `prior_state` — carried over from prior turn's activation state.
45
45
  * - `ann_top50` — entered via ANN top-K candidate pool.
46
46
  * - `both` — present in both prior state and ANN pool.
47
- * - `router` — selected by the Sonnet router (memory-v2 router
48
- * mode). Router-mode rows zero out all activation values
49
- * (`finalActivation`, `ownActivation`, `priorActivation`, channel
50
- * similarities, rerank boosts, `spreadContribution`) because the
51
- * router does not compute spreading-activation scores.
47
+ * - `router` — legacy tag for memory-v2 router selections written
48
+ * before tier-aware provenance landed. New rows never use this; old
49
+ * activation log rows still carry it and the inspector renders it
50
+ * as-is for backward compat.
51
+ * - `tier1` — router-mode, selected by the tier-1 (recently
52
+ * modified) batch.
53
+ * - `tier2` — router-mode, selected by the tier-2 (highest EMA)
54
+ * batch.
55
+ * - `tier3:<N>` — router-mode, selected by tier-3 batch N (0-indexed).
56
+ * A single-batch (no-tier carve-out) workspace produces `tier3:0`.
57
+ * The bucket index lets inspector queries attribute selections to
58
+ * specific hash-bucketed parallel calls.
52
59
  * - `carry_over` — router-mode row representing a slug carried over
53
60
  * from `priorEverInjected` that the router did NOT re-pick on this
54
61
  * turn. The cached attachment from a prior turn is still present
55
- * on a prior user message; emitting `source: "router"` for these
62
+ * on a prior user message; emitting one of the tier tags for these
56
63
  * rows would overcount router selections in inspector queries.
57
- * Same zeroed activation values as `router`.
64
+ *
65
+ * All router-mode rows (`tier*`, `router`, `carry_over`) zero out the
66
+ * activation values (`finalActivation`, `ownActivation`, etc.) because
67
+ * the router does not compute spreading-activation scores.
58
68
  */
59
- source: "prior_state" | "ann_top50" | "both" | "router" | "carry_over";
69
+ source:
70
+ | "prior_state"
71
+ | "ann_top50"
72
+ | "both"
73
+ | "router"
74
+ | "carry_over"
75
+ | "tier1"
76
+ | "tier2"
77
+ | `tier3:${number}`;
60
78
  /**
61
79
  * Per-turn outcome for this slug:
62
80
  * - `in_context` — already injected on a prior turn; cached attachment
@@ -97,11 +115,15 @@ export interface RecordMemoryV2ActivationLogParams {
97
115
  * `per-turn` for normal append injections, `errored` when `injectMemoryV2Block`
98
116
  * threw before completing — telemetry is still written so silent failures
99
117
  * are observable in the database, with whatever `concepts` rows had been
100
- * built so far (possibly empty). `router` indicates the Sonnet
101
- * router selected the per-turn page set; router-mode rows carry zeroed
102
- * activation values and `source: "router"` on every concept row.
118
+ * built so far (possibly empty). `router` indicates the LLM router selected
119
+ * the per-turn page set; router-mode rows carry zeroed activation values and
120
+ * `source: "router"` on every concept row. `v3_shadow` is written by the
121
+ * live-shadow v3 retrieval middleware: it records v3's selection set for
122
+ * comparison without affecting injected context. The harness oracle filters
123
+ * `mode='router'`, so `v3_shadow` rows never pollute it; the inspector can
124
+ * still surface them.
103
125
  */
104
- mode: "context-load" | "per-turn" | "errored" | "router";
126
+ mode: "context-load" | "per-turn" | "errored" | "router" | "v3_shadow";
105
127
  concepts: MemoryV2ConceptRowRecord[];
106
128
  config: MemoryV2ConfigSnapshot;
107
129
  }
@@ -149,7 +171,7 @@ export function backfillMemoryV2ActivationMessageId(
149
171
  export interface MemoryV2ActivationLog {
150
172
  conversationId: string;
151
173
  turn: number;
152
- mode: "context-load" | "per-turn" | "errored" | "router";
174
+ mode: "context-load" | "per-turn" | "errored" | "router" | "v3_shadow";
153
175
  concepts: MemoryV2ConceptRowRecord[];
154
176
  config: MemoryV2ConfigSnapshot;
155
177
  }
@@ -170,7 +192,12 @@ export function getMemoryV2ActivationLogByMessageIds(
170
192
  return {
171
193
  conversationId: row.conversationId,
172
194
  turn: row.turn,
173
- mode: row.mode as "context-load" | "per-turn" | "errored" | "router",
195
+ mode: row.mode as
196
+ | "context-load"
197
+ | "per-turn"
198
+ | "errored"
199
+ | "router"
200
+ | "v3_shadow",
174
201
  concepts: JSON.parse(row.conceptsJson) as MemoryV2ConceptRowRecord[],
175
202
  config: JSON.parse(row.configJson) as MemoryV2ConfigSnapshot,
176
203
  };
@@ -205,6 +205,7 @@ export function createCoreTables(database: DrizzleDb): void {
205
205
  conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
206
206
  message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
207
207
  delivery_status TEXT NOT NULL DEFAULT 'pending',
208
+ delivery_attempts INTEGER NOT NULL DEFAULT 0,
208
209
  created_at INTEGER NOT NULL,
209
210
  updated_at INTEGER NOT NULL,
210
211
  UNIQUE (source_channel, external_chat_id, external_message_id)
@@ -11,6 +11,7 @@ export function createExternalConversationBindingsTables(
11
11
  conversation_id TEXT PRIMARY KEY REFERENCES conversations(id) ON DELETE CASCADE,
12
12
  source_channel TEXT NOT NULL,
13
13
  external_chat_id TEXT NOT NULL,
14
+ external_chat_name TEXT,
14
15
  external_thread_id TEXT,
15
16
  external_user_id TEXT,
16
17
  display_name TEXT,
@@ -0,0 +1,15 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateConversationLastNotifiedProfile(
5
+ database: DrizzleDb,
6
+ ): void {
7
+ const raw = getSqliteFrom(database);
8
+ try {
9
+ raw.exec(
10
+ `ALTER TABLE conversations ADD COLUMN last_notified_inference_profile TEXT DEFAULT NULL`,
11
+ );
12
+ } catch {
13
+ // Column already exists — nothing to do.
14
+ }
15
+ }