@vellumai/assistant 0.8.0 → 0.8.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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -0,0 +1,108 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory retrospective — startup orphan cleanup.
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // When the daemon crashes mid-retrospective, the bootstrapped background
6
+ // conversation lingers in the `conversations` table (and possibly the
7
+ // `messages` table) as an orphan. The jobs-store recovery
8
+ // (`resetRunningJobsToPending`) handles re-running the job, which bootstraps
9
+ // a NEW background conversation — but the previous one is never deleted
10
+ // because the original handler's cleanup path didn't get a chance to run.
11
+ //
12
+ // This module sweeps those orphans on daemon startup. Run AFTER
13
+ // `resetRunningJobsToPending` so legitimate in-flight retries (which are
14
+ // represented by their pending job row, not by a memory-retrospective
15
+ // conversation directly) aren't swept.
16
+ //
17
+ // Sweep predicate:
18
+ // - `source = "memory-retrospective"`, AND
19
+ // - `last_message_at < now - 1 hour` (so a freshly-running job's
20
+ // conversation isn't swept on a startup that happens to race),
21
+ // - AND no pending OR running `memory_retrospective` job exists. (The
22
+ // orphan background conversation references the SOURCE conversation
23
+ // via the wake hint; if a job exists for that source, the background
24
+ // conversation might be the active one. We're conservative and only
25
+ // sweep when no job exists at all, since the worst-case false-positive
26
+ // is leaving a few extra orphans for the next sweep to catch.)
27
+
28
+ import { and, eq, inArray, isNotNull, lt, notInArray, sql } from "drizzle-orm";
29
+
30
+ import { getLogger } from "../util/logger.js";
31
+ import { deleteConversation } from "./conversation-crud.js";
32
+ import { getDb } from "./db-connection.js";
33
+ import { MEMORY_RETROSPECTIVE_SOURCE } from "./memory-retrospective-constants.js";
34
+ import { conversations, memoryJobs } from "./schema.js";
35
+
36
+ const log = getLogger("memory-retrospective-startup-cleanup");
37
+
38
+ const ORPHAN_AGE_MS = 60 * 60 * 1000;
39
+
40
+ export interface CleanupResult {
41
+ swept: number;
42
+ }
43
+
44
+ /**
45
+ * Find and delete orphan memory-retrospective background conversations.
46
+ * Idempotent — safe to call repeatedly. Returns the number of conversations
47
+ * deleted. Best-effort: errors deleting individual rows are logged and the
48
+ * sweep continues.
49
+ */
50
+ export function sweepOrphanMemoryRetrospectiveConversations(
51
+ now: number = Date.now(),
52
+ ): CleanupResult {
53
+ const cutoff = now - ORPHAN_AGE_MS;
54
+ const db = getDb();
55
+
56
+ const activeJobConversationIds = db
57
+ .select({
58
+ conversationId: sql<string>`json_extract(${memoryJobs.payload}, '$.conversationId')`,
59
+ })
60
+ .from(memoryJobs)
61
+ .where(
62
+ and(
63
+ eq(memoryJobs.type, "memory_retrospective"),
64
+ inArray(memoryJobs.status, ["pending", "running"]),
65
+ ),
66
+ )
67
+ .all()
68
+ .map((row) => row.conversationId)
69
+ .filter((id): id is string => typeof id === "string" && id.length > 0);
70
+
71
+ const orphans = db
72
+ .select({ id: conversations.id })
73
+ .from(conversations)
74
+ .where(
75
+ and(
76
+ eq(conversations.source, MEMORY_RETROSPECTIVE_SOURCE),
77
+ // Conservative: only sweep rows that have had at least one message
78
+ // AND haven't seen activity recently. Conversations without a
79
+ // last_message_at value are too fresh to assess.
80
+ isNotNull(conversations.lastMessageAt),
81
+ lt(conversations.lastMessageAt, cutoff),
82
+ activeJobConversationIds.length > 0
83
+ ? notInArray(conversations.id, activeJobConversationIds)
84
+ : sql`1=1`,
85
+ ),
86
+ )
87
+ .all();
88
+
89
+ let swept = 0;
90
+ for (const row of orphans) {
91
+ try {
92
+ deleteConversation(row.id);
93
+ swept++;
94
+ } catch (err) {
95
+ log.warn(
96
+ { err, conversationId: row.id },
97
+ "Failed to delete orphan memory-retrospective conversation; continuing",
98
+ );
99
+ }
100
+ }
101
+ if (swept > 0) {
102
+ log.info(
103
+ { swept, cutoff },
104
+ "Swept orphan memory-retrospective background conversations",
105
+ );
106
+ }
107
+ return { swept };
108
+ }
@@ -0,0 +1,162 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory retrospective — per-conversation state CRUD.
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // Two pointers move independently:
6
+ // - `lastProcessedMessageId` advances ONLY when a retrospective run
7
+ // completes successfully (correctness invariant — failures must
8
+ // re-process the same messages on the next attempt).
9
+ // - `lastRunAt` advances on EVERY job end (success or failure). Drives the
10
+ // per-conversation cooldown gate in the trigger-check helper so failing
11
+ // jobs can't loop in tight retries across trigger types.
12
+ //
13
+ // The schema enforces the foreign key with ON DELETE CASCADE, so deleting a
14
+ // conversation collects its state row automatically.
15
+
16
+ import { eq } from "drizzle-orm";
17
+
18
+ import { type DrizzleDb, getDb } from "./db-connection.js";
19
+ import { memoryRetrospectiveState } from "./schema.js";
20
+
21
+ export interface MemoryRetrospectiveState {
22
+ conversationId: string;
23
+ lastProcessedMessageId: string;
24
+ lastRunAt: number;
25
+ }
26
+
27
+ /**
28
+ * Load the state row for a conversation, or `null` if no row exists.
29
+ */
30
+ export function getRetrospectiveState(
31
+ conversationId: string,
32
+ ): MemoryRetrospectiveState | null {
33
+ const row = getDb()
34
+ .select()
35
+ .from(memoryRetrospectiveState)
36
+ .where(eq(memoryRetrospectiveState.conversationId, conversationId))
37
+ .get();
38
+ if (!row) return null;
39
+ return {
40
+ conversationId: row.conversationId,
41
+ lastProcessedMessageId: row.lastProcessedMessageId,
42
+ lastRunAt: row.lastRunAt,
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Upsert both pointers atomically. Used on successful retrospective runs.
48
+ */
49
+ export function upsertRetrospectiveState(args: MemoryRetrospectiveState): void {
50
+ const db = getDb();
51
+ db.insert(memoryRetrospectiveState)
52
+ .values({
53
+ conversationId: args.conversationId,
54
+ lastProcessedMessageId: args.lastProcessedMessageId,
55
+ lastRunAt: args.lastRunAt,
56
+ })
57
+ .onConflictDoUpdate({
58
+ target: memoryRetrospectiveState.conversationId,
59
+ set: {
60
+ lastProcessedMessageId: args.lastProcessedMessageId,
61
+ lastRunAt: args.lastRunAt,
62
+ },
63
+ })
64
+ .run();
65
+ }
66
+
67
+ /**
68
+ * Carry the source conversation's retrospective state into a forked child so
69
+ * the fork doesn't re-process content the parent already covered. Synchronous
70
+ * so it can run inside the bun:sqlite transaction wrapping `forkConversation`.
71
+ *
72
+ * Mapping for `lastProcessedMessageId`:
73
+ *
74
+ * - source has no state row → no-op (child inherits "first run" semantics
75
+ * and `findMostRecentRetrospectiveFor` walks the fork chain instead).
76
+ * - source pointer is the `""` sentinel (failed-only attempts, never
77
+ * succeeded) → child pointer is also `""`.
78
+ * - source pointer is within the copied range (`forkedMessageIds` has it) →
79
+ * child pointer is the mapped forked message ID.
80
+ * - source pointer is past the fork boundary (not in `forkedMessageIds`) →
81
+ * child pointer is the last copied message's mapped ID. All copied
82
+ * messages have already been retro'd by the source, so the child should
83
+ * wait for new post-fork messages before its first retro fires.
84
+ *
85
+ * `lastRunAt` is copied verbatim — the cooldown gate inherits from source.
86
+ */
87
+ export function forkRetrospectiveState(args: {
88
+ database: DrizzleDb;
89
+ sourceConversationId: string;
90
+ forkedConversationId: string;
91
+ forkedMessageIds: Map<string, string>;
92
+ lastCopiedSourceMessageId: string | null;
93
+ }): void {
94
+ const {
95
+ database,
96
+ sourceConversationId,
97
+ forkedConversationId,
98
+ forkedMessageIds,
99
+ lastCopiedSourceMessageId,
100
+ } = args;
101
+
102
+ const sourceRow = database
103
+ .select()
104
+ .from(memoryRetrospectiveState)
105
+ .where(eq(memoryRetrospectiveState.conversationId, sourceConversationId))
106
+ .get();
107
+ if (!sourceRow) return;
108
+
109
+ let forkedPointer = "";
110
+ if (sourceRow.lastProcessedMessageId !== "") {
111
+ const mapped = forkedMessageIds.get(sourceRow.lastProcessedMessageId);
112
+ if (mapped !== undefined) {
113
+ forkedPointer = mapped;
114
+ } else if (lastCopiedSourceMessageId !== null) {
115
+ // Source pointer is past the fork boundary — everything copied has
116
+ // already been processed by the source, so clamp to the last copied
117
+ // message so the fork waits for new post-fork messages.
118
+ forkedPointer = forkedMessageIds.get(lastCopiedSourceMessageId) ?? "";
119
+ }
120
+ }
121
+
122
+ database
123
+ .insert(memoryRetrospectiveState)
124
+ .values({
125
+ conversationId: forkedConversationId,
126
+ lastProcessedMessageId: forkedPointer,
127
+ lastRunAt: sourceRow.lastRunAt,
128
+ })
129
+ .onConflictDoUpdate({
130
+ target: memoryRetrospectiveState.conversationId,
131
+ set: {
132
+ lastProcessedMessageId: forkedPointer,
133
+ lastRunAt: sourceRow.lastRunAt,
134
+ },
135
+ })
136
+ .run();
137
+ }
138
+
139
+ /**
140
+ * Advance only `lastRunAt`. Used on every failure path so the cooldown gate
141
+ * applies to subsequent trigger-driven enqueues. If no row exists yet (first
142
+ * attempt failed), seed `lastProcessedMessageId` to the empty string — a
143
+ * sentinel meaning "nothing successfully processed yet" that subsequent
144
+ * `getMessagesSince(...)` queries treat the same as a missing row.
145
+ */
146
+ export function bumpRetrospectiveLastRunAt(
147
+ conversationId: string,
148
+ lastRunAt: number,
149
+ ): void {
150
+ const db = getDb();
151
+ db.insert(memoryRetrospectiveState)
152
+ .values({
153
+ conversationId,
154
+ lastProcessedMessageId: "",
155
+ lastRunAt,
156
+ })
157
+ .onConflictDoUpdate({
158
+ target: memoryRetrospectiveState.conversationId,
159
+ set: { lastRunAt },
160
+ })
161
+ .run();
162
+ }
@@ -0,0 +1,91 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory retrospective — periodic trigger check.
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // Called from post-turn hooks (after each agent turn completes). Decides
6
+ // whether to enqueue a retrospective for this conversation based on:
7
+ //
8
+ // 1. Cooldown gate: never within `minCooldownMs` of the last attempt
9
+ // (success or failure). Prevents tight retry loops across trigger
10
+ // types.
11
+ // 2. Interval threshold: time since last attempt >= `timeThresholdMs`.
12
+ // 3. Message count threshold: new messages since `lastProcessedMessageId`
13
+ // >= `messageThreshold`.
14
+ //
15
+ // First-run case (no state row) skips the cooldown — `lastRunAt = 0` so the
16
+ // gap is effectively `Infinity`. The interval threshold trips immediately;
17
+ // the message-count threshold trips once enough messages accumulate.
18
+
19
+ import type { AssistantConfig } from "../config/types.js";
20
+ import { getLogger } from "../util/logger.js";
21
+ import { countMessagesAfter } from "./conversation-crud.js";
22
+ import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
23
+ import { getRetrospectiveState } from "./memory-retrospective-state.js";
24
+
25
+ const log = getLogger("memory-retrospective-trigger-check");
26
+
27
+ export type RetrospectiveTrigger = "interval" | "message_count";
28
+
29
+ /**
30
+ * Returns the trigger kind that fired, or `null` if no threshold tripped.
31
+ * Exported separately from `maybeEnqueueRetrospective` so tests can assert on
32
+ * the decision without observing side effects.
33
+ */
34
+ export function shouldEnqueueRetrospective(args: {
35
+ state: { lastProcessedMessageId: string; lastRunAt: number } | null;
36
+ newMessageCount: number;
37
+ now: number;
38
+ timeThresholdMs: number;
39
+ messageThreshold: number;
40
+ minCooldownMs: number;
41
+ }): RetrospectiveTrigger | null {
42
+ const {
43
+ state,
44
+ newMessageCount,
45
+ now,
46
+ timeThresholdMs,
47
+ messageThreshold,
48
+ minCooldownMs,
49
+ } = args;
50
+
51
+ if (state && now - state.lastRunAt < minCooldownMs) return null;
52
+
53
+ if (state && now - state.lastRunAt >= timeThresholdMs) return "interval";
54
+ if (!state) return "interval";
55
+
56
+ if (newMessageCount >= messageThreshold) return "message_count";
57
+ return null;
58
+ }
59
+
60
+ /**
61
+ * Post-turn hook entry point. Looks up state, counts new messages, evaluates
62
+ * thresholds, and enqueues if appropriate. Best-effort — any thrown error is
63
+ * caught and logged so the agent turn cleanup path doesn't fail.
64
+ */
65
+ export function maybeEnqueueRetrospective(
66
+ conversationId: string,
67
+ config: AssistantConfig,
68
+ ): void {
69
+ try {
70
+ const state = getRetrospectiveState(conversationId);
71
+ const newMessageCount = countMessagesAfter(
72
+ conversationId,
73
+ state?.lastProcessedMessageId ?? null,
74
+ );
75
+ if (newMessageCount === 0) return;
76
+
77
+ const trigger = shouldEnqueueRetrospective({
78
+ state,
79
+ newMessageCount,
80
+ now: Date.now(),
81
+ timeThresholdMs: config.memory.retrospective.timeThresholdMs,
82
+ messageThreshold: config.memory.retrospective.messageThreshold,
83
+ minCooldownMs: config.memory.retrospective.minCooldownMs,
84
+ });
85
+ if (!trigger) return;
86
+
87
+ enqueueMemoryRetrospectiveIfEnabled({ conversationId, trigger });
88
+ } catch (err) {
89
+ log.warn({ err, conversationId }, "trigger-check failed; skipping enqueue");
90
+ }
91
+ }
@@ -39,8 +39,43 @@ export interface MemoryV2ConceptRowRecord {
39
39
  */
40
40
  inRerankPool: boolean;
41
41
  spreadContribution: number;
42
- source: "prior_state" | "ann_top50" | "both";
43
- status: "in_context" | "injected" | "not_injected" | "page_missing";
42
+ /**
43
+ * Provenance of this concept row.
44
+ * - `prior_state` — carried over from prior turn's activation state.
45
+ * - `ann_top50` — entered via ANN top-K candidate pool.
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.
52
+ * - `carry_over` — router-mode row representing a slug carried over
53
+ * from `priorEverInjected` that the router did NOT re-pick on this
54
+ * turn. The cached attachment from a prior turn is still present
55
+ * on a prior user message; emitting `source: "router"` for these
56
+ * rows would overcount router selections in inspector queries.
57
+ * Same zeroed activation values as `router`.
58
+ */
59
+ source: "prior_state" | "ann_top50" | "both" | "router" | "carry_over";
60
+ /**
61
+ * Per-turn outcome for this slug:
62
+ * - `in_context` — already injected on a prior turn; cached attachment
63
+ * remains visible without re-rendering.
64
+ * - `injected` — freshly rendered into this turn's user message.
65
+ * - `not_injected`— a candidate that didn't make `slugsToRender`.
66
+ * - `page_missing`— would-have-been-injected, but `readPage` returned
67
+ * null (file vanished between selection and render — stale Qdrant
68
+ * or edge-index entry).
69
+ * - `corrupt` — would-have-been-injected, but `readPage` threw
70
+ * (e.g. malformed frontmatter). Other slugs in the same batch
71
+ * rendered normally.
72
+ */
73
+ status:
74
+ | "in_context"
75
+ | "injected"
76
+ | "not_injected"
77
+ | "page_missing"
78
+ | "corrupt";
44
79
  }
45
80
 
46
81
  export interface MemoryV2ConfigSnapshot {
@@ -57,7 +92,16 @@ export interface MemoryV2ConfigSnapshot {
57
92
  export interface RecordMemoryV2ActivationLogParams {
58
93
  conversationId: string;
59
94
  turn: number;
60
- mode: "context-load" | "per-turn";
95
+ /**
96
+ * Call-site mode: `context-load` for fresh / post-compaction loads,
97
+ * `per-turn` for normal append injections, `errored` when `injectMemoryV2Block`
98
+ * threw before completing — telemetry is still written so silent failures
99
+ * 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.
103
+ */
104
+ mode: "context-load" | "per-turn" | "errored" | "router";
61
105
  concepts: MemoryV2ConceptRowRecord[];
62
106
  config: MemoryV2ConfigSnapshot;
63
107
  }
@@ -105,7 +149,7 @@ export function backfillMemoryV2ActivationMessageId(
105
149
  export interface MemoryV2ActivationLog {
106
150
  conversationId: string;
107
151
  turn: number;
108
- mode: "context-load" | "per-turn";
152
+ mode: "context-load" | "per-turn" | "errored" | "router";
109
153
  concepts: MemoryV2ConceptRowRecord[];
110
154
  config: MemoryV2ConfigSnapshot;
111
155
  }
@@ -126,7 +170,7 @@ export function getMemoryV2ActivationLogByMessageIds(
126
170
  return {
127
171
  conversationId: row.conversationId,
128
172
  turn: row.turn,
129
- mode: row.mode as "context-load" | "per-turn",
173
+ mode: row.mode as "context-load" | "per-turn" | "errored" | "router",
130
174
  concepts: JSON.parse(row.conceptsJson) as MemoryV2ConceptRowRecord[],
131
175
  config: JSON.parse(row.configJson) as MemoryV2ConfigSnapshot,
132
176
  };
@@ -52,6 +52,7 @@ const ZERO_COUNTS: ConceptFrequencyCounts = {
52
52
  in_context: 0,
53
53
  not_injected: 0,
54
54
  page_missing: 0,
55
+ corrupt: 0,
55
56
  };
56
57
 
57
58
  interface CountRow {
@@ -130,6 +131,9 @@ export async function getConceptFrequencySummary(
130
131
  case "page_missing":
131
132
  entry.counts.page_missing += row.count;
132
133
  break;
134
+ case "corrupt":
135
+ entry.counts.corrupt += row.count;
136
+ break;
133
137
  default:
134
138
  // Forward-compat: unknown status values are ignored, not summed into
135
139
  // totalEvaluations. The activation pipeline produces a closed enum.
@@ -121,7 +121,6 @@ export function extractMediaBlockMeta(
121
121
  }
122
122
  }
123
123
 
124
-
125
124
  function stableJson(value: unknown): string {
126
125
  try {
127
126
  return JSON.stringify(value);
@@ -129,3 +128,41 @@ function stableJson(value: unknown): string {
129
128
  return "<unserializable />";
130
129
  }
131
130
  }
131
+
132
+ /**
133
+ * Coerce stored message content into a single human-readable text string,
134
+ * dropping non-text blocks (images, tool calls, tool results, thinking,
135
+ * …). Used by call sites that want only the spoken text — sweep-model
136
+ * context, RAG backfill, bookmark previews. For richer renderings that
137
+ * include tool metadata, use {@link extractTextFromStoredMessageContent}
138
+ * instead.
139
+ *
140
+ * Handles the two on-disk shapes:
141
+ * - Modern rows: JSON-serialized `ContentBlock[]`
142
+ * - Legacy rows: plain string
143
+ *
144
+ * Parse failures fall back to returning the raw input trimmed (the
145
+ * legacy-string path).
146
+ */
147
+ export function stringifyMessageContent(stored: string): string {
148
+ let parsed: unknown;
149
+ try {
150
+ parsed = JSON.parse(stored);
151
+ } catch {
152
+ return stored.trim();
153
+ }
154
+ if (typeof parsed === "string") return parsed.trim();
155
+ if (!Array.isArray(parsed)) return "";
156
+ const parts: string[] = [];
157
+ for (const block of parsed) {
158
+ if (
159
+ block &&
160
+ typeof block === "object" &&
161
+ (block as { type?: string }).type === "text" &&
162
+ typeof (block as { text?: unknown }).text === "string"
163
+ ) {
164
+ parts.push((block as { text: string }).text);
165
+ }
166
+ }
167
+ return parts.join("\n").trim();
168
+ }
@@ -8,8 +8,13 @@ export function migrateAddConversationInferenceProfile(
8
8
  const columns = raw.query(`PRAGMA table_info(conversations)`).all() as Array<{
9
9
  name: string;
10
10
  }>;
11
+ // Skip if either the original camelCase column or the renamed snake_case
12
+ // column from migration 228 is already present. Without the snake_case
13
+ // check, this migration would re-add the camelCase column on every boot
14
+ // after 228 runs, leaving both columns permanently.
11
15
  const hasColumn = columns.some(
12
- (column) => column.name === "inferenceProfile",
16
+ (column) =>
17
+ column.name === "inferenceProfile" || column.name === "inference_profile",
13
18
  );
14
19
  if (hasColumn) {
15
20
  return;
@@ -6,19 +6,32 @@ import { tableHasColumn } from "./schema-introspection.js";
6
6
  * by migration 227) to `inference_profile` so it matches the snake_case
7
7
  * convention used by every other column on the table.
8
8
  *
9
- * Idempotent:
10
- * - camelCase column present, snake_case absent renames it.
11
- * - snake_case column already present no-op.
12
- * - neither column present no-op (shouldn't happen since 227 ran first,
13
- * but we guard for completeness).
9
+ * Idempotent and self-healing:
10
+ * - both columns present drop the camelCase one (heals instances that
11
+ * already booted twice with the original buggy migration 227, where 227
12
+ * re-added the camelCase column after this migration renamed it).
13
+ * - camelCase column present, snake_case absent → rename it.
14
+ * - snake_case column present, camelCase absent → no-op.
15
+ * - neither column present → no-op.
14
16
  */
15
17
  export function migrateRenameInferenceProfileSnakeCase(
16
18
  database: DrizzleDb,
17
19
  ): void {
18
- if (tableHasColumn(database, "conversations", "inference_profile")) {
20
+ const hasSnake = tableHasColumn(
21
+ database,
22
+ "conversations",
23
+ "inference_profile",
24
+ );
25
+ const hasCamel = tableHasColumn(
26
+ database,
27
+ "conversations",
28
+ "inferenceProfile",
29
+ );
30
+ if (hasSnake && hasCamel) {
31
+ database.run(`ALTER TABLE conversations DROP COLUMN inferenceProfile`);
19
32
  return;
20
33
  }
21
- if (!tableHasColumn(database, "conversations", "inferenceProfile")) {
34
+ if (!hasCamel) {
22
35
  return;
23
36
  }
24
37
  database.run(
@@ -615,7 +615,8 @@ function seedGuardianAndApprovalRows(raw: Database, now: number): void {
615
615
  created_at,
616
616
  updated_at
617
617
  ) VALUES
618
- ('call-standard-guardian', 'conv-standard', 'test-provider', '+15550100', '+15550101', 'initiated', ${now}, ${now});
618
+ ('call-standard-guardian', 'conv-standard', 'test-provider', '+15550100', '+15550101', 'initiated', ${now}, ${now}),
619
+ ('call-private-guardian', 'conv-private', 'test-provider', '+15550102', '+15550103', 'initiated', ${now}, ${now});
619
620
 
620
621
  INSERT INTO call_pending_questions (
621
622
  id,
@@ -708,6 +709,23 @@ function seedGuardianAndApprovalRows(raw: Database, now: number): void {
708
709
  ('scoped-grant-standard', 'request_id', 'canonical-request-standard', NULL, NULL, 'vellum', 'vellum', 'conv-standard', 'active', ${now + 60000}, ${now}, ${now}),
709
710
  ('scoped-grant-unscoped', 'tool_signature', NULL, 'test_tool', 'digest-123', 'vellum', 'vellum', NULL, 'active', ${now + 60000}, ${now}, ${now});
710
711
 
712
+ INSERT INTO scoped_approval_grants (
713
+ id,
714
+ scope_mode,
715
+ request_id,
716
+ tool_name,
717
+ input_digest,
718
+ request_channel,
719
+ decision_channel,
720
+ conversation_id,
721
+ call_session_id,
722
+ status,
723
+ expires_at,
724
+ created_at,
725
+ updated_at
726
+ ) VALUES
727
+ ('scoped-grant-private-call-only', 'tool_signature', NULL, 'test_tool', 'digest-456', 'vellum', 'vellum', NULL, 'call-private-guardian', 'active', ${now + 60000}, ${now}, ${now});
728
+
711
729
  INSERT INTO channel_guardian_approval_requests (
712
730
  id,
713
731
  run_id,
@@ -1034,6 +1052,13 @@ describe("migrateDeletePrivateConversations", () => {
1034
1052
  expect(
1035
1053
  countWhere(raw, "scoped_approval_grants", `id = 'scoped-grant-unscoped'`),
1036
1054
  ).toBe(1);
1055
+ expect(
1056
+ countWhere(
1057
+ raw,
1058
+ "scoped_approval_grants",
1059
+ `id = 'scoped-grant-private-call-only'`,
1060
+ ),
1061
+ ).toBe(0);
1037
1062
  expect(
1038
1063
  countWhere(
1039
1064
  raw,
@@ -1084,4 +1109,48 @@ describe("migrateDeletePrivateConversations", () => {
1084
1109
  ),
1085
1110
  ).toBe(1);
1086
1111
  });
1112
+
1113
+ test("removes orphan attachments left by prior runs that deleted private messages", () => {
1114
+ const db = createTestDb();
1115
+ const raw = getSqliteFrom(db);
1116
+ const now = Date.now();
1117
+
1118
+ bootstrapTables(raw);
1119
+ seedConversation(raw, "conv-standard", "standard");
1120
+ raw.exec(/*sql*/ `
1121
+ INSERT INTO attachments (
1122
+ id,
1123
+ original_filename,
1124
+ mime_type,
1125
+ size_bytes,
1126
+ kind,
1127
+ data_base64,
1128
+ created_at
1129
+ ) VALUES (
1130
+ 'orphan-private-attachment',
1131
+ 'leaked.txt',
1132
+ 'text/plain',
1133
+ 1,
1134
+ 'text',
1135
+ 'eA==',
1136
+ ${now}
1137
+ );
1138
+ `);
1139
+
1140
+ expect(
1141
+ countWhere(raw, "attachments", `id = 'orphan-private-attachment'`),
1142
+ ).toBe(1);
1143
+ expect(
1144
+ countWhere(raw, "attachments", `id = 'conv-standard-attachment'`),
1145
+ ).toBe(1);
1146
+
1147
+ migrateDeletePrivateConversations(db);
1148
+
1149
+ expect(
1150
+ countWhere(raw, "attachments", `id = 'orphan-private-attachment'`),
1151
+ ).toBe(0);
1152
+ expect(
1153
+ countWhere(raw, "attachments", `id = 'conv-standard-attachment'`),
1154
+ ).toBe(1);
1155
+ });
1087
1156
  });