@vellumai/assistant 0.7.3 → 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 (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Tests for SSE subscriber shed-on-backpressure observability.
3
+ *
4
+ * Verifies that when `controller.desiredSize <= 0`, the SSE route invokes
5
+ * the injected shed reporter with the correct reason and per-subscriber
6
+ * context. Both shed sites are covered: the event-callback path (slow
7
+ * subscriber + publishes filling the queue) and the heartbeat-timer path
8
+ * (slow subscriber with no published events). The healthy path asserts
9
+ * no shed report fires.
10
+ */
11
+ import { beforeEach, describe, expect, test } from "bun:test";
12
+
13
+ import { getDb } from "../memory/db-connection.js";
14
+ import { initializeDb } from "../memory/db-init.js";
15
+ import { buildAssistantEvent } from "../runtime/assistant-event.js";
16
+ import { AssistantEventHub } from "../runtime/assistant-event-hub.js";
17
+ import {
18
+ buildSseShedSentryContext,
19
+ handleSubscribeAssistantEvents,
20
+ type SseShedReason,
21
+ type SseSubscriberInstrumentation,
22
+ } from "../runtime/routes/events-routes.js";
23
+
24
+ initializeDb();
25
+
26
+ function clearTables() {
27
+ const db = getDb();
28
+ db.run("DELETE FROM conversation_keys");
29
+ db.run("DELETE FROM conversations");
30
+ }
31
+
32
+ interface ShedReport {
33
+ reason: SseShedReason;
34
+ events_delivered: number;
35
+ heartbeats_sent: number;
36
+ client_id: string | null;
37
+ interface_id: string | null;
38
+ conversation_key: string | null;
39
+ subscription_age_ms: number;
40
+ }
41
+
42
+ function makeReporterCaptor(): {
43
+ reports: ShedReport[];
44
+ reporter: (reason: SseShedReason, inst: SseSubscriberInstrumentation) => void;
45
+ } {
46
+ const reports: ShedReport[] = [];
47
+ return {
48
+ reports,
49
+ reporter: (reason, inst) => {
50
+ reports.push({
51
+ reason,
52
+ events_delivered: inst.eventsDelivered,
53
+ heartbeats_sent: inst.heartbeatsSent,
54
+ client_id: inst.clientId,
55
+ interface_id: inst.interfaceId,
56
+ conversation_key: inst.conversationKey,
57
+ subscription_age_ms: Date.now() - inst.subscribedAtMs,
58
+ });
59
+ },
60
+ };
61
+ }
62
+
63
+ const SSE_HIGH_WATER_MARK = 16;
64
+
65
+ describe("SSE route — backpressure shed observability", () => {
66
+ beforeEach(clearTables);
67
+
68
+ test("invokes shedReporter with reason=callback_backpressure when publishes saturate the queue", async () => {
69
+ const hub = new AssistantEventHub();
70
+ const { reports, reporter } = makeReporterCaptor();
71
+ const ac = new AbortController();
72
+
73
+ handleSubscribeAssistantEvents(
74
+ {
75
+ queryParams: { conversationKey: "shed-cb-test" },
76
+ abortSignal: ac.signal,
77
+ },
78
+ { hub, shedReporter: reporter },
79
+ );
80
+ expect(hub.subscriberCount()).toBe(1);
81
+
82
+ // Saturate the stream's bounded queue without reading from it.
83
+ // start() already enqueued the immediate heartbeat (queue=1), so
84
+ // publishing `SSE_HIGH_WATER_MARK` events triggers the shed on the
85
+ // final publish when desiredSize hits 0.
86
+ for (let i = 0; i < SSE_HIGH_WATER_MARK; i += 1) {
87
+ await hub.publish(buildAssistantEvent({ type: "pong" }));
88
+ }
89
+
90
+ expect(hub.subscriberCount()).toBe(0);
91
+ expect(reports.length).toBe(1);
92
+ expect(reports[0]?.reason).toBe("callback_backpressure");
93
+ expect(reports[0]?.events_delivered).toBe(SSE_HIGH_WATER_MARK - 1);
94
+ // The initial heartbeat enqueued by start() must be counted so the
95
+ // reported queue depth matches what was actually pushed.
96
+ expect(reports[0]?.heartbeats_sent).toBe(1);
97
+ expect(reports[0]?.conversation_key).toBe("shed-cb-test");
98
+ expect(typeof reports[0]?.subscription_age_ms).toBe("number");
99
+
100
+ ac.abort();
101
+ });
102
+
103
+ test("invokes shedReporter with reason=heartbeat_backpressure when the heartbeat tick finds desiredSize<=0", async () => {
104
+ const hub = new AssistantEventHub();
105
+ const { reports, reporter } = makeReporterCaptor();
106
+ const ac = new AbortController();
107
+
108
+ handleSubscribeAssistantEvents(
109
+ {
110
+ queryParams: { conversationKey: "shed-hb-test" },
111
+ abortSignal: ac.signal,
112
+ },
113
+ { hub, heartbeatIntervalMs: 20, shedReporter: reporter },
114
+ );
115
+ expect(hub.subscriberCount()).toBe(1);
116
+
117
+ // Fill the queue up to its limit without sending the publish that
118
+ // would shed via the callback path.
119
+ for (let i = 0; i < SSE_HIGH_WATER_MARK - 1; i += 1) {
120
+ await hub.publish(buildAssistantEvent({ type: "pong" }));
121
+ }
122
+ expect(reports.length).toBe(0);
123
+
124
+ await new Promise((r) => setTimeout(r, 60));
125
+
126
+ expect(reports.length).toBe(1);
127
+ expect(reports[0]?.reason).toBe("heartbeat_backpressure");
128
+ expect(reports[0]?.conversation_key).toBe("shed-hb-test");
129
+
130
+ ac.abort();
131
+ });
132
+
133
+ test("does not invoke shedReporter when a reader drains the stream", async () => {
134
+ const hub = new AssistantEventHub();
135
+ const { reports, reporter } = makeReporterCaptor();
136
+ const ac = new AbortController();
137
+
138
+ const stream = handleSubscribeAssistantEvents(
139
+ {
140
+ queryParams: { conversationKey: "shed-healthy-test" },
141
+ abortSignal: ac.signal,
142
+ },
143
+ { hub, heartbeatIntervalMs: 1_000, shedReporter: reporter },
144
+ );
145
+
146
+ const reader = stream.getReader();
147
+ void reader.read();
148
+
149
+ for (let i = 0; i < 32; i += 1) {
150
+ await hub.publish(buildAssistantEvent({ type: "pong" }));
151
+ void reader.read();
152
+ }
153
+
154
+ expect(reports.length).toBe(0);
155
+
156
+ ac.abort();
157
+ void reader.cancel();
158
+ });
159
+
160
+ test("captures client identity in the shed instrumentation context", async () => {
161
+ const hub = new AssistantEventHub();
162
+ const { reports, reporter } = makeReporterCaptor();
163
+ const ac = new AbortController();
164
+
165
+ handleSubscribeAssistantEvents(
166
+ {
167
+ queryParams: { conversationKey: "shed-client-test" },
168
+ headers: {
169
+ "x-vellum-client-id": "client-abc",
170
+ "x-vellum-interface-id": "macos",
171
+ },
172
+ abortSignal: ac.signal,
173
+ },
174
+ { hub, shedReporter: reporter },
175
+ );
176
+
177
+ for (let i = 0; i < SSE_HIGH_WATER_MARK; i += 1) {
178
+ await hub.publish(buildAssistantEvent({ type: "pong" }));
179
+ }
180
+
181
+ expect(reports.length).toBe(1);
182
+ expect(reports[0]?.client_id).toBe("client-abc");
183
+ expect(reports[0]?.interface_id).toBe("macos");
184
+
185
+ ac.abort();
186
+ });
187
+ });
188
+
189
+ describe("buildSseShedSentryContext", () => {
190
+ const inst: SseSubscriberInstrumentation = {
191
+ subscribedAtMs: 1_000,
192
+ eventsDelivered: 7,
193
+ heartbeatsSent: 3,
194
+ clientId: "client-xyz",
195
+ interfaceId: "macos",
196
+ // Channel-backed conversation key embedding a phone number.
197
+ conversationKey: "asst:self:whatsapp:447123456789",
198
+ };
199
+ const elDelay = { mean_ms: 1.2, p99_ms: 3.4, max_ms: 5.6 };
200
+
201
+ test("omits conversation_key so Sentry contexts do not leak PII", () => {
202
+ const ctx = buildSseShedSentryContext(
203
+ "callback_backpressure",
204
+ inst,
205
+ elDelay,
206
+ 2_500,
207
+ );
208
+ expect(ctx).not.toHaveProperty("conversation_key");
209
+ expect(ctx).not.toHaveProperty("conversationKey");
210
+ expect(JSON.stringify(ctx)).not.toContain("447123456789");
211
+ });
212
+
213
+ test("preserves non-PII per-subscriber and runtime fields", () => {
214
+ const ctx = buildSseShedSentryContext(
215
+ "heartbeat_backpressure",
216
+ inst,
217
+ elDelay,
218
+ 2_500,
219
+ );
220
+ expect(ctx).toMatchObject({
221
+ reason: "heartbeat_backpressure",
222
+ subscription_age_ms: 1_500,
223
+ events_delivered: 7,
224
+ heartbeats_sent: 3,
225
+ client_id: "client-xyz",
226
+ interface_id: "macos",
227
+ event_loop_delay_mean_ms: 1.2,
228
+ event_loop_delay_p99_ms: 3.4,
229
+ event_loop_delay_max_ms: 5.6,
230
+ });
231
+ });
232
+ });
@@ -389,18 +389,19 @@ describe("auto-analysis batch trigger uses analysis.batchSize cadence", () => {
389
389
  const originalExtractionBatch = TEST_CONFIG.memory.extraction.batchSize;
390
390
  const originalAnalysisBatch = TEST_CONFIG.analysis.batchSize;
391
391
 
392
+ const originalV2Enabled = TEST_CONFIG.memory.v2.enabled;
393
+
392
394
  beforeEach(() => {
393
- // memory-v2-enabled gates v1 graph_extract enqueue; force off so
395
+ _setOverridesForTesting({ "auto-analyze": true });
396
+ // memory.v2.enabled gates v1 graph_extract enqueue; force off so
394
397
  // these cadence tests can observe the v1 path.
395
- _setOverridesForTesting({
396
- "auto-analyze": true,
397
- "memory-v2-enabled": false,
398
- });
398
+ TEST_CONFIG.memory.v2.enabled = false;
399
399
  TEST_CONFIG.memory.extraction.batchSize = 2;
400
400
  TEST_CONFIG.analysis.batchSize = 5;
401
401
  });
402
402
 
403
403
  afterEach(() => {
404
+ TEST_CONFIG.memory.v2.enabled = originalV2Enabled;
404
405
  TEST_CONFIG.memory.extraction.batchSize = originalExtractionBatch;
405
406
  TEST_CONFIG.analysis.batchSize = originalAnalysisBatch;
406
407
  });
@@ -544,10 +545,10 @@ describe("auto-analysis batch trigger uses analysis.batchSize cadence", () => {
544
545
  });
545
546
 
546
547
  // ─────────────────────────────────────────────────────────────────
547
- // Indexer v1/v2 mutual exclusion: when memory-v2-enabled is on AND
548
- // memory.v2.enabled is on, the v1 graph_extract enqueue is suppressed
549
- // (v2 reads from buffer.md, so v1 graph data is unread). When either
550
- // gate is off, v1 graph_extract fires.
548
+ // Indexer v1/v2 mutual exclusion: when memory.v2.enabled is on, the
549
+ // v1 graph_extract enqueue is suppressed (v2 reads from buffer.md,
550
+ // so v1 graph data is unread). When v2 is disabled, v1 graph_extract
551
+ // fires.
551
552
  // ─────────────────────────────────────────────────────────────────
552
553
 
553
554
  describe("indexer v1/v2 mutual exclusion for graph_extract", () => {
@@ -564,8 +565,7 @@ describe("indexer v1/v2 mutual exclusion for graph_extract", () => {
564
565
  TEST_CONFIG.memory.v2.enabled = originalV2Enabled;
565
566
  });
566
567
 
567
- test("v2 active (flag on + config on) → graph_extract not enqueued", async () => {
568
- _setOverridesForTesting({ "memory-v2-enabled": true });
568
+ test("v2 active (config on) → graph_extract not enqueued", async () => {
569
569
  TEST_CONFIG.memory.v2.enabled = true;
570
570
 
571
571
  const source = createConversation("v2-active");
@@ -574,20 +574,7 @@ describe("indexer v1/v2 mutual exclusion for graph_extract", () => {
574
574
  expect(countJobsOfType("graph_extract", source.id)).toBe(0);
575
575
  });
576
576
 
577
- test("flag off → graph_extract enqueued", async () => {
578
- _setOverridesForTesting({ "memory-v2-enabled": false });
579
- TEST_CONFIG.memory.v2.enabled = true;
580
-
581
- const source = createConversation("v2-flag-off");
582
- await indexMessages(source.id, 2);
583
-
584
- expect(countJobsOfType("graph_extract", source.id)).toBeGreaterThanOrEqual(
585
- 1,
586
- );
587
- });
588
-
589
- test("config gate off (flag on) → graph_extract enqueued", async () => {
590
- _setOverridesForTesting({ "memory-v2-enabled": true });
577
+ test("config gate off → graph_extract enqueued", async () => {
591
578
  TEST_CONFIG.memory.v2.enabled = false;
592
579
 
593
580
  const source = createConversation("v2-config-off");
@@ -0,0 +1,87 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { SYNC_TAGS } from "../daemon/message-types/sync.js";
4
+ import type { AssistantEvent } from "../runtime/assistant-event.js";
5
+ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
6
+ import { ROUTES as AVATAR_ROUTES } from "../runtime/routes/avatar-routes.js";
7
+ import { publishIdentityChanged } from "../runtime/sync/resource-sync-events.js";
8
+
9
+ async function waitFor(predicate: () => boolean): Promise<void> {
10
+ const deadline = Date.now() + 500;
11
+ while (Date.now() < deadline) {
12
+ if (predicate()) {
13
+ return;
14
+ }
15
+ await new Promise((resolve) => setTimeout(resolve, 5));
16
+ }
17
+ throw new Error("Timed out waiting for avatar/identity sync event");
18
+ }
19
+
20
+ describe("avatar and identity sync events", () => {
21
+ test("notify_avatar_updated emits legacy avatar event and sync tag", async () => {
22
+ const received: AssistantEvent[] = [];
23
+ const subscription = assistantEventHub.subscribe({
24
+ type: "process",
25
+ callback: (event) => {
26
+ received.push(event);
27
+ },
28
+ });
29
+
30
+ try {
31
+ const route = AVATAR_ROUTES.find(
32
+ (candidate) => candidate.operationId === "notify_avatar_updated",
33
+ );
34
+ expect(route).toBeDefined();
35
+
36
+ await route!.handler({});
37
+ await waitFor(() => received.length === 2);
38
+
39
+ expect(received.map((event) => event.message.type)).toEqual([
40
+ "avatar_updated",
41
+ "sync_changed",
42
+ ]);
43
+ expect(received[1].message).toEqual({
44
+ type: "sync_changed",
45
+ tags: [SYNC_TAGS.assistantAvatar],
46
+ });
47
+ } finally {
48
+ subscription.dispose();
49
+ }
50
+ });
51
+
52
+ test("identity changes emit legacy identity event and sync tag", async () => {
53
+ const received: AssistantEvent[] = [];
54
+ const subscription = assistantEventHub.subscribe({
55
+ type: "process",
56
+ callback: (event) => {
57
+ received.push(event);
58
+ },
59
+ });
60
+
61
+ try {
62
+ publishIdentityChanged({
63
+ name: "Sage",
64
+ role: "Assistant",
65
+ personality: "Calm",
66
+ emoji: ":sparkles:",
67
+ home: "San Francisco",
68
+ });
69
+ await waitFor(() => received.length === 2);
70
+
71
+ expect(received.map((event) => event.message.type)).toEqual([
72
+ "identity_changed",
73
+ "sync_changed",
74
+ ]);
75
+ expect(received[0].message).toMatchObject({
76
+ type: "identity_changed",
77
+ name: "Sage",
78
+ });
79
+ expect(received[1].message).toEqual({
80
+ type: "sync_changed",
81
+ tags: [SYNC_TAGS.assistantIdentity],
82
+ });
83
+ } finally {
84
+ subscription.dispose();
85
+ }
86
+ });
87
+ });
@@ -1,5 +1,12 @@
1
1
  import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
+ // Default the warm-pool gate to OPEN — these tests probe background-job
4
+ // disk-pressure behavior, not the pre-first-message guard.
5
+ mock.module("../runtime/pre-first-message-gate.js", () => ({
6
+ hasReceivedUserMessage: () => true,
7
+ _resetPreFirstMessageGateCacheForTests: () => {},
8
+ }));
9
+
3
10
  mock.module("../util/logger.js", () => ({
4
11
  getLogger: () => ({
5
12
  info: () => {},
@@ -107,11 +114,13 @@ mock.module("../memory/conversation-crud.js", () => ({
107
114
  return { id: "conv-1", ...opts };
108
115
  },
109
116
  countConversationsByScheduleJobId: mock(() => 0),
117
+ countMessagesAfter: mock(() => 0),
110
118
  deleteMessageById: mock(() => {}),
111
119
  clearAll: mock(() => ({ conversations: 0, messages: 0 })),
112
120
  deleteConversation: mock(() => ({ memoryIds: [] })),
113
121
  deleteLastExchange: mock(() => 0),
114
122
  findAnalysisConversationFor: mock(() => null),
123
+ findMostRecentRetrospectiveFor: mock(() => null),
115
124
  forkConversation: mock(() => ({ id: "conv-fork" })),
116
125
  getConversationOverrideProfile: () => undefined,
117
126
  getConversationOverrideProfileFromRow: () => undefined,
@@ -126,6 +135,7 @@ mock.module("../memory/conversation-crud.js", () => ({
126
135
  getLastUserTimestampBefore: () => null,
127
136
  getMessageById: () => null,
128
137
  getMessages: () => [],
138
+ getMessagesAfter: () => [],
129
139
  getMessagesPaginated: () => ({ messages: [], hasMore: false }),
130
140
  getTurnTimeBounds: () => null,
131
141
  getConversation: () => null,
@@ -175,6 +185,7 @@ mock.module("../memory/jobs-store.js", () => ({
175
185
  SLOW_LLM_JOB_TYPES: [],
176
186
  upsertAutoAnalysisJob: mock(() => "job-auto-analysis"),
177
187
  upsertDebouncedJob: mock(() => "job-debounced"),
188
+ upsertMemoryRetrospectiveJob: mock(() => "job-memory-retrospective"),
178
189
  }));
179
190
 
180
191
  const mockMaybeRunDbMaintenance = mock(() => {});
@@ -187,7 +198,6 @@ mock.module("../memory/cleanup-schedule-state.js", () => ({
187
198
  markScheduledCleanupEnqueued: mock(() => {}),
188
199
  }));
189
200
 
190
- const { startFeedScheduler } = await import("../home/feed-scheduler.js");
191
201
  const { runMemoryJobsOnce } = await import("../memory/jobs-worker.js");
192
202
  const { FilingService } = await import("../filing/filing-service.js");
193
203
  const { WorkspaceHeartbeatService } =
@@ -202,27 +212,6 @@ describe("background workers disk pressure gate", () => {
202
212
  mockMaybeRunDbMaintenance.mockClear();
203
213
  });
204
214
 
205
- test("home feed scheduler skips producers while locked", async () => {
206
- const gmailDigestRunner = mock(async () => null);
207
- const rollupRunner = mock(async () => ({
208
- wroteCount: 1,
209
- skippedReason: "empty_items" as const,
210
- }));
211
- const handle = startFeedScheduler({
212
- runOnStart: false,
213
- gmailCountSource: async () => 0,
214
- gmailDigestRunner,
215
- rollupRunner,
216
- });
217
-
218
- const summary = await handle.runOnce(new Date("2026-05-05T12:00:00.000Z"));
219
- handle.stop();
220
-
221
- expect(summary).toEqual({ gmailDigestRan: false, rollupRan: false });
222
- expect(gmailDigestRunner).not.toHaveBeenCalled();
223
- expect(rollupRunner).not.toHaveBeenCalled();
224
- });
225
-
226
215
  test("memory jobs worker skips before claiming or maintenance writes", async () => {
227
216
  const processed = await runMemoryJobsOnce({ enableScheduledCleanup: true });
228
217
 
@@ -320,6 +320,7 @@ describe("POST /v1/btw", () => {
320
320
  expect(mockBuildSystemPrompt).toHaveBeenCalledWith({
321
321
  channelPersona: null,
322
322
  excludeBootstrap: true,
323
+ excludeCustomPrefix: true,
323
324
  userPersona: null,
324
325
  userSlug: null,
325
326
  });
@@ -1,6 +1,9 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
- import { isDeniedNumber } from "../calls/call-constants.js";
3
+ import {
4
+ getEndCallListenWindowMs,
5
+ isDeniedNumber,
6
+ } from "../calls/call-constants.js";
4
7
 
5
8
  describe("isDeniedNumber", () => {
6
9
  // Numbers that MUST be blocked
@@ -39,3 +42,9 @@ describe("isDeniedNumber", () => {
39
42
  });
40
43
  }
41
44
  });
45
+
46
+ describe("getEndCallListenWindowMs", () => {
47
+ test("leaves a brief response window before task-complete hangup", () => {
48
+ expect(getEndCallListenWindowMs()).toBe(15_000);
49
+ });
50
+ });
@@ -105,11 +105,13 @@ mock.module("../security/credential-key.js", () => ({
105
105
 
106
106
  let mockConsultationTimeoutMs = 90_000;
107
107
  let mockSilenceTimeoutMs = 30_000;
108
+ let mockEndCallListenWindowMs = 0;
108
109
 
109
110
  mock.module("../calls/call-constants.js", () => ({
110
111
  getMaxCallDurationMs: () => 12 * 60 * 1000,
111
112
  getUserConsultationTimeoutMs: () => mockConsultationTimeoutMs,
112
113
  getSilenceTimeoutMs: () => mockSilenceTimeoutMs,
114
+ getEndCallListenWindowMs: () => mockEndCallListenWindowMs,
113
115
  }));
114
116
 
115
117
  // ── Voice session bridge mock ────────────────────────────────────────
@@ -467,6 +469,7 @@ describe("call-controller", () => {
467
469
  // Reset consultation timeout to the default (long) value
468
470
  mockConsultationTimeoutMs = 90_000;
469
471
  mockSilenceTimeoutMs = 30_000;
472
+ mockEndCallListenWindowMs = 0;
470
473
  // Reset TTS config to defaults so per-test mutations don't leak.
471
474
  const cfg = loadConfig();
472
475
  cfg.services.tts.provider = "elevenlabs";
@@ -755,6 +758,130 @@ describe("call-controller", () => {
755
758
  controller.destroy();
756
759
  });
757
760
 
761
+ test("END_CALL waits through the listen window before completing", async () => {
762
+ mockEndCallListenWindowMs = 25;
763
+ mockStartVoiceTurn.mockImplementation(
764
+ createMockVoiceTurn(["Thank you for calling, goodbye! ", "[END_CALL]"]),
765
+ );
766
+ const { session, relay, controller } = setupController();
767
+
768
+ await controller.handleCallerUtterance("That is all, thanks");
769
+
770
+ expect(relay.endCalled).toBe(false);
771
+ expect(getCallSession(session.id)!.status).toBe("in_progress");
772
+
773
+ await new Promise((r) => setTimeout(r, 35));
774
+
775
+ expect(relay.endCalled).toBe(true);
776
+ const updatedSession = getCallSession(session.id);
777
+ expect(updatedSession!.status).toBe("completed");
778
+ expect(updatedSession!.endedAt).not.toBeNull();
779
+
780
+ controller.destroy();
781
+ });
782
+
783
+ test("delayed END_CALL completion skips side effects when session is already terminal", async () => {
784
+ mockEndCallListenWindowMs = 25;
785
+ mockStartVoiceTurn.mockImplementation(
786
+ createMockVoiceTurn(["Thank you for calling, goodbye! ", "[END_CALL]"]),
787
+ );
788
+ const { session, relay, controller } = setupController();
789
+
790
+ await controller.handleCallerUtterance("That is all, thanks");
791
+
792
+ const externalEndedAt = Date.now();
793
+ updateCallSession(session.id, {
794
+ status: "completed",
795
+ endedAt: externalEndedAt,
796
+ });
797
+
798
+ await new Promise((r) => setTimeout(r, 35));
799
+
800
+ expect(relay.endCalled).toBe(false);
801
+ const updatedSession = getCallSession(session.id);
802
+ expect(updatedSession!.status).toBe("completed");
803
+ expect(updatedSession!.endedAt).toBe(externalEndedAt);
804
+
805
+ controller.destroy();
806
+ });
807
+
808
+ test("callee speech during END_CALL listen window cancels pending completion", async () => {
809
+ mockEndCallListenWindowMs = 30;
810
+ const turnContents: string[] = [];
811
+ mockStartVoiceTurn.mockImplementation(
812
+ async (opts: {
813
+ content: string;
814
+ onTextDelta: (t: string) => void;
815
+ onComplete: () => void;
816
+ }) => {
817
+ turnContents.push(opts.content);
818
+ if (turnContents.length === 1) {
819
+ opts.onTextDelta("Goodbye! [END_CALL]");
820
+ } else {
821
+ opts.onTextDelta("Of course. I'm still here.");
822
+ }
823
+ opts.onComplete();
824
+ return { turnId: `run-${turnContents.length}`, abort: () => {} };
825
+ },
826
+ );
827
+ const { session, relay, controller } = setupController();
828
+
829
+ await controller.handleCallerUtterance("That is all, thanks");
830
+ expect(relay.endCalled).toBe(false);
831
+
832
+ await controller.handleCallerUtterance("Wait, one more thing");
833
+ await new Promise((r) => setTimeout(r, 40));
834
+
835
+ expect(relay.endCalled).toBe(false);
836
+ expect(getCallSession(session.id)!.status).toBe("in_progress");
837
+ expect(turnContents).toContain("Wait, one more thing");
838
+ const allText = relay.sentTokens.map((t) => t.token).join("");
839
+ expect(allText).toContain("I'm still here.");
840
+
841
+ controller.destroy();
842
+ });
843
+
844
+ test("END_CALL listen window restores in_progress after clearing pending guardian input", async () => {
845
+ mockEndCallListenWindowMs = 30;
846
+ const turnContents: string[] = [];
847
+ mockStartVoiceTurn.mockImplementation(
848
+ async (opts: {
849
+ content: string;
850
+ onTextDelta: (t: string) => void;
851
+ onComplete: () => void;
852
+ }) => {
853
+ turnContents.push(opts.content);
854
+ if (turnContents.length === 1) {
855
+ opts.onTextDelta("Let me check. [ASK_GUARDIAN: Is this okay?]");
856
+ } else if (turnContents.length === 2) {
857
+ opts.onTextDelta("Never mind, goodbye. [END_CALL]");
858
+ } else {
859
+ opts.onTextDelta("I'm still here.");
860
+ }
861
+ opts.onComplete();
862
+ return { turnId: `run-${turnContents.length}`, abort: () => {} };
863
+ },
864
+ );
865
+ const { session, relay, controller } = setupController();
866
+
867
+ await controller.handleCallerUtterance("Can you ask?");
868
+ expect(controller.getPendingConsultationQuestionId()).not.toBeNull();
869
+ expect(getCallSession(session.id)!.status).toBe("waiting_on_user");
870
+
871
+ await controller.handleCallerUtterance("Actually never mind");
872
+ expect(controller.getPendingConsultationQuestionId()).toBeNull();
873
+ expect(getCallSession(session.id)!.status).toBe("in_progress");
874
+ expect(relay.endCalled).toBe(false);
875
+
876
+ await controller.handleCallerUtterance("Wait, one more thing");
877
+ await new Promise((r) => setTimeout(r, 40));
878
+
879
+ expect(relay.endCalled).toBe(false);
880
+ expect(getCallSession(session.id)!.status).toBe("in_progress");
881
+
882
+ controller.destroy();
883
+ });
884
+
758
885
  // ── handleUserAnswer ──────────────────────────────────────────────
759
886
 
760
887
  test("handleUserAnswer: returns true immediately and fires LLM asynchronously", async () => {