@vellumai/assistant 0.6.6 → 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 (1603) hide show
  1. package/AGENTS.md +20 -0
  2. package/ARCHITECTURE.md +46 -38
  3. package/Dockerfile +27 -6
  4. package/README.md +9 -11
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +83 -149
  6. package/bun.lock +309 -119
  7. package/docs/architecture/memory.md +1 -90
  8. package/docs/architecture/security.md +28 -41
  9. package/docs/credential-execution-service.md +7 -5
  10. package/docs/skills.md +10 -10
  11. package/docs/stt-provider-onboarding.md +17 -45
  12. package/examples/plugins/echo/bun.lock +25 -0
  13. package/knip.json +9 -22
  14. package/node_modules/@vellumai/ces-client/bun.lock +33 -0
  15. package/node_modules/@vellumai/ces-client/package.json +25 -0
  16. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
  17. package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
  18. package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
  19. package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
  20. package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
  21. package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
  22. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
  23. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  24. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  25. package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
  26. package/node_modules/@vellumai/gateway-client/package.json +23 -0
  27. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
  28. package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
  29. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
  30. package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
  31. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
  32. package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
  33. package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
  34. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  35. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  36. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  37. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  38. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  39. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  40. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  41. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  42. package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
  43. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +887 -0
  44. package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
  45. package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
  46. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +86 -0
  47. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1342 -0
  48. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
  49. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
  50. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
  51. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +325 -0
  52. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
  53. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
  54. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
  55. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  56. package/node_modules/@vellumai/slack-text/package.json +18 -0
  57. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  58. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  59. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  60. package/openapi.yaml +3136 -650
  61. package/package.json +15 -7
  62. package/scripts/check-circular-deps.ts +80 -0
  63. package/scripts/generate-openapi.ts +29 -107
  64. package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +27 -27
  65. package/src/__tests__/access-request-decision.test.ts +2 -11
  66. package/src/__tests__/acp-session.test.ts +4 -150
  67. package/src/__tests__/actor-token-service.test.ts +17 -678
  68. package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
  69. package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
  70. package/src/__tests__/agent-loop-thinking.test.ts +4 -4
  71. package/src/__tests__/agent-wake-override-profile.test.ts +283 -0
  72. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
  73. package/src/__tests__/anthropic-provider.test.ts +183 -28
  74. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  75. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  76. package/src/__tests__/app-routes-csp.test.ts +106 -55
  77. package/src/__tests__/approval-cascade.test.ts +3 -370
  78. package/src/__tests__/approval-conversation-turn.test.ts +3 -8
  79. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  80. package/src/__tests__/approval-primitive.test.ts +2 -1
  81. package/src/__tests__/approval-routes-http.test.ts +36 -464
  82. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  83. package/src/__tests__/assistant-event.test.ts +0 -5
  84. package/src/__tests__/assistant-events-sse-hardening.test.ts +107 -92
  85. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  86. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
  87. package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
  88. package/src/__tests__/attachments-store.test.ts +46 -1
  89. package/src/__tests__/audit-log-rotation.test.ts +2 -1
  90. package/src/__tests__/auto-analysis-end-to-end.test.ts +8 -20
  91. package/src/__tests__/background-shell-bash.test.ts +227 -0
  92. package/src/__tests__/background-shell-host-bash.test.ts +465 -0
  93. package/src/__tests__/background-tool-registry.test.ts +145 -0
  94. package/src/__tests__/background-tool-routes.test.ts +175 -0
  95. package/src/__tests__/btw-routes.test.ts +147 -183
  96. package/src/__tests__/call-controller.test.ts +15 -2
  97. package/src/__tests__/call-conversation-messages.test.ts +2 -1
  98. package/src/__tests__/call-domain.test.ts +2 -2
  99. package/src/__tests__/call-pointer-messages.test.ts +11 -13
  100. package/src/__tests__/call-recovery.test.ts +2 -1
  101. package/src/__tests__/call-routes-http.test.ts +3 -14
  102. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  103. package/src/__tests__/call-store.test.ts +2 -1
  104. package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
  105. package/src/__tests__/canonical-guardian-store.test.ts +2 -2
  106. package/src/__tests__/catalog-files.test.ts +0 -26
  107. package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
  108. package/src/__tests__/channel-approval-routes.test.ts +88 -344
  109. package/src/__tests__/channel-approval.test.ts +9 -7
  110. package/src/__tests__/channel-approvals.test.ts +34 -197
  111. package/src/__tests__/channel-delivery-store.test.ts +11 -10
  112. package/src/__tests__/channel-guardian.test.ts +114 -171
  113. package/src/__tests__/channel-readiness-service.test.ts +8 -6
  114. package/src/__tests__/channel-reply-delivery.test.ts +3 -19
  115. package/src/__tests__/channel-retry-sweep.test.ts +2 -5
  116. package/src/__tests__/checker.test.ts +272 -3933
  117. package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
  118. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
  119. package/src/__tests__/cli.test.ts +1 -38
  120. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  121. package/src/__tests__/compaction-events.test.ts +2 -1
  122. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  123. package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
  124. package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
  125. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
  126. package/src/__tests__/config-model-image-provider.test.ts +0 -1
  127. package/src/__tests__/config-schema-cmd.test.ts +1 -1
  128. package/src/__tests__/config-schema.test.ts +36 -269
  129. package/src/__tests__/config-watcher.test.ts +12 -0
  130. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
  131. package/src/__tests__/connection-policy.test.ts +1 -52
  132. package/src/__tests__/contact-store-user-file.test.ts +2 -1
  133. package/src/__tests__/contacts-tools.test.ts +56 -29
  134. package/src/__tests__/contacts-write.test.ts +8 -125
  135. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  136. package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
  137. package/src/__tests__/context-search-agent-runner.test.ts +998 -0
  138. package/src/__tests__/context-search-conversations-source.test.ts +320 -0
  139. package/src/__tests__/context-search-fanout.test.ts +380 -0
  140. package/src/__tests__/context-search-memory-source.test.ts +430 -0
  141. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  142. package/src/__tests__/context-search-pkb-source.test.ts +493 -0
  143. package/src/__tests__/context-search-types.test.ts +95 -0
  144. package/src/__tests__/context-search-workspace-source.test.ts +532 -0
  145. package/src/__tests__/context-window-manager.test.ts +71 -0
  146. package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
  147. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +633 -0
  148. package/src/__tests__/conversation-agent-loop-overflow.test.ts +117 -31
  149. package/src/__tests__/conversation-agent-loop.test.ts +1004 -15
  150. package/src/__tests__/conversation-analysis-routes.test.ts +68 -88
  151. package/src/__tests__/conversation-attachments.test.ts +9 -20
  152. package/src/__tests__/conversation-attention-store.test.ts +2 -1
  153. package/src/__tests__/conversation-attention-telegram.test.ts +15 -5
  154. package/src/__tests__/conversation-clear-safety.test.ts +53 -95
  155. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -330
  156. package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
  157. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
  158. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  159. package/src/__tests__/conversation-disk-view.test.ts +5 -4
  160. package/src/__tests__/conversation-fork-crud.test.ts +26 -55
  161. package/src/__tests__/conversation-fork-route.test.ts +5 -74
  162. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  163. package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
  164. package/src/__tests__/conversation-inference-profile-route.test.ts +205 -0
  165. package/src/__tests__/conversation-init.benchmark.test.ts +4 -81
  166. package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
  167. package/src/__tests__/conversation-lifecycle.test.ts +4 -5
  168. package/src/__tests__/conversation-list-source.test.ts +2 -2
  169. package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
  170. package/src/__tests__/conversation-pairing.test.ts +0 -1
  171. package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
  172. package/src/__tests__/conversation-process-callsite.test.ts +79 -3
  173. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
  174. package/src/__tests__/conversation-queue.test.ts +4 -41
  175. package/src/__tests__/conversation-routes-disk-view.test.ts +55 -188
  176. package/src/__tests__/conversation-routes-guardian-reply.test.ts +64 -71
  177. package/src/__tests__/conversation-routes-slash-commands.test.ts +144 -64
  178. package/src/__tests__/conversation-runtime-assembly.test.ts +295 -84
  179. package/src/__tests__/conversation-slash-commands.test.ts +30 -47
  180. package/src/__tests__/conversation-slash-queue.test.ts +2 -1
  181. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  182. package/src/__tests__/conversation-speed-override.test.ts +0 -4
  183. package/src/__tests__/conversation-starter-routes.test.ts +254 -55
  184. package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
  185. package/src/__tests__/conversation-store.test.ts +2 -375
  186. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  187. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  188. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  189. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -47
  190. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
  191. package/src/__tests__/conversation-unread-route.test.ts +1 -1
  192. package/src/__tests__/conversation-usage.test.ts +255 -4
  193. package/src/__tests__/conversation-wipe.test.ts +2 -103
  194. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
  195. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  196. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  197. package/src/__tests__/conversations-defer-cli.test.ts +150 -0
  198. package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
  199. package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
  200. package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
  201. package/src/__tests__/credential-execution-client.test.ts +1 -1
  202. package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
  203. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  204. package/src/__tests__/credential-health-service.test.ts +68 -0
  205. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  206. package/src/__tests__/credential-security-invariants.test.ts +15 -5
  207. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  208. package/src/__tests__/credentials-cli.test.ts +45 -21
  209. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  210. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  211. package/src/__tests__/daemon-credential-client.test.ts +26 -108
  212. package/src/__tests__/db-acp-history.test.ts +284 -0
  213. package/src/__tests__/db-activation-state.test.ts +240 -0
  214. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  215. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
  216. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
  217. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
  218. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
  219. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  220. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
  221. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  222. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  223. package/src/__tests__/delete-propagation.test.ts +3 -2
  224. package/src/__tests__/deterministic-verification-control-plane.test.ts +38 -104
  225. package/src/__tests__/dm-backfill.test.ts +3 -2
  226. package/src/__tests__/document-conversations.test.ts +332 -0
  227. package/src/__tests__/edit-propagation.test.ts +5 -7
  228. package/src/__tests__/embedding-managed-proxy-selection.test.ts +3 -3
  229. package/src/__tests__/emit-event-signal.test.ts +4 -6
  230. package/src/__tests__/empty-response-pipeline.test.ts +1 -1
  231. package/src/__tests__/events-client-registration.test.ts +441 -0
  232. package/src/__tests__/file-write-tool.test.ts +2 -4
  233. package/src/__tests__/filing-service.test.ts +197 -19
  234. package/src/__tests__/first-greeting.test.ts +156 -150
  235. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  236. package/src/__tests__/followup-tools.test.ts +2 -1
  237. package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
  238. package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
  239. package/src/__tests__/gateway-only-guard.test.ts +4 -3
  240. package/src/__tests__/gemini-provider.test.ts +276 -10
  241. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  242. package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
  243. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
  244. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
  245. package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
  246. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
  247. package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
  248. package/src/__tests__/guardian-action-store.test.ts +2 -1
  249. package/src/__tests__/guardian-action-sweep.test.ts +9 -8
  250. package/src/__tests__/guardian-binding-drift-heal.test.ts +3 -2
  251. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
  252. package/src/__tests__/guardian-dispatch.test.ts +14 -11
  253. package/src/__tests__/guardian-grant-minting.test.ts +16 -17
  254. package/src/__tests__/guardian-outbound-http.test.ts +71 -106
  255. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
  256. package/src/__tests__/guardian-routing-invariants.test.ts +41 -92
  257. package/src/__tests__/guardian-routing-state.test.ts +15 -23
  258. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
  259. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +274 -0
  260. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -87
  261. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  262. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  263. package/src/__tests__/heartbeat-service.test.ts +325 -25
  264. package/src/__tests__/helpers/call-route-handler.ts +72 -0
  265. package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
  266. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  267. package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
  268. package/src/__tests__/helpers/mock-logger.ts +36 -0
  269. package/src/__tests__/history-repair-pipeline.test.ts +1 -1
  270. package/src/__tests__/home-state-routes.test.ts +10 -31
  271. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  272. package/src/__tests__/host-browser-e2e-cloud.test.ts +38 -498
  273. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +35 -95
  274. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  275. package/src/__tests__/host-browser-routes.test.ts +68 -153
  276. package/src/__tests__/host-browser-ws-events-e2e.test.ts +35 -31
  277. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  278. package/src/__tests__/host-file-proxy.test.ts +44 -98
  279. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  280. package/src/__tests__/host-proxy-interface.test.ts +3 -3
  281. package/src/__tests__/host-shell-tool.test.ts +35 -72
  282. package/src/__tests__/host-transfer-pending-interactions.test.ts +144 -0
  283. package/src/__tests__/host-transfer-proxy.test.ts +723 -0
  284. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  285. package/src/__tests__/http-user-message-parity.test.ts +18 -15
  286. package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
  287. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  288. package/src/__tests__/injector-chain.test.ts +25 -21
  289. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  290. package/src/__tests__/inline-command-runner.test.ts +0 -66
  291. package/src/__tests__/inline-skill-load-permissions.test.ts +41 -208
  292. package/src/__tests__/install-skill-routing.test.ts +2 -14
  293. package/src/__tests__/invite-redemption-service.test.ts +2 -1
  294. package/src/__tests__/invite-routes-http.test.ts +80 -12
  295. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
  296. package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
  297. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
  298. package/src/__tests__/list-messages-attachments.test.ts +52 -55
  299. package/src/__tests__/list-messages-page-latest.test.ts +283 -0
  300. package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
  301. package/src/__tests__/llm-call-pipeline.test.ts +7 -8
  302. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  303. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  304. package/src/__tests__/llm-context-normalization.test.ts +69 -4
  305. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  306. package/src/__tests__/llm-context-route-provider.test.ts +39 -113
  307. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
  308. package/src/__tests__/llm-resolver.test.ts +279 -0
  309. package/src/__tests__/llm-schema.test.ts +57 -1
  310. package/src/__tests__/llm-usage-store.test.ts +271 -5
  311. package/src/__tests__/log-export-routes.test.ts +89 -0
  312. package/src/__tests__/log-export-workspace.test.ts +28 -17
  313. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  314. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  315. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  316. package/src/__tests__/mcp-abort-signal.test.ts +2 -3
  317. package/src/__tests__/mcp-client-auth.test.ts +2 -3
  318. package/src/__tests__/memory-admin-recall.test.ts +221 -0
  319. package/src/__tests__/memory-recall-log-store.test.ts +2 -1
  320. package/src/__tests__/memory-retrieval-pipeline.test.ts +6 -8
  321. package/src/__tests__/memory-upsert-concurrency.test.ts +2 -1
  322. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  323. package/src/__tests__/migration-cross-version-compatibility.test.ts +209 -302
  324. package/src/__tests__/migration-export-http.test.ts +50 -43
  325. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  326. package/src/__tests__/migration-export-to-gcs.test.ts +531 -0
  327. package/src/__tests__/migration-import-commit-http.test.ts +82 -37
  328. package/src/__tests__/migration-import-from-gcs.test.ts +574 -0
  329. package/src/__tests__/migration-import-from-url.test.ts +34 -27
  330. package/src/__tests__/migration-import-preflight-http.test.ts +108 -108
  331. package/src/__tests__/migration-jobs-status.test.ts +164 -0
  332. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  333. package/src/__tests__/migration-transport.test.ts +115 -23
  334. package/src/__tests__/migration-validate-http.test.ts +149 -159
  335. package/src/__tests__/migration-wizard.test.ts +133 -27
  336. package/src/__tests__/mock-gateway-ipc.ts +32 -62
  337. package/src/__tests__/model-intents.test.ts +15 -2
  338. package/src/__tests__/nl-approval-parser.test.ts +13 -17
  339. package/src/__tests__/non-member-access-request.test.ts +14 -6
  340. package/src/__tests__/notification-guardian-path.test.ts +15 -8
  341. package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
  342. package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
  343. package/src/__tests__/oauth-apps-routes.test.ts +76 -122
  344. package/src/__tests__/oauth-cli.test.ts +14 -1
  345. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  346. package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
  347. package/src/__tests__/oauth-providers-routes.test.ts +78 -101
  348. package/src/__tests__/oauth-store.test.ts +22 -1
  349. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
  350. package/src/__tests__/openai-provider.test.ts +105 -6
  351. package/src/__tests__/openai-responses-provider.test.ts +146 -4
  352. package/src/__tests__/openrouter-provider-only.test.ts +22 -4
  353. package/src/__tests__/overflow-reduce-pipeline.test.ts +4 -9
  354. package/src/__tests__/permission-types.test.ts +3 -18
  355. package/src/__tests__/persistence-pipeline.test.ts +3 -2
  356. package/src/__tests__/pipeline-runner.test.ts +1 -1
  357. package/src/__tests__/platform-bash-auto-approve.test.ts +44 -28
  358. package/src/__tests__/platform.test.ts +11 -63
  359. package/src/__tests__/playbook-execution.test.ts +2 -1
  360. package/src/__tests__/playbook-tools.test.ts +2 -1
  361. package/src/__tests__/plugin-bootstrap.test.ts +51 -5
  362. package/src/__tests__/plugin-registry.test.ts +30 -0
  363. package/src/__tests__/plugin-route-contribution.test.ts +17 -11
  364. package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
  365. package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
  366. package/src/__tests__/plugin-types.test.ts +1 -1
  367. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  368. package/src/__tests__/pricing.test.ts +218 -5
  369. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  370. package/src/__tests__/profiler-routes.test.ts +112 -177
  371. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  372. package/src/__tests__/provider-send-message-override-profile.test.ts +273 -0
  373. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  374. package/src/__tests__/proxy-approval-callback.test.ts +6 -554
  375. package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
  376. package/src/__tests__/reaction-persistence.test.ts +12 -8
  377. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  378. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  379. package/src/__tests__/recording-handler.test.ts +64 -83
  380. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  381. package/src/__tests__/registry.test.ts +1 -0
  382. package/src/__tests__/relay-server.test.ts +37 -17
  383. package/src/__tests__/require-fresh-approval.test.ts +24 -182
  384. package/src/__tests__/resolve-trust-class.test.ts +2 -1
  385. package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
  386. package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
  387. package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
  388. package/src/__tests__/runtime-events-sse-parity.test.ts +15 -17
  389. package/src/__tests__/runtime-events-sse.test.ts +16 -33
  390. package/src/__tests__/schedule-routes.test.ts +226 -129
  391. package/src/__tests__/schedule-store.test.ts +119 -1
  392. package/src/__tests__/schedule-tools.test.ts +2 -1
  393. package/src/__tests__/scheduler-recurrence.test.ts +2 -1
  394. package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
  395. package/src/__tests__/scheduler-wake.test.ts +356 -0
  396. package/src/__tests__/scoped-approval-grants.test.ts +2 -1
  397. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
  398. package/src/__tests__/search-skills-unified.test.ts +9 -15
  399. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  400. package/src/__tests__/secret-ingress-http.test.ts +36 -23
  401. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  402. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  403. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  404. package/src/__tests__/secret-response-routing.test.ts +29 -15
  405. package/src/__tests__/secret-routes-managed-proxy.test.ts +51 -103
  406. package/src/__tests__/secret-scanner.test.ts +2 -545
  407. package/src/__tests__/send-endpoint-busy.test.ts +36 -38
  408. package/src/__tests__/sequence-store.test.ts +2 -1
  409. package/src/__tests__/server-history-render.test.ts +2 -2
  410. package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
  411. package/src/__tests__/set-permission-mode.test.ts +0 -10
  412. package/src/__tests__/settings-routes.test.ts +36 -69
  413. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  414. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  415. package/src/__tests__/skill-boundary-guard.test.ts +105 -0
  416. package/src/__tests__/skill-load-inline-command.test.ts +2 -2
  417. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  418. package/src/__tests__/skill-runtime-path.test.ts +64 -0
  419. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  420. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  421. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -32
  422. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  423. package/src/__tests__/slack-inbound-verification.test.ts +12 -64
  424. package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
  425. package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
  426. package/src/__tests__/slack-share-routes.test.ts +37 -72
  427. package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
  428. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  429. package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
  430. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  431. package/src/__tests__/subagent-notify-parent.test.ts +83 -109
  432. package/src/__tests__/subagent-role-registry.test.ts +3 -3
  433. package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
  434. package/src/__tests__/subagent-tools.test.ts +0 -1
  435. package/src/__tests__/suggestion-routes.test.ts +55 -62
  436. package/src/__tests__/system-prompt.test.ts +115 -13
  437. package/src/__tests__/task-compiler.test.ts +2 -1
  438. package/src/__tests__/task-management-tools.test.ts +2 -1
  439. package/src/__tests__/task-memory-cleanup.test.ts +2 -1
  440. package/src/__tests__/task-scheduler.test.ts +2 -1
  441. package/src/__tests__/telegram-config.test.ts +0 -1
  442. package/src/__tests__/terminal-tools.test.ts +3 -401
  443. package/src/__tests__/test-preload.ts +0 -11
  444. package/src/__tests__/thread-backfill.test.ts +947 -32
  445. package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
  446. package/src/__tests__/tool-approval-handler.test.ts +21 -63
  447. package/src/__tests__/tool-audit-listener.test.ts +3 -3
  448. package/src/__tests__/tool-domain-event-publisher.test.ts +3 -39
  449. package/src/__tests__/tool-error-pipeline.test.ts +6 -6
  450. package/src/__tests__/tool-execute-pipeline.test.ts +6 -14
  451. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  452. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +69 -16
  453. package/src/__tests__/tool-executor-lifecycle-events.test.ts +31 -62
  454. package/src/__tests__/tool-executor.test.ts +336 -1654
  455. package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
  456. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  457. package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
  458. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  459. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  460. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  461. package/src/__tests__/trust-context-guards.test.ts +1 -1
  462. package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
  463. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
  464. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +5 -151
  465. package/src/__tests__/trusted-contact-multichannel.test.ts +5 -6
  466. package/src/__tests__/trusted-contact-verification.test.ts +3 -2
  467. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  468. package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
  469. package/src/__tests__/twilio-routes.test.ts +25 -66
  470. package/src/__tests__/usage-attribution.test.ts +247 -0
  471. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
  472. package/src/__tests__/usage-cli.test.ts +143 -0
  473. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  474. package/src/__tests__/usage-routes.test.ts +223 -90
  475. package/src/__tests__/user-plugin-loader.test.ts +54 -12
  476. package/src/__tests__/validation-results-screen.test.ts +39 -16
  477. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  478. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +51 -139
  479. package/src/__tests__/verification-control-plane-policy.test.ts +97 -19
  480. package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
  481. package/src/__tests__/voice-invite-redemption.test.ts +2 -1
  482. package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
  483. package/src/__tests__/voice-session-bridge.test.ts +285 -106
  484. package/src/__tests__/volume-security-guard.test.ts +0 -2
  485. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
  486. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
  487. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
  488. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
  489. package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
  490. package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
  491. package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
  492. package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
  493. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
  494. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  495. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  496. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  497. package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
  498. package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
  499. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +252 -0
  500. package/src/acp/__tests__/client-handler.test.ts +64 -0
  501. package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
  502. package/src/acp/__tests__/helpers/which-stub.ts +45 -0
  503. package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
  504. package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
  505. package/src/acp/__tests__/session-manager.test.ts +83 -0
  506. package/src/acp/client-handler.ts +23 -139
  507. package/src/acp/index.ts +0 -15
  508. package/src/acp/resolve-agent.test.ts +291 -0
  509. package/src/acp/resolve-agent.ts +176 -0
  510. package/src/acp/session-manager.ts +193 -31
  511. package/src/acp/types.ts +2 -50
  512. package/src/agent/loop.ts +53 -15
  513. package/src/agent/message-types.ts +0 -2
  514. package/src/approvals/AGENTS.md +5 -1
  515. package/src/approvals/__tests__/guardian-feed-event.test.ts +11 -12
  516. package/src/approvals/approval-primitive.ts +3 -20
  517. package/src/approvals/guardian-decision-primitive.ts +37 -68
  518. package/src/approvals/guardian-request-resolvers.ts +38 -104
  519. package/src/avatar/character-components.ts +6 -6
  520. package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
  521. package/src/backup/__tests__/backup-worker.test.ts +36 -10
  522. package/src/backup/__tests__/paths.test.ts +5 -4
  523. package/src/backup/__tests__/restore.test.ts +45 -28
  524. package/src/backup/backup-worker.ts +37 -12
  525. package/src/backup/paths.ts +11 -24
  526. package/src/backup/restore.ts +7 -11
  527. package/src/browser/__tests__/operations.test.ts +0 -35
  528. package/src/browser/operations.ts +1 -47
  529. package/src/browser-session/events.ts +0 -9
  530. package/src/bundler/package-resolver.ts +2 -6
  531. package/src/calls/active-call-lease.ts +1 -1
  532. package/src/calls/call-constants.ts +1 -1
  533. package/src/calls/call-controller.ts +1 -5
  534. package/src/calls/call-domain.ts +14 -14
  535. package/src/calls/call-pointer-messages.ts +4 -9
  536. package/src/calls/call-store.ts +2 -34
  537. package/src/calls/guardian-action-sweep.ts +9 -25
  538. package/src/calls/guardian-dispatch.ts +1 -20
  539. package/src/calls/guardian-question-copy.ts +0 -108
  540. package/src/calls/media-stream-audio-transcode.ts +2 -41
  541. package/src/calls/media-stream-server.ts +2 -3
  542. package/src/calls/media-stream-stt-session.ts +1 -3
  543. package/src/calls/relay-access-wait.ts +5 -8
  544. package/src/calls/relay-server.ts +15 -42
  545. package/src/calls/relay-setup-router.ts +2 -2
  546. package/src/calls/relay-verification.ts +4 -4
  547. package/src/calls/twilio-rest.ts +1 -39
  548. package/src/calls/twilio-routes.ts +160 -78
  549. package/src/calls/voice-control-protocol.ts +10 -10
  550. package/src/calls/voice-ingress-preflight.ts +2 -2
  551. package/src/calls/voice-session-bridge.ts +141 -77
  552. package/src/channels/__tests__/types.test.ts +25 -3
  553. package/src/channels/permission-profiles.ts +2 -72
  554. package/src/channels/types.ts +25 -44
  555. package/src/cli/AGENTS.md +1 -0
  556. package/src/cli/__tests__/notifications.test.ts +12 -10
  557. package/src/cli/commands/__tests__/attachment.test.ts +14 -8
  558. package/src/cli/commands/__tests__/backup.test.ts +3 -14
  559. package/src/cli/commands/__tests__/browser.test.ts +36 -31
  560. package/src/cli/commands/__tests__/cache.test.ts +175 -23
  561. package/src/cli/commands/__tests__/memory-v2.test.ts +382 -0
  562. package/src/cli/commands/__tests__/task.test.ts +36 -35
  563. package/src/cli/commands/__tests__/trust.test.ts +236 -0
  564. package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
  565. package/src/cli/commands/__tests__/ui.test.ts +17 -17
  566. package/src/cli/commands/__tests__/watchers.test.ts +29 -29
  567. package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
  568. package/src/cli/commands/attachment.ts +12 -8
  569. package/src/cli/commands/auth.ts +1 -1
  570. package/src/cli/commands/avatar.ts +192 -9
  571. package/src/cli/commands/backup.ts +18 -48
  572. package/src/cli/commands/browser.ts +52 -4
  573. package/src/cli/commands/cache-fs.ts +8 -0
  574. package/src/cli/commands/cache.ts +157 -84
  575. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  576. package/src/cli/commands/clients.ts +74 -17
  577. package/src/cli/commands/completions.ts +3 -3
  578. package/src/cli/commands/contacts.ts +241 -86
  579. package/src/cli/commands/conversations-defer.ts +364 -0
  580. package/src/cli/commands/conversations-import.ts +2 -3
  581. package/src/cli/commands/conversations.ts +63 -53
  582. package/src/cli/commands/credential-execution.ts +1 -1
  583. package/src/cli/commands/credentials.ts +139 -5
  584. package/src/cli/commands/default-action.ts +1 -1
  585. package/src/cli/commands/domain.ts +2 -2
  586. package/src/cli/commands/email.ts +7 -7
  587. package/src/cli/commands/image-generation.ts +1 -1
  588. package/src/cli/commands/keys.ts +5 -2
  589. package/src/cli/commands/mcp.ts +1 -1
  590. package/src/cli/commands/memory-v2.ts +315 -0
  591. package/src/cli/commands/memory.ts +8 -8
  592. package/src/cli/commands/notifications.ts +21 -20
  593. package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
  594. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
  595. package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
  596. package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
  597. package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
  598. package/src/cli/commands/oauth/connect.ts +2 -2
  599. package/src/cli/commands/pending.ts +102 -0
  600. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
  601. package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
  602. package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
  603. package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
  604. package/src/cli/commands/platform/connect.ts +3 -3
  605. package/src/cli/commands/platform/disconnect.ts +4 -6
  606. package/src/cli/commands/platform/index.ts +12 -10
  607. package/src/cli/commands/routes.ts +7 -1
  608. package/src/cli/commands/sequence.ts +7 -7
  609. package/src/cli/commands/skills.ts +264 -116
  610. package/src/cli/commands/task.ts +12 -10
  611. package/src/cli/commands/trust.ts +105 -167
  612. package/src/cli/commands/ui.ts +3 -3
  613. package/src/cli/commands/usage.ts +29 -15
  614. package/src/cli/commands/watchers.ts +8 -8
  615. package/src/cli/commands/webhooks.ts +270 -0
  616. package/src/cli/lib/daemon-avatar-client.ts +37 -0
  617. package/src/cli/lib/daemon-credential-client.ts +41 -189
  618. package/src/cli/lib/ipc-params.ts +22 -0
  619. package/src/cli/program.ts +6 -0
  620. package/src/cli.ts +1 -82
  621. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  622. package/src/config/acp-defaults.test.ts +57 -0
  623. package/src/config/acp-defaults.ts +40 -0
  624. package/src/config/acp-schema.ts +1 -1
  625. package/src/config/assistant-feature-flags.ts +18 -142
  626. package/src/config/bundled-skills/acp/SKILL.md +44 -16
  627. package/src/config/bundled-skills/acp/TOOLS.json +45 -1
  628. package/src/config/bundled-skills/acp/tools/acp-list-agents.ts +12 -0
  629. package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
  630. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
  631. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
  632. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
  633. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
  634. package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
  635. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  636. package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
  637. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  638. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
  639. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
  640. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
  641. package/src/config/bundled-skills/settings/SKILL.md +2 -17
  642. package/src/config/bundled-skills/settings/TOOLS.json +0 -56
  643. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  644. package/src/config/bundled-tool-registry.ts +4 -6
  645. package/src/config/env-registry.ts +12 -2
  646. package/src/config/env.ts +10 -22
  647. package/src/config/feature-flag-registry.json +38 -46
  648. package/src/config/llm-callsite-catalog.ts +12 -0
  649. package/src/config/llm-context-resolution.ts +80 -0
  650. package/src/config/llm-resolver.ts +90 -36
  651. package/src/config/loader.ts +9 -12
  652. package/src/config/schema.ts +5 -228
  653. package/src/config/schemas/__tests__/filing.test.ts +58 -0
  654. package/src/config/schemas/__tests__/memory-v2.test.ts +187 -0
  655. package/src/config/schemas/call-site-catalog.ts +271 -0
  656. package/src/config/schemas/calls.ts +5 -5
  657. package/src/config/schemas/filing.ts +12 -0
  658. package/src/config/schemas/host-browser.ts +2 -2
  659. package/src/config/schemas/inference.ts +1 -3
  660. package/src/config/schemas/ingress.ts +2 -2
  661. package/src/config/schemas/llm.ts +82 -12
  662. package/src/config/schemas/memory-retrieval.ts +2 -2
  663. package/src/config/schemas/memory-storage.ts +1 -1
  664. package/src/config/schemas/memory-v2.ts +185 -0
  665. package/src/config/schemas/memory.ts +2 -0
  666. package/src/config/schemas/security.ts +1 -102
  667. package/src/config/schemas/services.ts +52 -13
  668. package/src/config/schemas/skills.ts +5 -5
  669. package/src/config/schemas/tts.ts +1 -1
  670. package/src/config/seed-inference-profiles.ts +117 -0
  671. package/src/config/skills.ts +1 -91
  672. package/src/config/types.ts +3 -47
  673. package/src/contacts/contact-store.ts +2 -19
  674. package/src/contacts/contacts-write.ts +1 -143
  675. package/src/contacts/types.ts +8 -10
  676. package/src/context/token-estimator.ts +1 -1
  677. package/src/context/tool-result-truncation.ts +1 -1
  678. package/src/context/window-manager.ts +45 -6
  679. package/src/credential-execution/approval-bridge.ts +7 -69
  680. package/src/credential-execution/client.ts +17 -422
  681. package/src/credential-execution/feature-gates.ts +1 -2
  682. package/src/credential-execution/managed-catalog.ts +1 -1
  683. package/src/credential-execution/process-manager.ts +34 -10
  684. package/src/credential-health/credential-health-service.ts +22 -17
  685. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
  686. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +76 -83
  687. package/src/daemon/__tests__/daemon-skill-host.test.ts +265 -0
  688. package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
  689. package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
  690. package/src/daemon/approval-generators.ts +2 -14
  691. package/src/daemon/classifier.ts +0 -106
  692. package/src/daemon/config-watcher.ts +14 -54
  693. package/src/daemon/connection-policy.ts +1 -40
  694. package/src/daemon/conversation-agent-loop-handlers.ts +89 -9
  695. package/src/daemon/conversation-agent-loop.ts +440 -88
  696. package/src/daemon/conversation-attachments.ts +5 -81
  697. package/src/daemon/conversation-error.ts +9 -5
  698. package/src/daemon/conversation-history.ts +9 -9
  699. package/src/daemon/conversation-launch.ts +21 -136
  700. package/src/daemon/conversation-lifecycle.ts +1 -1
  701. package/src/daemon/conversation-messaging.ts +2 -1
  702. package/src/daemon/conversation-notifiers.ts +1 -1
  703. package/src/daemon/conversation-process.ts +90 -174
  704. package/src/daemon/conversation-runtime-assembly.ts +245 -164
  705. package/src/daemon/conversation-slash.ts +50 -164
  706. package/src/daemon/conversation-store.ts +344 -0
  707. package/src/daemon/conversation-surfaces.ts +27 -32
  708. package/src/daemon/conversation-tool-setup.ts +23 -202
  709. package/src/daemon/conversation-usage.ts +36 -0
  710. package/src/daemon/conversation.ts +129 -381
  711. package/src/daemon/daemon-control.ts +4 -72
  712. package/src/daemon/daemon-skill-host.ts +259 -0
  713. package/src/daemon/dictation-profile-store.ts +2 -26
  714. package/src/daemon/external-plugins-bootstrap.ts +67 -13
  715. package/src/daemon/first-greeting.ts +44 -156
  716. package/src/daemon/handlers/config-channels.ts +14 -14
  717. package/src/daemon/handlers/config-embeddings.ts +1 -1
  718. package/src/daemon/handlers/config-ingress.ts +27 -166
  719. package/src/daemon/handlers/config-model.test.ts +17 -0
  720. package/src/daemon/handlers/config-model.ts +8 -53
  721. package/src/daemon/handlers/config-telegram.ts +6 -53
  722. package/src/daemon/handlers/config-voice.ts +0 -42
  723. package/src/daemon/handlers/conversations.ts +32 -345
  724. package/src/daemon/handlers/recording.ts +27 -159
  725. package/src/daemon/handlers/shared.ts +50 -99
  726. package/src/daemon/handlers/skills.ts +55 -114
  727. package/src/daemon/host-bash-proxy.ts +67 -45
  728. package/src/daemon/host-browser-proxy.ts +65 -27
  729. package/src/daemon/host-cu-proxy.ts +40 -39
  730. package/src/daemon/host-file-proxy.ts +58 -37
  731. package/src/daemon/host-transfer-proxy.ts +538 -0
  732. package/src/daemon/lifecycle.ts +71 -272
  733. package/src/daemon/meet-host-startup.ts +51 -0
  734. package/src/daemon/meet-host-supervisor.ts +781 -0
  735. package/src/daemon/meet-manifest-loader.ts +410 -0
  736. package/src/daemon/memory-v2-startup.ts +35 -0
  737. package/src/daemon/message-protocol.ts +4 -7
  738. package/src/daemon/message-types/acp.ts +1 -0
  739. package/src/daemon/message-types/conversations.ts +23 -2
  740. package/src/daemon/message-types/host-bash.ts +1 -0
  741. package/src/daemon/message-types/host-cu.ts +1 -0
  742. package/src/daemon/message-types/host-file.ts +1 -0
  743. package/src/daemon/message-types/host-transfer.ts +42 -0
  744. package/src/daemon/message-types/integrations.ts +6 -0
  745. package/src/daemon/message-types/messages.ts +24 -23
  746. package/src/daemon/message-types/schedules.ts +1 -0
  747. package/src/daemon/message-types/settings.ts +0 -6
  748. package/src/daemon/message-types/shared.ts +5 -2
  749. package/src/daemon/message-types/subagents.ts +2 -1
  750. package/src/daemon/message-types/workspace.ts +1 -3
  751. package/src/daemon/pkb-reminder-builder.test.ts +13 -12
  752. package/src/daemon/pkb-reminder-builder.ts +8 -16
  753. package/src/daemon/process-message.ts +479 -0
  754. package/src/daemon/providers-setup.ts +14 -6
  755. package/src/daemon/server.ts +58 -1702
  756. package/src/daemon/shutdown-handlers.ts +3 -3
  757. package/src/daemon/startup-error.ts +1 -1
  758. package/src/daemon/tool-side-effects.ts +125 -107
  759. package/src/daemon/trust-context.ts +45 -0
  760. package/src/daemon/wake-target-adapter.ts +218 -0
  761. package/src/email/feature-gate.ts +1 -1
  762. package/src/events/domain-events.ts +1 -16
  763. package/src/events/tool-audit-listener.ts +5 -9
  764. package/src/events/tool-domain-event-publisher.ts +0 -10
  765. package/src/events/tool-metrics-listener.ts +1 -21
  766. package/src/events/tool-trace-listener.ts +0 -14
  767. package/src/filing/filing-service.ts +207 -55
  768. package/src/followups/followup-store.ts +3 -71
  769. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +93 -21
  770. package/src/heartbeat/heartbeat-service.ts +55 -16
  771. package/src/home/__tests__/feed-writer.test.ts +0 -4
  772. package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
  773. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  774. package/src/home/__tests__/rollup-producer.test.ts +67 -2
  775. package/src/home/assistant-feed-authoring.ts +8 -1
  776. package/src/home/feed-types.ts +1 -1
  777. package/src/home/feed-writer.ts +1 -2
  778. package/src/home/relationship-state-writer.ts +17 -4
  779. package/src/home/rewrite-feed-title.ts +58 -0
  780. package/src/home/rollup-producer.ts +16 -3
  781. package/src/inbound/platform-callback-registration.ts +1 -17
  782. package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
  783. package/src/ipc/__tests__/browser-ipc.test.ts +72 -58
  784. package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
  785. package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
  786. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +253 -0
  787. package/src/ipc/__tests__/skill-server.test.ts +182 -0
  788. package/src/ipc/__tests__/socket-path.test.ts +69 -23
  789. package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
  790. package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
  791. package/src/ipc/assistant-server.ts +443 -0
  792. package/src/ipc/cli-client.ts +3 -3
  793. package/src/ipc/gateway-client.test.ts +131 -0
  794. package/src/ipc/gateway-client.ts +98 -123
  795. package/src/ipc/ipc-framing.ts +281 -0
  796. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +171 -0
  797. package/src/ipc/routes/db-proxy.ts +73 -0
  798. package/src/ipc/routes/route-adapter.ts +32 -0
  799. package/src/ipc/routes/trust-rules.test.ts +123 -0
  800. package/src/ipc/skill-ipc-types.ts +54 -0
  801. package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
  802. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +388 -0
  803. package/src/ipc/skill-routes/__tests__/identity.test.ts +62 -0
  804. package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
  805. package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
  806. package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
  807. package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
  808. package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
  809. package/src/ipc/skill-routes/config.ts +47 -0
  810. package/src/ipc/skill-routes/events.ts +120 -0
  811. package/src/ipc/skill-routes/identity.ts +21 -0
  812. package/src/ipc/skill-routes/index.ts +37 -0
  813. package/src/ipc/skill-routes/log.ts +40 -0
  814. package/src/ipc/skill-routes/memory.ts +76 -0
  815. package/src/ipc/skill-routes/platform.ts +39 -0
  816. package/src/ipc/skill-routes/providers.ts +163 -0
  817. package/src/ipc/skill-routes/registries.ts +393 -0
  818. package/src/ipc/skill-server.ts +738 -0
  819. package/src/ipc/skill-socket-path.ts +20 -0
  820. package/src/ipc/socket-cleanup.ts +92 -0
  821. package/src/ipc/socket-path.ts +63 -32
  822. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
  823. package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
  824. package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
  825. package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
  826. package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
  827. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
  828. package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
  829. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
  830. package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
  831. package/src/live-voice/__tests__/protocol.test.ts +295 -0
  832. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +413 -0
  833. package/src/live-voice/live-voice-archive.ts +758 -0
  834. package/src/live-voice/live-voice-metrics.ts +472 -0
  835. package/src/live-voice/live-voice-session-manager.ts +222 -0
  836. package/src/live-voice/live-voice-session.ts +1144 -0
  837. package/src/live-voice/live-voice-tts.ts +260 -0
  838. package/src/live-voice/protocol.ts +515 -0
  839. package/src/mcp/client.ts +2 -2
  840. package/src/mcp/manager.ts +0 -5
  841. package/src/media/types.ts +4 -4
  842. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
  843. package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
  844. package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
  845. package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
  846. package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
  847. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  848. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
  849. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  850. package/src/memory/admin.ts +65 -7
  851. package/src/memory/app-git-service.ts +0 -46
  852. package/src/memory/app-store.ts +154 -0
  853. package/src/memory/attachments-store.ts +20 -16
  854. package/src/memory/auto-analysis-enqueue.ts +2 -17
  855. package/src/memory/canonical-guardian-store.ts +2 -1
  856. package/src/memory/channel-verification-sessions.ts +1 -1
  857. package/src/memory/checkpoints.ts +1 -1
  858. package/src/memory/context-search/agent-protocol.ts +424 -0
  859. package/src/memory/context-search/agent-runner.ts +1295 -0
  860. package/src/memory/context-search/format.ts +160 -0
  861. package/src/memory/context-search/limits.ts +106 -0
  862. package/src/memory/context-search/search.ts +387 -0
  863. package/src/memory/context-search/sources/conversations.ts +278 -0
  864. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  865. package/src/memory/context-search/sources/memory.ts +95 -0
  866. package/src/memory/context-search/sources/pkb.ts +477 -0
  867. package/src/memory/context-search/sources/workspace.ts +1256 -0
  868. package/src/memory/context-search/types.ts +49 -0
  869. package/src/memory/conversation-analyze-job.ts +3 -24
  870. package/src/memory/conversation-attention-store.ts +1 -1
  871. package/src/memory/conversation-bootstrap.ts +1 -1
  872. package/src/memory/conversation-crud.ts +86 -119
  873. package/src/memory/conversation-directories.ts +1 -11
  874. package/src/memory/conversation-disk-view.ts +1 -5
  875. package/src/memory/conversation-display-order-migration.ts +11 -2
  876. package/src/memory/conversation-group-migration.ts +20 -4
  877. package/src/memory/conversation-key-store.ts +3 -4
  878. package/src/memory/conversation-queries.ts +13 -26
  879. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  880. package/src/memory/conversation-starter-validation.ts +88 -0
  881. package/src/memory/conversation-starters-cadence.ts +1 -1
  882. package/src/memory/conversation-title-service.ts +2 -1
  883. package/src/memory/db-connection.ts +62 -0
  884. package/src/memory/db-init.ts +28 -4
  885. package/src/memory/db-maintenance.ts +1 -1
  886. package/src/memory/delivery-channels.ts +1 -14
  887. package/src/memory/delivery-crud.ts +2 -32
  888. package/src/memory/delivery-status.ts +1 -1
  889. package/src/memory/embedding-backend.ts +3 -21
  890. package/src/memory/embedding-gemini.test.ts +4 -4
  891. package/src/memory/embedding-gemini.ts +0 -2
  892. package/src/memory/embedding-local.ts +6 -6
  893. package/src/memory/embedding-ollama.ts +6 -6
  894. package/src/memory/embedding-openai.ts +6 -6
  895. package/src/memory/embedding-types.ts +21 -0
  896. package/src/memory/external-conversation-store.ts +1 -1
  897. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +408 -0
  898. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
  899. package/src/memory/graph/bootstrap.test.ts +2 -7
  900. package/src/memory/graph/bootstrap.ts +2 -1
  901. package/src/memory/graph/capability-seed.ts +3 -3
  902. package/src/memory/graph/compaction.ts +1 -1
  903. package/src/memory/graph/consolidation.ts +13 -10
  904. package/src/memory/graph/conversation-graph-memory.ts +184 -12
  905. package/src/memory/graph/decay.ts +1 -1
  906. package/src/memory/graph/extraction.ts +53 -21
  907. package/src/memory/graph/graph-memory-state-store.ts +1 -1
  908. package/src/memory/graph/graph-search.test.ts +94 -2
  909. package/src/memory/graph/graph-search.ts +22 -7
  910. package/src/memory/graph/image-ref-utils.ts +1 -1
  911. package/src/memory/graph/injection.test.ts +2 -2
  912. package/src/memory/graph/injection.ts +1 -1
  913. package/src/memory/graph/retriever.test.ts +158 -4
  914. package/src/memory/graph/retriever.ts +17 -5
  915. package/src/memory/graph/store.test.ts +2 -1
  916. package/src/memory/graph/store.ts +1 -1
  917. package/src/memory/graph/tool-handlers.ts +73 -247
  918. package/src/memory/graph/tools.ts +35 -53
  919. package/src/memory/group-crud.ts +1 -2
  920. package/src/memory/guardian-action-store.ts +2 -84
  921. package/src/memory/guardian-approvals.ts +1 -49
  922. package/src/memory/guardian-rate-limits.ts +1 -1
  923. package/src/memory/indexer.ts +44 -32
  924. package/src/memory/invite-store.ts +1 -1
  925. package/src/memory/job-handlers/backfill.ts +1 -1
  926. package/src/memory/job-handlers/cleanup.ts +2 -1
  927. package/src/memory/job-handlers/conversation-starters.ts +54 -63
  928. package/src/memory/job-handlers/embedding.test.ts +2 -1
  929. package/src/memory/job-handlers/embedding.ts +1 -1
  930. package/src/memory/job-handlers/index-maintenance.ts +1 -1
  931. package/src/memory/job-handlers/summarization.ts +3 -3
  932. package/src/memory/job-utils.ts +3 -9
  933. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
  934. package/src/memory/jobs/embed-concept-page.ts +210 -0
  935. package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
  936. package/src/memory/jobs-store.ts +9 -2
  937. package/src/memory/jobs-worker.ts +56 -17
  938. package/src/memory/lifecycle-events-store.ts +1 -1
  939. package/src/memory/llm-request-log-store.ts +1 -42
  940. package/src/memory/llm-usage-store.ts +130 -44
  941. package/src/memory/media-store.ts +1 -1
  942. package/src/memory/memory-recall-log-store.ts +1 -1
  943. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  944. package/src/memory/migrations/038-actor-token-records.ts +3 -0
  945. package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
  946. package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
  947. package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
  948. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
  949. package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
  950. package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
  951. package/src/memory/migrations/230-acp-session-history.ts +41 -0
  952. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
  953. package/src/memory/migrations/232-activation-state.ts +38 -0
  954. package/src/memory/migrations/233-document-conversations.ts +54 -0
  955. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  956. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  957. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  958. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  959. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  960. package/src/memory/migrations/index.ts +24 -0
  961. package/src/memory/migrations/registry.ts +31 -0
  962. package/src/memory/pkb/pkb-index.test.ts +4 -5
  963. package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
  964. package/src/memory/pkb/pkb-search.test.ts +83 -3
  965. package/src/memory/pkb/pkb-search.ts +27 -14
  966. package/src/memory/published-pages-store.ts +1 -1
  967. package/src/memory/raw-query.ts +2 -68
  968. package/src/memory/schema/acp.ts +30 -0
  969. package/src/memory/schema/conversations.ts +8 -1
  970. package/src/memory/schema/index.ts +1 -0
  971. package/src/memory/schema/infrastructure.ts +26 -32
  972. package/src/memory/schema/memory-graph.ts +36 -14
  973. package/src/memory/scoped-approval-grants.ts +2 -1
  974. package/src/memory/search/semantic.ts +7 -18
  975. package/src/memory/shared-app-links-store.ts +2 -1
  976. package/src/memory/tool-usage-store.ts +3 -1
  977. package/src/memory/trace-event-store.ts +2 -1
  978. package/src/memory/turn-events-store.ts +1 -1
  979. package/src/memory/usage-buckets.ts +40 -1
  980. package/src/memory/usage-grouped-buckets.ts +127 -0
  981. package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
  982. package/src/memory/v2/__tests__/activation.test.ts +1155 -0
  983. package/src/memory/v2/__tests__/backfill-jobs.test.ts +483 -0
  984. package/src/memory/v2/__tests__/consolidation-job.test.ts +412 -0
  985. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  986. package/src/memory/v2/__tests__/injection.test.ts +1161 -0
  987. package/src/memory/v2/__tests__/migration.test.ts +840 -0
  988. package/src/memory/v2/__tests__/page-store.test.ts +517 -0
  989. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  990. package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
  991. package/src/memory/v2/__tests__/sim.test.ts +549 -0
  992. package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
  993. package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
  994. package/src/memory/v2/__tests__/skill-store.test.ts +463 -0
  995. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  996. package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
  997. package/src/memory/v2/activation-store.ts +109 -0
  998. package/src/memory/v2/activation.ts +561 -0
  999. package/src/memory/v2/backfill-jobs.ts +357 -0
  1000. package/src/memory/v2/consolidation-job.ts +306 -0
  1001. package/src/memory/v2/edge-index.ts +191 -0
  1002. package/src/memory/v2/injection.ts +431 -0
  1003. package/src/memory/v2/migration.ts +647 -0
  1004. package/src/memory/v2/now-text.ts +37 -0
  1005. package/src/memory/v2/page-store.ts +382 -0
  1006. package/src/memory/v2/prompts/consolidation.ts +261 -0
  1007. package/src/memory/v2/prompts/sweep.ts +56 -0
  1008. package/src/memory/v2/qdrant.ts +342 -0
  1009. package/src/memory/v2/sim.ts +206 -0
  1010. package/src/memory/v2/skill-content.ts +42 -0
  1011. package/src/memory/v2/skill-qdrant.ts +395 -0
  1012. package/src/memory/v2/skill-store.ts +176 -0
  1013. package/src/memory/v2/static-context.ts +62 -0
  1014. package/src/memory/v2/sweep-job.ts +298 -0
  1015. package/src/memory/v2/types.ts +106 -0
  1016. package/src/memory/validation.ts +0 -11
  1017. package/src/messaging/draft-store.ts +0 -6
  1018. package/src/messaging/provider-types.ts +8 -0
  1019. package/src/messaging/provider.ts +7 -0
  1020. package/src/messaging/providers/gmail/client.ts +1 -121
  1021. package/src/messaging/providers/index.ts +262 -0
  1022. package/src/messaging/providers/outlook/client.ts +0 -73
  1023. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  1024. package/src/messaging/providers/slack/adapter.ts +122 -21
  1025. package/src/messaging/providers/slack/api.ts +242 -0
  1026. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  1027. package/src/messaging/providers/slack/backfill.ts +89 -11
  1028. package/src/messaging/providers/slack/client.ts +10 -124
  1029. package/src/messaging/providers/slack/message-metadata.ts +13 -3
  1030. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  1031. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  1032. package/src/messaging/providers/slack/send.ts +383 -0
  1033. package/src/messaging/providers/slack/types.ts +1 -0
  1034. package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
  1035. package/src/messaging/providers/telegram-bot/api.ts +253 -0
  1036. package/src/messaging/providers/telegram-bot/client.ts +17 -58
  1037. package/src/messaging/providers/telegram-bot/send.ts +232 -0
  1038. package/src/messaging/providers/whatsapp/adapter.ts +4 -36
  1039. package/src/messaging/providers/whatsapp/api.ts +319 -0
  1040. package/src/messaging/providers/whatsapp/client.ts +4 -48
  1041. package/src/messaging/providers/whatsapp/send.ts +209 -0
  1042. package/src/notifications/adapters/slack.ts +5 -23
  1043. package/src/notifications/adapters/telegram.ts +8 -29
  1044. package/src/notifications/conversation-candidates.ts +1 -1
  1045. package/src/notifications/conversation-seed-composer.ts +12 -6
  1046. package/src/notifications/copy-composer.ts +1 -1
  1047. package/src/notifications/decision-engine.ts +1 -1
  1048. package/src/notifications/decisions-store.ts +1 -1
  1049. package/src/notifications/deliveries-store.ts +2 -1
  1050. package/src/notifications/deterministic-checks.ts +1 -1
  1051. package/src/notifications/events-store.ts +1 -13
  1052. package/src/notifications/preferences-store.ts +1 -1
  1053. package/src/notifications/signal.ts +0 -9
  1054. package/src/oauth/connection-resolver.test.ts +8 -0
  1055. package/src/oauth/connection-resolver.ts +6 -5
  1056. package/src/oauth/credential-token-resolver.ts +97 -0
  1057. package/src/oauth/manual-token-connection.ts +30 -34
  1058. package/src/oauth/oauth-store.ts +8 -5
  1059. package/src/outbound-proxy/certs.ts +0 -7
  1060. package/src/outbound-proxy/config.ts +0 -74
  1061. package/src/outbound-proxy/health.ts +0 -44
  1062. package/src/outbound-proxy/index.ts +0 -23
  1063. package/src/permissions/approval-policy.test.ts +149 -132
  1064. package/src/permissions/approval-policy.ts +65 -91
  1065. package/src/permissions/approval-provenance.test.ts +184 -0
  1066. package/src/permissions/approval-provenance.ts +70 -0
  1067. package/src/permissions/checker.test.ts +632 -0
  1068. package/src/permissions/checker.ts +270 -460
  1069. package/src/permissions/gateway-threshold-reader.ts +31 -47
  1070. package/src/permissions/ipc-risk-types.ts +95 -0
  1071. package/src/permissions/prompter.ts +13 -11
  1072. package/src/permissions/risk-types.ts +24 -210
  1073. package/src/permissions/secret-prompter.ts +21 -48
  1074. package/src/permissions/types.ts +49 -46
  1075. package/src/permissions/workspace-policy.ts +1 -8
  1076. package/src/platform/sync-identity.ts +0 -8
  1077. package/src/playbooks/playbook-compiler.ts +1 -1
  1078. package/src/plugins/defaults/index.ts +1 -1
  1079. package/src/plugins/defaults/injectors.ts +87 -23
  1080. package/src/plugins/defaults/llm-call.ts +6 -9
  1081. package/src/plugins/defaults/memory-retrieval.ts +1 -6
  1082. package/src/plugins/defaults/overflow-reduce.ts +12 -7
  1083. package/src/plugins/defaults/token-estimate.ts +2 -3
  1084. package/src/plugins/registry.ts +61 -1
  1085. package/src/plugins/types.ts +14 -7
  1086. package/src/plugins/user-loader.ts +36 -10
  1087. package/src/prompts/persona-resolver.ts +2 -4
  1088. package/src/prompts/system-prompt.ts +34 -31
  1089. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  1090. package/src/prompts/templates/SOUL.md +3 -1
  1091. package/src/prompts/update-bulletin-job.ts +2 -0
  1092. package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
  1093. package/src/providers/__tests__/retry-callsite.test.ts +141 -7
  1094. package/src/providers/anthropic/client.ts +143 -52
  1095. package/src/providers/call-site-routing.ts +49 -6
  1096. package/src/providers/fireworks/client.ts +3 -0
  1097. package/src/providers/gemini/client.ts +113 -23
  1098. package/src/providers/managed-proxy/context.ts +0 -17
  1099. package/src/providers/model-catalog.ts +188 -27
  1100. package/src/providers/model-intents.ts +7 -8
  1101. package/src/providers/openai/chat-completions-provider.ts +43 -7
  1102. package/src/providers/openai/responses-provider.ts +46 -5
  1103. package/src/providers/openrouter/client.ts +4 -5
  1104. package/src/providers/provider-env-vars.ts +4 -12
  1105. package/src/providers/provider-send-message.ts +61 -13
  1106. package/src/providers/ratelimit.ts +7 -2
  1107. package/src/providers/registry.ts +15 -10
  1108. package/src/providers/retry.ts +148 -31
  1109. package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
  1110. package/src/providers/speech-to-text/openai-whisper.ts +3 -6
  1111. package/src/providers/speech-to-text/provider-catalog.ts +75 -0
  1112. package/src/providers/speech-to-text/xai.ts +5 -5
  1113. package/src/providers/thinking-config.ts +34 -0
  1114. package/src/providers/types.ts +35 -10
  1115. package/src/providers/usage-tracking.ts +96 -0
  1116. package/src/runtime/AGENTS.md +16 -11
  1117. package/src/runtime/__tests__/agent-wake.test.ts +122 -9
  1118. package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
  1119. package/src/runtime/access-request-helper.ts +9 -20
  1120. package/src/runtime/actor-trust-resolver.ts +2 -2
  1121. package/src/runtime/agent-wake.ts +211 -68
  1122. package/src/runtime/approval-conversation-turn.ts +2 -15
  1123. package/src/runtime/approval-message-composer.ts +11 -60
  1124. package/src/runtime/assistant-event-hub.ts +541 -45
  1125. package/src/runtime/assistant-event.ts +16 -69
  1126. package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
  1127. package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
  1128. package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
  1129. package/src/runtime/auth/middleware.ts +5 -5
  1130. package/src/runtime/auth/route-policy.ts +205 -12
  1131. package/src/runtime/auth/token-service.ts +1 -111
  1132. package/src/runtime/capability-tokens.ts +89 -313
  1133. package/src/runtime/channel-approval-types.ts +1 -6
  1134. package/src/runtime/channel-approvals.ts +13 -81
  1135. package/src/runtime/channel-readiness-service.ts +2 -2
  1136. package/src/runtime/channel-reply-delivery.ts +2 -8
  1137. package/src/runtime/channel-retry-sweep.ts +20 -17
  1138. package/src/runtime/channel-verification-service.ts +3 -5
  1139. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
  1140. package/src/runtime/gateway-client.ts +37 -378
  1141. package/src/runtime/guardian-action-grant-minter.ts +2 -3
  1142. package/src/runtime/guardian-action-message-composer.ts +11 -52
  1143. package/src/runtime/guardian-action-service.ts +19 -7
  1144. package/src/runtime/guardian-decision-types.ts +4 -65
  1145. package/src/runtime/guardian-reply-router.ts +10 -19
  1146. package/src/runtime/guardian-vellum-migration.ts +5 -64
  1147. package/src/runtime/http-errors.ts +1 -32
  1148. package/src/runtime/http-router.ts +54 -8
  1149. package/src/runtime/http-server.ts +362 -1187
  1150. package/src/runtime/http-types.ts +20 -98
  1151. package/src/runtime/interactive-ui-types.ts +145 -0
  1152. package/src/runtime/interactive-ui.ts +37 -196
  1153. package/src/runtime/invite-redemption-service.ts +1 -1
  1154. package/src/runtime/invite-redemption-templates.ts +1 -1
  1155. package/src/runtime/local-actor-identity.ts +13 -43
  1156. package/src/runtime/message-composer-types.ts +134 -0
  1157. package/src/runtime/middleware/auth.ts +0 -20
  1158. package/src/runtime/middleware/rate-limiter.ts +1 -1
  1159. package/src/runtime/middleware/request-logger.ts +5 -2
  1160. package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
  1161. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  1162. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  1163. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  1164. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  1165. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  1166. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  1167. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  1168. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  1169. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +18 -2
  1170. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  1171. package/src/runtime/migrations/job-registry.ts +281 -0
  1172. package/src/runtime/migrations/migration-transport.ts +46 -13
  1173. package/src/runtime/migrations/migration-wizard.ts +2 -2
  1174. package/src/runtime/migrations/origin-mode.ts +40 -0
  1175. package/src/runtime/migrations/vbundle-builder.ts +133 -80
  1176. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  1177. package/src/runtime/migrations/vbundle-importer.ts +8 -8
  1178. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  1179. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -16
  1180. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  1181. package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
  1182. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  1183. package/src/runtime/nl-approval-parser.ts +16 -21
  1184. package/src/runtime/pending-interactions.ts +42 -16
  1185. package/src/runtime/routes/__tests__/acp-routes.test.ts +394 -0
  1186. package/src/runtime/routes/__tests__/backup-routes.test.ts +232 -339
  1187. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  1188. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
  1189. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  1190. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  1191. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  1192. package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
  1193. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
  1194. package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
  1195. package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
  1196. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  1197. package/src/runtime/routes/access-request-decision.ts +25 -50
  1198. package/src/runtime/routes/acp-routes.test.ts +368 -0
  1199. package/src/runtime/routes/acp-routes.ts +392 -170
  1200. package/src/runtime/routes/app-management-routes.ts +475 -662
  1201. package/src/runtime/routes/app-routes.ts +192 -177
  1202. package/src/runtime/routes/approval-routes.ts +163 -440
  1203. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
  1204. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
  1205. package/src/runtime/routes/attachment-routes.ts +409 -253
  1206. package/src/runtime/routes/audio-routes.ts +51 -18
  1207. package/src/runtime/routes/avatar-routes.ts +81 -76
  1208. package/src/runtime/routes/background-tool-routes.ts +94 -0
  1209. package/src/runtime/routes/backup-routes.ts +154 -336
  1210. package/src/runtime/routes/brain-graph-routes.ts +83 -110
  1211. package/src/runtime/routes/browser-routes.ts +127 -0
  1212. package/src/runtime/routes/btw-routes.ts +62 -106
  1213. package/src/runtime/routes/cache-routes.ts +96 -0
  1214. package/src/runtime/routes/call-routes.ts +208 -247
  1215. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1216. package/src/runtime/routes/channel-delivery-routes.ts +25 -27
  1217. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  1218. package/src/runtime/routes/channel-readiness-routes.ts +79 -120
  1219. package/src/runtime/routes/channel-route-definitions.ts +62 -0
  1220. package/src/runtime/routes/channel-route-shared.ts +15 -45
  1221. package/src/runtime/routes/channel-verification-routes.ts +207 -187
  1222. package/src/runtime/routes/client-routes.ts +81 -0
  1223. package/src/runtime/routes/consolidation-routes.ts +115 -0
  1224. package/src/runtime/routes/contact-routes.ts +533 -407
  1225. package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
  1226. package/src/runtime/routes/conversation-attention-routes.ts +55 -67
  1227. package/src/runtime/routes/conversation-list-routes.ts +248 -0
  1228. package/src/runtime/routes/conversation-management-routes.ts +591 -717
  1229. package/src/runtime/routes/conversation-query-routes.ts +621 -459
  1230. package/src/runtime/routes/conversation-routes.ts +396 -792
  1231. package/src/runtime/routes/conversation-starter-routes.ts +137 -108
  1232. package/src/runtime/routes/credential-prompt-routes.ts +124 -0
  1233. package/src/runtime/routes/debug-routes.ts +34 -39
  1234. package/src/runtime/routes/defer-routes.ts +230 -0
  1235. package/src/runtime/routes/diagnostics-routes.ts +79 -70
  1236. package/src/runtime/routes/documents-routes.ts +163 -117
  1237. package/src/runtime/routes/errors.ts +132 -0
  1238. package/src/runtime/routes/events-routes.ts +126 -119
  1239. package/src/runtime/routes/filing-routes.ts +80 -76
  1240. package/src/runtime/routes/global-search-routes.ts +51 -57
  1241. package/src/runtime/routes/group-routes.ts +199 -181
  1242. package/src/runtime/routes/guardian-action-routes.ts +100 -171
  1243. package/src/runtime/routes/guardian-approval-interception.ts +27 -58
  1244. package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
  1245. package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
  1246. package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
  1247. package/src/runtime/routes/heartbeat-routes.ts +194 -209
  1248. package/src/runtime/routes/home-feed-routes.ts +85 -187
  1249. package/src/runtime/routes/home-state-routes.ts +27 -24
  1250. package/src/runtime/routes/host-bash-routes.ts +45 -54
  1251. package/src/runtime/routes/host-browser-routes.ts +44 -99
  1252. package/src/runtime/routes/host-cu-routes.ts +80 -71
  1253. package/src/runtime/routes/host-file-routes.ts +53 -62
  1254. package/src/runtime/routes/host-transfer-routes.ts +216 -0
  1255. package/src/runtime/routes/http-adapter.ts +172 -0
  1256. package/src/runtime/routes/identity-routes.ts +161 -85
  1257. package/src/runtime/routes/inbound-conversation.ts +11 -18
  1258. package/src/runtime/routes/inbound-message-handler.ts +639 -232
  1259. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +81 -226
  1260. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
  1261. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -90
  1262. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
  1263. package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
  1264. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  1265. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
  1266. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
  1267. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
  1268. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  1269. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
  1270. package/src/runtime/routes/index.ts +201 -0
  1271. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
  1272. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
  1273. package/src/runtime/routes/integrations/slack/channel.ts +50 -71
  1274. package/src/runtime/routes/integrations/slack/share.ts +49 -58
  1275. package/src/runtime/routes/integrations/telegram.ts +91 -74
  1276. package/src/runtime/routes/integrations/twilio.ts +163 -240
  1277. package/src/runtime/routes/integrations/vercel.ts +57 -54
  1278. package/src/runtime/routes/interface-routes.ts +43 -0
  1279. package/src/runtime/routes/internal-oauth-routes.ts +56 -0
  1280. package/src/runtime/routes/internal-twilio-routes.ts +46 -0
  1281. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  1282. package/src/runtime/routes/llm-context-normalization.ts +4 -2
  1283. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1284. package/src/runtime/routes/log-export-routes.ts +90 -100
  1285. package/src/runtime/routes/memory-item-routes.test.ts +152 -175
  1286. package/src/runtime/routes/memory-item-routes.ts +243 -323
  1287. package/src/runtime/routes/memory-v2-routes.ts +188 -0
  1288. package/src/runtime/routes/migration-rollback-routes.ts +167 -212
  1289. package/src/runtime/routes/migration-routes.ts +1037 -377
  1290. package/src/runtime/routes/notification-routes.ts +199 -70
  1291. package/src/runtime/routes/oauth-apps.ts +254 -251
  1292. package/src/runtime/routes/oauth-providers.ts +66 -57
  1293. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +60 -120
  1294. package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
  1295. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
  1296. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
  1297. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
  1298. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
  1299. package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
  1300. package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
  1301. package/src/runtime/routes/playground/force-compact.ts +41 -54
  1302. package/src/runtime/routes/playground/guard.ts +18 -19
  1303. package/src/runtime/routes/playground/helpers.ts +103 -0
  1304. package/src/runtime/routes/playground/index.ts +15 -27
  1305. package/src/runtime/routes/playground/inject-failures.ts +48 -64
  1306. package/src/runtime/routes/playground/reset-circuit.ts +31 -57
  1307. package/src/runtime/routes/playground/seed-conversation.ts +66 -92
  1308. package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
  1309. package/src/runtime/routes/playground/state.ts +23 -24
  1310. package/src/runtime/routes/profiler-routes.ts +132 -167
  1311. package/src/runtime/routes/ps-routes.ts +120 -0
  1312. package/src/runtime/routes/recording-routes.ts +189 -270
  1313. package/src/runtime/routes/rename-conversation-routes.ts +85 -0
  1314. package/src/runtime/routes/schedule-routes.ts +239 -246
  1315. package/src/runtime/routes/secret-routes.ts +305 -282
  1316. package/src/runtime/routes/secrets-deps.ts +24 -0
  1317. package/src/runtime/routes/settings-routes.ts +370 -449
  1318. package/src/runtime/routes/skills-routes.ts +417 -471
  1319. package/src/runtime/routes/stt-routes.ts +196 -206
  1320. package/src/runtime/routes/subagents-routes.ts +125 -141
  1321. package/src/runtime/routes/suggest-trust-rule-routes.ts +275 -0
  1322. package/src/runtime/routes/surface-action-routes.ts +135 -190
  1323. package/src/runtime/routes/surface-content-routes.ts +84 -118
  1324. package/src/runtime/routes/task-routes.ts +354 -0
  1325. package/src/runtime/routes/telemetry-routes.ts +33 -49
  1326. package/src/runtime/routes/trace-event-routes.ts +55 -74
  1327. package/src/runtime/routes/trust-rules-routes.ts +61 -244
  1328. package/src/runtime/routes/tts-routes.ts +187 -169
  1329. package/src/runtime/routes/types.ts +139 -0
  1330. package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
  1331. package/src/runtime/routes/upgrade-broadcast-routes.ts +150 -198
  1332. package/src/runtime/routes/usage-routes.ts +222 -171
  1333. package/src/runtime/routes/user-routes.ts +88 -18
  1334. package/src/runtime/routes/wake-conversation-routes.ts +49 -0
  1335. package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
  1336. package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
  1337. package/src/runtime/routes/work-items-routes.test.ts +10 -20
  1338. package/src/runtime/routes/work-items-routes.ts +419 -437
  1339. package/src/runtime/routes/workspace-commit-routes.ts +30 -61
  1340. package/src/runtime/routes/workspace-routes.test.ts +254 -381
  1341. package/src/runtime/routes/workspace-routes.ts +238 -246
  1342. package/src/runtime/runtime-mode.ts +8 -1
  1343. package/src/runtime/services/__tests__/analyze-conversation.test.ts +82 -120
  1344. package/src/runtime/services/analyze-conversation.ts +18 -55
  1345. package/src/runtime/services/conversation-serializer.ts +179 -0
  1346. package/src/runtime/trust-context-resolver.ts +3 -2
  1347. package/src/runtime/verification-outbound-actions.ts +14 -50
  1348. package/src/runtime/verification-rate-limiter.ts +1 -1
  1349. package/src/schedule/schedule-store.ts +64 -18
  1350. package/src/schedule/scheduler.ts +101 -0
  1351. package/src/security/ces-credential-client.ts +32 -169
  1352. package/src/security/ces-rpc-credential-backend.ts +1 -1
  1353. package/src/security/credential-backend.ts +6 -6
  1354. package/src/security/oauth-completion-page.ts +1 -1
  1355. package/src/security/oauth2.ts +3 -6
  1356. package/src/security/secret-scanner.ts +14 -547
  1357. package/src/security/secure-keys.ts +31 -11
  1358. package/src/security/token-manager.ts +7 -3
  1359. package/src/sequence/analytics.ts +1 -1
  1360. package/src/sequence/guardrails.ts +3 -3
  1361. package/src/sequence/store.ts +2 -1
  1362. package/src/signals/bash.ts +1 -1
  1363. package/src/signals/cancel.ts +16 -25
  1364. package/src/signals/conversation-undo.ts +2 -27
  1365. package/src/signals/emit-event.ts +1 -2
  1366. package/src/signals/event-stream.ts +1 -1
  1367. package/src/signals/user-message.ts +108 -22
  1368. package/src/skills/catalog-cache.ts +7 -0
  1369. package/src/skills/catalog-files.ts +0 -5
  1370. package/src/skills/catalog-install.ts +29 -18
  1371. package/src/skills/category-inference.ts +0 -11
  1372. package/src/skills/clawhub.ts +4 -4
  1373. package/src/skills/inline-command-runner.ts +1 -7
  1374. package/src/skills/managed-store.ts +2 -2
  1375. package/src/skills/remote-skill-policy.ts +6 -7
  1376. package/src/subagent/index.ts +2 -6
  1377. package/src/subagent/manager.ts +94 -107
  1378. package/src/subagent/types.ts +9 -0
  1379. package/src/tasks/SPEC.md +2 -2
  1380. package/src/tasks/task-compiler.ts +1 -1
  1381. package/src/tasks/task-runner.ts +2 -22
  1382. package/src/tasks/task-store.ts +2 -29
  1383. package/src/telemetry/types.ts +6 -0
  1384. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  1385. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  1386. package/src/tools/acp/list-agents.test.ts +115 -0
  1387. package/src/tools/acp/list-agents.ts +31 -0
  1388. package/src/tools/acp/spawn.test.ts +378 -0
  1389. package/src/tools/acp/spawn.ts +142 -62
  1390. package/src/tools/acp/steer.test.ts +100 -0
  1391. package/src/tools/acp/steer.ts +38 -0
  1392. package/src/tools/background-tool-registry.ts +98 -0
  1393. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  1394. package/src/tools/browser/browser-execution.ts +38 -127
  1395. package/src/tools/browser/browser-manager.ts +1 -8
  1396. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  1397. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
  1398. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
  1399. package/src/tools/browser/cdp-client/factory.ts +48 -76
  1400. package/src/tools/browser/cdp-client/index.ts +1 -14
  1401. package/src/tools/browser/cdp-client/types.ts +4 -1
  1402. package/src/tools/computer-use/definitions.ts +1 -1
  1403. package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
  1404. package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
  1405. package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
  1406. package/src/tools/credentials/broker-types.ts +2 -1
  1407. package/src/tools/document/editor-template.ts +1 -1
  1408. package/src/tools/execution-timeout.ts +1 -1
  1409. package/src/tools/executor.ts +53 -45
  1410. package/src/tools/host-filesystem/edit.ts +3 -2
  1411. package/src/tools/host-filesystem/read.ts +3 -2
  1412. package/src/tools/host-filesystem/transfer.test.ts +271 -0
  1413. package/src/tools/host-filesystem/transfer.ts +235 -0
  1414. package/src/tools/host-filesystem/write.ts +3 -2
  1415. package/src/tools/host-terminal/host-shell.ts +192 -13
  1416. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  1417. package/src/tools/memory/register.test.ts +161 -1
  1418. package/src/tools/memory/register.ts +19 -34
  1419. package/src/tools/network/script-proxy/index.ts +1 -10
  1420. package/src/tools/permission-checker.ts +84 -220
  1421. package/src/tools/policy-context.ts +1 -8
  1422. package/src/tools/registry.ts +16 -1
  1423. package/src/tools/shared/shell-output.ts +4 -1
  1424. package/src/tools/side-effects.ts +2 -2
  1425. package/src/tools/skills/execute.ts +1 -1
  1426. package/src/tools/skills/sandbox-runner.ts +1 -6
  1427. package/src/tools/skills/skill-tool-factory.ts +32 -0
  1428. package/src/tools/subagent/spawn.ts +35 -11
  1429. package/src/tools/terminal/safe-env.ts +10 -1
  1430. package/src/tools/terminal/shell.ts +142 -88
  1431. package/src/tools/tool-approval-handler.ts +4 -70
  1432. package/src/tools/tool-input-summary.ts +10 -0
  1433. package/src/tools/types.ts +136 -183
  1434. package/src/tools/ui-surface/definitions.ts +2 -2
  1435. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  1436. package/src/tts/provider-catalog.ts +1 -1
  1437. package/src/usage/actors.ts +2 -1
  1438. package/src/usage/attribution.ts +185 -0
  1439. package/src/usage/pricing.ts +166 -0
  1440. package/src/usage/types.ts +14 -0
  1441. package/src/util/debounce.ts +0 -21
  1442. package/src/util/errors.ts +0 -8
  1443. package/src/util/json.ts +13 -0
  1444. package/src/util/log-redact.ts +0 -1
  1445. package/src/util/logger.ts +3 -3
  1446. package/src/util/platform.ts +85 -124
  1447. package/src/util/pricing.ts +158 -8
  1448. package/src/watcher/engine.ts +42 -20
  1449. package/src/watcher/watcher-store.ts +2 -1
  1450. package/src/work-items/work-item-runner.ts +15 -42
  1451. package/src/work-items/work-item-store.ts +1 -1
  1452. package/src/workspace/git-service.ts +1 -6
  1453. package/src/workspace/migrations/006-services-config.ts +10 -1
  1454. package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
  1455. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
  1456. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
  1457. package/src/workspace/migrations/031-drop-user-md.ts +1 -1
  1458. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
  1459. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  1460. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
  1461. package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
  1462. package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
  1463. package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
  1464. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
  1465. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
  1466. package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
  1467. package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
  1468. package/src/workspace/migrations/060-memory-v2-init.ts +37 -0
  1469. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  1470. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  1471. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  1472. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  1473. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
  1474. package/src/workspace/migrations/registry.ts +26 -0
  1475. package/src/workspace/migrations/runner.ts +2 -2
  1476. package/src/workspace/provider-commit-message-generator.ts +4 -4
  1477. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  1478. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  1479. package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
  1480. package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
  1481. package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
  1482. package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
  1483. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
  1484. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
  1485. package/src/__tests__/ephemeral-permissions.test.ts +0 -474
  1486. package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
  1487. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
  1488. package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
  1489. package/src/__tests__/pairing-concurrent.test.ts +0 -84
  1490. package/src/__tests__/pairing-routes.test.ts +0 -181
  1491. package/src/__tests__/parser.test.ts +0 -595
  1492. package/src/__tests__/permission-checker-host-gate.test.ts +0 -488
  1493. package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
  1494. package/src/__tests__/permission-mode.test.ts +0 -89
  1495. package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
  1496. package/src/__tests__/risk-classifier-parity.test.ts +0 -230
  1497. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  1498. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  1499. package/src/__tests__/secret-detection-handler.test.ts +0 -74
  1500. package/src/__tests__/secret-scanner-executor.test.ts +0 -451
  1501. package/src/__tests__/shell-identity.test.ts +0 -236
  1502. package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
  1503. package/src/__tests__/shell-parser-property.test.ts +0 -936
  1504. package/src/__tests__/starter-bundle.test.ts +0 -173
  1505. package/src/__tests__/stt-catalog-parity.test.ts +0 -282
  1506. package/src/__tests__/task-runner.test.ts +0 -224
  1507. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  1508. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  1509. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -354
  1510. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  1511. package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
  1512. package/src/__tests__/trust-store.test.ts +0 -2013
  1513. package/src/__tests__/v2-consent-policy.test.ts +0 -103
  1514. package/src/browser/identifiers.ts +0 -51
  1515. package/src/cli/db.ts +0 -1
  1516. package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
  1517. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
  1518. package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
  1519. package/src/context/__tests__/microcompact.test.ts +0 -805
  1520. package/src/context/microcompact.ts +0 -443
  1521. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
  1522. package/src/daemon/approved-devices-store.ts +0 -110
  1523. package/src/daemon/external-skills-bootstrap.ts +0 -41
  1524. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  1525. package/src/daemon/message-types/trust.ts +0 -71
  1526. package/src/daemon/pairing-store.ts +0 -229
  1527. package/src/events/tool-notification-listener.ts +0 -17
  1528. package/src/ipc/cli-server.ts +0 -252
  1529. package/src/ipc/routes/attachment.ts +0 -114
  1530. package/src/ipc/routes/browser-context.ts +0 -63
  1531. package/src/ipc/routes/browser.ts +0 -97
  1532. package/src/ipc/routes/cache.ts +0 -96
  1533. package/src/ipc/routes/get-contact.ts +0 -16
  1534. package/src/ipc/routes/index.ts +0 -35
  1535. package/src/ipc/routes/list-clients.ts +0 -31
  1536. package/src/ipc/routes/merge-contacts.ts +0 -17
  1537. package/src/ipc/routes/notification.ts +0 -133
  1538. package/src/ipc/routes/rename-conversation.ts +0 -59
  1539. package/src/ipc/routes/search-contacts.ts +0 -19
  1540. package/src/ipc/routes/task-queue.ts +0 -226
  1541. package/src/ipc/routes/task.ts +0 -173
  1542. package/src/ipc/routes/upsert-contact.ts +0 -25
  1543. package/src/ipc/routes/wake-conversation.ts +0 -19
  1544. package/src/memory/db.ts +0 -23
  1545. package/src/permissions/arg-parser.test.ts +0 -161
  1546. package/src/permissions/arg-parser.ts +0 -141
  1547. package/src/permissions/bash-risk-classifier.test.ts +0 -1620
  1548. package/src/permissions/bash-risk-classifier.ts +0 -950
  1549. package/src/permissions/command-registry.test.ts +0 -774
  1550. package/src/permissions/command-registry.ts +0 -1005
  1551. package/src/permissions/defaults.ts +0 -314
  1552. package/src/permissions/file-risk-classifier.test.ts +0 -535
  1553. package/src/permissions/file-risk-classifier.ts +0 -274
  1554. package/src/permissions/permission-mode.ts +0 -24
  1555. package/src/permissions/schedule-risk-classifier.test.ts +0 -129
  1556. package/src/permissions/schedule-risk-classifier.ts +0 -85
  1557. package/src/permissions/shell-identity.ts +0 -297
  1558. package/src/permissions/skill-risk-classifier.test.ts +0 -311
  1559. package/src/permissions/skill-risk-classifier.ts +0 -214
  1560. package/src/permissions/trust-client.ts +0 -359
  1561. package/src/permissions/trust-store-interface.ts +0 -100
  1562. package/src/permissions/trust-store.ts +0 -1330
  1563. package/src/permissions/v2-consent-policy.ts +0 -87
  1564. package/src/permissions/web-risk-classifier.test.ts +0 -170
  1565. package/src/permissions/web-risk-classifier.ts +0 -89
  1566. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
  1567. package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
  1568. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  1569. package/src/runtime/__tests__/client-registry.test.ts +0 -293
  1570. package/src/runtime/actor-refresh-token-store.ts +0 -156
  1571. package/src/runtime/actor-token-store.ts +0 -207
  1572. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
  1573. package/src/runtime/auth/credential-service.ts +0 -352
  1574. package/src/runtime/chrome-extension-registry.ts +0 -368
  1575. package/src/runtime/client-registry.ts +0 -261
  1576. package/src/runtime/conversation-approval-overrides.ts +0 -86
  1577. package/src/runtime/routes/browser-extension-pair-routes.ts +0 -575
  1578. package/src/runtime/routes/channel-routes.ts +0 -112
  1579. package/src/runtime/routes/contact-routes.test.ts +0 -298
  1580. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
  1581. package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
  1582. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -336
  1583. package/src/runtime/routes/invite-routes.ts +0 -280
  1584. package/src/runtime/routes/pairing-routes.ts +0 -431
  1585. package/src/runtime/routes/playground/deps.ts +0 -56
  1586. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
  1587. package/src/runtime/services/analyze-deps-singleton.ts +0 -32
  1588. package/src/tasks/ephemeral-permissions.ts +0 -55
  1589. package/src/tools/secret-detection-handler.ts +0 -359
  1590. package/src/tools/terminal/backends/native.ts +0 -327
  1591. package/src/tools/terminal/backends/types.ts +0 -37
  1592. package/src/tools/terminal/parser.ts +0 -623
  1593. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  1594. package/src/tools/terminal/sandbox.ts +0 -40
  1595. package/src/types/qrcode.d.ts +0 -13
  1596. package/src/util/network-info.ts +0 -55
  1597. /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
  1598. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  1599. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  1600. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  1601. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  1602. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  1603. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
@@ -18,10 +18,8 @@ import {
18
18
  createUserMessage,
19
19
  } from "../../agent/message-types.js";
20
20
  import {
21
- canServiceRegistryBrowser,
22
21
  CHANNEL_IDS,
23
22
  INTERFACE_IDS,
24
- type InterfaceId,
25
23
  isInteractiveInterface,
26
24
  parseChannelId,
27
25
  parseInterfaceId,
@@ -29,6 +27,7 @@ import {
29
27
  } from "../../channels/types.js";
30
28
  import { isHttpAuthDisabled } from "../../config/env.js";
31
29
  import { getConfig } from "../../config/loader.js";
30
+ import { createApprovalConversationGenerator } from "../../daemon/approval-generators.js";
32
31
  import type { Conversation } from "../../daemon/conversation.js";
33
32
  import {
34
33
  buildModelInfoEvent,
@@ -36,34 +35,34 @@ import {
36
35
  isModelSlashCommand,
37
36
  } from "../../daemon/conversation-process.js";
38
37
  import {
38
+ buildSlashContextForContent,
39
39
  resolveSlash,
40
- type SlashContext,
41
40
  } from "../../daemon/conversation-slash.js";
41
+ import { getOrCreateConversation as getOrCreateConversationInstance } from "../../daemon/conversation-store.js";
42
42
  import {
43
43
  getCannedFirstGreeting,
44
44
  isWakeUpGreeting,
45
45
  } from "../../daemon/first-greeting.js";
46
46
  import { renderHistoryContent } from "../../daemon/handlers/shared.js";
47
- import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
48
- import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
49
47
  import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
50
- import { HostFileProxy } from "../../daemon/host-file-proxy.js";
51
48
  import type { ServerMessage } from "../../daemon/message-protocol.js";
52
49
  import type {
53
50
  HostProxyTransportMetadata,
54
51
  NonHostProxyTransportMetadata,
55
52
  } from "../../daemon/message-types/conversations.js";
56
- import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
57
- import { emitFeedEvent } from "../../home/emit-feed-event.js";
53
+ import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
58
54
  import {
59
55
  writeOnboardingSidecar,
60
56
  writeRelationshipState,
61
57
  } from "../../home/relationship-state-writer.js";
62
- import { rewriteCommandPreview } from "../../home/rewrite-command-preview.js";
63
- import * as attachmentsStore from "../../memory/attachments-store.js";
58
+ import { ipcCall } from "../../ipc/gateway-client.js";
59
+ import {
60
+ getAttachmentById,
61
+ getAttachmentMetadataForMessage,
62
+ getAttachmentsByIds,
63
+ getSourcePathsForAttachments,
64
+ } from "../../memory/attachments-store.js";
64
65
  import {
65
- createCanonicalGuardianRequest,
66
- generateCanonicalRequestCode,
67
66
  listCanonicalGuardianRequests,
68
67
  listPendingRequestsByConversationScope,
69
68
  resolveCanonicalGuardianRequest,
@@ -76,6 +75,7 @@ import {
76
75
  hasMessages,
77
76
  type MessageRow,
78
77
  provenanceFromTrustContext,
78
+ setConversationInferenceProfile,
79
79
  setConversationOriginChannelIfUnset,
80
80
  setConversationOriginInterfaceIfUnset,
81
81
  } from "../../memory/conversation-crud.js";
@@ -87,21 +87,17 @@ import { searchConversations } from "../../memory/conversation-queries.js";
87
87
  import { getConfiguredProvider } from "../../providers/provider-send-message.js";
88
88
  import type { Provider } from "../../providers/types.js";
89
89
  import { checkIngressForSecrets } from "../../security/secret-ingress.js";
90
- import { redactSecrets } from "../../security/secret-scanner.js";
91
- import { summarizeToolInput } from "../../tools/tool-input-summary.js";
92
90
  import { getLogger } from "../../util/logger.js";
93
- import { getWorkspacePromptPath } from "../../util/platform.js";
91
+ import {
92
+ getInterfacesDir,
93
+ getWorkspacePromptPath,
94
+ } from "../../util/platform.js";
94
95
  import { silentlyWithLog } from "../../util/silently.js";
95
96
  import { buildAssistantEvent } from "../assistant-event.js";
97
+ import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
96
98
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
97
- import type { AuthContext } from "../auth/types.js";
98
- import { getChromeExtensionRegistry } from "../chrome-extension-registry.js";
99
- import { getClientRegistry } from "../client-registry.js";
100
- import { bridgeConfirmationRequestToGuardian } from "../confirmation-request-guardian-bridge.js";
101
99
  import { routeGuardianReply } from "../guardian-reply-router.js";
102
100
  import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
103
- import { httpError } from "../http-errors.js";
104
- import type { RouteDefinition } from "../http-router.js";
105
101
  import type {
106
102
  ApprovalConversationGenerator,
107
103
  RuntimeAttachmentMetadata,
@@ -114,6 +110,9 @@ import {
114
110
  resolveTrustContext,
115
111
  withSourceChannel,
116
112
  } from "../trust-context-resolver.js";
113
+ import { BadRequestError, InternalError, RouteError } from "./errors.js";
114
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
115
+ import { RouteResponse } from "./types.js";
117
116
 
118
117
  const log = getLogger("conversation-routes");
119
118
 
@@ -121,6 +120,15 @@ const log = getLogger("conversation-routes");
121
120
  const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/g;
122
121
 
123
122
  const SUGGESTION_CACHE_MAX = 100;
123
+ const VALID_RISK_THRESHOLDS = ["none", "low", "medium", "high"] as const;
124
+ type RiskThreshold = (typeof VALID_RISK_THRESHOLDS)[number];
125
+
126
+ function isValidRiskThreshold(value: unknown): value is RiskThreshold {
127
+ return (
128
+ typeof value === "string" &&
129
+ VALID_RISK_THRESHOLDS.includes(value as RiskThreshold)
130
+ );
131
+ }
124
132
 
125
133
  function collectCanonicalGuardianRequestHintIds(
126
134
  conversationId: string,
@@ -333,18 +341,6 @@ async function tryConsumeCanonicalGuardianReply(params: {
333
341
  return { consumed: true, messageId };
334
342
  }
335
343
 
336
- function resolveCanonicalRequestSourceType(
337
- sourceChannel: string | undefined,
338
- ): "desktop" | "channel" | "voice" {
339
- if (sourceChannel === "phone") {
340
- return "voice";
341
- }
342
- if (sourceChannel === "vellum") {
343
- return "desktop";
344
- }
345
- return "channel";
346
- }
347
-
348
344
  function getInterfaceFilesWithMtimes(
349
345
  interfacesDir: string | null,
350
346
  ): Array<{ path: string; mtimeMs: number }> {
@@ -368,11 +364,11 @@ function getInterfaceFilesWithMtimes(
368
364
  }
369
365
 
370
366
  export function handleListMessages(
371
- url: URL,
367
+ { queryParams }: RouteHandlerArgs,
372
368
  interfacesDir: string | null,
373
- ): Response {
374
- const conversationId = url.searchParams.get("conversationId");
375
- const conversationKey = url.searchParams.get("conversationKey");
369
+ ): Record<string, unknown> {
370
+ const conversationId = queryParams?.conversationId;
371
+ const conversationKey = queryParams?.conversationKey;
376
372
 
377
373
  let resolvedConversationId: string | undefined;
378
374
  if (conversationId) {
@@ -381,30 +377,40 @@ export function handleListMessages(
381
377
  const mapping = getConversationByKey(conversationKey);
382
378
  resolvedConversationId = mapping?.conversationId;
383
379
  } else {
384
- return httpError(
385
- "BAD_REQUEST",
380
+ throw new BadRequestError(
386
381
  "conversationKey or conversationId query parameter is required",
387
- 400,
388
382
  );
389
383
  }
390
384
 
391
- if (!resolvedConversationId) {
392
- return Response.json({ messages: [] });
393
- }
394
-
395
- const beforeTimestampRaw = url.searchParams.get("beforeTimestamp");
396
- const limitRaw = url.searchParams.get("limit");
385
+ const beforeTimestampRaw = queryParams?.beforeTimestamp;
386
+ const limitRaw = queryParams?.limit;
387
+ const pageRaw = queryParams?.page;
397
388
 
398
389
  // Validate: reject NaN values with 400
399
- if (beforeTimestampRaw !== null && isNaN(Number(beforeTimestampRaw))) {
400
- return httpError(
401
- "BAD_REQUEST",
402
- "beforeTimestamp must be a valid number",
403
- 400,
404
- );
390
+ if (beforeTimestampRaw != null && isNaN(Number(beforeTimestampRaw))) {
391
+ throw new BadRequestError("beforeTimestamp must be a valid number");
405
392
  }
406
- if (limitRaw !== null && isNaN(Number(limitRaw))) {
407
- return httpError("BAD_REQUEST", "limit must be a valid number", 400);
393
+ if (limitRaw != null && isNaN(Number(limitRaw))) {
394
+ throw new BadRequestError("limit must be a valid number");
395
+ }
396
+ if (pageRaw != null && pageRaw !== "latest") {
397
+ throw new BadRequestError("page must be 'latest' when provided");
398
+ }
399
+ const isLatestPage = pageRaw === "latest";
400
+
401
+ if (!resolvedConversationId) {
402
+ // Unresolved conversation keys still need to advertise the stable
403
+ // `page=latest` contract so the web client can rely on metadata fields
404
+ // being present even before any message is persisted.
405
+ if (isLatestPage && beforeTimestampRaw == null) {
406
+ return {
407
+ messages: [],
408
+ hasMore: false,
409
+ oldestTimestamp: null,
410
+ oldestMessageId: null,
411
+ };
412
+ }
413
+ return { messages: [] };
408
414
  }
409
415
 
410
416
  const beforeTimestamp = beforeTimestampRaw
@@ -415,10 +421,12 @@ export function handleListMessages(
415
421
  ? Math.min(Math.max(Math.floor(Number(limitRaw)), 1), 500)
416
422
  : undefined;
417
423
 
418
- // Option A: only paginate when beforeTimestamp is present.
419
- // Initial load and reconnect send limit but no beforeTimestamp — those must continue
420
- // returning all messages for zero regression risk.
421
- const isPaginated = beforeTimestamp != null;
424
+ // Paginate when either `beforeTimestamp` (older-page request) or
425
+ // `page=latest` (initial newest-N request) is set. When both are sent,
426
+ // `beforeTimestamp` wins because the caller is explicitly asking for an
427
+ // older page; `getMessagesPaginated` ignores `beforeTimestamp === undefined`
428
+ // and returns the newest `limit` messages in chronological order.
429
+ const isPaginated = beforeTimestamp != null || isLatestPage;
422
430
 
423
431
  let rawMessages: MessageRow[];
424
432
  let hasMore = false;
@@ -583,12 +591,12 @@ export function handleListMessages(
583
591
  // aren't lost before DB compaction relinks them.
584
592
  const idsToQuery = [m.id, ...(mergedIdMap.get(m.id) ?? [])];
585
593
  const linked = idsToQuery.flatMap((id) =>
586
- attachmentsStore.getAttachmentMetadataForMessage(id),
594
+ getAttachmentMetadataForMessage(id),
587
595
  );
588
596
  if (linked.length > 0) {
589
597
  msgAttachments = linked.map((a) => {
590
598
  if (a.mimeType.startsWith("image/")) {
591
- const full = attachmentsStore.getAttachmentById(a.id, {
599
+ const full = getAttachmentById(a.id, {
592
600
  hydrateFileData: true,
593
601
  });
594
602
  return {
@@ -664,15 +672,28 @@ export function handleListMessages(
664
672
  rawMessages.length > 0 ? rawMessages[0].createdAt : undefined;
665
673
  const oldestMessageId =
666
674
  rawMessages.length > 0 ? rawMessages[0].id : undefined;
667
- return Response.json({
675
+ // `page=latest` always emits both metadata fields so the web client has
676
+ // a stable contract; emit `null` when the conversation is empty.
677
+ // The existing `beforeTimestamp` branch keeps its conditional shape to
678
+ // avoid disturbing current callers.
679
+ if (isLatestPage && beforeTimestamp == null) {
680
+ return {
681
+ messages,
682
+ hasMore,
683
+ oldestTimestamp: oldestTimestamp ?? null,
684
+ oldestMessageId: oldestMessageId ?? null,
685
+ };
686
+ }
687
+
688
+ return {
668
689
  messages,
669
690
  hasMore,
670
691
  ...(oldestTimestamp != null ? { oldestTimestamp } : {}),
671
692
  ...(oldestMessageId != null ? { oldestMessageId } : {}),
672
- });
693
+ };
673
694
  }
674
695
 
675
- return Response.json({ messages });
696
+ return { messages };
676
697
  }
677
698
 
678
699
  // ── Tool-result merging ─────────────────────────────────────────────
@@ -973,337 +994,6 @@ function mergeConsecutiveAssistantMessages(messages: MessageRow[]): {
973
994
  return { messages: result, mergedIdMap };
974
995
  }
975
996
 
976
- /**
977
- * Build an `onEvent` callback that publishes every outbound event to the
978
- * assistant event hub, maintaining ordered delivery through a serial chain.
979
- *
980
- * Also registers pending interactions when confirmation_request,
981
- * secret_request, host_bash_request, host_browser_request, host_file_request,
982
- * or host_cu_request events flow through, so standalone approval/result
983
- * endpoints can look up the conversation by requestId.
984
- */
985
- function makeHubPublisher(
986
- deps: SendMessageDeps,
987
- conversationId: string,
988
- conversation: Conversation,
989
- ): (msg: ServerMessage) => void {
990
- let hubChain: Promise<void> = Promise.resolve();
991
- return (msg: ServerMessage) => {
992
- // Register pending interactions for approval events
993
- if (msg.type === "confirmation_request") {
994
- pendingInteractions.register(msg.requestId, {
995
- conversation,
996
- conversationId,
997
- kind: "confirmation",
998
- confirmationDetails: {
999
- toolName: msg.toolName,
1000
- input: msg.input,
1001
- riskLevel: msg.riskLevel,
1002
- executionTarget: msg.executionTarget,
1003
- allowlistOptions: msg.allowlistOptions,
1004
- scopeOptions: msg.scopeOptions,
1005
- persistentDecisionsAllowed: msg.persistentDecisionsAllowed,
1006
- temporaryOptionsAvailable: msg.temporaryOptionsAvailable,
1007
- },
1008
- });
1009
-
1010
- const inputRecord = msg.input as Record<string, unknown>;
1011
- const commandPreview =
1012
- redactSecrets(summarizeToolInput(msg.toolName, inputRecord)) ||
1013
- undefined;
1014
- const technicalTitle = commandPreview
1015
- ? `Requesting permission: ${commandPreview}`
1016
- : `Requesting approval to use ${msg.toolName}.`;
1017
- const dedupKey = `tool-approval:${msg.requestId}`;
1018
-
1019
- // Emit immediately with the technical preview.
1020
- void emitFeedEvent({
1021
- source: "assistant",
1022
- title: technicalTitle,
1023
- summary: technicalTitle,
1024
- dedupKey,
1025
- urgency: msg.riskLevel === "high" ? "high" : "medium",
1026
- conversationId,
1027
- }).catch((err) => {
1028
- log.warn(
1029
- { err, requestId: msg.requestId },
1030
- "Failed to emit tool approval request feed event",
1031
- );
1032
- });
1033
-
1034
- // Background: rewrite into prose and update the feed item.
1035
- if (commandPreview) {
1036
- void rewriteCommandPreview(msg.toolName, commandPreview)
1037
- .then((prose) => {
1038
- if (prose) {
1039
- const proseTitle = `Requesting permission: ${prose}`;
1040
- return emitFeedEvent({
1041
- source: "assistant",
1042
- title: proseTitle,
1043
- summary: proseTitle,
1044
- dedupKey,
1045
- urgency: msg.riskLevel === "high" ? "high" : "medium",
1046
- conversationId,
1047
- });
1048
- }
1049
- })
1050
- .catch((err) => {
1051
- log.warn(
1052
- { err, requestId: msg.requestId },
1053
- "Failed to update feed event with prose rewrite",
1054
- );
1055
- });
1056
- }
1057
-
1058
- // Create a canonical guardian request so HTTP handlers can find it
1059
- // via applyCanonicalGuardianDecision.
1060
- try {
1061
- const trustContext = conversation.trustContext;
1062
- const sourceChannel = trustContext?.sourceChannel ?? "vellum";
1063
- const inputRecord = msg.input as Record<string, unknown>;
1064
- const activityRaw =
1065
- (typeof inputRecord.activity === "string"
1066
- ? inputRecord.activity
1067
- : undefined) ??
1068
- (typeof inputRecord.reason === "string"
1069
- ? inputRecord.reason
1070
- : undefined);
1071
- const canonicalRequest = createCanonicalGuardianRequest({
1072
- id: msg.requestId,
1073
- kind: "tool_approval",
1074
- sourceType: resolveCanonicalRequestSourceType(sourceChannel),
1075
- sourceChannel,
1076
- conversationId,
1077
- requesterExternalUserId: trustContext?.requesterExternalUserId,
1078
- requesterChatId: trustContext?.requesterChatId,
1079
- guardianExternalUserId: trustContext?.guardianExternalUserId,
1080
- guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
1081
- toolName: msg.toolName,
1082
- commandPreview:
1083
- redactSecrets(summarizeToolInput(msg.toolName, inputRecord)) ||
1084
- undefined,
1085
- riskLevel: msg.riskLevel,
1086
- activityText: activityRaw ? redactSecrets(activityRaw) : undefined,
1087
- executionTarget: msg.executionTarget,
1088
- status: "pending",
1089
- requestCode: generateCanonicalRequestCode(),
1090
- expiresAt: Date.now() + 5 * 60 * 1000,
1091
- });
1092
-
1093
- // For trusted-contact conversations, bridge to guardian.question so the
1094
- // guardian gets notified and can approve via callback/request-code.
1095
- if (trustContext) {
1096
- bridgeConfirmationRequestToGuardian({
1097
- canonicalRequest,
1098
- trustContext,
1099
- conversationId,
1100
- toolName: msg.toolName,
1101
- assistantId:
1102
- conversation.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
1103
- });
1104
- }
1105
- } catch (err) {
1106
- log.debug(
1107
- { err, requestId: msg.requestId, conversationId },
1108
- "Failed to create canonical request from hub publisher",
1109
- );
1110
- }
1111
- } else if (msg.type === "secret_request") {
1112
- pendingInteractions.register(msg.requestId, {
1113
- conversation,
1114
- conversationId,
1115
- kind: "secret",
1116
- });
1117
- } else {
1118
- registerHostProxyPendingInteraction(msg, conversation, conversationId);
1119
- }
1120
-
1121
- // ServerMessage is a large union; conversationId exists on most but not all variants.
1122
- const msgConversationId =
1123
- "conversationId" in msg &&
1124
- typeof (msg as { conversationId?: unknown }).conversationId === "string"
1125
- ? (msg as { conversationId: string }).conversationId
1126
- : undefined;
1127
- // `conversation_list_invalidated` is a list-level system event: it
1128
- // describes no particular conversation and every connected client
1129
- // should refresh its sidebar. Publish it unscoped so the SSE hub does
1130
- // not filter it out by the subscriber's `filter.conversationId`.
1131
- // Other events (including `conversation_title_updated`) stay scoped to
1132
- // their conversation — unscoped scoped-events would leak foreign
1133
- // `conversationId` values to native clients' speculative ID-resolution
1134
- // path. For `conversation_title_updated` we instead enqueue a matching
1135
- // unscoped `conversation_list_invalidated` below so other clients'
1136
- // sidebars can refresh and pick up the new title.
1137
- const resolvedConversationId =
1138
- msg.type === "conversation_list_invalidated"
1139
- ? undefined
1140
- : (msgConversationId ?? conversationId);
1141
- const event = buildAssistantEvent(
1142
- DAEMON_INTERNAL_ASSISTANT_ID,
1143
- msg,
1144
- resolvedConversationId,
1145
- );
1146
- hubChain = (async () => {
1147
- await hubChain;
1148
- try {
1149
- await deps.assistantEventHub.publish(event);
1150
- } catch (err) {
1151
- log.warn(
1152
- { err },
1153
- "assistant-events hub subscriber threw during POST /messages",
1154
- );
1155
- }
1156
-
1157
- // When the agent loop auto-generates a conversation title, also
1158
- // broadcast an unscoped `conversation_list_invalidated` so every
1159
- // connected client's sidebar can refresh and pick up the new title.
1160
- // Without this, clients viewing other conversations (or a draft)
1161
- // would never learn that the title for this conversation changed.
1162
- // The scoped `conversation_title_updated` above still handles the
1163
- // in-place update for the client currently viewing this conversation.
1164
- if (msg.type === "conversation_title_updated") {
1165
- try {
1166
- await deps.assistantEventHub.publish(
1167
- buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
1168
- type: "conversation_list_invalidated",
1169
- reason: "renamed",
1170
- }),
1171
- );
1172
- } catch (err) {
1173
- log.warn(
1174
- { err },
1175
- "Failed to publish conversation_list_invalidated after title update",
1176
- );
1177
- }
1178
- }
1179
- })();
1180
- };
1181
- }
1182
-
1183
- /**
1184
- * Register pending interactions for host proxy request envelopes so
1185
- * standalone result endpoints can resolve by requestId.
1186
- *
1187
- * Returns the registered requestId when a host proxy request was registered.
1188
- * Callers that route through non-hub transports (e.g. registry-routed
1189
- * host_browser sends) can use this to clean up the registration if send fails.
1190
- */
1191
- function registerHostProxyPendingInteraction(
1192
- msg: ServerMessage,
1193
- conversation: Conversation,
1194
- conversationId: string,
1195
- ): string | undefined {
1196
- if (msg.type === "host_bash_request") {
1197
- pendingInteractions.register(msg.requestId, {
1198
- conversation,
1199
- conversationId,
1200
- kind: "host_bash",
1201
- });
1202
- return msg.requestId;
1203
- }
1204
- if (msg.type === "host_browser_request") {
1205
- pendingInteractions.register(msg.requestId, {
1206
- conversation,
1207
- conversationId,
1208
- kind: "host_browser",
1209
- });
1210
- return msg.requestId;
1211
- }
1212
- if (msg.type === "host_file_request") {
1213
- pendingInteractions.register(msg.requestId, {
1214
- conversation,
1215
- conversationId,
1216
- kind: "host_file",
1217
- });
1218
- return msg.requestId;
1219
- }
1220
- if (msg.type === "host_cu_request") {
1221
- pendingInteractions.register(msg.requestId, {
1222
- conversation,
1223
- conversationId,
1224
- kind: "host_cu",
1225
- });
1226
- return msg.requestId;
1227
- }
1228
- return undefined;
1229
- }
1230
-
1231
- /**
1232
- * Resolve the host_browser sender function for a conversation turn.
1233
- *
1234
- * When the guardian has an active extension connection in the
1235
- * ChromeExtensionRegistry, returns a registry-routed sender that forwards
1236
- * `host_browser_request` / `host_browser_cancel` frames through the
1237
- * WebSocket to the connected extension. Otherwise returns the SSE hub
1238
- * emitter (`onEvent`).
1239
- *
1240
- * For `chrome-extension` turns the registry sender is **always** returned
1241
- * regardless of the POST-time connection check. The chrome-extension
1242
- * interface has no SSE consumer for `host_browser_request` frames, so
1243
- * falling back to `onEvent` would cause CDP calls to stall until the proxy
1244
- * timeout (30 s) instead of failing immediately at send time when the
1245
- * registry throws on a missing connection.
1246
- *
1247
- * This helper is interface-agnostic: both chrome-extension and macOS turns
1248
- * can obtain a registry-routed sender when extension connectivity exists.
1249
- * The `isRegistryRouted` flag lets the caller decide whether to set
1250
- * `hostBrowserSenderOverride` and whether to provision a `HostBrowserProxy`
1251
- * for interfaces that don't statically support host_browser (e.g. macOS).
1252
- */
1253
- function resolveHostBrowserSender(
1254
- conversation: Conversation,
1255
- conversationId: string,
1256
- authContext: AuthContext,
1257
- onEvent: (msg: ServerMessage) => void,
1258
- sourceInterface: InterfaceId,
1259
- ): { sender: (msg: ServerMessage) => void; isRegistryRouted: boolean } {
1260
- // Check whether the guardian has any active extension connection.
1261
- const guardianId =
1262
- conversation.trustContext?.guardianPrincipalId ??
1263
- authContext.actorPrincipalId;
1264
- const hasExtensionConnection =
1265
- !!guardianId && !!getChromeExtensionRegistry().get(guardianId);
1266
-
1267
- // For chrome-extension, always use the registry sender so that send-time
1268
- // failures produce immediate errors rather than 30-second proxy timeouts.
1269
- // The SSE hub has no extension consumer, so falling back to onEvent is
1270
- // never correct for this interface.
1271
- if (!hasExtensionConnection && sourceInterface !== "chrome-extension") {
1272
- return { sender: onEvent, isRegistryRouted: false };
1273
- }
1274
-
1275
- // Build a registry-routed sender. The guardian principal ID is resolved
1276
- // at send time rather than captured here so that queue-drain restores
1277
- // (which re-fire this closure outside the original POST context) follow
1278
- // the conversation's bound guardian identity rather than a stale
1279
- // authContext.actorPrincipalId.
1280
- const registrySender = (msg: ServerMessage): void => {
1281
- const requestId = registerHostProxyPendingInteraction(
1282
- msg,
1283
- conversation,
1284
- conversationId,
1285
- );
1286
- const gid =
1287
- conversation.trustContext?.guardianPrincipalId ??
1288
- authContext.actorPrincipalId;
1289
- if (!gid) {
1290
- if (requestId) pendingInteractions.resolve(requestId);
1291
- throw new Error(
1292
- "host_browser send skipped: no guardianId on AuthContext",
1293
- );
1294
- }
1295
- const ok = getChromeExtensionRegistry().send(gid, msg);
1296
- if (!ok) {
1297
- if (requestId) pendingInteractions.resolve(requestId);
1298
- throw new Error(
1299
- `host_browser send failed: no active connection for guardian ${gid}`,
1300
- );
1301
- }
1302
- };
1303
-
1304
- return { sender: registrySender, isRegistryRouted: true };
1305
- }
1306
-
1307
997
  /**
1308
998
  * Persist the pre-chat onboarding payload to disk.
1309
999
  *
@@ -1395,15 +1085,13 @@ export function persistOnboardingArtifacts(onboarding: {
1395
1085
  }
1396
1086
 
1397
1087
  export async function handleSendMessage(
1398
- req: Request,
1088
+ { body: rawBody, headers }: RouteHandlerArgs,
1399
1089
  deps: {
1400
1090
  sendMessageDeps?: SendMessageDeps;
1401
1091
  approvalConversationGenerator?: ApprovalConversationGenerator;
1402
- heartbeatService?: HeartbeatService;
1403
1092
  },
1404
- authContext: AuthContext,
1405
- ): Promise<Response> {
1406
- const body = (await req.json()) as {
1093
+ ): Promise<unknown> {
1094
+ const body = (rawBody ?? {}) as {
1407
1095
  conversationKey?: string;
1408
1096
  content?: string;
1409
1097
  attachmentIds?: string[];
@@ -1416,6 +1104,8 @@ export async function handleSendMessage(
1416
1104
  hostUsername?: string;
1417
1105
  clientId?: string;
1418
1106
  clientMessageId?: string;
1107
+ inferenceProfile?: string | null;
1108
+ riskThreshold?: string;
1419
1109
  onboarding?: {
1420
1110
  tools: string[];
1421
1111
  tasks: string[];
@@ -1425,35 +1115,70 @@ export async function handleSendMessage(
1425
1115
  };
1426
1116
  };
1427
1117
 
1118
+ const actorPrincipalId = headers?.["x-vellum-actor-principal-id"];
1119
+ const principalType = headers?.["x-vellum-principal-type"];
1120
+
1428
1121
  const { conversationKey, content, attachmentIds } = body;
1429
1122
  const clientMessageId =
1430
1123
  typeof body.clientMessageId === "string" ? body.clientMessageId : undefined;
1124
+ const requestedInferenceProfile =
1125
+ typeof body.inferenceProfile === "string"
1126
+ ? body.inferenceProfile
1127
+ : undefined;
1128
+ const requestedRiskThreshold = body.riskThreshold;
1129
+ if (
1130
+ body.inferenceProfile != null &&
1131
+ typeof body.inferenceProfile !== "string"
1132
+ ) {
1133
+ throw new BadRequestError(
1134
+ "inferenceProfile must be a non-empty string or null",
1135
+ );
1136
+ }
1137
+ if (requestedInferenceProfile === "") {
1138
+ throw new BadRequestError(
1139
+ "inferenceProfile must be a non-empty string or null",
1140
+ );
1141
+ }
1142
+ if (requestedInferenceProfile !== undefined) {
1143
+ const profiles = getConfig().llm.profiles ?? {};
1144
+ if (
1145
+ !Object.prototype.hasOwnProperty.call(profiles, requestedInferenceProfile)
1146
+ ) {
1147
+ throw new BadRequestError(
1148
+ `Profile "${requestedInferenceProfile}" is not defined in llm.profiles`,
1149
+ );
1150
+ }
1151
+ }
1152
+ if (
1153
+ requestedRiskThreshold !== undefined &&
1154
+ !isValidRiskThreshold(requestedRiskThreshold)
1155
+ ) {
1156
+ throw new BadRequestError(
1157
+ `riskThreshold must be one of: ${VALID_RISK_THRESHOLDS.join(", ")}`,
1158
+ );
1159
+ }
1431
1160
  if (!body.sourceChannel || typeof body.sourceChannel !== "string") {
1432
- return httpError("BAD_REQUEST", "sourceChannel is required", 400);
1161
+ throw new BadRequestError("sourceChannel is required");
1433
1162
  }
1434
1163
  const sourceChannel = parseChannelId(body.sourceChannel);
1435
1164
 
1436
1165
  if (!sourceChannel) {
1437
- return httpError(
1438
- "BAD_REQUEST",
1166
+ throw new BadRequestError(
1439
1167
  `Invalid sourceChannel: ${
1440
1168
  body.sourceChannel
1441
1169
  }. Valid values: ${CHANNEL_IDS.join(", ")}`,
1442
- 400,
1443
1170
  );
1444
1171
  }
1445
1172
 
1446
1173
  if (!body.interface || typeof body.interface !== "string") {
1447
- return httpError("BAD_REQUEST", "interface is required", 400);
1174
+ throw new BadRequestError("interface is required");
1448
1175
  }
1449
1176
  const sourceInterface = parseInterfaceId(body.interface);
1450
1177
  if (!sourceInterface) {
1451
- return httpError(
1452
- "BAD_REQUEST",
1178
+ throw new BadRequestError(
1453
1179
  `Invalid interface: ${body.interface}. Valid values: ${INTERFACE_IDS.join(
1454
1180
  ", ",
1455
1181
  )}`,
1456
- 400,
1457
1182
  );
1458
1183
  }
1459
1184
 
@@ -1465,7 +1190,7 @@ export async function handleSendMessage(
1465
1190
 
1466
1191
  // Reject non-string content values (numbers, objects, etc.)
1467
1192
  if (content != null && typeof content !== "string") {
1468
- return httpError("BAD_REQUEST", "content must be a string", 400);
1193
+ throw new BadRequestError("content must be a string");
1469
1194
  }
1470
1195
 
1471
1196
  const trimmedContent = typeof content === "string" ? content.trim() : "";
@@ -1473,23 +1198,17 @@ export async function handleSendMessage(
1473
1198
  Array.isArray(attachmentIds) && attachmentIds.length > 0;
1474
1199
 
1475
1200
  if (trimmedContent.length === 0 && !hasAttachments) {
1476
- return httpError(
1477
- "BAD_REQUEST",
1478
- "content or attachmentIds is required",
1479
- 400,
1480
- );
1201
+ throw new BadRequestError("content or attachmentIds is required");
1481
1202
  }
1482
1203
 
1483
1204
  // Validate that all attachment IDs resolve
1484
1205
  if (hasAttachments) {
1485
- const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds);
1206
+ const resolved = getAttachmentsByIds(attachmentIds);
1486
1207
  if (resolved.length !== attachmentIds.length) {
1487
1208
  const resolvedIds = new Set(resolved.map((a) => a.id));
1488
1209
  const missing = attachmentIds.filter((id) => !resolvedIds.has(id));
1489
- return httpError(
1490
- "BAD_REQUEST",
1210
+ throw new BadRequestError(
1491
1211
  `Attachment IDs not found: ${missing.join(", ")}`,
1492
- 400,
1493
1212
  );
1494
1213
  }
1495
1214
  }
@@ -1498,36 +1217,52 @@ export async function handleSendMessage(
1498
1217
  if (trimmedContent.length > 0 && !body.bypassSecretCheck) {
1499
1218
  const ingressResult = checkIngressForSecrets(trimmedContent);
1500
1219
  if (ingressResult.blocked) {
1501
- return Response.json(
1502
- {
1220
+ return new RouteResponse(
1221
+ JSON.stringify({
1503
1222
  accepted: false,
1504
1223
  error: "secret_blocked",
1505
1224
  message: ingressResult.userNotice,
1506
1225
  detectedTypes: ingressResult.detectedTypes,
1507
- },
1508
- { status: 422 },
1226
+ }),
1227
+ { "content-type": "application/json" },
1228
+ 422,
1509
1229
  );
1510
1230
  }
1511
1231
  }
1512
1232
 
1513
1233
  if (!deps.sendMessageDeps) {
1514
- return httpError(
1515
- "SERVICE_UNAVAILABLE",
1234
+ throw new RouteError(
1516
1235
  "Message processing is not available",
1236
+ "SERVICE_UNAVAILABLE",
1517
1237
  503,
1518
1238
  );
1519
1239
  }
1520
1240
 
1521
1241
  // Desktop messages are always from the guardian — reset the heartbeat
1522
1242
  // timer so the next heartbeat is a full interval after this interaction.
1523
- deps.heartbeatService?.resetTimer();
1243
+ HeartbeatService.getInstance()?.resetTimer();
1524
1244
 
1525
- const conversationType =
1526
- body.conversationType === "private" ? ("private" as const) : undefined;
1527
1245
  const mapping = getOrCreateConversation(resolvedConversationKey, {
1528
- conversationType,
1246
+ conversationType: "standard",
1529
1247
  });
1530
1248
 
1249
+ if (requestedRiskThreshold !== undefined) {
1250
+ const result = await ipcCall("set_conversation_threshold", {
1251
+ conversationId: mapping.conversationId,
1252
+ threshold: requestedRiskThreshold,
1253
+ });
1254
+ if (result === undefined) {
1255
+ log.error(
1256
+ {
1257
+ conversationId: mapping.conversationId,
1258
+ threshold: requestedRiskThreshold,
1259
+ },
1260
+ "Failed to set conversation risk threshold override via gateway IPC",
1261
+ );
1262
+ throw new InternalError("Failed to persist risk threshold override");
1263
+ }
1264
+ }
1265
+
1531
1266
  const smDeps = deps.sendMessageDeps;
1532
1267
 
1533
1268
  // Notify all connected clients that the conversation list changed when
@@ -1542,7 +1277,7 @@ export async function handleSendMessage(
1542
1277
  if (!hasMessages(mapping.conversationId)) {
1543
1278
  smDeps.assistantEventHub
1544
1279
  .publish(
1545
- buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
1280
+ buildAssistantEvent({
1546
1281
  type: "conversation_list_invalidated",
1547
1282
  reason: "created",
1548
1283
  }),
@@ -1571,27 +1306,18 @@ export async function handleSendMessage(
1571
1306
  interfaceId: sourceInterface,
1572
1307
  } satisfies NonHostProxyTransportMetadata);
1573
1308
 
1574
- // Register/refresh the client in the unified client registry so
1575
- // `assistant clients list` can discover all connected interfaces.
1576
- // Uses the client-supplied clientId when available (stable per-install
1577
- // UUID), falling back to a synthetic key derived from interfaceId so
1578
- // older clients that don't send clientId still appear in the registry.
1579
- const effectiveClientId =
1580
- typeof body.clientId === "string" && body.clientId.length > 0
1581
- ? body.clientId
1582
- : `synthetic:${sourceInterface}`;
1583
- getClientRegistry().register({
1584
- clientId: effectiveClientId,
1585
- interfaceId: sourceInterface,
1586
- hostHomeDir: body.hostHomeDir,
1587
- hostUsername: body.hostUsername,
1588
- });
1589
-
1590
1309
  const conversation = await smDeps.getOrCreateConversation(
1591
1310
  mapping.conversationId,
1592
1311
  { transport },
1593
1312
  );
1594
1313
 
1314
+ if (requestedInferenceProfile !== undefined) {
1315
+ setConversationInferenceProfile(
1316
+ mapping.conversationId,
1317
+ requestedInferenceProfile,
1318
+ );
1319
+ }
1320
+
1595
1321
  // Store pre-chat onboarding context on the conversation when this is the
1596
1322
  // very first message (no prior messages loaded). Artifact persistence
1597
1323
  // (IDENTITY.md, USER.md, sidecar) is deferred: on the canned greeting
@@ -1607,11 +1333,11 @@ export async function handleSendMessage(
1607
1333
  // Resolve guardian context from the AuthContext's actorPrincipalId.
1608
1334
  // The JWT-verified principal is used as the sender identity through
1609
1335
  // the same trust resolution pipeline that channel ingress uses.
1610
- if (authContext.actorPrincipalId) {
1336
+ if (actorPrincipalId) {
1611
1337
  // Dev bypass (HTTP auth disabled): the synthetic "dev-bypass" principal
1612
1338
  // won't match any guardian binding. Resolve from the local guardian
1613
1339
  // binding instead, which produces the correct guardian trust context.
1614
- if (isHttpAuthDisabled() && authContext.actorPrincipalId === "dev-bypass") {
1340
+ if (isHttpAuthDisabled() && actorPrincipalId === "dev-bypass") {
1615
1341
  conversation.setTrustContext(resolveLocalTrustContext(sourceChannel));
1616
1342
  } else {
1617
1343
  const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
@@ -1619,24 +1345,24 @@ export async function handleSendMessage(
1619
1345
  assistantId,
1620
1346
  sourceChannel: "vellum",
1621
1347
  conversationExternalId: "local",
1622
- actorExternalId: authContext.actorPrincipalId,
1348
+ actorExternalId: actorPrincipalId,
1623
1349
  });
1624
1350
  if (trustCtx.trustClass === "unknown") {
1625
1351
  // Attempt to heal guardian binding drift: after a DB reset the
1626
1352
  // guardian binding gets a new vellum-principal-* UUID while the
1627
1353
  // client still holds a valid JWT with the old one. The signing
1628
1354
  // key survives the reset, so the JWT is authentic — just stale.
1629
- const healed = healGuardianBindingDrift(authContext.actorPrincipalId);
1355
+ const healed = healGuardianBindingDrift(actorPrincipalId);
1630
1356
  if (healed) {
1631
1357
  trustCtx = resolveTrustContext({
1632
1358
  assistantId,
1633
1359
  sourceChannel: "vellum",
1634
1360
  conversationExternalId: "local",
1635
- actorExternalId: authContext.actorPrincipalId,
1361
+ actorExternalId: actorPrincipalId,
1636
1362
  });
1637
1363
  log.info(
1638
1364
  {
1639
- actorPrincipalId: authContext.actorPrincipalId,
1365
+ actorPrincipalId: actorPrincipalId,
1640
1366
  trustClass: trustCtx.trustClass,
1641
1367
  },
1642
1368
  "Trust re-resolved after guardian binding drift heal",
@@ -1644,10 +1370,10 @@ export async function handleSendMessage(
1644
1370
  } else {
1645
1371
  log.warn(
1646
1372
  {
1647
- actorPrincipalId: authContext.actorPrincipalId,
1373
+ actorPrincipalId: actorPrincipalId,
1648
1374
  sourceChannel,
1649
1375
  trustClass: trustCtx.trustClass,
1650
- principalType: authContext.principalType,
1376
+ principalType: principalType,
1651
1377
  },
1652
1378
  "JWT-verified actor resolved to unknown trust class — possible guardian binding drift (e.g. DB reset without re-bootstrap)",
1653
1379
  );
@@ -1661,95 +1387,13 @@ export async function handleSendMessage(
1661
1387
  conversation.setTrustContext({ trustClass: "guardian", sourceChannel });
1662
1388
  }
1663
1389
 
1664
- const onEvent = makeHubPublisher(
1665
- smDeps,
1666
- mapping.conversationId,
1667
- conversation,
1668
- );
1669
1390
  const isInteractive = isInteractiveInterface(sourceInterface);
1670
- // Only create each host proxy for interfaces that support the matching
1671
- // capability. macOS supports all four; the chrome-extension interface only
1672
- // supports host_browser. Non-desktop conversations (CLI, channels, headless)
1673
- // fall back to local execution.
1674
- // Set the proxy BEFORE updateClient so updateClient's call to
1675
- // hostBashProxy.updateSender targets the correct (new) proxy.
1676
- if (supportsHostProxy(sourceInterface, "host_bash")) {
1677
- // Reuse the existing proxy if the conversation is actively processing a
1678
- // host bash request to avoid orphaning in-flight requests.
1679
- if (!conversation.isProcessing() || !conversation.hostBashProxy) {
1680
- const proxy = new HostBashProxy(onEvent, (requestId) => {
1681
- pendingInteractions.resolve(requestId);
1682
- });
1683
- conversation.setHostBashProxy(proxy);
1684
- }
1685
- } else if (!conversation.isProcessing()) {
1686
- conversation.setHostBashProxy(undefined);
1687
- }
1688
- // Resolve the host_browser sender — registry-routed when the guardian has
1689
- // an active extension connection, SSE hub otherwise. This applies to both
1690
- // chrome-extension and macOS interfaces so that macOS turns can route
1691
- // browser automation through the user's real Chrome session when available.
1692
- const { sender: browserProxySendToClient, isRegistryRouted } =
1693
- resolveHostBrowserSender(
1694
- conversation,
1695
- mapping.conversationId,
1696
- authContext,
1697
- onEvent,
1698
- sourceInterface,
1699
- );
1700
-
1701
- // Stash the registry-routed sender on the conversation so queue-drain
1702
- // restores (which run outside of conversation-routes.ts and only have
1703
- // access to `sendToClient`) can preserve it when calling
1704
- // `restoreBrowserProxyAvailability()`. The override is set when the
1705
- // sender is registry-routed (regardless of interface) and cleared when
1706
- // the SSE hub sender is used, so the drain path always restores the
1707
- // correct transport.
1708
- if (isRegistryRouted) {
1709
- conversation.hostBrowserSenderOverride = browserProxySendToClient;
1710
- } else {
1711
- conversation.hostBrowserSenderOverride = undefined;
1712
- }
1713
-
1714
- // Provision the host browser proxy. Both macOS and chrome-extension
1715
- // natively support host_browser. For macOS, the proxy is wired to the
1716
- // SSE sender by default so `host_browser_request` frames reach the
1717
- // desktop client directly. When the guardian also has an active extension
1718
- // connection (isRegistryRouted), the registry-routed sender is used
1719
- // instead so browser tools route through the user's real Chrome session.
1720
- // For chrome-extension, the registry sender is always used.
1721
- const shouldProvisionBrowserProxy =
1722
- supportsHostProxy(sourceInterface, "host_browser") ||
1723
- (canServiceRegistryBrowser(sourceInterface) && isRegistryRouted);
1724
- if (shouldProvisionBrowserProxy) {
1725
- if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
1726
- const browserProxy = new HostBrowserProxy(
1727
- browserProxySendToClient,
1728
- (requestId) => {
1729
- pendingInteractions.resolve(requestId);
1730
- },
1731
- );
1732
- conversation.setHostBrowserProxy(browserProxy);
1733
- }
1734
- } else if (!conversation.isProcessing()) {
1735
- conversation.setHostBrowserProxy(undefined);
1736
- }
1737
- if (supportsHostProxy(sourceInterface, "host_file")) {
1738
- if (!conversation.isProcessing() || !conversation.hostFileProxy) {
1739
- const fileProxy = new HostFileProxy(onEvent, (requestId) => {
1740
- pendingInteractions.resolve(requestId);
1741
- });
1742
- conversation.setHostFileProxy(fileProxy);
1743
- }
1744
- } else if (!conversation.isProcessing()) {
1745
- conversation.setHostFileProxy(undefined);
1746
- }
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).
1747
1394
  if (supportsHostProxy(sourceInterface, "host_cu")) {
1748
1395
  if (!conversation.isProcessing() || !conversation.hostCuProxy) {
1749
- const cuProxy = new HostCuProxy(onEvent, (requestId) => {
1750
- pendingInteractions.resolve(requestId);
1751
- });
1752
- conversation.setHostCuProxy(cuProxy);
1396
+ conversation.setHostCuProxy(new HostCuProxy());
1753
1397
  }
1754
1398
  // Only preactivate CU when the conversation is idle — if the conversation is
1755
1399
  // processing, this message will be queued and preactivation is deferred
@@ -1761,14 +1405,6 @@ export async function handleSendMessage(
1761
1405
  conversation.setHostCuProxy(undefined);
1762
1406
  }
1763
1407
  // Wire sendToClient to the SSE hub so all subsystems can reach the HTTP client.
1764
- // Called after setHostBashProxy so updateSender targets the current proxy.
1765
- // When proxies are preserved during an active turn (non-desktop request while
1766
- // processing), skip updating proxy senders to avoid degrading them. The gate
1767
- // matches the host_bash capability because the legacy "reject send during
1768
- // host bash" flow is what this is really protecting.
1769
- const preservingProxies =
1770
- conversation.isProcessing() &&
1771
- !supportsHostProxy(sourceInterface, "host_bash");
1772
1408
  // hasNoClient must remain `!isInteractive` so downstream tool gating
1773
1409
  // (`isToolActiveForContext` for HOST_TOOL_NAMES, `createToolExecutor`'s
1774
1410
  // `isInteractive: !ctx.hasNoClient`) keeps host_bash/host_file/host_cu
@@ -1776,23 +1412,7 @@ export async function handleSendMessage(
1776
1412
  // is non-interactive (no SSE prompter UI) but still has a connected client
1777
1413
  // that can service host_browser_request events; we restore that single
1778
1414
  // proxy explicitly below without relaxing `hasNoClient`.
1779
- conversation.updateClient(onEvent, !isInteractive, {
1780
- skipProxySenderUpdate: preservingProxies,
1781
- });
1782
- // Re-enable the browser proxy for turns that provisioned one. This covers:
1783
- // - macOS: always provisioned (SSE sender or registry-routed when extension
1784
- // is connected)
1785
- // - chrome-extension: natively supports host_browser (non-interactive but
1786
- // has a connected client for host_browser_request events)
1787
- //
1788
- // The helper bypasses the `hasNoClient` gate so chrome-extension turns can
1789
- // drive the browser via CDP without leaking host_bash/host_file tool
1790
- // availability. It reads `hostBrowserSenderOverride` (set above when
1791
- // registry-routed) and applies the correct sender — including after
1792
- // queue-drain restores run from conversation-process.ts.
1793
- if (shouldProvisionBrowserProxy) {
1794
- conversation.restoreBrowserProxyAvailability?.();
1795
- }
1415
+ conversation.updateClient(broadcastMessage, !isInteractive);
1796
1416
 
1797
1417
  // ── Canned first-greeting fast path ──
1798
1418
  // On a completely fresh workspace, skip LLM inference for the macOS
@@ -1847,21 +1467,26 @@ export async function handleSendMessage(
1847
1467
  );
1848
1468
  conversation.getMessages().push(assistantMsg);
1849
1469
 
1850
- const response = Response.json(
1851
- { accepted: true, messageId: persisted.id, conversationId },
1852
- { status: 202 },
1853
- );
1470
+ const response = {
1471
+ accepted: true,
1472
+ messageId: persisted.id,
1473
+ conversationId,
1474
+ };
1854
1475
 
1855
1476
  setTimeout(() => {
1856
- onEvent({
1477
+ broadcastMessage({
1857
1478
  type: "user_message_echo",
1858
1479
  text: rawContent,
1859
1480
  conversationId,
1860
1481
  messageId: persisted.id,
1861
1482
  clientMessageId,
1862
1483
  });
1863
- onEvent({ type: "assistant_text_delta", text: cannedGreeting });
1864
- onEvent({ type: "message_complete", conversationId });
1484
+ broadcastMessage({
1485
+ type: "assistant_text_delta",
1486
+ text: cannedGreeting,
1487
+ conversationId,
1488
+ });
1489
+ broadcastMessage({ type: "message_complete", conversationId });
1865
1490
  conversation.processing = false;
1866
1491
  silentlyWithLog(
1867
1492
  conversation.drainQueue(),
@@ -1914,7 +1539,7 @@ export async function handleSendMessage(
1914
1539
  content: content ?? "",
1915
1540
  attachments,
1916
1541
  conversation,
1917
- onEvent,
1542
+ onEvent: broadcastMessage,
1918
1543
  // Desktop path: disable NL classification to avoid consuming non-decision
1919
1544
  // messages while a tool confirmation is pending. Deterministic code-prefix
1920
1545
  // and callback parsing remain active. Mirrors conversation-process.ts behavior.
@@ -1926,16 +1551,13 @@ export async function handleSendMessage(
1926
1551
  verifiedActorPrincipalId,
1927
1552
  });
1928
1553
  if (inlineReplyResult.consumed) {
1929
- return Response.json(
1930
- {
1931
- accepted: true,
1932
- conversationId: mapping.conversationId,
1933
- ...(inlineReplyResult.messageId
1934
- ? { messageId: inlineReplyResult.messageId }
1935
- : {}),
1936
- },
1937
- { status: 202 },
1938
- );
1554
+ return {
1555
+ accepted: true,
1556
+ conversationId: mapping.conversationId,
1557
+ ...(inlineReplyResult.messageId
1558
+ ? { messageId: inlineReplyResult.messageId }
1559
+ : {}),
1560
+ };
1939
1561
  }
1940
1562
  } catch (err) {
1941
1563
  log.warn(
@@ -1950,7 +1572,7 @@ export async function handleSendMessage(
1950
1572
  const enqueueResult = conversation.enqueueMessage(
1951
1573
  content ?? "",
1952
1574
  attachments,
1953
- onEvent,
1575
+ broadcastMessage,
1954
1576
  requestId,
1955
1577
  undefined, // activeSurfaceId
1956
1578
  undefined, // currentPage
@@ -1967,9 +1589,10 @@ export async function handleSendMessage(
1967
1589
  clientMessageId,
1968
1590
  );
1969
1591
  if (enqueueResult.rejected) {
1970
- return Response.json(
1971
- { accepted: false, error: "queue_full" },
1972
- { status: 429 },
1592
+ return new RouteResponse(
1593
+ JSON.stringify({ accepted: false, error: "queue_full" }),
1594
+ { "content-type": "application/json" },
1595
+ 429,
1973
1596
  );
1974
1597
  }
1975
1598
 
@@ -1987,10 +1610,7 @@ export async function handleSendMessage(
1987
1610
  for (const interaction of pendingInteractions.getByConversation(
1988
1611
  mapping.conversationId,
1989
1612
  )) {
1990
- if (
1991
- interaction.conversation === conversation &&
1992
- interaction.kind === "confirmation"
1993
- ) {
1613
+ if (interaction.kind === "confirmation") {
1994
1614
  conversation.emitConfirmationStateChanged({
1995
1615
  conversationId: mapping.conversationId,
1996
1616
  requestId: interaction.requestId,
@@ -2005,7 +1625,7 @@ export async function handleSendMessage(
2005
1625
  }
2006
1626
  }
2007
1627
  conversation.denyAllPendingConfirmations();
2008
- pendingInteractions.removeByConversation(conversation);
1628
+ pendingInteractions.removeByConversation(mapping.conversationId);
2009
1629
  }
2010
1630
 
2011
1631
  // Expire any orphaned canonical requests that survived without a
@@ -2018,10 +1638,11 @@ export async function handleSendMessage(
2018
1638
  );
2019
1639
  }
2020
1640
 
2021
- return Response.json(
2022
- { accepted: true, queued: true, conversationId: mapping.conversationId },
2023
- { status: 202 },
2024
- );
1641
+ return {
1642
+ accepted: true,
1643
+ queued: true,
1644
+ conversationId: mapping.conversationId,
1645
+ };
2025
1646
  }
2026
1647
 
2027
1648
  // Auto-deny pending confirmations for idle conversations. The legacy
@@ -2033,10 +1654,7 @@ export async function handleSendMessage(
2033
1654
  for (const interaction of pendingInteractions.getByConversation(
2034
1655
  mapping.conversationId,
2035
1656
  )) {
2036
- if (
2037
- interaction.conversation === conversation &&
2038
- interaction.kind === "confirmation"
2039
- ) {
1657
+ if (interaction.kind === "confirmation") {
2040
1658
  conversation.emitConfirmationStateChanged({
2041
1659
  conversationId: mapping.conversationId,
2042
1660
  requestId: interaction.requestId,
@@ -2051,7 +1669,7 @@ export async function handleSendMessage(
2051
1669
  }
2052
1670
  }
2053
1671
  conversation.denyAllPendingConfirmations();
2054
- pendingInteractions.removeByConversation(conversation);
1672
+ pendingInteractions.removeByConversation(mapping.conversationId);
2055
1673
  }
2056
1674
 
2057
1675
  // Expire any orphaned canonical requests that survived without a
@@ -2072,17 +1690,14 @@ export async function handleSendMessage(
2072
1690
 
2073
1691
  // Resolve slash commands before persisting or running the agent loop.
2074
1692
  const rawContent = content ?? "";
2075
- const config = getConfig();
2076
- const slashContext: SlashContext = {
1693
+ const slashContext = buildSlashContextForContent(rawContent, {
1694
+ conversationId: mapping.conversationId,
2077
1695
  messageCount: conversation.getMessages().length,
2078
1696
  inputTokens: conversation.usageStats.inputTokens,
2079
1697
  outputTokens: conversation.usageStats.outputTokens,
2080
- maxInputTokens: config.llm.default.contextWindow.maxInputTokens,
2081
- model: config.llm.default.model,
2082
- provider: config.llm.default.provider,
2083
1698
  estimatedCost: conversation.usageStats.estimatedCost,
2084
1699
  userMessageInterface: sourceInterface,
2085
- };
1700
+ });
2086
1701
  const slashResult = await resolveSlash(rawContent, slashContext);
2087
1702
 
2088
1703
  if (slashResult.kind === "unknown") {
@@ -2139,17 +1754,14 @@ export async function handleSendMessage(
2139
1754
  // Snapshot model info now so the deferred callback cannot observe
2140
1755
  // a config change from a concurrent request.
2141
1756
  const modelInfoEvent = isModelSlashCommand(rawContent)
2142
- ? await buildModelInfoEvent()
1757
+ ? await buildModelInfoEvent(mapping.conversationId)
2143
1758
  : null;
2144
1759
 
2145
- const response = Response.json(
2146
- {
2147
- accepted: true,
2148
- messageId: persisted.id,
2149
- conversationId: mapping.conversationId,
2150
- },
2151
- { status: 202 },
2152
- );
1760
+ const response = {
1761
+ accepted: true,
1762
+ messageId: persisted.id,
1763
+ conversationId: mapping.conversationId,
1764
+ };
2153
1765
 
2154
1766
  // Defer event publishing to next tick so the HTTP response reaches the
2155
1767
  // client first. This ensures the client's serverToLocalConversationMap is
@@ -2162,7 +1774,7 @@ export async function handleSendMessage(
2162
1774
  const conversationId = mapping.conversationId;
2163
1775
  const message = slashResult.message;
2164
1776
  setTimeout(() => {
2165
- onEvent({
1777
+ broadcastMessage({
2166
1778
  type: "user_message_echo",
2167
1779
  text: rawContent,
2168
1780
  conversationId,
@@ -2170,10 +1782,14 @@ export async function handleSendMessage(
2170
1782
  clientMessageId,
2171
1783
  });
2172
1784
  if (modelInfoEvent) {
2173
- onEvent(modelInfoEvent);
1785
+ broadcastMessage(modelInfoEvent);
2174
1786
  }
2175
- onEvent({ type: "assistant_text_delta", text: message });
2176
- onEvent({
1787
+ broadcastMessage({
1788
+ type: "assistant_text_delta",
1789
+ text: message,
1790
+ conversationId,
1791
+ });
1792
+ broadcastMessage({
2177
1793
  type: "message_complete",
2178
1794
  conversationId: conversationId,
2179
1795
  });
@@ -2219,7 +1835,7 @@ export async function handleSendMessage(
2219
1835
  // HTTP timeout on large contexts, causing a false "Failed to send".
2220
1836
  (async () => {
2221
1837
  try {
2222
- onEvent({
1838
+ broadcastMessage({
2223
1839
  type: "user_message_echo",
2224
1840
  text: rawContent,
2225
1841
  conversationId,
@@ -2243,11 +1859,15 @@ export async function handleSendMessage(
2243
1859
  );
2244
1860
  conversation.getMessages().push(assistantMsg);
2245
1861
 
2246
- onEvent({ type: "assistant_text_delta", text: responseText });
2247
- onEvent({ type: "message_complete", conversationId });
1862
+ broadcastMessage({
1863
+ type: "assistant_text_delta",
1864
+ text: responseText,
1865
+ conversationId,
1866
+ });
1867
+ broadcastMessage({ type: "message_complete", conversationId });
2248
1868
  } catch (err) {
2249
1869
  log.error({ err, conversationId }, "Compact command failed");
2250
- onEvent({
1870
+ broadcastMessage({
2251
1871
  type: "conversation_error",
2252
1872
  conversationId,
2253
1873
  code: "UNKNOWN",
@@ -2263,14 +1883,11 @@ export async function handleSendMessage(
2263
1883
  }
2264
1884
  })();
2265
1885
 
2266
- return Response.json(
2267
- {
2268
- accepted: true,
2269
- messageId: persisted.id,
2270
- conversationId,
2271
- },
2272
- { status: 202 },
2273
- );
1886
+ return {
1887
+ accepted: true,
1888
+ messageId: persisted.id,
1889
+ conversationId,
1890
+ };
2274
1891
  }
2275
1892
 
2276
1893
  const resolvedContent = slashResult.content;
@@ -2288,7 +1905,7 @@ export async function handleSendMessage(
2288
1905
  throw err;
2289
1906
  }
2290
1907
 
2291
- onEvent({
1908
+ broadcastMessage({
2292
1909
  type: "user_message_echo",
2293
1910
  text: resolvedContent,
2294
1911
  conversationId: mapping.conversationId,
@@ -2297,9 +1914,9 @@ export async function handleSendMessage(
2297
1914
  clientMessageId,
2298
1915
  });
2299
1916
 
2300
- // 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.
2301
1918
  conversation
2302
- .runAgentLoop(resolvedContent, messageId, onEvent, {
1919
+ .runAgentLoop(resolvedContent, messageId, broadcastMessage, {
2303
1920
  isInteractive,
2304
1921
  isUserMessage: true,
2305
1922
  })
@@ -2310,10 +1927,11 @@ export async function handleSendMessage(
2310
1927
  );
2311
1928
  });
2312
1929
 
2313
- return Response.json(
2314
- { accepted: true, messageId, conversationId: mapping.conversationId },
2315
- { status: 202 },
2316
- );
1930
+ return {
1931
+ accepted: true,
1932
+ messageId,
1933
+ conversationId: mapping.conversationId,
1934
+ };
2317
1935
  }
2318
1936
 
2319
1937
  function escapeXmlContent(text: string): string {
@@ -2400,54 +2018,39 @@ async function generateLlmSuggestion(
2400
2018
  }
2401
2019
 
2402
2020
  export async function handleGetSuggestion(
2403
- url: URL,
2021
+ { queryParams }: RouteHandlerArgs,
2404
2022
  deps: {
2405
2023
  suggestionCache: Map<string, string>;
2406
2024
  suggestionInFlight: Map<string, Promise<string | null>>;
2407
2025
  },
2408
- ): Promise<Response> {
2409
- const conversationKey = url.searchParams.get("conversationKey");
2026
+ ): Promise<Record<string, unknown>> {
2027
+ const noSuggestion = {
2028
+ suggestion: null,
2029
+ messageId: null,
2030
+ source: "none" as const,
2031
+ };
2032
+
2033
+ const conversationKey = queryParams?.conversationKey;
2410
2034
  if (!conversationKey) {
2411
- return httpError(
2412
- "BAD_REQUEST",
2413
- "conversationKey query parameter is required",
2414
- 400,
2415
- );
2035
+ throw new BadRequestError("conversationKey query parameter is required");
2416
2036
  }
2417
2037
 
2418
2038
  const mapping = getConversationByKey(conversationKey);
2419
- if (!mapping) {
2420
- return Response.json({
2421
- suggestion: null,
2422
- messageId: null,
2423
- source: "none" as const,
2424
- });
2425
- }
2039
+ if (!mapping) return noSuggestion;
2426
2040
 
2427
2041
  const rawMessages = getMessages(mapping.conversationId);
2428
- if (rawMessages.length === 0) {
2429
- return Response.json({
2430
- suggestion: null,
2431
- messageId: null,
2432
- source: "none" as const,
2433
- });
2434
- }
2042
+ if (rawMessages.length === 0) return noSuggestion;
2435
2043
 
2436
2044
  // Staleness check: compare requested messageId against the latest
2437
2045
  // assistant message BEFORE filtering by text content. This ensures
2438
2046
  // that a newer tool-only assistant turn (empty text) still causes
2439
2047
  // older messageId requests to be correctly marked as stale.
2440
- const requestedMessageId = url.searchParams.get("messageId");
2048
+ const requestedMessageId = queryParams?.messageId;
2441
2049
  if (requestedMessageId) {
2442
2050
  for (let i = rawMessages.length - 1; i >= 0; i--) {
2443
2051
  if (rawMessages[i].role === "assistant") {
2444
2052
  if (rawMessages[i].id !== requestedMessageId) {
2445
- return Response.json({
2446
- suggestion: null,
2447
- messageId: null,
2448
- source: "none" as const,
2449
- stale: true,
2450
- });
2053
+ return { ...noSuggestion, stale: true };
2451
2054
  }
2452
2055
  break;
2453
2056
  }
@@ -2475,22 +2078,13 @@ export async function handleGetSuggestion(
2475
2078
  // If a messageId was requested and the first text-bearing assistant
2476
2079
  // message is a *different* message, the request is stale.
2477
2080
  if (requestedMessageId && msg.id !== requestedMessageId) {
2478
- return Response.json({
2479
- suggestion: null,
2480
- messageId: null,
2481
- source: "none" as const,
2482
- stale: true,
2483
- });
2081
+ return { ...noSuggestion, stale: true };
2484
2082
  }
2485
2083
 
2486
2084
  // Return cached suggestion if we already generated one for this message
2487
2085
  const cached = suggestionCache.get(msg.id);
2488
2086
  if (cached !== undefined) {
2489
- return Response.json({
2490
- suggestion: cached,
2491
- messageId: msg.id,
2492
- source: "llm" as const,
2493
- });
2087
+ return { suggestion: cached, messageId: msg.id, source: "llm" as const };
2494
2088
  }
2495
2089
 
2496
2090
  // Find the most recent user message preceding this assistant turn so the
@@ -2534,11 +2128,11 @@ export async function handleGetSuggestion(
2534
2128
  }
2535
2129
  suggestionCache.set(msg.id, llmSuggestion);
2536
2130
 
2537
- return Response.json({
2131
+ return {
2538
2132
  suggestion: llmSuggestion,
2539
2133
  messageId: msg.id,
2540
2134
  source: "llm" as const,
2541
- });
2135
+ };
2542
2136
  }
2543
2137
  } catch (err) {
2544
2138
  suggestionInFlight.delete(msg.id);
@@ -2554,18 +2148,10 @@ export async function handleGetSuggestion(
2554
2148
  );
2555
2149
  }
2556
2150
 
2557
- return Response.json({
2558
- suggestion: null,
2559
- messageId: null,
2560
- source: "none" as const,
2561
- });
2151
+ return noSuggestion;
2562
2152
  }
2563
2153
 
2564
- return Response.json({
2565
- suggestion: null,
2566
- messageId: null,
2567
- source: "none" as const,
2568
- });
2154
+ return noSuggestion;
2569
2155
  }
2570
2156
 
2571
2157
  /**
@@ -2574,19 +2160,17 @@ export async function handleGetSuggestion(
2574
2160
  * Full-text search across all conversations (message content + titles).
2575
2161
  * Returns ranked results grouped by conversation, each with matching message excerpts.
2576
2162
  */
2577
- function handleSearchConversations(url: URL): Response {
2578
- const query = url.searchParams.get("q") ?? "";
2163
+ function handleSearchConversations({
2164
+ queryParams,
2165
+ }: RouteHandlerArgs): Record<string, unknown> {
2166
+ const query = queryParams?.q ?? "";
2579
2167
  if (!query.trim()) {
2580
- return httpError("BAD_REQUEST", "q query parameter is required", 400);
2168
+ throw new BadRequestError("q query parameter is required");
2581
2169
  }
2582
2170
 
2583
- const limit = url.searchParams.has("limit")
2584
- ? Number(url.searchParams.get("limit"))
2585
- : undefined;
2586
- const maxMessagesPerConversation = url.searchParams.has(
2587
- "maxMessagesPerConversation",
2588
- )
2589
- ? Number(url.searchParams.get("maxMessagesPerConversation"))
2171
+ const limit = queryParams?.limit ? Number(queryParams.limit) : undefined;
2172
+ const maxMessagesPerConversation = queryParams?.maxMessagesPerConversation
2173
+ ? Number(queryParams.maxMessagesPerConversation)
2590
2174
  : undefined;
2591
2175
 
2592
2176
  const results = searchConversations(query, {
@@ -2597,105 +2181,125 @@ function handleSearchConversations(url: URL): Response {
2597
2181
  : {}),
2598
2182
  });
2599
2183
 
2600
- return Response.json({ query, results });
2184
+ return { query, results };
2185
+ }
2186
+
2187
+ // ---------------------------------------------------------------------------
2188
+ // Module-level state
2189
+ // ---------------------------------------------------------------------------
2190
+
2191
+ const suggestionCache = new Map<string, string>();
2192
+ const suggestionInFlight = new Map<string, Promise<string | null>>();
2193
+
2194
+ function resolveAttachments(attachmentIds: string[]) {
2195
+ const resolved = getAttachmentsByIds(attachmentIds, {
2196
+ hydrateFileData: true,
2197
+ });
2198
+ const sourcePaths = getSourcePathsForAttachments(attachmentIds);
2199
+ return resolved.map((a) => ({
2200
+ id: a.id,
2201
+ filename: a.originalFilename,
2202
+ mimeType: a.mimeType,
2203
+ data: a.dataBase64,
2204
+ ...(sourcePaths.has(a.id) ? { filePath: sourcePaths.get(a.id) } : {}),
2205
+ }));
2601
2206
  }
2602
2207
 
2603
2208
  // ---------------------------------------------------------------------------
2604
2209
  // Route definitions
2605
2210
  // ---------------------------------------------------------------------------
2606
2211
 
2607
- export function conversationRouteDefinitions(deps: {
2608
- interfacesDir: string | null;
2609
- sendMessageDeps?: SendMessageDeps;
2610
- approvalConversationGenerator?: ApprovalConversationGenerator;
2611
- suggestionCache: Map<string, string>;
2612
- suggestionInFlight: Map<string, Promise<string | null>>;
2613
- getHeartbeatService?: () => HeartbeatService | undefined;
2614
- }): RouteDefinition[] {
2615
- return [
2616
- {
2617
- endpoint: "messages",
2618
- method: "GET",
2619
- summary: "List messages",
2620
- description:
2621
- "Return messages for a conversation, including attachments and interface file metadata.",
2622
- tags: ["messages"],
2623
- responseBody: z.object({
2624
- messages: z.array(z.unknown()).describe("Array of message objects"),
2625
- hasMore: z
2626
- .boolean()
2627
- .optional()
2628
- .describe("Whether older messages exist beyond this page"),
2629
- oldestTimestamp: z
2630
- .number()
2631
- .optional()
2632
- .describe(
2633
- "Timestamp of the oldest message in this page (ms since epoch)",
2634
- ),
2635
- oldestMessageId: z
2636
- .string()
2637
- .optional()
2638
- .describe("ID of the oldest message in this page"),
2639
- }),
2640
- handler: ({ url }) => handleListMessages(url, deps.interfacesDir),
2641
- },
2642
- {
2643
- endpoint: "messages",
2644
- method: "POST",
2645
- summary: "Send a message",
2646
- description:
2647
- "Send a user message to a conversation and trigger the assistant response.",
2648
- tags: ["messages"],
2649
- requestBody: z.object({
2650
- conversationKey: z.string().optional(),
2651
- content: z.string().describe("Message text content"),
2652
- attachments: z
2653
- .array(z.unknown())
2654
- .describe("Optional file attachments")
2655
- .optional(),
2656
- conversationType: z.string().optional(),
2657
- slashCommand: z.string().optional(),
2658
- }),
2659
- handler: async ({ req, authContext }) =>
2660
- handleSendMessage(
2661
- req,
2662
- {
2663
- sendMessageDeps: deps.sendMessageDeps,
2664
- approvalConversationGenerator: deps.approvalConversationGenerator,
2665
- heartbeatService: deps.getHeartbeatService?.(),
2666
- },
2667
- authContext,
2212
+ export const ROUTES: RouteDefinition[] = [
2213
+ {
2214
+ operationId: "messages_get",
2215
+ endpoint: "messages",
2216
+ method: "GET",
2217
+ summary: "List messages",
2218
+ description:
2219
+ "Return messages for a conversation, including attachments and interface file metadata.",
2220
+ tags: ["messages"],
2221
+ responseBody: z.object({
2222
+ messages: z.array(z.unknown()).describe("Array of message objects"),
2223
+ hasMore: z
2224
+ .boolean()
2225
+ .optional()
2226
+ .describe("Whether older messages exist beyond this page"),
2227
+ oldestTimestamp: z
2228
+ .number()
2229
+ .nullable()
2230
+ .optional()
2231
+ .describe(
2232
+ "Timestamp of the oldest message in this page (ms since epoch). Null when page=latest is used on an empty conversation.",
2668
2233
  ),
2669
- },
2670
- {
2671
- endpoint: "search",
2672
- method: "GET",
2673
- summary: "Search conversations",
2674
- description: "Full-text search across all conversations.",
2675
- tags: ["conversations"],
2676
- responseBody: z.object({
2677
- query: z.string(),
2678
- results: z.array(z.unknown()),
2234
+ oldestMessageId: z
2235
+ .string()
2236
+ .nullable()
2237
+ .optional()
2238
+ .describe("ID of the oldest message in this page"),
2239
+ }),
2240
+ handler: (args) => handleListMessages(args, getInterfacesDir()),
2241
+ },
2242
+ {
2243
+ operationId: "messages_post",
2244
+ endpoint: "messages",
2245
+ method: "POST",
2246
+ summary: "Send a message",
2247
+ description:
2248
+ "Send a user message to a conversation and trigger the assistant response.",
2249
+ tags: ["messages"],
2250
+ responseStatus: "202",
2251
+ requestBody: z.object({
2252
+ conversationKey: z.string().optional(),
2253
+ content: z.string().describe("Message text content"),
2254
+ attachments: z
2255
+ .array(z.unknown())
2256
+ .describe("Optional file attachments")
2257
+ .optional(),
2258
+ conversationType: z.string().optional(),
2259
+ slashCommand: z.string().optional(),
2260
+ inferenceProfile: z.string().nullable().optional(),
2261
+ riskThreshold: z.enum(VALID_RISK_THRESHOLDS).optional(),
2262
+ }),
2263
+ handler: async (args) =>
2264
+ handleSendMessage(args, {
2265
+ sendMessageDeps: {
2266
+ getOrCreateConversation: getOrCreateConversationInstance,
2267
+ assistantEventHub,
2268
+ resolveAttachments,
2269
+ },
2270
+ approvalConversationGenerator: createApprovalConversationGenerator(),
2679
2271
  }),
2680
- handler: ({ url }) => handleSearchConversations(url),
2681
- },
2682
- {
2683
- endpoint: "suggestion",
2684
- method: "GET",
2685
- summary: "Get reply suggestion",
2686
- description:
2687
- "Return an LLM-generated follow-up suggestion for the most recent assistant message.",
2688
- tags: ["messages"],
2689
- responseBody: z.object({
2690
- suggestion: z.string(),
2691
- messageId: z.string(),
2692
- source: z.string(),
2272
+ },
2273
+ {
2274
+ operationId: "search_get",
2275
+ endpoint: "search",
2276
+ method: "GET",
2277
+ summary: "Search conversations",
2278
+ description: "Full-text search across all conversations.",
2279
+ tags: ["conversations"],
2280
+ responseBody: z.object({
2281
+ query: z.string(),
2282
+ results: z.array(z.unknown()),
2283
+ }),
2284
+ handler: handleSearchConversations,
2285
+ },
2286
+ {
2287
+ operationId: "suggestion_get",
2288
+ endpoint: "suggestion",
2289
+ method: "GET",
2290
+ summary: "Get reply suggestion",
2291
+ description:
2292
+ "Return an LLM-generated follow-up suggestion for the most recent assistant message.",
2293
+ tags: ["messages"],
2294
+ responseBody: z.object({
2295
+ suggestion: z.string(),
2296
+ messageId: z.string(),
2297
+ source: z.string(),
2298
+ }),
2299
+ handler: async (args) =>
2300
+ handleGetSuggestion(args, {
2301
+ suggestionCache,
2302
+ suggestionInFlight,
2693
2303
  }),
2694
- handler: async ({ url }) =>
2695
- handleGetSuggestion(url, {
2696
- suggestionCache: deps.suggestionCache,
2697
- suggestionInFlight: deps.suggestionInFlight,
2698
- }),
2699
- },
2700
- ];
2701
- }
2304
+ },
2305
+ ];