@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
@@ -1,6 +1,6 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
- import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
3
- import { getProvider, listProviders } from "../providers/registry.js";
2
+ import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
3
+ import { resolveDefaultProvider } from "../providers/connection-resolution.js";
4
4
  import type { Provider } from "../providers/types.js";
5
5
  import {
6
6
  APPROVAL_COPY_MAX_TOKENS,
@@ -79,15 +79,18 @@ const VALID_DISPOSITIONS: ReadonlySet<string> = new Set([
79
79
  export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
80
80
  return async (context, options = {}) => {
81
81
  const config = loadConfig();
82
- let baseProvider: Provider;
83
- try {
84
- baseProvider = getProvider(config.llm.default.provider);
85
- } catch {
86
- return null;
87
- }
82
+ // Connection-aware default-provider resolution. Throws
83
+ // `ConnectionResolutionError` on hard config errors (missing /
84
+ // unknown / mismatched connection). Returns null on soft credential
85
+ // failures (vault miss, transient auth) — we treat null as "no
86
+ // provider available" and skip generating copy.
87
+ const baseProvider: Provider | null = await resolveDefaultProvider(config);
88
+ if (!baseProvider) return null;
88
89
  // Wrap so per-call `callSite` can route to an alternative provider
89
90
  // transport when `llm.callSites.<id>.provider` overrides the default.
90
- const provider = wrapWithCallSiteRouting(baseProvider);
91
+ // The `wrapWithCallSiteRouting` helper threads `config` through so the
92
+ // wrapper's per-call resolution is also connection-aware.
93
+ const provider = wrapWithCallSiteRouting(baseProvider, config);
91
94
 
92
95
  const fallbackText =
93
96
  options.fallbackText?.trim() || getFallbackMessage(context);
@@ -136,12 +139,19 @@ export function createApprovalCopyGenerator(): ApprovalCopyGenerator {
136
139
  export function createApprovalConversationGenerator(): ApprovalConversationGenerator {
137
140
  return async (context) => {
138
141
  const config = loadConfig();
139
- if (!listProviders().includes(config.llm.default.provider)) {
142
+ // Connection-aware default + per-call routing. `resolveDefaultProvider`
143
+ // throws `ConnectionResolutionError` on hard config errors (missing /
144
+ // unknown / mismatched connection) and returns null on soft credential
145
+ // failures (vault miss, transient auth) — we treat null as "no
146
+ // provider available" and throw a domain-specific error below. We do
147
+ // not pre-gate on `listProviders()` because the default provider lives
148
+ // behind a `provider_connection` and never appears in the registry's
149
+ // initialization-time provider list.
150
+ const baseProvider = await resolveDefaultProvider(config);
151
+ if (!baseProvider) {
140
152
  throw new Error("No provider available for approval conversation");
141
153
  }
142
- const provider = wrapWithCallSiteRouting(
143
- getProvider(config.llm.default.provider),
144
- );
154
+ const provider = wrapWithCallSiteRouting(baseProvider, config);
145
155
 
146
156
  const pendingDescription = context.pendingApprovals
147
157
  .map((p) => `- Request ${p.requestId}: tool "${p.toolName}"`)
@@ -212,19 +222,3 @@ export function createApprovalConversationGenerator(): ApprovalConversationGener
212
222
  return result;
213
223
  };
214
224
  }
215
-
216
- /**
217
- * Wrap a base Provider so per-call `callSite` metadata can route the actual
218
- * transport to a different provider when `llm.callSites.<id>.provider`
219
- * differs from the default. Without this wrapper, only request metadata
220
- * reflects the callSite — the HTTP transport stays bound to the default.
221
- */
222
- function wrapWithCallSiteRouting(base: Provider): Provider {
223
- return new CallSiteRoutingProvider(base, (name) => {
224
- try {
225
- return getProvider(name);
226
- } catch {
227
- return undefined;
228
- }
229
- });
230
- }
@@ -18,6 +18,7 @@ import { getConfig, invalidateConfigCache } from "../config/loader.js";
18
18
  import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js";
19
19
  import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
20
20
  import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
21
+ import { invalidateLlmRequestLogSourceCache } from "../memory/llm-request-log-source.js";
21
22
  import { initializeProviders } from "../providers/registry.js";
22
23
  import { handleCancelSignal } from "../signals/cancel.js";
23
24
  import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
@@ -140,6 +141,7 @@ export class ConfigWatcher {
140
141
  return false;
141
142
  }
142
143
  clearEmbeddingBackendCache();
144
+ invalidateLlmRequestLogSourceCache();
143
145
  // If cleanup retention settings changed, reset the cleanup scheduler
144
146
  // throttle so the next worker tick re-enqueues jobs with the new values
145
147
  // instead of waiting out the remaining enqueueIntervalMs (default 6h).
@@ -118,6 +118,12 @@ export interface EventHandlerState {
118
118
  orderingErrorDetected: boolean;
119
119
  deferredOrderingError: string | null;
120
120
  contextTooLargeDetected: boolean;
121
+ /**
122
+ * Set when the provider rejects with an image-dimension error. The agent
123
+ * loop strips or downscales oversized image blocks from ctx.messages and
124
+ * retries once before surfacing an error to the user.
125
+ */
126
+ imageTooLargeDetected: boolean;
121
127
  /**
122
128
  * The provider error object when context_too_large is detected, preserved
123
129
  * so `parseActualTokensFromError` can prefer the typed
@@ -127,6 +133,11 @@ export interface EventHandlerState {
127
133
  */
128
134
  contextTooLargeError: unknown;
129
135
  providerErrorUserMessage: string | null;
136
+ /**
137
+ * First persisted assistant row in this run; history keeps this id when it
138
+ * merges tool-turn rows into one display bubble.
139
+ */
140
+ firstAssistantMessageId: string | undefined;
130
141
  lastAssistantMessageId: string | undefined;
131
142
  readonly pendingToolResults: Map<string, PendingToolResult>;
132
143
  readonly persistedToolUseIds: Set<string>;
@@ -220,8 +231,10 @@ export function createEventHandlerState(): EventHandlerState {
220
231
  orderingErrorDetected: false,
221
232
  deferredOrderingError: null,
222
233
  contextTooLargeDetected: false,
234
+ imageTooLargeDetected: false,
223
235
  contextTooLargeError: null,
224
236
  providerErrorUserMessage: null,
237
+ firstAssistantMessageId: undefined,
225
238
  lastAssistantMessageId: undefined,
226
239
  pendingToolResults: new Map(),
227
240
  persistedToolUseIds: new Set(),
@@ -245,6 +258,12 @@ export function createEventHandlerState(): EventHandlerState {
245
258
  };
246
259
  }
247
260
 
261
+ export function getClientDisplayMessageId(
262
+ state: EventHandlerState,
263
+ ): string | undefined {
264
+ return state.firstAssistantMessageId ?? state.lastAssistantMessageId;
265
+ }
266
+
248
267
  // ── Shared Helper ────────────────────────────────────────────────────
249
268
 
250
269
  // providerNameOverride should be supplied when the caller already knows the
@@ -781,6 +800,10 @@ function handleError(
781
800
  if (classified.code === "CONTEXT_TOO_LARGE") {
782
801
  state.contextTooLargeDetected = true;
783
802
  state.contextTooLargeError = event.error;
803
+ } else if (classified.code === "IMAGE_TOO_LARGE") {
804
+ // Trigger silent recovery: the agent loop will strip/downscale images
805
+ // in ctx.messages and retry once before surfacing an error.
806
+ state.imageTooLargeDetected = true;
784
807
  } else if (
785
808
  classified.code === "PROVIDER_ORDERING" ||
786
809
  classified.code === "PROVIDER_WEB_SEARCH"
@@ -1004,6 +1027,7 @@ export async function handleMessageComplete(
1004
1027
  DEFAULT_TIMEOUTS.persistence,
1005
1028
  )) as PersistAddResult;
1006
1029
  const assistantMsg = assistantPersistResult.message;
1030
+ state.firstAssistantMessageId ??= assistantMsg.id;
1007
1031
  state.lastAssistantMessageId = assistantMsg.id;
1008
1032
 
1009
1033
  // Backfill message_id on all LLM request logs from this turn.
@@ -11,6 +11,7 @@ import { join } from "node:path";
11
11
 
12
12
  import { v4 as uuid } from "uuid";
13
13
 
14
+ import { optimizeImageForTransport } from "../agent/image-optimize.js";
14
15
  import type {
15
16
  AgentEvent,
16
17
  AgentLoop,
@@ -28,6 +29,7 @@ import {
28
29
  contextWindowConfigFromEffective,
29
30
  resolveEffectiveContextWindow,
30
31
  } from "../config/llm-context-resolution.js";
32
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
31
33
  import { getConfig } from "../config/loader.js";
32
34
  import type { LLMCallSite } from "../config/schemas/llm.js";
33
35
  import type { ContextWindowConfig } from "../config/types.js";
@@ -41,9 +43,7 @@ import {
41
43
  } from "../context/token-estimator.js";
42
44
  import type { ContextWindowManager } from "../context/window-manager.js";
43
45
  import type { ToolProfiler } from "../events/tool-profiling-listener.js";
44
- import { emitFeedEvent } from "../home/emit-feed-event.js";
45
46
  import { writeRelationshipState } from "../home/relationship-state-writer.js";
46
- import { rewriteFeedTitle } from "../home/rewrite-feed-title.js";
47
47
  import {
48
48
  clearSentryConversationContext,
49
49
  setSentryConversationContext,
@@ -71,11 +71,12 @@ import {
71
71
  } from "../memory/conversation-title-service.js";
72
72
  import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
73
73
  import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
74
+ import { enqueueMemoryRetrospectiveOnCompaction } from "../memory/memory-retrospective-enqueue.js";
74
75
  import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
75
76
  import type { QdrantSparseVector } from "../memory/qdrant-client.js";
76
77
  import {
77
78
  readMemoryV2StaticContent,
78
- shouldLoadMemoryV2Static,
79
+ shouldExposePersonalMemory,
79
80
  } from "../memory/v2/static-context.js";
80
81
  import type { PermissionPrompter } from "../permissions/prompter.js";
81
82
  import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
@@ -147,6 +148,7 @@ import {
147
148
  createEventHandlerState,
148
149
  dispatchAgentEvent,
149
150
  type EventHandlerDeps,
151
+ getClientDisplayMessageId,
150
152
  } from "./conversation-agent-loop-handlers.js";
151
153
  import {
152
154
  approveHostAttachmentRead,
@@ -679,7 +681,9 @@ export async function runAgentLoopImpl(
679
681
  overrideProfile: turnOverrideProfile ?? undefined,
680
682
  });
681
683
  const turnContextWindowConfig = contextWindowConfigFromEffective(
682
- config.llm.default.contextWindow,
684
+ resolveCallSiteConfig(turnCallSite, config.llm, {
685
+ overrideProfile: turnOverrideProfile ?? undefined,
686
+ }).contextWindow,
683
687
  effectiveContextWindow,
684
688
  );
685
689
  (
@@ -1411,33 +1415,44 @@ export async function runAgentLoopImpl(
1411
1415
 
1412
1416
  // The `remember` tool handles scratchpad-style memory writes directly to the graph.
1413
1417
 
1418
+ // Personal-memory trust gate: PKB, NOW.md, and v2 static blocks all
1419
+ // hold private user content. Block exposure to non-guardian actors
1420
+ // arriving over a remote channel; internal/local flows pass through.
1421
+ // See `shouldExposePersonalMemory` for the threat model.
1422
+ const personalMemoryAllowed = shouldExposePersonalMemory({
1423
+ sourceChannel: ctx.trustContext?.sourceChannel,
1424
+ isTrustedActor,
1425
+ });
1426
+
1414
1427
  // Inject NOW.md and PKB content only on the first turn (or after
1415
1428
  // compaction re-strips them). Old injections persist in history and
1416
1429
  // are never stripped on normal turns — this preserves the cached prefix.
1417
1430
  // PKB/NOW content is sourced from the `memoryRetrieval` pipeline above
1418
1431
  // so plugins can override either source without touching the agent loop.
1419
- const currentNowContent = memoryResult.nowContent;
1432
+ const currentNowContent = personalMemoryAllowed
1433
+ ? memoryResult.nowContent
1434
+ : null;
1420
1435
  const shouldInjectNowAndPkb = isFirstMessage || compactedThisTurn;
1421
1436
  const nowScratchpad = shouldInjectNowAndPkb ? currentNowContent : null;
1422
1437
 
1423
- const currentPkbContent = memoryResult.pkbContent;
1438
+ const currentPkbContent = personalMemoryAllowed
1439
+ ? memoryResult.pkbContent
1440
+ : null;
1424
1441
  const pkbContext = shouldInjectNowAndPkb ? currentPkbContent : null;
1425
1442
  const pkbActive = currentPkbContent !== null;
1426
1443
 
1427
- // V2 static memory block (essentials/threads/recent/buffer). Same
1428
- // first-turn / post-compaction cadence as PKB. `shouldLoadMemoryV2Static`
1429
- // also blocks remote-channel non-guardian actors from inducing the
1430
- // model to recite private memory; `readMemoryV2StaticContent` self-gates
1431
- // on the v2 flag + config and returns null when v2 is off, so the file
1432
- // reads are skipped on non-injection turns.
1433
- const currentMemoryV2Static = shouldLoadMemoryV2Static({
1434
- shouldInjectNowAndPkb,
1435
- sourceChannel: ctx.trustContext?.sourceChannel,
1436
- isTrustedActor,
1437
- })
1444
+ // V2 static memory block (essentials/threads/recent/buffer).
1445
+ // `currentMemoryV2Static` is the trust-gated content reused by every
1446
+ // re-injection path it stays non-null on non-full-mode turns so
1447
+ // that mid-turn reducer compaction (which strips the prior `<memory>`
1448
+ // block) can restore the freshest content. `memoryV2Static` is the
1449
+ // first-turn / post-compaction cadence-gated value for initial
1450
+ // injection only. `readMemoryV2StaticContent` self-gates on the v2
1451
+ // flag + config and returns null when v2 is off.
1452
+ const currentMemoryV2Static = personalMemoryAllowed
1438
1453
  ? readMemoryV2StaticContent()
1439
1454
  : null;
1440
- const memoryV2Static = currentMemoryV2Static;
1455
+ const memoryV2Static = shouldInjectNowAndPkb ? currentMemoryV2Static : null;
1441
1456
 
1442
1457
  // PKB relevance-hint inputs. Resolved once per turn and reused across
1443
1458
  // re-injections so post-compaction rebuilds pick up fresh hints against
@@ -1575,7 +1590,8 @@ export async function runAgentLoopImpl(
1575
1590
  injection.blocks.pkbSystemReminder ||
1576
1591
  injection.blocks.workspaceBlock ||
1577
1592
  injection.blocks.nowScratchpadBlock ||
1578
- injection.blocks.pkbContextBlock
1593
+ injection.blocks.pkbContextBlock ||
1594
+ injection.blocks.memoryV2StaticBlock
1579
1595
  ) {
1580
1596
  try {
1581
1597
  const metadataUpdates: Record<string, unknown> = {};
@@ -1597,6 +1613,10 @@ export async function runAgentLoopImpl(
1597
1613
  if (injection.blocks.pkbContextBlock) {
1598
1614
  metadataUpdates.pkbContextBlock = injection.blocks.pkbContextBlock;
1599
1615
  }
1616
+ if (injection.blocks.memoryV2StaticBlock) {
1617
+ metadataUpdates.memoryV2StaticBlock =
1618
+ injection.blocks.memoryV2StaticBlock;
1619
+ }
1600
1620
  await runPipeline<PersistArgs, PersistResult>(
1601
1621
  "persistence",
1602
1622
  getMiddlewaresFor("persistence"),
@@ -2240,6 +2260,83 @@ export async function runAgentLoopImpl(
2240
2260
  }
2241
2261
  }
2242
2262
 
2263
+ // ── Image-dimension overflow recovery ──────────────────────────
2264
+ // When the provider rejects because an image block exceeds its pixel
2265
+ // cap, strip every image block from ctx.messages and retry once.
2266
+ // optimizeImageForTransport already ran at upload time; if sips was
2267
+ // unavailable (non-macOS) it returns the same bytes unchanged. In
2268
+ // that case we swap the block for a text note so the model can tell
2269
+ // the user what happened instead of hard-failing with a red banner.
2270
+ if (state.imageTooLargeDetected) {
2271
+ state.imageTooLargeDetected = false;
2272
+ rlog.warn(
2273
+ { phase: "image-recovery" },
2274
+ "Image too large — stripping oversized image blocks and retrying",
2275
+ );
2276
+ ctx.messages = ctx.messages.map((msg) => {
2277
+ if (!Array.isArray(msg.content)) return msg;
2278
+ if (!msg.content.some((b) => b.type === "image")) return msg;
2279
+ return {
2280
+ ...msg,
2281
+ content: msg.content.flatMap((b): ContentBlock[] => {
2282
+ if (b.type !== "image") return [b];
2283
+ const resized = optimizeImageForTransport(
2284
+ b.source.data,
2285
+ b.source.media_type,
2286
+ );
2287
+ if (resized.data !== b.source.data) {
2288
+ // sips managed to downscale — use the smaller version
2289
+ return [
2290
+ {
2291
+ ...b,
2292
+ source: {
2293
+ type: "base64" as const,
2294
+ media_type: resized.mediaType,
2295
+ data: resized.data,
2296
+ },
2297
+ },
2298
+ ];
2299
+ }
2300
+ // Can't resize — replace with a text annotation so the model
2301
+ // can explain the situation rather than silently dropping context
2302
+ return [
2303
+ {
2304
+ type: "text" as const,
2305
+ text: "(An image was attached but could not be sent — its dimensions exceed the provider limit and automatic resize was not available. Please resize the image and try again.)",
2306
+ },
2307
+ ];
2308
+ }),
2309
+ };
2310
+ });
2311
+ runMessages = ctx.messages;
2312
+ updatedHistory = await ctx.agentLoop.run(
2313
+ runMessages,
2314
+ eventHandler,
2315
+ abortController.signal,
2316
+ reqId,
2317
+ onCheckpoint,
2318
+ turnCallSite,
2319
+ loopTurnCtx,
2320
+ turnOverrideProfile,
2321
+ effectiveContextWindow.maxInputTokens,
2322
+ );
2323
+ if (state.imageTooLargeDetected) {
2324
+ rlog.error(
2325
+ { phase: "image-recovery" },
2326
+ "Image-recovery retry also failed — surfacing error to user",
2327
+ );
2328
+ const classified = classifyConversationError(
2329
+ new Error("Image dimensions too large"),
2330
+ { phase: "agent_loop" },
2331
+ );
2332
+ deps.onEvent(
2333
+ buildConversationErrorMessage(deps.ctx.conversationId, classified),
2334
+ );
2335
+ state.providerErrorUserMessage = classified.userMessage;
2336
+ state.imageTooLargeDetected = false;
2337
+ }
2338
+ }
2339
+
2243
2340
  // ── Bounded context overflow convergence loop ──────────────────
2244
2341
  // When the provider rejects with context-too-large, iterate through
2245
2342
  // reducer tiers (forced compaction, tool-result truncation, media
@@ -2834,6 +2931,7 @@ export async function runAgentLoopImpl(
2834
2931
  ctx.lastAssistantAttachments = assistantAttachments;
2835
2932
  ctx.lastAttachmentWarnings = attachmentResult.directiveWarnings;
2836
2933
  syncLastAssistantMessageToDisk();
2934
+ const clientDisplayMessageId = getClientDisplayMessageId(state);
2837
2935
 
2838
2936
  // Re-check: the user may have cancelled during attachment resolution
2839
2937
  if (abortController.signal.aborted) {
@@ -2874,6 +2972,9 @@ export async function runAgentLoopImpl(
2874
2972
  ...(state.lastAssistantMessageId
2875
2973
  ? { messageId: state.lastAssistantMessageId }
2876
2974
  : {}),
2975
+ ...(clientDisplayMessageId
2976
+ ? { displayMessageId: clientDisplayMessageId }
2977
+ : {}),
2877
2978
  });
2878
2979
  } else {
2879
2980
  ctx.emitActivityState("idle", "message_complete", "global", reqId);
@@ -2897,86 +2998,11 @@ export async function runAgentLoopImpl(
2897
2998
  ...(state.lastAssistantMessageId
2898
2999
  ? { messageId: state.lastAssistantMessageId }
2899
3000
  : {}),
3001
+ ...(clientDisplayMessageId
3002
+ ? { displayMessageId: clientDisplayMessageId }
3003
+ : {}),
2900
3004
  });
2901
3005
 
2902
- // Emit a home-feed event for background/scheduled conversation completions.
2903
- // Scoped to message_complete only (not cancelled/handoff), wrapped in
2904
- // try-catch so malformed message content can never propagate errors.
2905
- try {
2906
- const conv = getConversation(ctx.conversationId);
2907
- if (
2908
- conv &&
2909
- (conv.conversationType === "background" ||
2910
- conv.conversationType === "scheduled")
2911
- ) {
2912
- const lastMsg = state.lastAssistantMessageId
2913
- ? getMessageById(state.lastAssistantMessageId, ctx.conversationId)
2914
- : undefined;
2915
- let summary: string;
2916
- if (lastMsg) {
2917
- const parsed: unknown = JSON.parse(lastMsg.content);
2918
- if (typeof parsed === "string") {
2919
- summary = parsed.slice(0, 200);
2920
- } else if (Array.isArray(parsed)) {
2921
- const textBlock = parsed.find(
2922
- (b: { type?: string }) => b.type === "text",
2923
- );
2924
- summary =
2925
- typeof textBlock?.text === "string"
2926
- ? textBlock.text.slice(0, 200)
2927
- : (conv.title ?? "Background task completed.");
2928
- } else {
2929
- summary = conv.title ?? "Background task completed.";
2930
- }
2931
- } else {
2932
- summary = conv.title ?? "Background task completed.";
2933
- }
2934
- const feedTitle =
2935
- conv.title && !isReplaceableTitle(conv.title)
2936
- ? conv.title
2937
- : "Background task";
2938
- const dedupKey = `bg-conv:${ctx.conversationId}`;
2939
- void emitFeedEvent({
2940
- source: "assistant",
2941
- title: feedTitle,
2942
- summary,
2943
- dedupKey,
2944
- conversationId: ctx.conversationId,
2945
- }).catch((err) => {
2946
- log.warn(
2947
- { err, conversationId: ctx.conversationId },
2948
- "Failed to emit background conversation feed event",
2949
- );
2950
- });
2951
-
2952
- if (isReplaceableTitle(conv.title ?? null)) {
2953
- void rewriteFeedTitle(feedTitle)
2954
- .then((prose) => {
2955
- if (prose && prose !== feedTitle) {
2956
- return emitFeedEvent({
2957
- source: "assistant",
2958
- title: prose,
2959
- summary,
2960
- dedupKey,
2961
- conversationId: ctx.conversationId,
2962
- });
2963
- }
2964
- })
2965
- .catch((err) => {
2966
- log.warn(
2967
- { err, conversationId: ctx.conversationId },
2968
- "Failed to update feed event with prose title rewrite",
2969
- );
2970
- });
2971
- }
2972
- }
2973
- } catch (feedErr) {
2974
- log.warn(
2975
- { err: feedErr, conversationId: ctx.conversationId },
2976
- "Failed to build home-feed event for background conversation",
2977
- );
2978
- }
2979
-
2980
3006
  // Proactive artifact: fire once when the processed turn was the 4th user message.
2981
3007
  // Only trigger for real user-authored turns (not subagent/system messages).
2982
3008
  {
@@ -3274,6 +3300,10 @@ export async function applyCompactionResult(
3274
3300
  ctx.conversationId,
3275
3301
  ctx.trustContext?.trustClass,
3276
3302
  );
3303
+ enqueueMemoryRetrospectiveOnCompaction(
3304
+ ctx.conversationId,
3305
+ ctx.trustContext?.trustClass,
3306
+ );
3277
3307
  const summarySignals = computeSummaryQualitySignals(result.summaryText);
3278
3308
  onEvent({
3279
3309
  type: "context_compacted",
@@ -120,6 +120,13 @@ const STREAMING_ERROR_PATTERNS = [
120
120
  ];
121
121
 
122
122
  // User-initiated cancellation patterns — these should NOT produce conversation_error
123
+ // Image-input validation patterns — Anthropic 400s with this message when an image
124
+ // block exceeds the per-side pixel cap. Distinct classification matters because
125
+ // retrying with the same oversized image is futile; the user needs to resize.
126
+ const IMAGE_DIMENSIONS_TOO_LARGE_PATTERNS = [
127
+ /image dimensions? exceeds? max allowed size/i,
128
+ ];
129
+
123
130
  const CANCEL_PATTERNS = [/abort/i, /cancel/i];
124
131
 
125
132
  /**
@@ -370,6 +377,15 @@ function classifyCore(
370
377
  errorCategory: "provider_not_configured",
371
378
  };
372
379
  }
380
+ if (isImageDimensionsTooLarge(message)) {
381
+ return {
382
+ code: "IMAGE_TOO_LARGE",
383
+ userMessage:
384
+ "An attached image is too large for the AI provider — image dimensions must be under 8000 pixels per side. Resize the image and try again.",
385
+ retryable: false,
386
+ errorCategory: "image_dimensions_too_large",
387
+ };
388
+ }
373
389
  return {
374
390
  code: "PROVIDER_API",
375
391
  userMessage: "The AI provider rejected the request.",
@@ -388,6 +404,11 @@ export function isContextTooLarge(message: string): boolean {
388
404
  return CONTEXT_TOO_LARGE_PATTERNS.some((p) => p.test(message));
389
405
  }
390
406
 
407
+ /** Check whether an error message indicates an image-input dimension failure. */
408
+ function isImageDimensionsTooLarge(message: string): boolean {
409
+ return IMAGE_DIMENSIONS_TOO_LARGE_PATTERNS.some((p) => p.test(message));
410
+ }
411
+
391
412
  /** Check whether an error message indicates a web-search-specific ordering failure. */
392
413
  function isWebSearchOrderingError(message: string): boolean {
393
414
  return WEB_SEARCH_ORDERING_PATTERNS.some((p) => p.test(message));
@@ -17,6 +17,7 @@ import {
17
17
  type MessageRow,
18
18
  } from "../memory/conversation-crud.js";
19
19
  import { enqueueMemoryJob } from "../memory/jobs-store.js";
20
+ import { enqueueMemoryRetrospectiveIfEnabled } from "../memory/memory-retrospective-enqueue.js";
20
21
  import type { PermissionPrompter } from "../permissions/prompter.js";
21
22
  import type { SecretPrompter } from "../permissions/secret-prompter.js";
22
23
  import type { ContentBlock, Message } from "../providers/types.js";
@@ -183,6 +184,7 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
183
184
  ctx.contextCompactedAt = conv?.contextCompactedAt ?? null;
184
185
  }
185
186
 
187
+ const personalMemoryAllowed = !isUntrustedTrustClass(trustClass);
186
188
  const parsedMessages: Message[] = dbMessages
187
189
  .slice(ctx.contextCompactedMessageCount)
188
190
  .map((m, index, arr) => {
@@ -215,7 +217,8 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
215
217
  // shape right-to-left, since each prepend shifts previously-
216
218
  // prepended blocks one slot right:
217
219
  // [<workspace>, <turn_context>, <NOW.md>, <memory __injected>,
218
- // <system_reminder>, <knowledge_base>, ...original]
220
+ // <memory>\n…</memory>, <system_reminder>, <knowledge_base>,
221
+ // ...original]
219
222
  //
220
223
  // Persisted non-tail rows rehydrate the full set so Anthropic's
221
224
  // prefix cache keeps matching msg[0] across daemon restarts and
@@ -238,15 +241,37 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
238
241
  ];
239
242
  }
240
243
 
244
+ // The v2 static memory block (essentials/threads/recent/buffer
245
+ // wrapped in `<memory>…</memory>`) carries personal user memory.
246
+ // Trust-gated to mirror `shouldExposePersonalMemory` at injection
247
+ // time — untrusted-actor views must not read persisted personal
248
+ // memory back through metadata. Skipped on the tail row because
249
+ // the next turn re-injects fresh content on full-mode turns.
250
+ if (
251
+ !isTail &&
252
+ personalMemoryAllowed &&
253
+ typeof meta.memoryV2StaticBlock === "string"
254
+ ) {
255
+ content = [
256
+ { type: "text" as const, text: meta.memoryV2StaticBlock },
257
+ ...content,
258
+ ];
259
+ }
260
+
241
261
  // Memory remains rehydrated on all rows (existing behavior).
242
262
  // Strip any pre-existing wrapper before re-wrapping so historical
243
263
  // rows persisted with the wrapper (v2 path before the
244
264
  // injectedBlockText contract was unified with v1's unwrapped form)
245
- // don't render double-wrapped after rehydrate.
265
+ // don't render double-wrapped after rehydrate. Only unwrap when
266
+ // the full <memory>...</memory> pair is present so we don't mutate
267
+ // legitimate unwrapped payloads that happen to start with
268
+ // "<memory>\n" or end with "\n</memory>".
246
269
  if (typeof meta.memoryInjectedBlock === "string") {
247
- const inner = meta.memoryInjectedBlock
248
- .replace(/^<memory>\n/, "")
249
- .replace(/\n<\/memory>$/, "");
270
+ const block = meta.memoryInjectedBlock;
271
+ const inner =
272
+ block.startsWith("<memory>\n") && block.endsWith("\n</memory>")
273
+ ? block.slice("<memory>\n".length, -"\n</memory>".length)
274
+ : block;
250
275
  content = [
251
276
  {
252
277
  type: "text" as const,
@@ -411,6 +436,22 @@ export function disposeConversation(ctx: DisposeContext): void {
411
436
  } catch {
412
437
  // Best-effort — don't block conversation disposal
413
438
  }
439
+
440
+ try {
441
+ // Memory-retrospective lifecycle safety-net. The periodic triggers
442
+ // (interval / message_count / pre-compaction) handle the common
443
+ // path; lifecycle catches the gap between the last interval fire
444
+ // and conversation eviction. The job's `no_new_messages` early
445
+ // return makes this a cheap no-op when the periodic path already
446
+ // covered things. `enqueueMemoryRetrospectiveIfEnabled` has its
447
+ // own internal recursion guard.
448
+ enqueueMemoryRetrospectiveIfEnabled({
449
+ conversationId: ctx.conversationId,
450
+ trigger: "lifecycle",
451
+ });
452
+ } catch {
453
+ // Best-effort — don't block conversation disposal
454
+ }
414
455
  }
415
456
 
416
457
  abortConversation(