@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
@@ -3,18 +3,15 @@ import {
3
3
  diskPressureBackgroundSkipLogFields,
4
4
  shouldLogDiskPressureBackgroundSkip,
5
5
  } from "../daemon/disk-pressure-background-gate.js";
6
- import { emitFeedEvent } from "../home/emit-feed-event.js";
7
6
  import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
8
7
  import { getConversation } from "../memory/conversation-crud.js";
9
8
  import { invalidateAssistantInferredItemsForConversation } from "../memory/task-memory-cleanup.js";
9
+ import { emitNotificationSignal } from "../notifications/emit-signal.js";
10
10
  import { wakeAgentForOpportunity } from "../runtime/agent-wake.js";
11
+ import { runBackgroundJob } from "../runtime/background-job-runner.js";
11
12
  import { runSequencesOnce } from "../sequence/engine.js";
12
13
  import { getLogger } from "../util/logger.js";
13
- import {
14
- runWatchersOnce,
15
- type WatcherEscalator,
16
- type WatcherNotifier,
17
- } from "../watcher/engine.js";
14
+ import { runWatchersOnce, type WatcherNotifier } from "../watcher/engine.js";
18
15
  import { hasSetConstructs } from "./recurrence-engine.js";
19
16
  import { applyRetryDecision, decideRetry } from "./retry-policy.js";
20
17
  import { runScript, type ScriptResult } from "./run-script.js";
@@ -63,6 +60,20 @@ const TICK_INTERVAL_MS = 15_000;
63
60
  */
64
61
  const WAKE_MAX_RETRIES = 20;
65
62
 
63
+ /**
64
+ * Hard timeout for `talk`-mode scheduled jobs. Schedules can do
65
+ * non-trivial work (research, summarize the day, etc.), so the cap is
66
+ * generous; it exists primarily so a wedged turn cannot block the next
67
+ * scheduler tick indefinitely. Mirrors the heartbeat/filing budgets.
68
+ */
69
+ const SCHEDULE_TALK_TIMEOUT_MS = 30 * 60 * 1000;
70
+
71
+ /**
72
+ * Apply retry policy on schedule-execution failure. Retries are scheduled by
73
+ * `applyRetryDecision`; once retries are exhausted, the `emitAlert` callback
74
+ * fires an `activity.failed` notification so the user sees that a job
75
+ * permanently failed rather than just silently disappearing.
76
+ */
66
77
  function handleExecutionFailure(params: {
67
78
  job: ScheduleJob;
68
79
  errorMsg: string;
@@ -77,8 +88,13 @@ function handleExecutionFailure(params: {
77
88
  scheduleRetry,
78
89
  failOneShotPermanently,
79
90
  resetRetryCount,
80
- emitAlert: (title, summary, dedupKey) =>
81
- emitScheduleFeedEvent({ title, summary, dedupKey }),
91
+ emitAlert: (_title, _summary, dedupKey) =>
92
+ emitScheduleActivityFailed({
93
+ jobId: params.job.id,
94
+ jobName: params.job.name,
95
+ errorMessage: params.errorMsg,
96
+ dedupKey,
97
+ }),
82
98
  log,
83
99
  });
84
100
  }
@@ -87,7 +103,6 @@ export function startScheduler(
87
103
  processMessage: ScheduleMessageProcessor,
88
104
  notifyScheduleOneShot: ScheduleNotifyModeNotifier,
89
105
  watcherNotifier?: WatcherNotifier,
90
- watcherEscalator?: WatcherEscalator,
91
106
  onScheduleConversationCreated?: ScheduleConversationCreatedNotifier,
92
107
  ): SchedulerHandle {
93
108
  let stopped = false;
@@ -101,7 +116,6 @@ export function startScheduler(
101
116
  processMessage,
102
117
  notifyScheduleOneShot,
103
118
  watcherNotifier,
104
- watcherEscalator,
105
119
  onScheduleConversationCreated,
106
120
  );
107
121
  } catch (err) {
@@ -123,7 +137,6 @@ export function startScheduler(
123
137
  processMessage,
124
138
  notifyScheduleOneShot,
125
139
  watcherNotifier,
126
- watcherEscalator,
127
140
  onScheduleConversationCreated,
128
141
  );
129
142
  },
@@ -138,7 +151,6 @@ export async function runScheduleOnce(
138
151
  processMessage: ScheduleMessageProcessor,
139
152
  notifyScheduleOneShot: ScheduleNotifyModeNotifier,
140
153
  watcherNotifier?: WatcherNotifier,
141
- watcherEscalator?: WatcherEscalator,
142
154
  onScheduleConversationCreated?: ScheduleConversationCreatedNotifier,
143
155
  ): Promise<number> {
144
156
  const now = Date.now();
@@ -181,21 +193,11 @@ export async function runScheduleOnce(
181
193
  const successRunId = createScheduleRun(job.id, `notify-ok:${job.id}`);
182
194
  completeScheduleRun(successRunId, { status: "ok" });
183
195
  completeOneShot(job.id);
184
- emitScheduleFeedEvent({
185
- title: job.name,
186
- summary: "Reminder fired.",
187
- dedupKey: `schedule-notify-oneshot:${job.id}`,
188
- });
189
196
  } else {
190
197
  // Track recurring notify-mode success so lastStatus resets to ok
191
198
  // and retryCount clears after a transient failure.
192
199
  const runId = createScheduleRun(job.id, `notify-ok:${job.id}`);
193
200
  completeScheduleRun(runId, { status: "ok" });
194
- emitScheduleFeedEvent({
195
- title: job.name,
196
- summary: "Scheduled notification fired.",
197
- dedupKey: `schedule-run:${runId}`,
198
- });
199
201
  }
200
202
  } catch (err) {
201
203
  log.warn(
@@ -234,13 +236,6 @@ export async function runScheduleOnce(
234
236
  error: result.stderr || undefined,
235
237
  });
236
238
  if (result.exitCode === 0) {
237
- if (!job.quiet) {
238
- emitScheduleFeedEvent({
239
- title: job.name,
240
- summary: "Script ran.",
241
- dedupKey: `schedule-run:${runId}`,
242
- });
243
- }
244
239
  if (isOneShot) completeOneShot(job.id);
245
240
  } else {
246
241
  const errorMsg =
@@ -337,13 +332,6 @@ export async function runScheduleOnce(
337
332
  completeScheduleRun(successRunId, { status: "ok" });
338
333
  completeOneShot(job.id);
339
334
  }
340
- if (!job.quiet) {
341
- emitScheduleFeedEvent({
342
- title: job.name,
343
- summary: "Deferred wake fired.",
344
- dedupKey: `schedule-wake:${job.id}`,
345
- });
346
- }
347
335
  } catch (err) {
348
336
  log.warn(
349
337
  { err, jobId: job.id, name: job.name, wakeConversationId, isOneShot },
@@ -412,24 +400,23 @@ export async function runScheduleOnce(
412
400
  // Track the schedule run using the task's conversation
413
401
  const runId = createScheduleRun(job.id, result.conversationId);
414
402
  if (result.status === "failed") {
403
+ const errorMessage = result.error ?? "Task run failed";
415
404
  completeScheduleRun(runId, {
416
405
  status: "error",
417
- error: result.error ?? "Task run failed",
406
+ error: errorMessage,
407
+ });
408
+ emitTaskActivityFailed({
409
+ taskId,
410
+ conversationId: result.conversationId,
411
+ errorMessage,
418
412
  });
419
413
  handleExecutionFailure({
420
414
  job,
421
- errorMsg: result.error ?? "Task run failed",
415
+ errorMsg: errorMessage,
422
416
  isOneShot,
423
417
  });
424
418
  } else {
425
419
  completeScheduleRun(runId, { status: "ok" });
426
- if (!job.quiet) {
427
- emitScheduleFeedEvent({
428
- title: job.name,
429
- summary: "Scheduled task ran.",
430
- dedupKey: `schedule-run:${runId}`,
431
- });
432
- }
433
420
  if (isOneShot) completeOneShot(job.id);
434
421
  }
435
422
  processed += 1;
@@ -464,6 +451,11 @@ export async function runScheduleOnce(
464
451
  });
465
452
  const runId = createScheduleRun(job.id, fallbackConversation.id);
466
453
  completeScheduleRun(runId, { status: "error", error: message });
454
+ emitTaskActivityFailed({
455
+ taskId,
456
+ conversationId: fallbackConversation.id,
457
+ errorMessage: message,
458
+ });
467
459
  handleExecutionFailure({
468
460
  job,
469
461
  errorMsg: message,
@@ -474,71 +466,104 @@ export async function runScheduleOnce(
474
466
  }
475
467
 
476
468
  // Reuse the conversation from the last successful run when the flag is set
477
- // and a prior conversation still exists; otherwise bootstrap a new one.
478
- let conversationId: string | null = null;
479
- let conversationReused = false;
469
+ // and a prior conversation still exists; otherwise route through the
470
+ // shared `runBackgroundJob` runner (which bootstraps fresh, applies the
471
+ // standard timeout, and emits `activity.failed` on any failure).
472
+ const isRruleSetMsg =
473
+ job.syntax === "rrule" &&
474
+ job.expression != null &&
475
+ hasSetConstructs(job.expression);
476
+
477
+ let reusedConversationId: string | null = null;
480
478
  if (job.reuseConversation && !isOneShot) {
481
479
  const lastId = getLastScheduleConversationId(job.id);
482
480
  if (lastId && getConversation(lastId)) {
483
- conversationId = lastId;
484
- conversationReused = true;
481
+ reusedConversationId = lastId;
485
482
  }
486
483
  }
487
- if (!conversationId) {
488
- const conversation = bootstrapConversation({
489
- conversationType: "scheduled",
490
- source: "schedule",
484
+
485
+ log.info(
486
+ {
487
+ jobId: job.id,
488
+ name: job.name,
489
+ syntax: job.syntax,
490
+ expression: job.expression,
491
+ isRruleSet: isRruleSetMsg,
492
+ isOneShot,
493
+ ...(reusedConversationId
494
+ ? { conversationId: reusedConversationId }
495
+ : {}),
496
+ },
497
+ isOneShot ? "Executing one-shot schedule" : "Executing schedule",
498
+ );
499
+
500
+ let conversationId: string;
501
+ let ok: boolean;
502
+ let errorMsg: string | undefined;
503
+ const conversationReused = reusedConversationId != null;
504
+
505
+ if (reusedConversationId) {
506
+ // Reuse path: keep using the injected `processMessage` callback so the
507
+ // existing conversation is continued in place. `runBackgroundJob`
508
+ // unconditionally bootstraps a new conversation and is therefore not a
509
+ // drop-in replacement for the reuse semantics.
510
+ conversationId = reusedConversationId;
511
+ onScheduleConversationCreated?.({
512
+ conversationId,
491
513
  scheduleJobId: job.id,
492
- groupId: "system:scheduled",
514
+ title: job.name,
515
+ });
516
+ try {
517
+ await processMessage(conversationId, job.message, {
518
+ trustClass: "guardian",
519
+ });
520
+ ok = true;
521
+ } catch (err) {
522
+ ok = false;
523
+ errorMsg = err instanceof Error ? err.message : String(err);
524
+ }
525
+ } else {
526
+ // Fresh-bootstrap path: route through the shared runner so failures
527
+ // surface via `activity.failed` and we get the standard timeout +
528
+ // error-classification policy applied to every background producer.
529
+ // The runner fires `onConversationCreated` synchronously after bootstrap
530
+ // (before `processMessage` starts) so the macOS sidebar gets the new
531
+ // conversation immediately rather than after the up-to-30-min job ends.
532
+ const result = await runBackgroundJob({
533
+ jobName: `schedule:${job.id}`,
534
+ source: "schedule",
535
+ prompt: job.message,
536
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
537
+ callSite: "mainAgent",
538
+ timeoutMs: SCHEDULE_TALK_TIMEOUT_MS,
493
539
  origin: "schedule",
494
- systemHint: isOneShot
495
- ? `Reminder: ${job.name}`
496
- : `Schedule: ${job.name}`,
540
+ groupId: "system:scheduled",
541
+ conversationType: "scheduled",
542
+ scheduleJobId: job.id,
543
+ suppressFailureNotifications: job.quiet === true,
544
+ onConversationCreated: (newConversationId) => {
545
+ onScheduleConversationCreated?.({
546
+ conversationId: newConversationId,
547
+ scheduleJobId: job.id,
548
+ title: job.name,
549
+ });
550
+ },
497
551
  });
498
- conversationId = conversation.id;
552
+ conversationId = result.conversationId;
553
+ ok = result.ok;
554
+ errorMsg = result.error?.message;
499
555
  }
500
- onScheduleConversationCreated?.({
501
- conversationId,
502
- scheduleJobId: job.id,
503
- title: job.name,
504
- });
556
+
505
557
  const runId = createScheduleRun(job.id, conversationId);
506
- const isRruleSetMsg =
507
- job.syntax === "rrule" &&
508
- job.expression != null &&
509
- hasSetConstructs(job.expression);
510
558
 
511
- try {
512
- log.info(
513
- {
514
- jobId: job.id,
515
- name: job.name,
516
- syntax: job.syntax,
517
- expression: job.expression,
518
- isRruleSet: isRruleSetMsg,
519
- isOneShot,
520
- conversationId,
521
- },
522
- isOneShot ? "Executing one-shot schedule" : "Executing schedule",
523
- );
524
- await processMessage(conversationId, job.message, {
525
- trustClass: "guardian",
526
- });
559
+ if (ok) {
527
560
  completeScheduleRun(runId, { status: "ok" });
528
- if (!job.quiet) {
529
- emitScheduleFeedEvent({
530
- title: job.name,
531
- summary: isOneShot ? "One-shot reminder ran." : "Scheduled job ran.",
532
- dedupKey: `schedule-run:${runId}`,
533
- });
534
- }
535
561
  if (isOneShot) completeOneShot(job.id);
536
562
  processed += 1;
537
- } catch (err) {
538
- const message = err instanceof Error ? err.message : String(err);
563
+ } else {
539
564
  log.warn(
540
565
  {
541
- err,
566
+ err: errorMsg,
542
567
  jobId: job.id,
543
568
  name: job.name,
544
569
  syntax: job.syntax,
@@ -550,8 +575,12 @@ export async function runScheduleOnce(
550
575
  ? "One-shot schedule execution failed"
551
576
  : "Schedule execution failed",
552
577
  );
553
- completeScheduleRun(runId, { status: "error", error: message });
554
- handleExecutionFailure({ job, errorMsg: message, isOneShot });
578
+ completeScheduleRun(runId, { status: "error", error: errorMsg });
579
+ handleExecutionFailure({
580
+ job,
581
+ errorMsg: errorMsg ?? "Schedule run failed",
582
+ isOneShot,
583
+ });
555
584
 
556
585
  // Only skip invalidation when the conversation was *actually* reused,
557
586
  // i.e. it contains prior successful context worth preserving. When
@@ -572,13 +601,9 @@ export async function runScheduleOnce(
572
601
  }
573
602
 
574
603
  // ── Watchers (event-driven polling) ────────────────────────────────
575
- if (watcherNotifier && watcherEscalator) {
604
+ if (watcherNotifier) {
576
605
  try {
577
- const watcherProcessed = await runWatchersOnce(
578
- processMessage,
579
- watcherNotifier,
580
- watcherEscalator,
581
- );
606
+ const watcherProcessed = await runWatchersOnce(watcherNotifier);
582
607
  processed += watcherProcessed;
583
608
  } catch (err) {
584
609
  log.error({ err }, "Watcher tick failed");
@@ -587,7 +612,7 @@ export async function runScheduleOnce(
587
612
 
588
613
  // ── Sequences (multi-step outreach) ──────────────────────────────
589
614
  try {
590
- const sequenceProcessed = await runSequencesOnce(processMessage);
615
+ const sequenceProcessed = await runSequencesOnce();
591
616
  processed += sequenceProcessed;
592
617
  } catch (err) {
593
618
  log.error({ err }, "Sequence engine tick failed");
@@ -600,30 +625,82 @@ export async function runScheduleOnce(
600
625
  }
601
626
 
602
627
  /**
603
- * Fire-and-forget home-feed emit for a successful schedule run.
604
- *
605
- * Wraps {@link emitFeedEvent} with local error handling so a schema
606
- * failure or writer hiccup can never interrupt the scheduler tick
607
- * loop. The dedupKey is always derived from the schedule run id (or
608
- * the job id, for one-shot notify-mode which fires before a run
609
- * record is created) so each run lands as its own entry in the
610
- * activity log — the writer's per-source cap keeps total volume
611
- * bounded.
628
+ * Emit an `activity.failed` notification for a failed scheduled task run.
629
+ * Mirrors the shape `runBackgroundJob` produces for its own failures so the
630
+ * home feed and native notifications stay consistent regardless of which
631
+ * code path executed the work. Fire-and-forget a notification failure
632
+ * must never break scheduler operation.
612
633
  */
613
- function emitScheduleFeedEvent(params: {
614
- title: string;
615
- summary: string;
634
+ function emitTaskActivityFailed(args: {
635
+ taskId: string;
636
+ conversationId: string;
637
+ errorMessage: string;
638
+ }): void {
639
+ const day = new Date().toISOString().slice(0, 10);
640
+ emitNotificationSignal({
641
+ sourceChannel: "scheduler",
642
+ sourceContextId: args.conversationId,
643
+ sourceEventName: "activity.failed",
644
+ dedupeKey: `activity-failed:task:${args.taskId}:${day}`,
645
+ contextPayload: {
646
+ jobName: `task:${args.taskId}`,
647
+ errorMessage: args.errorMessage,
648
+ errorKind: "exception",
649
+ },
650
+ attentionHints: {
651
+ requiresAction: false,
652
+ urgency: "medium",
653
+ isAsyncBackground: true,
654
+ visibleInSourceNow: false,
655
+ },
656
+ }).catch((emitErr) => {
657
+ log.warn(
658
+ {
659
+ err: emitErr instanceof Error ? emitErr.message : String(emitErr),
660
+ taskId: args.taskId,
661
+ conversationId: args.conversationId,
662
+ },
663
+ "Failed to emit activity.failed notification for scheduled task",
664
+ );
665
+ });
666
+ }
667
+
668
+ /**
669
+ * Emit an `activity.failed` notification for a schedule whose retries have
670
+ * been exhausted. Distinct from `emitTaskActivityFailed` (which fires per
671
+ * failed task run) — this one fires once when the retry policy has given
672
+ * up, so the dedupeKey caller is the per-attempt key passed in by
673
+ * `applyRetryDecision` (already includes the job id and a timestamp).
674
+ */
675
+ function emitScheduleActivityFailed(args: {
676
+ jobId: string;
677
+ jobName: string;
678
+ errorMessage: string;
616
679
  dedupKey: string;
617
680
  }): void {
618
- void emitFeedEvent({
619
- source: "assistant",
620
- title: params.title,
621
- summary: params.summary,
622
- dedupKey: params.dedupKey,
623
- }).catch((err) => {
681
+ emitNotificationSignal({
682
+ sourceChannel: "scheduler",
683
+ sourceContextId: args.jobId,
684
+ sourceEventName: "activity.failed",
685
+ dedupeKey: args.dedupKey,
686
+ contextPayload: {
687
+ jobName: `schedule:${args.jobName}`,
688
+ errorMessage: args.errorMessage,
689
+ errorKind: "exception",
690
+ },
691
+ attentionHints: {
692
+ requiresAction: false,
693
+ urgency: "medium",
694
+ isAsyncBackground: true,
695
+ visibleInSourceNow: false,
696
+ },
697
+ }).catch((emitErr) => {
624
698
  log.warn(
625
- { err, dedupKey: params.dedupKey },
626
- "Failed to emit schedule feed event",
699
+ {
700
+ err: emitErr instanceof Error ? emitErr.message : String(emitErr),
701
+ jobId: args.jobId,
702
+ },
703
+ "Failed to emit activity.failed notification for exhausted schedule",
627
704
  );
628
705
  });
629
706
  }
@@ -40,18 +40,19 @@ const STORE_PATH = join(TEST_DIR, "keys.enc");
40
40
  * Regression test for the env-var fallback in `getProviderKeyAsync`.
41
41
  *
42
42
  * PR #27126 introduced `getLlmProviderEnvVar` which is LLM-scoped only.
43
- * After that PR, calls like `getProviderKeyAsync("brave")` and
44
- * `getProviderKeyAsync("perplexity")` stopped resolving the env var when
45
- * the secure store was empty, breaking web-search for users with
46
- * env-var-sourced Brave/Perplexity keys. The fix (this PR) routes the
47
- * fallback through `getAnyProviderEnvVar` which consults both the LLM
48
- * catalog and the search-provider map.
43
+ * After that PR, calls like `getProviderKeyAsync("brave")`,
44
+ * `getProviderKeyAsync("perplexity")`, and other search-provider keys stopped
45
+ * resolving the env var when the secure store was empty, breaking web-search
46
+ * for users with env-var-sourced search keys. The fix routes the fallback
47
+ * through `getAnyProviderEnvVar` which consults both the LLM catalog and the
48
+ * search-provider map.
49
49
  */
50
50
  describe("getProviderKeyAsync env-var fallback (regression #27126)", () => {
51
51
  const SAVED_ENV: Record<string, string | undefined> = {};
52
52
  const MANAGED_VARS = [
53
53
  "BRAVE_API_KEY",
54
54
  "PERPLEXITY_API_KEY",
55
+ "TAVILY_API_KEY",
55
56
  "ANTHROPIC_API_KEY",
56
57
  "OPENAI_API_KEY",
57
58
  ];
@@ -97,6 +98,11 @@ describe("getProviderKeyAsync env-var fallback (regression #27126)", () => {
97
98
  expect(await getProviderKeyAsync("perplexity")).toBe("pplx-env-test");
98
99
  });
99
100
 
101
+ test("returns TAVILY_API_KEY from process.env when secure store is empty", async () => {
102
+ process.env.TAVILY_API_KEY = "tavily-env-test";
103
+ expect(await getProviderKeyAsync("tavily")).toBe("tavily-env-test");
104
+ });
105
+
100
106
  test("returns ANTHROPIC_API_KEY from process.env when secure store is empty (LLM regression)", async () => {
101
107
  process.env.ANTHROPIC_API_KEY = "anthropic-env-test";
102
108
  expect(await getProviderKeyAsync("anthropic")).toBe("anthropic-env-test");
@@ -130,4 +130,7 @@ export const PREFIX_PATTERNS: SecretPrefixPattern[] = [
130
130
 
131
131
  // -- Perplexity --
132
132
  { label: "Perplexity API Key", regex: /pplx-[A-Za-z0-9]{40,}/ },
133
+
134
+ // -- Tavily --
135
+ { label: "Tavily API Key", regex: /tvly-[A-Za-z0-9]{20,}/ },
133
136
  ];
@@ -6,10 +6,8 @@
6
6
  * sends through the messaging layer.
7
7
  */
8
8
 
9
- import { emitFeedEvent } from "../home/emit-feed-event.js";
10
- import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
11
9
  import { getMessages } from "../memory/conversation-crud.js";
12
- import type { ScheduleMessageProcessor } from "../schedule/scheduler-types.js";
10
+ import { runBackgroundJob } from "../runtime/background-job-runner.js";
13
11
  import { getLogger } from "../util/logger.js";
14
12
  import { recordEvent } from "./analytics.js";
15
13
  import { checkAllPreSend, recordSend } from "./guardrails.js";
@@ -28,14 +26,13 @@ const log = getLogger("sequence-engine");
28
26
 
29
27
  const BATCH_SIZE = 10;
30
28
  const ERROR_RETRY_DELAY_MS = 60_000;
29
+ const STEP_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes per step
31
30
 
32
31
  /**
33
32
  * Process due sequence enrollments. Called by the scheduler on each tick.
34
33
  * Returns the number of enrollments processed.
35
34
  */
36
- export async function runSequencesOnce(
37
- processMessage: ScheduleMessageProcessor,
38
- ): Promise<number> {
35
+ export async function runSequencesOnce(): Promise<number> {
39
36
  const now = Date.now();
40
37
  const claimed = claimDueEnrollments(now, BATCH_SIZE);
41
38
  if (claimed.length === 0) return 0;
@@ -43,7 +40,7 @@ export async function runSequencesOnce(
43
40
  let processed = 0;
44
41
  for (const enrollment of claimed) {
45
42
  try {
46
- await processEnrollment(enrollment, processMessage);
43
+ await processEnrollment(enrollment);
47
44
  processed += 1;
48
45
  } catch (err) {
49
46
  log.error(
@@ -83,7 +80,6 @@ export async function runSequencesOnce(
83
80
 
84
81
  async function processEnrollment(
85
82
  enrollment: SequenceEnrollment,
86
- processMessage: ScheduleMessageProcessor,
87
83
  ): Promise<void> {
88
84
  const sequence = getSequence(enrollment.sequenceId);
89
85
  if (!sequence) {
@@ -146,30 +142,54 @@ async function processEnrollment(
146
142
  // Build the prompt for the assistant to generate and send the email
147
143
  const prompt = buildStepPrompt(enrollment, sequence, step);
148
144
 
149
- // Create a conversation for this step execution
150
- const conversation = bootstrapConversation({
151
- source: "sequence",
152
- origin: "sequence",
153
- systemHint: `Sequence: ${sequence.name} — Step ${step.index + 1}`,
154
- });
155
-
156
145
  log.info(
157
146
  {
158
147
  enrollmentId: enrollment.id,
159
148
  sequenceId: sequence.id,
160
149
  step: step.index,
161
150
  contactEmail: enrollment.contactEmail,
162
- conversationId: conversation.id,
163
151
  },
164
152
  "Processing sequence step",
165
153
  );
166
154
 
167
- await processMessage(conversation.id, prompt);
155
+ const result = await runBackgroundJob({
156
+ jobName: "sequence-step",
157
+ source: "sequence",
158
+ prompt,
159
+ systemHint: `Sequence: ${sequence.name} — Step ${step.index + 1}`,
160
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
161
+ callSite: "mainAgent",
162
+ timeoutMs: STEP_TIMEOUT_MS,
163
+ origin: "sequence",
164
+ });
165
+
166
+ if (!result.ok) {
167
+ // Timeouts do not cancel the in-flight `processMessage`, so retrying
168
+ // could double-send. Exit the enrollment instead of rescheduling.
169
+ if (result.errorKind === "timeout") {
170
+ log.error(
171
+ {
172
+ enrollmentId: enrollment.id,
173
+ sequenceId: sequence.id,
174
+ step: step.index,
175
+ },
176
+ "Sequence step timed out — exiting enrollment to prevent duplicate outreach",
177
+ );
178
+ recordEvent(sequence.id, enrollment.id, "fail", step.index, {
179
+ reason: "step_timeout",
180
+ });
181
+ exitEnrollment(enrollment.id, "failed");
182
+ return;
183
+ }
184
+ throw (
185
+ result.error ?? new Error(`Background job failed: ${result.errorKind}`)
186
+ );
187
+ }
168
188
 
169
189
  // Try to extract the email thread ID from conversation tool results so
170
190
  // subsequent steps can reply in the same conversation.
171
191
  const extractedConversationId =
172
- extractThreadIdFromConversation(conversation.id) ?? undefined;
192
+ extractThreadIdFromConversation(result.conversationId) ?? undefined;
173
193
  if (extractedConversationId) {
174
194
  log.info(
175
195
  { enrollmentId: enrollment.id, conversationId: extractedConversationId },
@@ -201,28 +221,6 @@ async function processEnrollment(
201
221
  recordSend(sequence.id);
202
222
  recordEvent(sequence.id, enrollment.id, "send", step.index);
203
223
 
204
- // Fire-and-forget home-feed activity log entry. Each (enrollment,
205
- // step) pair is a distinct real signal (an email actually went
206
- // out), so the dedupKey embeds both — repeat emits for the same
207
- // step are impossible because the enrollment advances after this
208
- // line, but if they did occur they'd land on the same entry.
209
- void emitFeedEvent({
210
- source: "assistant",
211
- title: sequence.name,
212
- summary: `Sent step ${step.index + 1} of ${sequence.steps.length} to ${enrollment.contactEmail}.`,
213
- dedupKey: `sequence-step:${enrollment.id}:${step.index}`,
214
- }).catch((err) => {
215
- log.warn(
216
- {
217
- err,
218
- sequenceId: sequence.id,
219
- enrollmentId: enrollment.id,
220
- step: step.index,
221
- },
222
- "Failed to emit sequence step feed event",
223
- );
224
- });
225
-
226
224
  // Advance to the next step
227
225
  const nextStepIndex = enrollment.currentStep + 1;
228
226
  if (nextStepIndex >= sequence.steps.length) {