@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
@@ -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) {