@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
@@ -18,11 +18,8 @@ import {
18
18
  createUserMessage,
19
19
  } from "../../agent/message-types.js";
20
20
  import {
21
- canServiceRegistryBrowser,
22
- canServiceSseBrowser,
23
21
  CHANNEL_IDS,
24
22
  INTERFACE_IDS,
25
- type InterfaceId,
26
23
  isInteractiveInterface,
27
24
  parseChannelId,
28
25
  parseInterfaceId,
@@ -38,8 +35,8 @@ import {
38
35
  isModelSlashCommand,
39
36
  } from "../../daemon/conversation-process.js";
40
37
  import {
38
+ buildSlashContextForContent,
41
39
  resolveSlash,
42
- type SlashContext,
43
40
  } from "../../daemon/conversation-slash.js";
44
41
  import { getOrCreateConversation as getOrCreateConversationInstance } from "../../daemon/conversation-store.js";
45
42
  import {
@@ -47,23 +44,17 @@ import {
47
44
  isWakeUpGreeting,
48
45
  } from "../../daemon/first-greeting.js";
49
46
  import { renderHistoryContent } from "../../daemon/handlers/shared.js";
50
- import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
51
- import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
52
47
  import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
53
- import { HostFileProxy } from "../../daemon/host-file-proxy.js";
54
- import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
55
48
  import type { ServerMessage } from "../../daemon/message-protocol.js";
56
49
  import type {
57
50
  HostProxyTransportMetadata,
58
51
  NonHostProxyTransportMetadata,
59
52
  } from "../../daemon/message-types/conversations.js";
60
53
  import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
61
- import { emitFeedEvent } from "../../home/emit-feed-event.js";
62
54
  import {
63
55
  writeOnboardingSidecar,
64
56
  writeRelationshipState,
65
57
  } from "../../home/relationship-state-writer.js";
66
- import { rewriteCommandPreview } from "../../home/rewrite-command-preview.js";
67
58
  import { ipcCall } from "../../ipc/gateway-client.js";
68
59
  import {
69
60
  getAttachmentById,
@@ -72,8 +63,6 @@ import {
72
63
  getSourcePathsForAttachments,
73
64
  } from "../../memory/attachments-store.js";
74
65
  import {
75
- createCanonicalGuardianRequest,
76
- generateCanonicalRequestCode,
77
66
  listCanonicalGuardianRequests,
78
67
  listPendingRequestsByConversationScope,
79
68
  resolveCanonicalGuardianRequest,
@@ -98,8 +87,6 @@ import { searchConversations } from "../../memory/conversation-queries.js";
98
87
  import { getConfiguredProvider } from "../../providers/provider-send-message.js";
99
88
  import type { Provider } from "../../providers/types.js";
100
89
  import { checkIngressForSecrets } from "../../security/secret-ingress.js";
101
- import { redactSecrets } from "../../security/secret-scanner.js";
102
- import { summarizeToolInput } from "../../tools/tool-input-summary.js";
103
90
  import { getLogger } from "../../util/logger.js";
104
91
  import {
105
92
  getInterfacesDir,
@@ -107,11 +94,8 @@ import {
107
94
  } from "../../util/platform.js";
108
95
  import { silentlyWithLog } from "../../util/silently.js";
109
96
  import { buildAssistantEvent } from "../assistant-event.js";
110
- import { assistantEventHub } from "../assistant-event-hub.js";
97
+ import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
111
98
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
112
- import { getChromeExtensionRegistry } from "../chrome-extension-registry.js";
113
- import { getClientRegistry } from "../client-registry.js";
114
- import { bridgeConfirmationRequestToGuardian } from "../confirmation-request-guardian-bridge.js";
115
99
  import { routeGuardianReply } from "../guardian-reply-router.js";
116
100
  import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
117
101
  import type {
@@ -357,18 +341,6 @@ async function tryConsumeCanonicalGuardianReply(params: {
357
341
  return { consumed: true, messageId };
358
342
  }
359
343
 
360
- function resolveCanonicalRequestSourceType(
361
- sourceChannel: string | undefined,
362
- ): "desktop" | "channel" | "voice" {
363
- if (sourceChannel === "phone") {
364
- return "voice";
365
- }
366
- if (sourceChannel === "vellum") {
367
- return "desktop";
368
- }
369
- return "channel";
370
- }
371
-
372
344
  function getInterfaceFilesWithMtimes(
373
345
  interfacesDir: string | null,
374
346
  ): Array<{ path: string; mtimeMs: number }> {
@@ -1022,348 +994,6 @@ function mergeConsecutiveAssistantMessages(messages: MessageRow[]): {
1022
994
  return { messages: result, mergedIdMap };
1023
995
  }
1024
996
 
1025
- /**
1026
- * Build an `onEvent` callback that publishes every outbound event to the
1027
- * assistant event hub, maintaining ordered delivery through a serial chain.
1028
- *
1029
- * Also registers pending interactions when confirmation_request,
1030
- * secret_request, host_bash_request, host_browser_request, host_file_request,
1031
- * or host_cu_request events flow through, so standalone approval/result
1032
- * endpoints can look up the conversation by requestId.
1033
- */
1034
- function makeHubPublisher(
1035
- deps: SendMessageDeps,
1036
- conversationId: string,
1037
- conversation: Conversation,
1038
- ): (msg: ServerMessage) => void {
1039
- let hubChain: Promise<void> = Promise.resolve();
1040
- return (msg: ServerMessage) => {
1041
- // Register pending interactions for approval events
1042
- if (msg.type === "confirmation_request") {
1043
- pendingInteractions.register(msg.requestId, {
1044
- conversation,
1045
- conversationId,
1046
- kind: "confirmation",
1047
- confirmationDetails: {
1048
- toolName: msg.toolName,
1049
- input: msg.input,
1050
- riskLevel: msg.riskLevel,
1051
- executionTarget: msg.executionTarget,
1052
- allowlistOptions: msg.allowlistOptions,
1053
- scopeOptions: msg.scopeOptions,
1054
- persistentDecisionsAllowed: msg.persistentDecisionsAllowed,
1055
- },
1056
- });
1057
-
1058
- const inputRecord = msg.input as Record<string, unknown>;
1059
- const commandPreview =
1060
- redactSecrets(summarizeToolInput(msg.toolName, inputRecord)) ||
1061
- undefined;
1062
- const technicalTitle = commandPreview
1063
- ? `Requesting permission: ${commandPreview}`
1064
- : `Requesting approval to use ${msg.toolName}.`;
1065
- const dedupKey = `tool-approval:${msg.requestId}`;
1066
-
1067
- // Emit immediately with the technical preview.
1068
- void emitFeedEvent({
1069
- source: "assistant",
1070
- title: technicalTitle,
1071
- summary: technicalTitle,
1072
- dedupKey,
1073
- urgency: msg.riskLevel === "high" ? "high" : "medium",
1074
- conversationId,
1075
- detailPanel: { kind: "toolPermission" },
1076
- }).catch((err) => {
1077
- log.warn(
1078
- { err, requestId: msg.requestId },
1079
- "Failed to emit tool approval request feed event",
1080
- );
1081
- });
1082
-
1083
- // Background: rewrite into prose and update the feed item.
1084
- if (commandPreview) {
1085
- void rewriteCommandPreview(msg.toolName, commandPreview)
1086
- .then((prose) => {
1087
- if (prose) {
1088
- const proseTitle = `Requesting permission: ${prose}`;
1089
- return emitFeedEvent({
1090
- source: "assistant",
1091
- title: proseTitle,
1092
- summary: proseTitle,
1093
- dedupKey,
1094
- urgency: msg.riskLevel === "high" ? "high" : "medium",
1095
- conversationId,
1096
- detailPanel: { kind: "toolPermission" },
1097
- });
1098
- }
1099
- })
1100
- .catch((err) => {
1101
- log.warn(
1102
- { err, requestId: msg.requestId },
1103
- "Failed to update feed event with prose rewrite",
1104
- );
1105
- });
1106
- }
1107
-
1108
- // Create a canonical guardian request so HTTP handlers can find it
1109
- // via applyCanonicalGuardianDecision.
1110
- try {
1111
- const trustContext = conversation.trustContext;
1112
- const sourceChannel = trustContext?.sourceChannel ?? "vellum";
1113
- const inputRecord = msg.input as Record<string, unknown>;
1114
- const activityRaw =
1115
- (typeof inputRecord.activity === "string"
1116
- ? inputRecord.activity
1117
- : undefined) ??
1118
- (typeof inputRecord.reason === "string"
1119
- ? inputRecord.reason
1120
- : undefined);
1121
- const canonicalRequest = createCanonicalGuardianRequest({
1122
- id: msg.requestId,
1123
- kind: "tool_approval",
1124
- sourceType: resolveCanonicalRequestSourceType(sourceChannel),
1125
- sourceChannel,
1126
- conversationId,
1127
- requesterExternalUserId: trustContext?.requesterExternalUserId,
1128
- requesterChatId: trustContext?.requesterChatId,
1129
- guardianExternalUserId: trustContext?.guardianExternalUserId,
1130
- guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
1131
- toolName: msg.toolName,
1132
- commandPreview:
1133
- redactSecrets(summarizeToolInput(msg.toolName, inputRecord)) ||
1134
- undefined,
1135
- riskLevel: msg.riskLevel,
1136
- activityText: activityRaw ? redactSecrets(activityRaw) : undefined,
1137
- executionTarget: msg.executionTarget,
1138
- status: "pending",
1139
- requestCode: generateCanonicalRequestCode(),
1140
- expiresAt: Date.now() + 5 * 60 * 1000,
1141
- });
1142
-
1143
- // For trusted-contact conversations, bridge to guardian.question so the
1144
- // guardian gets notified and can approve via callback/request-code.
1145
- if (trustContext) {
1146
- bridgeConfirmationRequestToGuardian({
1147
- canonicalRequest,
1148
- trustContext,
1149
- conversationId,
1150
- toolName: msg.toolName,
1151
- assistantId:
1152
- conversation.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
1153
- });
1154
- }
1155
- } catch (err) {
1156
- log.debug(
1157
- { err, requestId: msg.requestId, conversationId },
1158
- "Failed to create canonical request from hub publisher",
1159
- );
1160
- }
1161
- } else if (msg.type === "secret_request") {
1162
- pendingInteractions.register(msg.requestId, {
1163
- conversation,
1164
- conversationId,
1165
- kind: "secret",
1166
- });
1167
- } else {
1168
- registerHostProxyPendingInteraction(msg, conversation, conversationId);
1169
- }
1170
-
1171
- // ServerMessage is a large union; conversationId exists on most but not all variants.
1172
- const msgConversationId =
1173
- "conversationId" in msg &&
1174
- typeof (msg as { conversationId?: unknown }).conversationId === "string"
1175
- ? (msg as { conversationId: string }).conversationId
1176
- : undefined;
1177
- // `conversation_list_invalidated` is a list-level system event: it
1178
- // describes no particular conversation and every connected client
1179
- // should refresh its sidebar. Publish it unscoped so the SSE hub does
1180
- // not filter it out by the subscriber's `filter.conversationId`.
1181
- // Other events (including `conversation_title_updated`) stay scoped to
1182
- // their conversation — unscoped scoped-events would leak foreign
1183
- // `conversationId` values to native clients' speculative ID-resolution
1184
- // path. For `conversation_title_updated` we instead enqueue a matching
1185
- // unscoped `conversation_list_invalidated` below so other clients'
1186
- // sidebars can refresh and pick up the new title.
1187
- const resolvedConversationId =
1188
- msg.type === "conversation_list_invalidated"
1189
- ? undefined
1190
- : (msgConversationId ?? conversationId);
1191
- const event = buildAssistantEvent(
1192
- DAEMON_INTERNAL_ASSISTANT_ID,
1193
- msg,
1194
- resolvedConversationId,
1195
- );
1196
- hubChain = (async () => {
1197
- await hubChain;
1198
- try {
1199
- await deps.assistantEventHub.publish(event);
1200
- } catch (err) {
1201
- log.warn(
1202
- { err },
1203
- "assistant-events hub subscriber threw during POST /messages",
1204
- );
1205
- }
1206
-
1207
- // When the agent loop auto-generates a conversation title, also
1208
- // broadcast an unscoped `conversation_list_invalidated` so every
1209
- // connected client's sidebar can refresh and pick up the new title.
1210
- // Without this, clients viewing other conversations (or a draft)
1211
- // would never learn that the title for this conversation changed.
1212
- // The scoped `conversation_title_updated` above still handles the
1213
- // in-place update for the client currently viewing this conversation.
1214
- if (msg.type === "conversation_title_updated") {
1215
- try {
1216
- await deps.assistantEventHub.publish(
1217
- buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
1218
- type: "conversation_list_invalidated",
1219
- reason: "renamed",
1220
- }),
1221
- );
1222
- } catch (err) {
1223
- log.warn(
1224
- { err },
1225
- "Failed to publish conversation_list_invalidated after title update",
1226
- );
1227
- }
1228
- }
1229
- })();
1230
- };
1231
- }
1232
-
1233
- /**
1234
- * Register pending interactions for host proxy request envelopes so
1235
- * standalone result endpoints can resolve by requestId.
1236
- *
1237
- * Returns the registered requestId when a host proxy request was registered.
1238
- * Callers that route through non-hub transports (e.g. registry-routed
1239
- * host_browser sends) can use this to clean up the registration if send fails.
1240
- */
1241
- function registerHostProxyPendingInteraction(
1242
- msg: ServerMessage,
1243
- conversation: Conversation,
1244
- conversationId: string,
1245
- ): string | undefined {
1246
- if (msg.type === "host_bash_request") {
1247
- pendingInteractions.register(msg.requestId, {
1248
- conversation,
1249
- conversationId,
1250
- kind: "host_bash",
1251
- });
1252
- return msg.requestId;
1253
- }
1254
- if (msg.type === "host_browser_request") {
1255
- pendingInteractions.register(msg.requestId, {
1256
- conversation,
1257
- conversationId,
1258
- kind: "host_browser",
1259
- });
1260
- return msg.requestId;
1261
- }
1262
- if (msg.type === "host_file_request") {
1263
- pendingInteractions.register(msg.requestId, {
1264
- conversation,
1265
- conversationId,
1266
- kind: "host_file",
1267
- });
1268
- return msg.requestId;
1269
- }
1270
- if (msg.type === "host_cu_request") {
1271
- pendingInteractions.register(msg.requestId, {
1272
- conversation,
1273
- conversationId,
1274
- kind: "host_cu",
1275
- });
1276
- return msg.requestId;
1277
- }
1278
- if (msg.type === "host_transfer_request") {
1279
- pendingInteractions.register(msg.requestId, {
1280
- conversation,
1281
- conversationId,
1282
- kind: "host_transfer",
1283
- });
1284
- return msg.requestId;
1285
- }
1286
- return undefined;
1287
- }
1288
-
1289
- /**
1290
- * Resolve the host_browser sender function for a conversation turn.
1291
- *
1292
- * Transport selection:
1293
- * 1. **WebSocket registry** — when the guardian has an active entry in
1294
- * ChromeExtensionRegistry (self-hosted direct WS connection), the
1295
- * registry-routed sender is returned. Frames go directly over the
1296
- * WebSocket to the extension.
1297
- * 2. **SSE event hub** — when no WebSocket connection exists but a
1298
- * chrome-extension client is connected via SSE (cloud/platform mode),
1299
- * the SSE hub sender (`onEvent`) is returned. The extension receives
1300
- * `host_browser_request` frames as SSE events and POSTs results back
1301
- * to `/v1/host-browser-result`.
1302
- *
1303
- * When neither transport is available, `onEvent` is returned as the
1304
- * default sender (used by macOS for its native host_browser path).
1305
- * `hasSseExtension` is `false` in that case so the caller can avoid
1306
- * provisioning a stale `HostBrowserProxy` for interfaces that don't
1307
- * natively support host_browser.
1308
- */
1309
- function resolveHostBrowserSender(
1310
- conversation: Conversation,
1311
- conversationId: string,
1312
- actorPrincipalId: string | undefined,
1313
- onEvent: (msg: ServerMessage) => void,
1314
- sourceInterface: InterfaceId,
1315
- ): {
1316
- sender: (msg: ServerMessage) => void;
1317
- isRegistryRouted: boolean;
1318
- hasSseExtension: boolean;
1319
- } {
1320
- const guardianId =
1321
- conversation.trustContext?.guardianPrincipalId ?? actorPrincipalId;
1322
- const hasExtensionConnection =
1323
- !!guardianId && !!getChromeExtensionRegistry().get(guardianId);
1324
-
1325
- // Priority 1: WebSocket registry — direct WS to the extension.
1326
- if (hasExtensionConnection) {
1327
- const registrySender = (msg: ServerMessage): void => {
1328
- const requestId = registerHostProxyPendingInteraction(
1329
- msg,
1330
- conversation,
1331
- conversationId,
1332
- );
1333
- const gid =
1334
- conversation.trustContext?.guardianPrincipalId ?? actorPrincipalId;
1335
- if (!gid) {
1336
- if (requestId) pendingInteractions.resolve(requestId);
1337
- throw new Error(
1338
- "host_browser send skipped: no guardianId on AuthContext",
1339
- );
1340
- }
1341
- const ok = getChromeExtensionRegistry().send(gid, msg);
1342
- if (!ok) {
1343
- if (requestId) pendingInteractions.resolve(requestId);
1344
- throw new Error(
1345
- `host_browser send failed: no active connection for guardian ${gid}`,
1346
- );
1347
- }
1348
- };
1349
- return {
1350
- sender: registrySender,
1351
- isRegistryRouted: true,
1352
- hasSseExtension: false,
1353
- };
1354
- }
1355
-
1356
- // Priority 2: SSE-connected chrome extension (cloud/platform mode).
1357
- // Check the ClientRegistry for a chrome-extension client specifically —
1358
- // getMostRecentByCapability("host_browser") would also match macOS
1359
- // clients, which handle browser frames through their own native path.
1360
- const hasSseExtension =
1361
- canServiceSseBrowser(sourceInterface) &&
1362
- !!getClientRegistry().getMostRecentByInterface("chrome-extension");
1363
-
1364
- return { sender: onEvent, isRegistryRouted: false, hasSseExtension };
1365
- }
1366
-
1367
997
  /**
1368
998
  * Persist the pre-chat onboarding payload to disk.
1369
999
  *
@@ -1647,7 +1277,7 @@ export async function handleSendMessage(
1647
1277
  if (!hasMessages(mapping.conversationId)) {
1648
1278
  smDeps.assistantEventHub
1649
1279
  .publish(
1650
- buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
1280
+ buildAssistantEvent({
1651
1281
  type: "conversation_list_invalidated",
1652
1282
  reason: "created",
1653
1283
  }),
@@ -1757,106 +1387,13 @@ export async function handleSendMessage(
1757
1387
  conversation.setTrustContext({ trustClass: "guardian", sourceChannel });
1758
1388
  }
1759
1389
 
1760
- const onEvent = makeHubPublisher(
1761
- smDeps,
1762
- mapping.conversationId,
1763
- conversation,
1764
- );
1765
1390
  const isInteractive = isInteractiveInterface(sourceInterface);
1766
- // Only create each host proxy for interfaces that support the matching
1767
- // capability. macOS supports all four; the chrome-extension interface only
1768
- // supports host_browser. Non-desktop conversations (CLI, channels, headless)
1769
- // fall back to local execution.
1770
- // Set the proxy BEFORE updateClient so updateClient's call to
1771
- // hostBashProxy.updateSender targets the correct (new) proxy.
1772
- if (supportsHostProxy(sourceInterface, "host_bash")) {
1773
- // Reuse the existing proxy if the conversation is actively processing a
1774
- // host bash request to avoid orphaning in-flight requests.
1775
- if (!conversation.isProcessing() || !conversation.hostBashProxy) {
1776
- const proxy = new HostBashProxy(onEvent, (requestId) => {
1777
- pendingInteractions.resolve(requestId);
1778
- });
1779
- conversation.setHostBashProxy(proxy);
1780
- }
1781
- } else if (!conversation.isProcessing()) {
1782
- conversation.setHostBashProxy(undefined);
1783
- }
1784
- // Resolve the host_browser sender — registry-routed when the guardian has
1785
- // an active WS extension connection, SSE hub when a chrome-extension is
1786
- // connected via SSE (cloud mode), or SSE hub as default for macOS.
1787
- const {
1788
- sender: browserProxySendToClient,
1789
- isRegistryRouted,
1790
- hasSseExtension,
1791
- } = resolveHostBrowserSender(
1792
- conversation,
1793
- mapping.conversationId,
1794
- actorPrincipalId,
1795
- onEvent,
1796
- sourceInterface,
1797
- );
1798
-
1799
- // Stash the registry-routed sender on the conversation so queue-drain
1800
- // restores (which run outside of conversation-routes.ts and only have
1801
- // access to `sendToClient`) can preserve it when calling
1802
- // `restoreBrowserProxyAvailability()`. The override is set when the
1803
- // sender is registry-routed (regardless of interface) and cleared when
1804
- // the SSE hub sender is used, so the drain path always restores the
1805
- // correct transport.
1806
- if (isRegistryRouted) {
1807
- conversation.hostBrowserSenderOverride = browserProxySendToClient;
1808
- } else {
1809
- conversation.hostBrowserSenderOverride = undefined;
1810
- }
1811
-
1812
- // Provision the host browser proxy when a viable transport exists:
1813
- // - macOS: natively supports host_browser via its own SSE path
1814
- // - WS registry: extension connected via direct WebSocket
1815
- // - SSE extension: chrome extension connected via SSE (cloud mode)
1816
- //
1817
- // For chrome-extension, require an active transport (WS or SSE). Without
1818
- // one, host_browser_request frames would be emitted to the SSE hub with
1819
- // no consumer, causing a 30s proxy timeout instead of failing fast.
1820
- const shouldProvisionBrowserProxy =
1821
- supportsHostProxy(sourceInterface) ||
1822
- (canServiceRegistryBrowser(sourceInterface) && isRegistryRouted) ||
1823
- hasSseExtension;
1824
- if (shouldProvisionBrowserProxy) {
1825
- if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
1826
- const browserProxy = new HostBrowserProxy(
1827
- browserProxySendToClient,
1828
- (requestId) => {
1829
- pendingInteractions.resolve(requestId);
1830
- },
1831
- );
1832
- conversation.setHostBrowserProxy(browserProxy);
1833
- }
1834
- } else if (!conversation.isProcessing()) {
1835
- conversation.setHostBrowserProxy(undefined);
1836
- }
1837
- if (supportsHostProxy(sourceInterface, "host_file")) {
1838
- if (!conversation.isProcessing() || !conversation.hostFileProxy) {
1839
- const fileProxy = new HostFileProxy(onEvent, (requestId) => {
1840
- pendingInteractions.resolve(requestId);
1841
- });
1842
- conversation.setHostFileProxy(fileProxy);
1843
- }
1844
- if (!conversation.isProcessing() || !conversation.getHostTransferProxy()) {
1845
- const transferProxy = new HostTransferProxy(onEvent, (requestId) => {
1846
- pendingInteractions.resolve(requestId);
1847
- });
1848
- conversation.setHostTransferProxy(transferProxy);
1849
- }
1850
- } else if (!conversation.isProcessing()) {
1851
- conversation.setHostFileProxy(undefined);
1852
- conversation.setHostTransferProxy(undefined);
1853
- }
1391
+ // Bash/File/Transfer singletons are globally available via isAvailable()
1392
+ // no per-conversation gating needed. CU is per-conversation (owns step
1393
+ // count, AX tree history, loop detection).
1854
1394
  if (supportsHostProxy(sourceInterface, "host_cu")) {
1855
1395
  if (!conversation.isProcessing() || !conversation.hostCuProxy) {
1856
- const cuProxy = new HostCuProxy(onEvent, (requestId) => {
1857
- pendingInteractions.resolve(requestId);
1858
- });
1859
- conversation.setHostCuProxy(cuProxy);
1396
+ conversation.setHostCuProxy(new HostCuProxy());
1860
1397
  }
1861
1398
  // Only preactivate CU when the conversation is idle — if the conversation is
1862
1399
  // processing, this message will be queued and preactivation is deferred
@@ -1868,14 +1405,6 @@ export async function handleSendMessage(
1868
1405
  conversation.setHostCuProxy(undefined);
1869
1406
  }
1870
1407
  // Wire sendToClient to the SSE hub so all subsystems can reach the HTTP client.
1871
- // Called after setHostBashProxy so updateSender targets the current proxy.
1872
- // When proxies are preserved during an active turn (non-desktop request while
1873
- // processing), skip updating proxy senders to avoid degrading them. The gate
1874
- // matches the host_bash capability because the legacy "reject send during
1875
- // host bash" flow is what this is really protecting.
1876
- const preservingProxies =
1877
- conversation.isProcessing() &&
1878
- !supportsHostProxy(sourceInterface, "host_bash");
1879
1408
  // hasNoClient must remain `!isInteractive` so downstream tool gating
1880
1409
  // (`isToolActiveForContext` for HOST_TOOL_NAMES, `createToolExecutor`'s
1881
1410
  // `isInteractive: !ctx.hasNoClient`) keeps host_bash/host_file/host_cu
@@ -1883,23 +1412,7 @@ export async function handleSendMessage(
1883
1412
  // is non-interactive (no SSE prompter UI) but still has a connected client
1884
1413
  // that can service host_browser_request events; we restore that single
1885
1414
  // proxy explicitly below without relaxing `hasNoClient`.
1886
- conversation.updateClient(onEvent, !isInteractive, {
1887
- skipProxySenderUpdate: preservingProxies,
1888
- });
1889
- // Re-enable the browser proxy for turns that provisioned one. This covers:
1890
- // - macOS: always provisioned (SSE sender or registry-routed when extension
1891
- // is connected)
1892
- // - chrome-extension: natively supports host_browser (non-interactive but
1893
- // has a connected client for host_browser_request events)
1894
- //
1895
- // The helper bypasses the `hasNoClient` gate so chrome-extension turns can
1896
- // drive the browser via CDP without leaking host_bash/host_file tool
1897
- // availability. It reads `hostBrowserSenderOverride` (set above when
1898
- // registry-routed) and applies the correct sender — including after
1899
- // queue-drain restores run from conversation-process.ts.
1900
- if (shouldProvisionBrowserProxy) {
1901
- conversation.restoreBrowserProxyAvailability?.();
1902
- }
1415
+ conversation.updateClient(broadcastMessage, !isInteractive);
1903
1416
 
1904
1417
  // ── Canned first-greeting fast path ──
1905
1418
  // On a completely fresh workspace, skip LLM inference for the macOS
@@ -1961,15 +1474,19 @@ export async function handleSendMessage(
1961
1474
  };
1962
1475
 
1963
1476
  setTimeout(() => {
1964
- onEvent({
1477
+ broadcastMessage({
1965
1478
  type: "user_message_echo",
1966
1479
  text: rawContent,
1967
1480
  conversationId,
1968
1481
  messageId: persisted.id,
1969
1482
  clientMessageId,
1970
1483
  });
1971
- onEvent({ type: "assistant_text_delta", text: cannedGreeting });
1972
- onEvent({ type: "message_complete", conversationId });
1484
+ broadcastMessage({
1485
+ type: "assistant_text_delta",
1486
+ text: cannedGreeting,
1487
+ conversationId,
1488
+ });
1489
+ broadcastMessage({ type: "message_complete", conversationId });
1973
1490
  conversation.processing = false;
1974
1491
  silentlyWithLog(
1975
1492
  conversation.drainQueue(),
@@ -2022,7 +1539,7 @@ export async function handleSendMessage(
2022
1539
  content: content ?? "",
2023
1540
  attachments,
2024
1541
  conversation,
2025
- onEvent,
1542
+ onEvent: broadcastMessage,
2026
1543
  // Desktop path: disable NL classification to avoid consuming non-decision
2027
1544
  // messages while a tool confirmation is pending. Deterministic code-prefix
2028
1545
  // and callback parsing remain active. Mirrors conversation-process.ts behavior.
@@ -2055,7 +1572,7 @@ export async function handleSendMessage(
2055
1572
  const enqueueResult = conversation.enqueueMessage(
2056
1573
  content ?? "",
2057
1574
  attachments,
2058
- onEvent,
1575
+ broadcastMessage,
2059
1576
  requestId,
2060
1577
  undefined, // activeSurfaceId
2061
1578
  undefined, // currentPage
@@ -2093,10 +1610,7 @@ export async function handleSendMessage(
2093
1610
  for (const interaction of pendingInteractions.getByConversation(
2094
1611
  mapping.conversationId,
2095
1612
  )) {
2096
- if (
2097
- interaction.conversation === conversation &&
2098
- interaction.kind === "confirmation"
2099
- ) {
1613
+ if (interaction.kind === "confirmation") {
2100
1614
  conversation.emitConfirmationStateChanged({
2101
1615
  conversationId: mapping.conversationId,
2102
1616
  requestId: interaction.requestId,
@@ -2111,7 +1625,7 @@ export async function handleSendMessage(
2111
1625
  }
2112
1626
  }
2113
1627
  conversation.denyAllPendingConfirmations();
2114
- pendingInteractions.removeByConversation(conversation);
1628
+ pendingInteractions.removeByConversation(mapping.conversationId);
2115
1629
  }
2116
1630
 
2117
1631
  // Expire any orphaned canonical requests that survived without a
@@ -2140,10 +1654,7 @@ export async function handleSendMessage(
2140
1654
  for (const interaction of pendingInteractions.getByConversation(
2141
1655
  mapping.conversationId,
2142
1656
  )) {
2143
- if (
2144
- interaction.conversation === conversation &&
2145
- interaction.kind === "confirmation"
2146
- ) {
1657
+ if (interaction.kind === "confirmation") {
2147
1658
  conversation.emitConfirmationStateChanged({
2148
1659
  conversationId: mapping.conversationId,
2149
1660
  requestId: interaction.requestId,
@@ -2158,7 +1669,7 @@ export async function handleSendMessage(
2158
1669
  }
2159
1670
  }
2160
1671
  conversation.denyAllPendingConfirmations();
2161
- pendingInteractions.removeByConversation(conversation);
1672
+ pendingInteractions.removeByConversation(mapping.conversationId);
2162
1673
  }
2163
1674
 
2164
1675
  // Expire any orphaned canonical requests that survived without a
@@ -2179,17 +1690,14 @@ export async function handleSendMessage(
2179
1690
 
2180
1691
  // Resolve slash commands before persisting or running the agent loop.
2181
1692
  const rawContent = content ?? "";
2182
- const config = getConfig();
2183
- const slashContext: SlashContext = {
1693
+ const slashContext = buildSlashContextForContent(rawContent, {
1694
+ conversationId: mapping.conversationId,
2184
1695
  messageCount: conversation.getMessages().length,
2185
1696
  inputTokens: conversation.usageStats.inputTokens,
2186
1697
  outputTokens: conversation.usageStats.outputTokens,
2187
- maxInputTokens: config.llm.default.contextWindow.maxInputTokens,
2188
- model: config.llm.default.model,
2189
- provider: config.llm.default.provider,
2190
1698
  estimatedCost: conversation.usageStats.estimatedCost,
2191
1699
  userMessageInterface: sourceInterface,
2192
- };
1700
+ });
2193
1701
  const slashResult = await resolveSlash(rawContent, slashContext);
2194
1702
 
2195
1703
  if (slashResult.kind === "unknown") {
@@ -2246,7 +1754,7 @@ export async function handleSendMessage(
2246
1754
  // Snapshot model info now so the deferred callback cannot observe
2247
1755
  // a config change from a concurrent request.
2248
1756
  const modelInfoEvent = isModelSlashCommand(rawContent)
2249
- ? await buildModelInfoEvent()
1757
+ ? await buildModelInfoEvent(mapping.conversationId)
2250
1758
  : null;
2251
1759
 
2252
1760
  const response = {
@@ -2266,7 +1774,7 @@ export async function handleSendMessage(
2266
1774
  const conversationId = mapping.conversationId;
2267
1775
  const message = slashResult.message;
2268
1776
  setTimeout(() => {
2269
- onEvent({
1777
+ broadcastMessage({
2270
1778
  type: "user_message_echo",
2271
1779
  text: rawContent,
2272
1780
  conversationId,
@@ -2274,10 +1782,14 @@ export async function handleSendMessage(
2274
1782
  clientMessageId,
2275
1783
  });
2276
1784
  if (modelInfoEvent) {
2277
- onEvent(modelInfoEvent);
1785
+ broadcastMessage(modelInfoEvent);
2278
1786
  }
2279
- onEvent({ type: "assistant_text_delta", text: message });
2280
- onEvent({
1787
+ broadcastMessage({
1788
+ type: "assistant_text_delta",
1789
+ text: message,
1790
+ conversationId,
1791
+ });
1792
+ broadcastMessage({
2281
1793
  type: "message_complete",
2282
1794
  conversationId: conversationId,
2283
1795
  });
@@ -2323,7 +1835,7 @@ export async function handleSendMessage(
2323
1835
  // HTTP timeout on large contexts, causing a false "Failed to send".
2324
1836
  (async () => {
2325
1837
  try {
2326
- onEvent({
1838
+ broadcastMessage({
2327
1839
  type: "user_message_echo",
2328
1840
  text: rawContent,
2329
1841
  conversationId,
@@ -2347,11 +1859,15 @@ export async function handleSendMessage(
2347
1859
  );
2348
1860
  conversation.getMessages().push(assistantMsg);
2349
1861
 
2350
- onEvent({ type: "assistant_text_delta", text: responseText });
2351
- onEvent({ type: "message_complete", conversationId });
1862
+ broadcastMessage({
1863
+ type: "assistant_text_delta",
1864
+ text: responseText,
1865
+ conversationId,
1866
+ });
1867
+ broadcastMessage({ type: "message_complete", conversationId });
2352
1868
  } catch (err) {
2353
1869
  log.error({ err, conversationId }, "Compact command failed");
2354
- onEvent({
1870
+ broadcastMessage({
2355
1871
  type: "conversation_error",
2356
1872
  conversationId,
2357
1873
  code: "UNKNOWN",
@@ -2389,7 +1905,7 @@ export async function handleSendMessage(
2389
1905
  throw err;
2390
1906
  }
2391
1907
 
2392
- onEvent({
1908
+ broadcastMessage({
2393
1909
  type: "user_message_echo",
2394
1910
  text: resolvedContent,
2395
1911
  conversationId: mapping.conversationId,
@@ -2398,9 +1914,9 @@ export async function handleSendMessage(
2398
1914
  clientMessageId,
2399
1915
  });
2400
1916
 
2401
- // Fire-and-forget the agent loop; events flow to the hub via onEvent.
1917
+ // Fire-and-forget the agent loop; events flow to the hub via broadcastMessage.
2402
1918
  conversation
2403
- .runAgentLoop(resolvedContent, messageId, onEvent, {
1919
+ .runAgentLoop(resolvedContent, messageId, broadcastMessage, {
2404
1920
  isInteractive,
2405
1921
  isUserMessage: true,
2406
1922
  })