@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
@@ -18,6 +18,9 @@
18
18
  * handles registration, touch (heartbeat), and unregistration (dispose).
19
19
  */
20
20
 
21
+ import { type IntervalHistogram, monitorEventLoopDelay } from "node:perf_hooks";
22
+
23
+ import * as Sentry from "@sentry/node";
21
24
  import { z } from "zod";
22
25
 
23
26
  import type { HostProxyCapability } from "../../channels/types.js";
@@ -44,6 +47,175 @@ const log = getLogger("events-routes");
44
47
  /** Keep-alive comment sent to idle clients every 7 s by default. */
45
48
  const DEFAULT_HEARTBEAT_INTERVAL_MS = 7_000;
46
49
 
50
+ /**
51
+ * Resolution of the event-loop delay histogram, per
52
+ * https://nodejs.org/api/perf_hooks.html#perf_hooksmonitoreventloopdelayoptions.
53
+ * A 20 ms resolution gives sub-tick visibility while keeping overhead near zero.
54
+ */
55
+ const EVENT_LOOP_DELAY_RESOLUTION_MS = 20;
56
+
57
+ /**
58
+ * How often we reset the cumulative event-loop delay histogram so subsequent
59
+ * percentile snapshots reflect recent behavior rather than the entire process
60
+ * lifetime. Matches the default window used by `@fastify/under-pressure` and
61
+ * `prom-client` for runtime-pressure metrics.
62
+ */
63
+ const EVENT_LOOP_DELAY_RESET_INTERVAL_MS = 60_000;
64
+
65
+ let eventLoopDelay: IntervalHistogram | null = null;
66
+ let eventLoopResetTimer: ReturnType<typeof setInterval> | null = null;
67
+
68
+ /**
69
+ * Lazily start a cumulative event-loop delay histogram on the first SSE
70
+ * subscriber, and schedule a periodic reset so percentile readings stay
71
+ * meaningful across long-lived daemon processes.
72
+ *
73
+ * Guarded with try/catch because `node:perf_hooks.monitorEventLoopDelay`
74
+ * was a stub in some older Bun versions; if the runtime ever regresses,
75
+ * we still emit the shed log + Sentry capture without lag stats rather
76
+ * than crashing the SSE handler.
77
+ */
78
+ function ensureEventLoopDelayMonitorStarted(): void {
79
+ if (eventLoopDelay !== null) return;
80
+ try {
81
+ const histogram = monitorEventLoopDelay({
82
+ resolution: EVENT_LOOP_DELAY_RESOLUTION_MS,
83
+ });
84
+ histogram.enable();
85
+ eventLoopDelay = histogram;
86
+ eventLoopResetTimer = setInterval(() => {
87
+ try {
88
+ histogram.reset();
89
+ } catch {
90
+ if (eventLoopResetTimer) {
91
+ clearInterval(eventLoopResetTimer);
92
+ eventLoopResetTimer = null;
93
+ }
94
+ }
95
+ }, EVENT_LOOP_DELAY_RESET_INTERVAL_MS);
96
+ eventLoopResetTimer.unref?.();
97
+ } catch (err) {
98
+ log.warn({ err }, "failed to start event-loop delay monitor");
99
+ eventLoopDelay = null;
100
+ }
101
+ }
102
+
103
+ export interface EventLoopDelaySnapshot {
104
+ mean_ms: number | null;
105
+ p99_ms: number | null;
106
+ max_ms: number | null;
107
+ }
108
+
109
+ function nsToMs(ns: number): number | null {
110
+ if (!Number.isFinite(ns)) return null;
111
+ // Round to the nearest microsecond, then express in ms (3 decimal places).
112
+ return Math.round(ns / 1e3) / 1e3;
113
+ }
114
+
115
+ function sampleEventLoopDelay(): EventLoopDelaySnapshot {
116
+ const histogram = eventLoopDelay;
117
+ if (histogram === null) {
118
+ return { mean_ms: null, p99_ms: null, max_ms: null };
119
+ }
120
+ try {
121
+ return {
122
+ mean_ms: nsToMs(histogram.mean),
123
+ p99_ms: nsToMs(histogram.percentile(99)),
124
+ max_ms: nsToMs(histogram.max),
125
+ };
126
+ } catch {
127
+ return { mean_ms: null, p99_ms: null, max_ms: null };
128
+ }
129
+ }
130
+
131
+ export interface SseSubscriberInstrumentation {
132
+ subscribedAtMs: number;
133
+ eventsDelivered: number;
134
+ heartbeatsSent: number;
135
+ clientId: string | null;
136
+ interfaceId: string | null;
137
+ conversationKey: string | null;
138
+ }
139
+
140
+ export type SseShedReason = "callback_backpressure" | "heartbeat_backpressure";
141
+
142
+ export type SseShedReporter = (
143
+ reason: SseShedReason,
144
+ inst: SseSubscriberInstrumentation,
145
+ ) => void;
146
+
147
+ /**
148
+ * Build the structured payload sent to Sentry when an SSE subscriber is
149
+ * shed under backpressure.
150
+ *
151
+ * The conversation key is deliberately excluded: for channel-backed
152
+ * conversations (WhatsApp, Telegram, etc.) the key embeds external
153
+ * identifiers — phone numbers, chat IDs — and Sentry contexts are not
154
+ * run through the PII redactor in `instrument.ts` (only
155
+ * `exception.values`, `breadcrumbs`, and `extra` are). Correlation
156
+ * with the client-side `sse_watchdog_fired` event is achieved via the
157
+ * `client_id` tag + timestamp instead.
158
+ */
159
+ export function buildSseShedSentryContext(
160
+ reason: SseShedReason,
161
+ inst: SseSubscriberInstrumentation,
162
+ elDelay: EventLoopDelaySnapshot,
163
+ nowMs: number,
164
+ ): Record<string, unknown> {
165
+ return {
166
+ reason,
167
+ subscription_age_ms: nowMs - inst.subscribedAtMs,
168
+ events_delivered: inst.eventsDelivered,
169
+ heartbeats_sent: inst.heartbeatsSent,
170
+ client_id: inst.clientId,
171
+ interface_id: inst.interfaceId,
172
+ event_loop_delay_mean_ms: elDelay.mean_ms,
173
+ event_loop_delay_p99_ms: elDelay.p99_ms,
174
+ event_loop_delay_max_ms: elDelay.max_ms,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Report a backpressure-shed event from an SSE subscriber to logs and Sentry.
180
+ *
181
+ * SSE subscribers are shed when `controller.desiredSize <= 0`: the consumer
182
+ * has stopped reading and the stream's bounded queue is full. From the
183
+ * daemon's side this looks identical to a hung client — and the visible
184
+ * symptom on the client side is the 45 s idle-watchdog firing (Sentry
185
+ * issue `sse_watchdog_fired`). Surfacing the shed lets us time-correlate
186
+ * the two sides and attribute stalls to either backpressure or another
187
+ * cause (network drop, event-loop starvation, etc.).
188
+ *
189
+ * The Sentry call uses level="warning" intentionally: a shed is a
190
+ * saturation event, not an internal error.
191
+ */
192
+ const defaultSseShedReporter: SseShedReporter = (reason, inst) => {
193
+ const elDelay = sampleEventLoopDelay();
194
+ const sentryContext = buildSseShedSentryContext(
195
+ reason,
196
+ inst,
197
+ elDelay,
198
+ Date.now(),
199
+ );
200
+ log.warn(
201
+ { ...sentryContext, conversation_key: inst.conversationKey },
202
+ "sse subscriber shed under backpressure",
203
+ );
204
+
205
+ try {
206
+ Sentry.withScope((scope) => {
207
+ scope.setLevel("warning");
208
+ scope.setTag("sse_shed_reason", reason);
209
+ if (inst.clientId) scope.setTag("client_id", inst.clientId);
210
+ if (inst.interfaceId) scope.setTag("interface_id", inst.interfaceId);
211
+ scope.setContext("sse_shed", sentryContext);
212
+ Sentry.captureMessage(`sse_subscriber_shed:${reason}`);
213
+ });
214
+ } catch {
215
+ // Never let a telemetry failure break the SSE path.
216
+ }
217
+ };
218
+
47
219
  /**
48
220
  * Stream assistant events as Server-Sent Events.
49
221
  *
@@ -63,12 +235,15 @@ const DEFAULT_HEARTBEAT_INTERVAL_MS = 7_000;
63
235
  * Options (for testing):
64
236
  * hub -- override the event hub (defaults to process singleton).
65
237
  * heartbeatIntervalMs -- how often to emit keep-alive comments (default 7 s).
238
+ * shedReporter -- override the callback invoked when a subscriber is shed
239
+ * under backpressure (defaults to log + Sentry capture).
66
240
  */
67
241
  export function handleSubscribeAssistantEvents(
68
242
  args: RouteHandlerArgs,
69
243
  options?: {
70
244
  hub?: AssistantEventHub;
71
245
  heartbeatIntervalMs?: number;
246
+ shedReporter?: SseShedReporter;
72
247
  },
73
248
  ): ReadableStream<Uint8Array> {
74
249
  const { queryParams, headers, abortSignal } = args;
@@ -108,6 +283,7 @@ export function handleSubscribeAssistantEvents(
108
283
  const hub = options?.hub ?? assistantEventHub;
109
284
  const heartbeatIntervalMs =
110
285
  options?.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
286
+ const shedReporter = options?.shedReporter ?? defaultSseShedReporter;
111
287
 
112
288
  const ALL_CAPABILITIES: HostProxyCapability[] = [
113
289
  "host_bash",
@@ -134,6 +310,17 @@ export function handleSubscribeAssistantEvents(
134
310
  let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
135
311
  let sub!: AssistantEventSubscription;
136
312
 
313
+ const instrumentation: SseSubscriberInstrumentation = {
314
+ subscribedAtMs: Date.now(),
315
+ eventsDelivered: 0,
316
+ heartbeatsSent: 0,
317
+ clientId,
318
+ interfaceId,
319
+ conversationKey: conversationKey ?? null,
320
+ };
321
+
322
+ ensureEventLoopDelayMonitorStarted();
323
+
137
324
  function cleanup() {
138
325
  if (heartbeatTimer) {
139
326
  clearInterval(heartbeatTimer);
@@ -151,11 +338,13 @@ export function handleSubscribeAssistantEvents(
151
338
  if (!controller) return;
152
339
  try {
153
340
  if (controller.desiredSize != null && controller.desiredSize <= 0) {
341
+ shedReporter("callback_backpressure", instrumentation);
154
342
  sub.dispose();
155
343
  cleanup();
156
344
  return;
157
345
  }
158
346
  controller.enqueue(encoder.encode(formatSseFrame(event)));
347
+ instrumentation.eventsDelivered += 1;
159
348
  } catch {
160
349
  sub.dispose();
161
350
  cleanup();
@@ -205,10 +394,12 @@ export function handleSubscribeAssistantEvents(
205
394
  }
206
395
 
207
396
  controller.enqueue(encoder.encode(formatSseHeartbeat()));
397
+ instrumentation.heartbeatsSent += 1;
208
398
 
209
399
  heartbeatTimer = setInterval(() => {
210
400
  try {
211
401
  if (controller.desiredSize != null && controller.desiredSize <= 0) {
402
+ shedReporter("heartbeat_backpressure", instrumentation);
212
403
  sub.dispose();
213
404
  cleanup();
214
405
  return;
@@ -217,6 +408,7 @@ export function handleSubscribeAssistantEvents(
217
408
  hub.touchClient(clientId);
218
409
  }
219
410
  controller.enqueue(encoder.encode(formatSseHeartbeat()));
411
+ instrumentation.heartbeatsSent += 1;
220
412
  } catch {
221
413
  sub.dispose();
222
414
  cleanup();
@@ -2,14 +2,13 @@
2
2
  * Route handlers for filing management.
3
3
  *
4
4
  * `available` reflects whether the filing service is the active background
5
- * memory job for this instance. When the `memory-v2-enabled` flag is on,
5
+ * memory job for this instance. When `config.memory.v2.enabled` is true,
6
6
  * filing yields to the consolidation job (see consolidation-routes.ts) and
7
7
  * returns `available: false` so the UI can hide the row.
8
8
  */
9
9
 
10
10
  import { z } from "zod";
11
11
 
12
- import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
13
12
  import { getConfig } from "../../config/loader.js";
14
13
  import { FilingService } from "../../filing/filing-service.js";
15
14
  import { getLogger } from "../../util/logger.js";
@@ -19,7 +18,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
19
18
  const log = getLogger("filing-routes");
20
19
 
21
20
  function isFilingAvailable(): boolean {
22
- return !isAssistantFeatureFlagEnabled("memory-v2-enabled", getConfig());
21
+ return !getConfig().memory.v2.enabled;
23
22
  }
24
23
 
25
24
  // ---------------------------------------------------------------------------
@@ -26,11 +26,9 @@ import {
26
26
  type FeedItem,
27
27
  feedItemSchema,
28
28
  type FeedItemStatus,
29
- lowPriorityCollapsedSchema,
30
29
  suggestedPromptSchema,
31
30
  } from "../../home/feed-types.js";
32
31
  import { patchFeedItemStatus, readHomeFeed } from "../../home/feed-writer.js";
33
- import { runRollupProducer } from "../../home/rollup-producer.js";
34
32
  import { getSuggestedPrompts } from "../../home/suggested-prompts.js";
35
33
  import {
36
34
  addMessage,
@@ -42,26 +40,6 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
42
40
 
43
41
  const log = getLogger("home-feed-routes");
44
42
 
45
- /**
46
- * Debounce window for the on-visit rollup refresh. A GET on the feed
47
- * route fires the rollup producer fire-and-forget at most once per
48
- * window — repeat GETs within this interval (e.g. from a client that
49
- * polls aggressively, or from multiple panels opening in rapid
50
- * succession) skip the trigger and just return the cached feed.
51
- */
52
- const ON_VISIT_REFRESH_DEBOUNCE_MS = 10 * 60 * 1000;
53
-
54
- let lastOnVisitRefreshAt = 0;
55
-
56
- /**
57
- * Reset the on-visit debounce gate. Test-only — production callers
58
- * should never touch this. Exported with an underscore-prefixed name
59
- * so lint rules can flag misuse.
60
- */
61
- export function __resetOnVisitRefreshStateForTests(): void {
62
- lastOnVisitRefreshAt = 0;
63
- }
64
-
65
43
  // ---------------------------------------------------------------------------
66
44
  // Response / request schemas
67
45
  // ---------------------------------------------------------------------------
@@ -77,7 +55,6 @@ const getHomeFeedResponseSchema = z.object({
77
55
  updatedAt: z.string(),
78
56
  contextBanner: contextBannerSchema,
79
57
  suggestedPrompts: z.array(suggestedPromptSchema),
80
- lowPriorityCollapsed: lowPriorityCollapsedSchema,
81
58
  });
82
59
 
83
60
  const patchFeedItemRequestSchema = z.object({
@@ -139,15 +116,11 @@ export async function handleGetHomeFeed({
139
116
  const timeAwaySeconds = parsed;
140
117
 
141
118
  const feed = readHomeFeed();
142
- const filtered = feed.items.filter((item) => {
143
- if (item.minTimeAway === undefined) return true;
144
- return item.minTimeAway <= timeAwaySeconds;
145
- });
146
-
147
- const LOW_PRIORITY_THRESHOLD = 30;
148
- const lowPriorityItems = filtered.filter(
149
- (item) => item.priority < LOW_PRIORITY_THRESHOLD,
150
- );
119
+ // v2 schema dropped per-item `minTimeAway` gating; surface every item
120
+ // and let the client decide what to render based on its own
121
+ // session state. `timeAwaySeconds` survives only to feed the
122
+ // context-banner relative-time label.
123
+ const filtered = feed.items;
151
124
 
152
125
  const now = new Date();
153
126
  const contextBanner = {
@@ -156,11 +129,6 @@ export async function handleGetHomeFeed({
156
129
  newCount: filtered.filter((i) => i.status === "new").length,
157
130
  };
158
131
 
159
- const lowPriorityCollapsed = {
160
- count: lowPriorityItems.length,
161
- itemIds: lowPriorityItems.map((item) => item.id),
162
- };
163
-
164
132
  const suggestedPrompts = await getSuggestedPrompts();
165
133
 
166
134
  log.debug(
@@ -168,60 +136,20 @@ export async function handleGetHomeFeed({
168
136
  timeAwayBucket: timeAwayBucket(timeAwaySeconds),
169
137
  totalItems: feed.items.length,
170
138
  filteredItems: filtered.length,
171
- lowPriorityCount: lowPriorityItems.length,
172
139
  newCount: contextBanner.newCount,
173
140
  suggestedPromptsCount: suggestedPrompts.length,
174
141
  },
175
142
  "GET /v1/home/feed",
176
143
  );
177
144
 
178
- maybeTriggerOnVisitRollupRefresh(now);
179
-
180
145
  return {
181
146
  items: filtered,
182
147
  updatedAt: feed.updatedAt,
183
148
  contextBanner,
184
149
  suggestedPrompts,
185
- lowPriorityCollapsed,
186
150
  };
187
151
  }
188
152
 
189
- function maybeTriggerOnVisitRollupRefresh(now: Date): void {
190
- const nowMs = now.getTime();
191
- if (nowMs - lastOnVisitRefreshAt < ON_VISIT_REFRESH_DEBOUNCE_MS) return;
192
- const previousRefreshAt = lastOnVisitRefreshAt;
193
- lastOnVisitRefreshAt = nowMs;
194
- void runRollupProducer(now)
195
- .then((result) => {
196
- const skippedBeforeLLM =
197
- result.skippedReason === "no_provider" ||
198
- result.skippedReason === "no_actions" ||
199
- result.skippedReason === "in_flight";
200
- if (skippedBeforeLLM) {
201
- if (lastOnVisitRefreshAt === nowMs) {
202
- lastOnVisitRefreshAt = previousRefreshAt;
203
- }
204
- log.debug(
205
- { skippedReason: result.skippedReason },
206
- "On-visit rollup refresh skipped; debounce gate rolled back",
207
- );
208
- } else if (result.skippedReason !== null) {
209
- log.debug(
210
- { skippedReason: result.skippedReason },
211
- "On-visit rollup refresh skipped",
212
- );
213
- } else {
214
- log.info(
215
- { wroteCount: result.wroteCount },
216
- "On-visit rollup refresh completed",
217
- );
218
- }
219
- })
220
- .catch((err) => {
221
- log.warn({ err }, "On-visit rollup refresh failed");
222
- });
223
- }
224
-
225
153
  export async function handlePatchFeedItem({
226
154
  pathParams = {},
227
155
  body,
@@ -309,7 +237,7 @@ export const ROUTES: RouteDefinition[] = [
309
237
  type: "integer",
310
238
  required: true,
311
239
  description:
312
- "Seconds since the user was last active in the client. Used to filter items with a `minTimeAway` gate and to compute the context-banner relative-time label.",
240
+ "Seconds since the user was last active in the client. Used to compute the context-banner relative-time label.",
313
241
  },
314
242
  ],
315
243
  responseBody: getHomeFeedResponseSchema,
@@ -19,8 +19,13 @@ import type {
19
19
  HostAppControlResultPayload,
20
20
  HostAppControlState,
21
21
  } from "../../daemon/message-types/host-app-control.js";
22
+ import {
23
+ enforceSameActorOrThrow,
24
+ SAME_ACTOR_FORBIDDEN_DESCRIPTION,
25
+ } from "../auth/same-actor.js";
26
+ import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
22
27
  import * as pendingInteractions from "../pending-interactions.js";
23
- import { BadRequestError } from "./errors.js";
28
+ import { BadRequestError, ForbiddenError } from "./errors.js";
24
29
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
25
30
 
26
31
  const VALID_STATES: ReadonlySet<HostAppControlState> = new Set([
@@ -33,7 +38,7 @@ const VALID_STATES: ReadonlySet<HostAppControlState> = new Set([
33
38
  // POST /v1/host-app-control-result
34
39
  // ---------------------------------------------------------------------------
35
40
 
36
- function handleHostAppControlResult({ body }: RouteHandlerArgs) {
41
+ function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
37
42
  if (!body || typeof body !== "object") {
38
43
  throw new BadRequestError("Request body is required");
39
44
  }
@@ -72,6 +77,34 @@ function handleHostAppControlResult({ body }: RouteHandlerArgs) {
72
77
  return { accepted: true };
73
78
  }
74
79
 
80
+ // Same-actor binding: when the pending interaction has a targetClientId,
81
+ // validate the submitting client matches and the actor principals align.
82
+ // Mirrors host-browser / host-cu / host-bash result routes.
83
+ if (peeked.targetClientId != null) {
84
+ const headerMap = headers ?? {};
85
+ const submittingClientId =
86
+ headerMap["x-vellum-client-id"]?.trim() || undefined;
87
+ if (!submittingClientId) {
88
+ throw new BadRequestError(
89
+ "x-vellum-client-id header is missing for a targeted host app-control request.",
90
+ );
91
+ }
92
+ if (submittingClientId !== peeked.targetClientId) {
93
+ throw new ForbiddenError(
94
+ `Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
95
+ );
96
+ }
97
+ const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
98
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
99
+ );
100
+ enforceSameActorOrThrow({
101
+ sourceActorPrincipalId: submittingActorPrincipalId,
102
+ targetActorPrincipalId: peeked.targetActorPrincipalId,
103
+ targetClientId: peeked.targetClientId,
104
+ op: "host_app_control",
105
+ });
106
+ }
107
+
75
108
  const interaction = pendingInteractions.resolve(requestId)!;
76
109
  const conversation = findConversation(interaction.conversationId);
77
110
  if (!conversation) {
@@ -129,6 +162,15 @@ export const ROUTES: RouteDefinition[] = [
129
162
  responseBody: z.object({
130
163
  accepted: z.boolean(),
131
164
  }),
165
+ additionalResponses: {
166
+ "400": {
167
+ description:
168
+ "x-vellum-client-id header is missing for a targeted host app-control request.",
169
+ },
170
+ "403": {
171
+ description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
172
+ },
173
+ },
132
174
  handler: handleHostAppControlResult,
133
175
  },
134
176
  ];
@@ -10,15 +10,22 @@ import {
10
10
  markTargetInvalidated,
11
11
  publishCdpEvent,
12
12
  } from "../../browser-session/events.js";
13
- import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
13
+ import {
14
+ enforceSameActorOrThrow,
15
+ SAME_ACTOR_FORBIDDEN_DESCRIPTION,
16
+ } from "../auth/same-actor.js";
17
+ import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
14
18
  import * as pendingInteractions from "../pending-interactions.js";
15
- import { BadRequestError, ConflictError, NotFoundError } from "./errors.js";
19
+ import {
20
+ BadRequestError,
21
+ ConflictError,
22
+ ForbiddenError,
23
+ NotFoundError,
24
+ } from "./errors.js";
16
25
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
17
26
 
18
27
  /**
19
- * Result of attempting to resolve a host browser result frame. Used by both
20
- * the HTTP endpoint and the WS relay path so they share the same validation
21
- * and resolution semantics.
28
+ * Result of attempting to resolve a host browser result frame.
22
29
  *
23
30
  * Success → the pending interaction was consumed and the conversation was
24
31
  * notified.
@@ -30,8 +37,8 @@ export type HostBrowserResultResolution =
30
37
  | { ok: true }
31
38
  | {
32
39
  ok: false;
33
- code: "BAD_REQUEST" | "NOT_FOUND" | "CONFLICT";
34
- status: 400 | 404 | 409;
40
+ code: "BAD_REQUEST" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT";
41
+ status: 400 | 403 | 404 | 409;
35
42
  message: string;
36
43
  };
37
44
 
@@ -40,22 +47,26 @@ export type HostBrowserResultResolution =
40
47
  * the pending interaction by requestId, validates its kind is
41
48
  * `host_browser`, and forwards the response to the owning conversation.
42
49
  *
43
- * NOTE: The WebSocket `host_browser_result` frame path does NOT go
44
- * through this function it is handled by `HostBrowserProxy.resolveResult`
45
- * directly, which only consults `pendingInteractions` and does not
46
- * currently perform a kind check. That asymmetry is pre-existing; if
47
- * the WS path is ever opened to less-trusted clients, it should adopt
48
- * the same kind-check guard added here.
50
+ * Same-actor binding: when the pending interaction has a
51
+ * `targetClientId` (set by the proxy at request time when an actor is
52
+ * known), the submitting client must (a) identify itself via
53
+ * `x-vellum-client-id` matching the captured target, and (b) the
54
+ * submitting actor's principal must match the actor captured for that
55
+ * client at registration time. Mirrors the host-cu / host-bash result
56
+ * routes.
49
57
  *
50
58
  * This function does NOT perform auth — callers are expected to have
51
59
  * already authenticated the caller (the HTTP route uses
52
60
  * `requireBoundGuardian`).
53
61
  */
54
- export function resolveHostBrowserResultByRequestId(frame: {
55
- requestId?: unknown;
56
- content?: unknown;
57
- isError?: unknown;
58
- }): HostBrowserResultResolution {
62
+ export function resolveHostBrowserResultByRequestId(
63
+ frame: {
64
+ requestId?: unknown;
65
+ content?: unknown;
66
+ isError?: unknown;
67
+ },
68
+ headers?: Record<string, string | undefined>,
69
+ ): HostBrowserResultResolution {
59
70
  const { requestId, content, isError } = frame;
60
71
 
61
72
  if (!requestId || typeof requestId !== "string") {
@@ -86,11 +97,60 @@ export function resolveHostBrowserResultByRequestId(frame: {
86
97
  };
87
98
  }
88
99
 
100
+ // Validate submitting client matches the targeted client (if any).
101
+ if (peeked.targetClientId != null) {
102
+ const headerMap = headers ?? {};
103
+ const submittingClientId =
104
+ headerMap["x-vellum-client-id"]?.trim() || undefined;
105
+ if (!submittingClientId) {
106
+ return {
107
+ ok: false,
108
+ code: "BAD_REQUEST",
109
+ status: 400,
110
+ message:
111
+ "x-vellum-client-id header is missing for a targeted host browser request.",
112
+ };
113
+ }
114
+ if (submittingClientId !== peeked.targetClientId) {
115
+ return {
116
+ ok: false,
117
+ code: "FORBIDDEN",
118
+ status: 403,
119
+ message: `Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
120
+ };
121
+ }
122
+
123
+ // Defense-in-depth: require the submitting actor's principal id to match
124
+ // the actor principal id captured when the target client opened its SSE
125
+ // stream. This prevents a different authenticated user with knowledge of
126
+ // both the requestId and target clientId from submitting a result on
127
+ // behalf of the targeted client.
128
+ const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
129
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
130
+ );
131
+ try {
132
+ enforceSameActorOrThrow({
133
+ sourceActorPrincipalId: submittingActorPrincipalId,
134
+ targetActorPrincipalId: peeked.targetActorPrincipalId,
135
+ targetClientId: peeked.targetClientId,
136
+ op: "host_browser",
137
+ });
138
+ } catch (err) {
139
+ // enforceSameActorOrThrow throws ForbiddenError on rejection.
140
+ return {
141
+ ok: false,
142
+ code: "FORBIDDEN",
143
+ status: 403,
144
+ message: err instanceof Error ? err.message : "Same-actor check failed",
145
+ };
146
+ }
147
+ }
148
+
89
149
  const normalizedContent = typeof content === "string" ? content : "";
90
150
  const normalizedIsError = typeof isError === "boolean" ? isError : false;
91
151
 
92
- const proxy = HostBrowserProxy.instance;
93
- proxy.resolveResult(requestId, {
152
+ const interaction = pendingInteractions.resolve(requestId);
153
+ interaction?.rpcResolve?.({
94
154
  content: normalizedContent,
95
155
  isError: normalizedIsError,
96
156
  });
@@ -188,13 +248,18 @@ export function resolveHostBrowserSessionInvalidated(frame: {
188
248
  // POST /v1/host-browser-result
189
249
  // ---------------------------------------------------------------------------
190
250
 
191
- function handleHostBrowserResult({ body }: RouteHandlerArgs) {
251
+ function handleHostBrowserResult({ body, headers }: RouteHandlerArgs) {
192
252
  if (!body || typeof body !== "object") {
193
253
  throw new BadRequestError("Request body is required");
194
254
  }
195
255
 
196
- const resolution = resolveHostBrowserResultByRequestId(body);
256
+ const resolution = resolveHostBrowserResultByRequestId(
257
+ body,
258
+ headers as Record<string, string | undefined> | undefined,
259
+ );
197
260
  if (!resolution.ok) {
261
+ if (resolution.code === "FORBIDDEN")
262
+ throw new ForbiddenError(resolution.message);
198
263
  if (resolution.code === "NOT_FOUND")
199
264
  throw new NotFoundError(resolution.message);
200
265
  if (resolution.code === "CONFLICT")
@@ -260,6 +325,22 @@ export const ROUTES: RouteDefinition[] = [
260
325
  responseBody: z.object({
261
326
  accepted: z.boolean(),
262
327
  }),
328
+ additionalResponses: {
329
+ "400": {
330
+ description:
331
+ "x-vellum-client-id header is missing for a targeted host browser request.",
332
+ },
333
+ "403": {
334
+ description: SAME_ACTOR_FORBIDDEN_DESCRIPTION,
335
+ },
336
+ "404": {
337
+ description: "No pending browser request for the given requestId.",
338
+ },
339
+ "409": {
340
+ description:
341
+ "Pending interaction kind is not host_browser (mismatched proxy ID space).",
342
+ },
343
+ },
263
344
  handler: handleHostBrowserResult,
264
345
  },
265
346
  {