@vellumai/assistant 0.7.0 → 0.7.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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -8,18 +8,21 @@
8
8
  import { and, desc, eq, inArray, sql } from "drizzle-orm";
9
9
  import { z } from "zod";
10
10
 
11
+ import {
12
+ checkpointKey,
13
+ CK_ITEM_COUNT,
14
+ CK_LAST_GEN_AT,
15
+ countActiveMemoryNodes,
16
+ getCheckpointValue,
17
+ parseCheckpointInt,
18
+ } from "../../memory/conversation-starter-checkpoints.js";
11
19
  import {
12
20
  buildConversationStarterValidationContext,
13
21
  isValidConversationStarterText,
14
22
  } from "../../memory/conversation-starter-validation.js";
15
23
  import { getDb } from "../../memory/db-connection.js";
16
24
  import { enqueueMemoryJob } from "../../memory/jobs-store.js";
17
- import { rawGet } from "../../memory/raw-query.js";
18
- import {
19
- conversationStarters,
20
- memoryCheckpoints,
21
- memoryJobs,
22
- } from "../../memory/schema.js";
25
+ import { conversationStarters, memoryJobs } from "../../memory/schema.js";
23
26
  import { NotFoundError } from "./errors.js";
24
27
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
25
28
 
@@ -36,19 +39,10 @@ interface StarterItem {
36
39
  batch: number;
37
40
  }
38
41
 
39
- const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
40
- const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
41
42
  export const CONVERSATION_STARTERS_STALE_TTL_MS = 24 * 60 * 60 * 1000;
42
43
 
43
- function checkpointKey(base: string, scopeId: string): string {
44
- return `${base}:${scopeId}`;
45
- }
46
-
47
- function parseCheckpointInt(value: string | undefined): number | null {
48
- if (!value) return null;
49
- const parsed = Number.parseInt(value, 10);
50
- return Number.isFinite(parsed) ? parsed : null;
51
- }
44
+ /** Minimum interval between re-enqueue attempts triggered by invalid items. */
45
+ const REFRESH_COOLDOWN_MS = 60_000;
52
46
 
53
47
  function hasActiveConversationStarterJob(
54
48
  db: ReturnType<typeof getDb>,
@@ -190,36 +184,24 @@ function handleListConversationStarters({
190
184
  const total = validItems.length;
191
185
 
192
186
  if (allItems.length > 0) {
193
- const totalActive =
194
- rawGet<{ c: number }>(
195
- `SELECT COUNT(*) AS c FROM memory_graph_nodes WHERE fidelity != 'gone' AND scope_id = ?`,
196
- scopeId,
197
- )?.c ?? 0;
187
+ const totalActive = countActiveMemoryNodes(scopeId);
198
188
  const lastCount = parseCheckpointInt(
199
- db
200
- .select({ value: memoryCheckpoints.value })
201
- .from(memoryCheckpoints)
202
- .where(eq(memoryCheckpoints.key, checkpointKey(CK_ITEM_COUNT, scopeId)))
203
- .get()?.value,
189
+ getCheckpointValue(checkpointKey(CK_ITEM_COUNT, scopeId)),
204
190
  );
205
191
  const lastGenAt = parseCheckpointInt(
206
- db
207
- .select({ value: memoryCheckpoints.value })
208
- .from(memoryCheckpoints)
209
- .where(
210
- eq(memoryCheckpoints.key, checkpointKey(CK_LAST_GEN_AT, scopeId)),
211
- )
212
- .get()?.value,
192
+ getCheckpointValue(checkpointKey(CK_LAST_GEN_AT, scopeId)),
213
193
  );
214
194
  const staleByAge =
215
195
  lastGenAt == null ||
216
196
  Date.now() - lastGenAt >= CONVERSATION_STARTERS_STALE_TTL_MS;
217
197
  const checkpointAhead = lastCount != null && totalActive < lastCount;
218
198
  let hasActiveJob = hasActiveConversationStarterJob(db, scopeId);
199
+ const withinCooldown =
200
+ lastGenAt != null && Date.now() - lastGenAt < REFRESH_COOLDOWN_MS;
219
201
  const shouldRefresh =
220
202
  staleByAge ||
221
203
  checkpointAhead ||
222
- (invalidItemCount > 0 && totalActive > 0);
204
+ (invalidItemCount > 0 && totalActive > 0 && !withinCooldown);
223
205
 
224
206
  if (shouldRefresh && !hasActiveJob) {
225
207
  enqueueMemoryJob("generate_conversation_starters", { scopeId });
@@ -235,12 +217,9 @@ function handleListConversationStarters({
235
217
  };
236
218
  }
237
219
 
238
- const memoryCount = rawGet<{ c: number }>(
239
- `SELECT COUNT(*) AS c FROM memory_graph_nodes WHERE fidelity != 'gone' AND scope_id = ?`,
240
- scopeId,
241
- );
220
+ const memoryCount = countActiveMemoryNodes(scopeId);
242
221
 
243
- if (!memoryCount || memoryCount.c === 0) {
222
+ if (memoryCount === 0) {
244
223
  return { starters: [], total: 0, status: "empty" };
245
224
  }
246
225
 
@@ -25,6 +25,23 @@ interface DocumentRow {
25
25
 
26
26
  type DocumentListRow = Omit<DocumentRow, "content">;
27
27
 
28
+ // ---------------------------------------------------------------------------
29
+ // Junction table helper
30
+ // ---------------------------------------------------------------------------
31
+
32
+ /** Insert a document–conversation association (idempotent via INSERT OR IGNORE). */
33
+ function addDocumentConversation(
34
+ surfaceId: string,
35
+ conversationId: string,
36
+ ): void {
37
+ rawRun(
38
+ /*sql*/ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
39
+ surfaceId,
40
+ conversationId,
41
+ Date.now(),
42
+ );
43
+ }
44
+
28
45
  // ---------------------------------------------------------------------------
29
46
  // Shared business logic (used by both message handlers and HTTP routes)
30
47
  // ---------------------------------------------------------------------------
@@ -58,6 +75,20 @@ function saveDocument(params: {
58
75
  { surfaceId: params.surfaceId, title: params.title },
59
76
  "Saved document",
60
77
  );
78
+
79
+ // Best-effort: associate the document with the conversation.
80
+ // Failures (e.g. migration not yet applied, table missing) must not
81
+ // cause the save response to report failure — the document itself is
82
+ // already persisted at this point.
83
+ try {
84
+ addDocumentConversation(params.surfaceId, params.conversationId);
85
+ } catch (err) {
86
+ log.warn(
87
+ { err, surfaceId: params.surfaceId },
88
+ "Failed to record document–conversation association",
89
+ );
90
+ }
91
+
61
92
  return { success: true, surfaceId: params.surfaceId };
62
93
  } catch (error) {
63
94
  log.error({ err: error, surfaceId: params.surfaceId }, "Save error");
@@ -123,21 +154,30 @@ function listDocuments(conversationId?: string): Array<{
123
154
  updatedAt: number;
124
155
  }> {
125
156
  try {
126
- let query = /*sql*/ `
127
- SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
128
- FROM documents
129
- `;
130
- const params: string[] = [];
157
+ let results: DocumentListRow[];
131
158
 
132
159
  if (conversationId) {
133
- query += " WHERE conversation_id = ?";
134
- params.push(conversationId);
160
+ // Query via junction table so we return the *matched* conversation_id
161
+ // (not the origin conversation_id from the documents table).
162
+ results = rawAll<DocumentListRow>(
163
+ /*sql*/ `
164
+ SELECT d.surface_id, dc.conversation_id AS conversation_id,
165
+ d.title, d.word_count, d.created_at, d.updated_at
166
+ FROM documents d
167
+ INNER JOIN document_conversations dc ON d.surface_id = dc.surface_id
168
+ WHERE dc.conversation_id = ?
169
+ ORDER BY d.updated_at DESC
170
+ `,
171
+ conversationId,
172
+ );
173
+ } else {
174
+ results = rawAll<DocumentListRow>(/*sql*/ `
175
+ SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
176
+ FROM documents
177
+ ORDER BY updated_at DESC
178
+ `);
135
179
  }
136
180
 
137
- query += " ORDER BY updated_at DESC";
138
-
139
- const results = rawAll<DocumentListRow>(query, ...params);
140
-
141
181
  log.info({ count: results.length }, "Listed documents");
142
182
  return results.map((row) => ({
143
183
  surfaceId: row.surface_id,
@@ -233,13 +273,8 @@ export const ROUTES: RouteDefinition[] = [
233
273
  surfaceId: z.string(),
234
274
  }),
235
275
  handler: ({ body }) => {
236
- const {
237
- surfaceId,
238
- conversationId,
239
- title,
240
- content,
241
- wordCount,
242
- } = (body ?? {}) as {
276
+ const { surfaceId, conversationId, title, content, wordCount } = (body ??
277
+ {}) as {
243
278
  surfaceId?: string;
244
279
  conversationId?: string;
245
280
  title?: string;
@@ -11,30 +11,20 @@
11
11
  * that conversation. When omitted, subscribers receive events from ALL
12
12
  * conversations for this assistant (unfiltered).
13
13
  *
14
- * If the conversationKey has no server-side mapping yet (e.g. a client-
15
- * generated draft UUID that has not been sent a first message), this
16
- * handler eagerly materialises the conversation so the subscriber's
17
- * `filter.conversationId` matches the id under which the first turn's
18
- * scoped events (text deltas, tool calls, message_complete) will be
19
- * published by `handleSendMessage`. The `conversation_list_invalidated`
20
- * notification for other clients is driven by `handleSendMessage`'s
21
- * first-message check, so eager materialisation here is safe and does
22
- * not hide the first-message notification from other clients.
23
- *
24
14
  * Client registration:
25
15
  * Clients may send `X-Vellum-Client-Id` and `X-Vellum-Interface-Id`
26
- * request headers to register in the ClientRegistry on connect and
27
- * automatically unregister on disconnect. When both headers are present,
28
- * the client is registered immediately, touched on each heartbeat, and
29
- * unregistered when the stream closes. When either header is missing,
30
- * registration is skipped (backwards compat).
16
+ * request headers. When both are present, the subscriber is registered
17
+ * as a client in the event hub with derived capabilities. The hub
18
+ * handles registration, touch (heartbeat), and unregistration (dispose).
31
19
  */
32
20
 
33
- import { parseInterfaceId } from "../../channels/types.js";
21
+ import type { HostProxyCapability } from "../../channels/types.js";
22
+ import { parseInterfaceId, supportsHostProxy } from "../../channels/types.js";
34
23
  import { getOrCreateConversation } from "../../memory/conversation-key-store.js";
35
24
  import { getLogger } from "../../util/logger.js";
36
25
  import { formatSseFrame, formatSseHeartbeat } from "../assistant-event.js";
37
26
  import type {
27
+ AssistantEventCallback,
38
28
  AssistantEventFilter,
39
29
  AssistantEventSubscription,
40
30
  } from "../assistant-event-hub.js";
@@ -42,15 +32,13 @@ import {
42
32
  AssistantEventHub,
43
33
  assistantEventHub,
44
34
  } from "../assistant-event-hub.js";
45
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
46
- import { getClientRegistry } from "../client-registry.js";
47
35
  import { BadRequestError, ServiceUnavailableError } from "./errors.js";
48
36
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
49
37
 
50
38
  const log = getLogger("events-routes");
51
39
 
52
- /** Keep-alive comment sent to idle clients every 30 s by default. */
53
- const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;
40
+ /** Keep-alive comment sent to idle clients every 7 s by default. */
41
+ const DEFAULT_HEARTBEAT_INTERVAL_MS = 7_000;
54
42
 
55
43
  /**
56
44
  * Stream assistant events as Server-Sent Events.
@@ -64,12 +52,13 @@ const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;
64
52
  * X-Vellum-Client-Id -- stable per-install UUID identifying this client.
65
53
  * X-Vellum-Interface-Id -- interface type (e.g. "macos", "ios", "web").
66
54
  *
67
- * When both are present the client is registered in the ClientRegistry on
68
- * connect and unregistered on disconnect.
55
+ * When both are present, the subscriber is registered as a client in the
56
+ * event hub with metadata (interfaceId, capabilities). The hub handles
57
+ * lifecycle — dispose() unregisters the client automatically.
69
58
  *
70
59
  * Options (for testing):
71
60
  * hub -- override the event hub (defaults to process singleton).
72
- * heartbeatIntervalMs -- how often to emit keep-alive comments (default 30 s).
61
+ * heartbeatIntervalMs -- how often to emit keep-alive comments (default 7 s).
73
62
  */
74
63
  export function handleSubscribeAssistantEvents(
75
64
  args: RouteHandlerArgs,
@@ -85,7 +74,7 @@ export function handleSubscribeAssistantEvents(
85
74
  throw new BadRequestError("conversationKey must not be empty");
86
75
  }
87
76
 
88
- // ── Client registration from headers ──────────────────────────────────
77
+ // ── Client identity from headers ──────────────────────────────────────
89
78
  const rawClientId = headers?.["x-vellum-client-id"];
90
79
  const rawInterfaceId = headers?.["x-vellum-interface-id"];
91
80
  const clientId = rawClientId?.trim() || null;
@@ -103,32 +92,23 @@ export function handleSubscribeAssistantEvents(
103
92
  );
104
93
  }
105
94
 
106
- const registry = getClientRegistry();
107
- if (clientId && interfaceId) {
108
- registry.register({ clientId, interfaceId });
109
- log.info(
110
- { clientId, interfaceId },
111
- "client registered via /events SSE connect",
112
- );
113
- }
114
-
115
95
  const hub = options?.hub ?? assistantEventHub;
116
96
  const heartbeatIntervalMs =
117
97
  options?.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
118
98
 
119
- const filter: AssistantEventFilter = {
120
- assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
121
- };
99
+ const ALL_CAPABILITIES: HostProxyCapability[] = [
100
+ "host_bash",
101
+ "host_file",
102
+ "host_cu",
103
+ "host_browser",
104
+ ];
105
+
106
+ const filter: AssistantEventFilter = {};
122
107
  if (conversationKey) {
123
- // Eagerly resolve (and if necessary create) the conversation so the
124
- // subscriber's filter matches the id under which first-turn scoped
125
- // events will be published. The `conversation_list_invalidated`
126
- // publish is driven by `handleSendMessage`'s first-message check,
127
- // so eager materialisation here is safe and does not suppress the
128
- // cross-client notification.
129
108
  const mapping = getOrCreateConversation(conversationKey);
130
109
  filter.conversationId = mapping.conversationId;
131
110
  }
111
+
132
112
  const encoder = new TextEncoder();
133
113
 
134
114
  // -- Eager subscribe --------------------------------------------------------
@@ -145,9 +125,6 @@ export function handleSubscribeAssistantEvents(
145
125
  clearInterval(heartbeatTimer);
146
126
  heartbeatTimer = null;
147
127
  }
148
- if (clientId) {
149
- registry.unregister(clientId);
150
- }
151
128
  try {
152
129
  controllerRef?.close();
153
130
  } catch {
@@ -155,85 +132,76 @@ export function handleSubscribeAssistantEvents(
155
132
  }
156
133
  }
157
134
 
135
+ const callback: AssistantEventCallback = (event) => {
136
+ const controller = controllerRef;
137
+ if (!controller) return;
138
+ try {
139
+ if (controller.desiredSize != null && controller.desiredSize <= 0) {
140
+ sub.dispose();
141
+ cleanup();
142
+ return;
143
+ }
144
+ controller.enqueue(encoder.encode(formatSseFrame(event)));
145
+ } catch {
146
+ sub.dispose();
147
+ cleanup();
148
+ }
149
+ };
150
+
158
151
  try {
159
- sub = hub.subscribe(
152
+ const subscriberBase = {
160
153
  filter,
161
- (event) => {
162
- const controller = controllerRef;
163
- if (!controller) return;
164
- try {
165
- // Shed stalled consumers: desiredSize <= 0 means the 16-event buffer
166
- // is full and the client isn't draining it.
167
- if (controller.desiredSize != null && controller.desiredSize <= 0) {
168
- sub.dispose();
169
- cleanup();
170
- return;
171
- }
172
- controller.enqueue(encoder.encode(formatSseFrame(event)));
173
- } catch {
174
- sub.dispose();
175
- cleanup();
176
- }
177
- },
178
- {
179
- // Called by the hub when a newer connection evicts this one (capacity
180
- // management: oldest subscriber out, newest in).
181
- onEvict: cleanup,
182
- },
183
- );
154
+ callback,
155
+ onEvict: cleanup,
156
+ };
157
+
158
+ sub =
159
+ clientId && interfaceId
160
+ ? hub.subscribe({
161
+ ...subscriberBase,
162
+ type: "client" as const,
163
+ clientId,
164
+ interfaceId,
165
+ capabilities: ALL_CAPABILITIES.filter((cap) =>
166
+ supportsHostProxy(interfaceId, cap),
167
+ ),
168
+ })
169
+ : hub.subscribe({
170
+ ...subscriberBase,
171
+ type: "process" as const,
172
+ });
184
173
  } catch (err) {
185
174
  if (err instanceof RangeError) {
186
- if (clientId) {
187
- registry.unregister(clientId);
188
- }
189
175
  throw new ServiceUnavailableError("Too many concurrent connections");
190
176
  }
191
177
  throw err;
192
178
  }
193
179
 
194
- // Allow up to 16 queued frames before treating the consumer as stalled.
195
- // This absorbs normal token-stream bursts without prematurely closing the
196
- // connection, while still shedding genuinely slow clients.
197
180
  const stream = new ReadableStream<Uint8Array>(
198
181
  {
199
182
  start(controller) {
200
183
  controllerRef = controller;
201
184
 
202
- // If the client already disconnected before start() ran, clean up
203
- // immediately -- the abort event fires once and won't be re-dispatched.
204
185
  if (abortSignal?.aborted) {
205
186
  sub.dispose();
206
187
  cleanup();
207
188
  return;
208
189
  }
209
190
 
210
- // Immediately enqueue a heartbeat comment so the HTTP status line and
211
- // headers are flushed to the client without waiting for a real event.
212
- // Without this, Bun may buffer the headers until the first data chunk
213
- // arrives, causing clients (e.g. Python `requests`) to hang until the
214
- // periodic heartbeat fires or an event is published.
215
191
  controller.enqueue(encoder.encode(formatSseHeartbeat()));
216
192
 
217
- // Send a keep-alive comment on each interval to prevent proxies and
218
- // load-balancers from treating idle connections as timed out.
219
193
  heartbeatTimer = setInterval(() => {
220
194
  try {
221
- // Apply the same slow-consumer guard as the event path: stop
222
- // feeding heartbeats into a queue the client is not draining.
223
195
  if (controller.desiredSize != null && controller.desiredSize <= 0) {
224
196
  sub.dispose();
225
197
  cleanup();
226
198
  return;
227
199
  }
228
- // Touch the client on each heartbeat to keep it fresh in the
229
- // registry. Without this, long-idle SSE connections would be
230
- // evicted by the staleness sweep despite being connected.
231
200
  if (clientId) {
232
- registry.touch(clientId);
201
+ hub.touchClient(clientId);
233
202
  }
234
203
  controller.enqueue(encoder.encode(formatSseHeartbeat()));
235
204
  } catch {
236
- // Controller already closed (e.g. client disconnected).
237
205
  sub.dispose();
238
206
  cleanup();
239
207
  }
@@ -1,17 +1,27 @@
1
1
  /**
2
2
  * Route handlers for filing management.
3
+ *
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,
6
+ * filing yields to the consolidation job (see consolidation-routes.ts) and
7
+ * returns `available: false` so the UI can hide the row.
3
8
  */
4
9
 
5
10
  import { z } from "zod";
6
11
 
12
+ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
7
13
  import { getConfig } from "../../config/loader.js";
8
14
  import { FilingService } from "../../filing/filing-service.js";
9
15
  import { getLogger } from "../../util/logger.js";
10
- import { InternalError } from "./errors.js";
16
+ import { BadRequestError, InternalError } from "./errors.js";
11
17
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
12
18
 
13
19
  const log = getLogger("filing-routes");
14
20
 
21
+ function isFilingAvailable(): boolean {
22
+ return !isAssistantFeatureFlagEnabled("memory-v2-enabled", getConfig());
23
+ }
24
+
15
25
  // ---------------------------------------------------------------------------
16
26
  // Shared ROUTES
17
27
  // ---------------------------------------------------------------------------
@@ -27,6 +37,7 @@ export const ROUTES: RouteDefinition[] = [
27
37
  description: "Return the current filing schedule configuration.",
28
38
  tags: ["filing"],
29
39
  responseBody: z.object({
40
+ available: z.boolean(),
30
41
  enabled: z.boolean(),
31
42
  intervalMs: z.number(),
32
43
  activeHoursStart: z.number().nullable(),
@@ -39,6 +50,7 @@ export const ROUTES: RouteDefinition[] = [
39
50
  const config = getConfig().filing;
40
51
  const svc = FilingService.getInstance();
41
52
  return {
53
+ available: isFilingAvailable(),
42
54
  enabled: config.enabled,
43
55
  intervalMs: config.intervalMs,
44
56
  activeHoursStart: config.activeHoursStart ?? null,
@@ -63,6 +75,11 @@ export const ROUTES: RouteDefinition[] = [
63
75
  ran: z.boolean().describe("Whether the filing actually ran"),
64
76
  }),
65
77
  handler: async (_args: RouteHandlerArgs) => {
78
+ if (!isFilingAvailable()) {
79
+ throw new BadRequestError(
80
+ "Filing is not the active background memory job (memory v2 is enabled)",
81
+ );
82
+ }
66
83
  const svc = FilingService.getInstance();
67
84
  if (!svc) {
68
85
  throw new InternalError("Filing service not available");
@@ -29,15 +29,11 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
29
29
  // GET /v1/guardian-actions/pending?conversationId=...
30
30
  // ---------------------------------------------------------------------------
31
31
 
32
- function handleGuardianActionsPending({
33
- queryParams = {},
34
- }: RouteHandlerArgs) {
32
+ function handleGuardianActionsPending({ queryParams = {} }: RouteHandlerArgs) {
35
33
  const conversationId = queryParams.conversationId;
36
34
 
37
35
  if (!conversationId) {
38
- throw new BadRequestError(
39
- "conversationId query parameter is required",
40
- );
36
+ throw new BadRequestError("conversationId query parameter is required");
41
37
  }
42
38
 
43
39
  const prompts = listGuardianDecisionPrompts({
@@ -51,7 +47,7 @@ function handleGuardianActionsPending({
51
47
  // POST /v1/guardian-actions/decision
52
48
  // ---------------------------------------------------------------------------
53
49
 
54
- export async function handleGuardianActionDecision({
50
+ async function handleGuardianActionDecision({
55
51
  body,
56
52
  headers = {},
57
53
  }: RouteHandlerArgs) {
@@ -231,8 +227,7 @@ export const ROUTES: RouteDefinition[] = [
231
227
  endpoint: "guardian-actions/pending",
232
228
  method: "GET",
233
229
  summary: "List pending guardian actions",
234
- description:
235
- "Return pending guardian decision prompts for a conversation.",
230
+ description: "Return pending guardian decision prompts for a conversation.",
236
231
  tags: ["guardian"],
237
232
  queryParams: [
238
233
  {
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { z } from "zod";
8
8
 
9
+ import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
9
10
  import * as pendingInteractions from "../pending-interactions.js";
10
11
  import {
11
12
  BadRequestError,
@@ -48,9 +49,9 @@ function handleHostBashResult({ body }: RouteHandlerArgs) {
48
49
  );
49
50
  }
50
51
 
51
- const interaction = pendingInteractions.resolve(requestId)!;
52
+ pendingInteractions.resolve(requestId);
52
53
 
53
- interaction.conversation!.resolveHostBash(requestId, {
54
+ HostBashProxy.instance.resolve(requestId, {
54
55
  stdout: stdout ?? "",
55
56
  stderr: stderr ?? "",
56
57
  exitCode: exitCode ?? null,
@@ -10,8 +10,8 @@ import {
10
10
  markTargetInvalidated,
11
11
  publishCdpEvent,
12
12
  } from "../../browser-session/events.js";
13
- import * as pendingInteractions from "../pending-interactions.js";
14
- import { BadRequestError, ConflictError, NotFoundError } from "./errors.js";
13
+ import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
14
+ import { BadRequestError, NotFoundError } from "./errors.js";
15
15
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
16
16
 
17
17
  /**
@@ -29,8 +29,8 @@ export type HostBrowserResultResolution =
29
29
  | { ok: true }
30
30
  | {
31
31
  ok: false;
32
- code: "BAD_REQUEST" | "NOT_FOUND" | "CONFLICT";
33
- status: 400 | 404 | 409;
32
+ code: "BAD_REQUEST" | "NOT_FOUND";
33
+ status: 400 | 404;
34
34
  message: string;
35
35
  };
36
36
 
@@ -61,10 +61,8 @@ export function resolveHostBrowserResultByRequestId(frame: {
61
61
  };
62
62
  }
63
63
 
64
- // Peek first (non-destructive) so we can validate the interaction kind
65
- // without accidentally consuming a confirmation or secret interaction.
66
- const peeked = pendingInteractions.get(requestId);
67
- if (!peeked) {
64
+ const proxy = HostBrowserProxy.instance;
65
+ if (!proxy.hasPendingRequest(requestId)) {
68
66
  return {
69
67
  ok: false,
70
68
  code: "NOT_FOUND",
@@ -73,32 +71,10 @@ export function resolveHostBrowserResultByRequestId(frame: {
73
71
  };
74
72
  }
75
73
 
76
- if (peeked.kind !== "host_browser") {
77
- return {
78
- ok: false,
79
- code: "CONFLICT",
80
- status: 409,
81
- message: `Pending interaction is of kind "${peeked.kind}", expected "host_browser"`,
82
- };
83
- }
84
-
85
- // Validation passed — consume the pending interaction.
86
- const interaction = pendingInteractions.resolve(requestId)!;
87
-
88
74
  const normalizedContent = typeof content === "string" ? content : "";
89
75
  const normalizedIsError = typeof isError === "boolean" ? isError : false;
90
76
 
91
- if (!interaction.conversation) {
92
- return {
93
- ok: false,
94
- code: "BAD_REQUEST",
95
- status: 400,
96
- message:
97
- "host_browser pending interaction has no associated conversation",
98
- };
99
- }
100
-
101
- interaction.conversation.resolveHostBrowser(requestId, {
77
+ proxy.resolve(requestId, {
102
78
  content: normalizedContent,
103
79
  isError: normalizedIsError,
104
80
  });
@@ -203,8 +179,8 @@ function handleHostBrowserResult({ body }: RouteHandlerArgs) {
203
179
 
204
180
  const resolution = resolveHostBrowserResultByRequestId(body);
205
181
  if (!resolution.ok) {
206
- if (resolution.code === "NOT_FOUND") throw new NotFoundError(resolution.message);
207
- if (resolution.code === "CONFLICT") throw new ConflictError(resolution.message);
182
+ if (resolution.code === "NOT_FOUND")
183
+ throw new NotFoundError(resolution.message);
208
184
  throw new BadRequestError(resolution.message);
209
185
  }
210
186
 
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { z } from "zod";
8
8
 
9
+ import { findConversation } from "../../daemon/conversation-store.js";
9
10
  import * as pendingInteractions from "../pending-interactions.js";
10
11
  import {
11
12
  BadRequestError,
@@ -69,8 +70,12 @@ function handleHostCuResult({ body }: RouteHandlerArgs) {
69
70
  }
70
71
 
71
72
  const interaction = pendingInteractions.resolve(requestId)!;
73
+ const conversation = findConversation(interaction.conversationId);
74
+ if (!conversation) {
75
+ throw new NotFoundError("Conversation not found for host CU result");
76
+ }
72
77
 
73
- interaction.conversation!.resolveHostCu(requestId, {
78
+ conversation.hostCuProxy?.resolve(requestId, {
74
79
  axTree,
75
80
  axDiff,
76
81
  screenshot,