@vellumai/assistant 0.6.3 → 0.6.4

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 (667) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +5 -13
  4. package/docs/backup-troubleshooting.md +52 -0
  5. package/docs/browser-use-architecture-phase2.md +174 -0
  6. package/docs/stt-provider-onboarding.md +120 -0
  7. package/knip.json +12 -2
  8. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  9. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  10. package/openapi.yaml +982 -72
  11. package/package.json +4 -6
  12. package/scripts/generate-openapi.ts +0 -1
  13. package/scripts/test.sh +73 -18
  14. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  15. package/src/__tests__/agent-loop.test.ts +123 -0
  16. package/src/__tests__/anthropic-provider.test.ts +263 -10
  17. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  18. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  19. package/src/__tests__/browser-fill-credential.test.ts +11 -0
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  22. package/src/__tests__/btw-routes.test.ts +7 -0
  23. package/src/__tests__/call-controller.test.ts +581 -20
  24. package/src/__tests__/catalog-files.test.ts +138 -0
  25. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  26. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  27. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  28. package/src/__tests__/checker.test.ts +157 -10
  29. package/src/__tests__/clawhub-files.test.ts +347 -0
  30. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  31. package/src/__tests__/config-analysis.test.ts +100 -0
  32. package/src/__tests__/config-schema.test.ts +1013 -66
  33. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  34. package/src/__tests__/config-watcher.test.ts +43 -8
  35. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  36. package/src/__tests__/contacts-write.test.ts +197 -0
  37. package/src/__tests__/context-window-manager.test.ts +88 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  40. package/src/__tests__/conversation-agent-loop.test.ts +98 -2
  41. package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
  42. package/src/__tests__/conversation-error.test.ts +70 -0
  43. package/src/__tests__/conversation-history-web-search.test.ts +11 -4
  44. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  45. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  46. package/src/__tests__/conversation-list-source.test.ts +145 -0
  47. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  48. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  49. package/src/__tests__/conversation-queue.test.ts +901 -60
  50. package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
  51. package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
  52. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  53. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  54. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  55. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  56. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  59. package/src/__tests__/credential-health-service.test.ts +352 -0
  60. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  61. package/src/__tests__/credential-vault-unit.test.ts +379 -3
  62. package/src/__tests__/credentials-cli.test.ts +40 -16
  63. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  64. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  65. package/src/__tests__/device-id.test.ts +112 -0
  66. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  67. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  68. package/src/__tests__/email-html-renderer.test.ts +71 -0
  69. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  70. package/src/__tests__/emit-event-signal.test.ts +71 -0
  71. package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
  72. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  73. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  74. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  75. package/src/__tests__/gemini-provider.test.ts +64 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  77. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  78. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  79. package/src/__tests__/gmail-preferences.test.ts +117 -0
  80. package/src/__tests__/headless-browser-interactions.test.ts +43 -0
  81. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  82. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  83. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  84. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  85. package/src/__tests__/heartbeat-service.test.ts +70 -17
  86. package/src/__tests__/home-state-routes.test.ts +162 -0
  87. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  88. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  89. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  90. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  91. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  92. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  93. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  94. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  95. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  96. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  97. package/src/__tests__/llm-usage-store.test.ts +363 -0
  98. package/src/__tests__/media-stream-output.test.ts +555 -0
  99. package/src/__tests__/media-stream-parser.test.ts +374 -0
  100. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  101. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  102. package/src/__tests__/media-turn-detector.test.ts +440 -0
  103. package/src/__tests__/message-queue.test.ts +125 -0
  104. package/src/__tests__/migration-export-http.test.ts +6 -6
  105. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  106. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  107. package/src/__tests__/migration-validate-http.test.ts +3 -3
  108. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  109. package/src/__tests__/model-intents.test.ts +2 -2
  110. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  111. package/src/__tests__/oauth-cli.test.ts +2 -0
  112. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  115. package/src/__tests__/oauth-store.test.ts +85 -0
  116. package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
  117. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  118. package/src/__tests__/openai-provider.test.ts +176 -0
  119. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  120. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  121. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  122. package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
  123. package/src/__tests__/persona-resolver.test.ts +251 -0
  124. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  125. package/src/__tests__/platform.test.ts +92 -1
  126. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  127. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  128. package/src/__tests__/pricing.test.ts +174 -0
  129. package/src/__tests__/qdrant-manager.test.ts +29 -8
  130. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  131. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  132. package/src/__tests__/relay-server.test.ts +423 -5
  133. package/src/__tests__/search-skills-unified.test.ts +118 -0
  134. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  135. package/src/__tests__/secure-keys.test.ts +107 -0
  136. package/src/__tests__/send-endpoint-busy.test.ts +5 -1
  137. package/src/__tests__/sequence-store.test.ts +1 -1
  138. package/src/__tests__/server-history-render.test.ts +49 -0
  139. package/src/__tests__/settings-routes.test.ts +201 -0
  140. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  141. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  142. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  143. package/src/__tests__/skills.test.ts +5 -2
  144. package/src/__tests__/skillssh-files.test.ts +446 -0
  145. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  146. package/src/__tests__/slack-channel-config.test.ts +564 -1
  147. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  148. package/src/__tests__/stt-stream-session.test.ts +535 -0
  149. package/src/__tests__/system-prompt.test.ts +112 -26
  150. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  151. package/src/__tests__/terminal-tools.test.ts +18 -7
  152. package/src/__tests__/test-preload.ts +18 -0
  153. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  155. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  156. package/src/__tests__/tool-executor.test.ts +33 -24
  157. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  158. package/src/__tests__/trust-store.test.ts +7 -1
  159. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  160. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  161. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  162. package/src/__tests__/twilio-routes.test.ts +376 -0
  163. package/src/__tests__/unicode.test.ts +293 -0
  164. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  165. package/src/__tests__/update-bulletin.test.ts +206 -5
  166. package/src/__tests__/usage-routes.test.ts +25 -4
  167. package/src/__tests__/user-reference.test.ts +46 -61
  168. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  169. package/src/__tests__/voice-config-update.test.ts +403 -0
  170. package/src/__tests__/voice-quality.test.ts +434 -19
  171. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  172. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  173. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  174. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  175. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  176. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  177. package/src/__tests__/workspace-policy.test.ts +2 -0
  178. package/src/agent/image-optimize.ts +24 -12
  179. package/src/agent/loop.ts +43 -3
  180. package/src/backup/__tests__/backup-key.test.ts +152 -0
  181. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  182. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  183. package/src/backup/__tests__/local-writer.test.ts +218 -0
  184. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  185. package/src/backup/__tests__/paths.test.ts +300 -0
  186. package/src/backup/__tests__/restore.test.ts +498 -0
  187. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  188. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  189. package/src/backup/backup-key.ts +137 -0
  190. package/src/backup/backup-worker.ts +459 -0
  191. package/src/backup/list-snapshots.ts +147 -0
  192. package/src/backup/local-writer.ts +133 -0
  193. package/src/backup/offsite-writer.ts +222 -0
  194. package/src/backup/paths.ts +226 -0
  195. package/src/backup/restore.ts +322 -0
  196. package/src/backup/snapshot-lock.ts +431 -0
  197. package/src/backup/stream-crypt.ts +263 -0
  198. package/src/bundler/package-resolver.ts +4 -0
  199. package/src/calls/audio-store.ts +11 -5
  200. package/src/calls/call-controller.ts +226 -71
  201. package/src/calls/call-domain.ts +9 -0
  202. package/src/calls/call-speech-output.ts +190 -0
  203. package/src/calls/call-transport.ts +77 -0
  204. package/src/calls/media-stream-audio-transcode.ts +173 -0
  205. package/src/calls/media-stream-output.ts +660 -0
  206. package/src/calls/media-stream-parser.ts +300 -0
  207. package/src/calls/media-stream-protocol.ts +166 -0
  208. package/src/calls/media-stream-server.ts +592 -0
  209. package/src/calls/media-stream-stt-session.ts +460 -0
  210. package/src/calls/media-turn-detector.ts +230 -0
  211. package/src/calls/relay-server.ts +90 -75
  212. package/src/calls/resolve-call-tts-provider.ts +136 -0
  213. package/src/calls/telephony-stt-routing.ts +145 -0
  214. package/src/calls/tts-call-strategy.ts +161 -0
  215. package/src/calls/tts-text-sanitizer.ts +32 -16
  216. package/src/calls/twilio-routes.ts +281 -17
  217. package/src/calls/voice-quality.ts +78 -35
  218. package/src/calls/voice-session-bridge.ts +8 -1
  219. package/src/channels/types.ts +16 -0
  220. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  221. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  222. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  223. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  224. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  225. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  226. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  227. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  228. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  229. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  230. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  231. package/src/cli/commands/backup.ts +993 -0
  232. package/src/cli/commands/conversations.ts +77 -0
  233. package/src/cli/commands/credentials.ts +0 -1
  234. package/src/cli/commands/domain.ts +210 -0
  235. package/src/cli/commands/email.ts +255 -3
  236. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  237. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  238. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  239. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  240. package/src/cli/commands/oauth/mode.ts +12 -3
  241. package/src/cli/commands/oauth/providers.ts +15 -0
  242. package/src/cli/commands/oauth/shared.ts +2 -1
  243. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
  244. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  245. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  246. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  247. package/src/cli/program.ts +30 -4
  248. package/src/config/__tests__/backup-schema.test.ts +134 -0
  249. package/src/config/assistant-feature-flags.ts +61 -62
  250. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  251. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  252. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  253. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  254. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  255. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  256. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  258. package/src/config/bundled-skills/gmail/SKILL.md +53 -7
  259. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  260. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  261. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  262. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  263. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  264. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  265. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  266. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  267. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  268. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  269. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  270. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  271. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  272. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  273. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  274. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  275. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  276. package/src/config/bundled-skills/outlook/SKILL.md +2 -2
  277. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  278. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  279. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  280. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  281. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  282. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  283. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  284. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  285. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  286. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  287. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  288. package/src/config/bundled-tool-registry.ts +8 -0
  289. package/src/config/env-registry.ts +24 -0
  290. package/src/config/env.ts +34 -10
  291. package/src/config/feature-flag-registry.json +46 -14
  292. package/src/config/loader.ts +26 -12
  293. package/src/config/schema.ts +35 -10
  294. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  295. package/src/config/schemas/analysis.ts +51 -0
  296. package/src/config/schemas/backup.ts +72 -0
  297. package/src/config/schemas/calls.ts +1 -26
  298. package/src/config/schemas/elevenlabs.ts +0 -59
  299. package/src/config/schemas/filing.ts +47 -7
  300. package/src/config/schemas/heartbeat.ts +27 -5
  301. package/src/config/schemas/host-browser.ts +47 -1
  302. package/src/config/schemas/inference.ts +1 -1
  303. package/src/config/schemas/memory-lifecycle.ts +14 -2
  304. package/src/config/schemas/services.ts +44 -0
  305. package/src/config/schemas/stt.ts +59 -0
  306. package/src/config/schemas/tts.ts +230 -0
  307. package/src/config/schemas/updates.ts +14 -0
  308. package/src/config/skills.ts +4 -0
  309. package/src/config/types.ts +4 -0
  310. package/src/contacts/contact-store.ts +56 -11
  311. package/src/contacts/contacts-write.ts +38 -1
  312. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  313. package/src/context/tool-result-truncation.ts +2 -1
  314. package/src/context/window-manager.ts +45 -12
  315. package/src/credential-execution/executable-discovery.ts +12 -2
  316. package/src/credential-execution/process-manager.ts +33 -2
  317. package/src/credential-health/credential-health-service.ts +366 -0
  318. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  319. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  320. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  321. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  322. package/src/daemon/config-watcher.ts +99 -5
  323. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  324. package/src/daemon/conversation-agent-loop.ts +101 -24
  325. package/src/daemon/conversation-error.ts +11 -0
  326. package/src/daemon/conversation-history.ts +40 -6
  327. package/src/daemon/conversation-launch.ts +220 -0
  328. package/src/daemon/conversation-lifecycle.ts +59 -9
  329. package/src/daemon/conversation-messaging.ts +37 -3
  330. package/src/daemon/conversation-notifiers.ts +5 -0
  331. package/src/daemon/conversation-process.ts +581 -19
  332. package/src/daemon/conversation-queue-manager.ts +24 -0
  333. package/src/daemon/conversation-runtime-assembly.ts +11 -1
  334. package/src/daemon/conversation-slash.ts +36 -0
  335. package/src/daemon/conversation-surfaces.ts +94 -4
  336. package/src/daemon/conversation-tool-setup.ts +25 -0
  337. package/src/daemon/conversation-usage.ts +7 -4
  338. package/src/daemon/conversation.ts +86 -28
  339. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  340. package/src/daemon/handlers/conversations.ts +4 -1
  341. package/src/daemon/handlers/shared.ts +22 -0
  342. package/src/daemon/handlers/skills.ts +321 -77
  343. package/src/daemon/host-browser-proxy.ts +2 -1
  344. package/src/daemon/lifecycle.ts +122 -25
  345. package/src/daemon/message-protocol.ts +6 -0
  346. package/src/daemon/message-types/conversations.ts +34 -1
  347. package/src/daemon/message-types/home.ts +40 -0
  348. package/src/daemon/message-types/meet.ts +143 -0
  349. package/src/daemon/message-types/messages.ts +14 -0
  350. package/src/daemon/message-types/schedules.ts +34 -2
  351. package/src/daemon/message-types/skills.ts +16 -0
  352. package/src/daemon/message-types/surfaces.ts +2 -0
  353. package/src/daemon/server.ts +347 -2
  354. package/src/daemon/shutdown-handlers.ts +32 -4
  355. package/src/daemon/shutdown-registry.ts +40 -0
  356. package/src/daemon/tool-side-effects.ts +9 -0
  357. package/src/email/html-renderer.ts +76 -0
  358. package/src/heartbeat/heartbeat-service.ts +93 -7
  359. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  360. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  361. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  362. package/src/home/__tests__/feed-types.test.ts +275 -0
  363. package/src/home/__tests__/feed-writer.test.ts +688 -0
  364. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  365. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  366. package/src/home/__tests__/progress-formula.test.ts +213 -0
  367. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  368. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  369. package/src/home/assistant-feed-authoring.ts +124 -0
  370. package/src/home/emit-feed-event.ts +158 -0
  371. package/src/home/feed-scheduler.ts +247 -0
  372. package/src/home/feed-types.ts +181 -0
  373. package/src/home/feed-writer.ts +469 -0
  374. package/src/home/platform-gmail-digest.ts +163 -0
  375. package/src/home/progress-formula.ts +86 -0
  376. package/src/home/relationship-state-writer.ts +824 -0
  377. package/src/home/relationship-state.ts +143 -0
  378. package/src/home/rollup-producer.ts +384 -0
  379. package/src/hooks/runner.ts +7 -0
  380. package/src/inbound/platform-callback-registration.ts +12 -3
  381. package/src/inbound/public-ingress-urls.ts +12 -0
  382. package/src/instrument.ts +1 -1
  383. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  384. package/src/ipc/cli-client.ts +151 -0
  385. package/src/ipc/cli-server.ts +234 -0
  386. package/src/ipc/gateway-client.ts +180 -0
  387. package/src/ipc/routes/index.ts +5 -0
  388. package/src/ipc/routes/wake-conversation.ts +19 -0
  389. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  390. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  391. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  392. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  393. package/src/memory/app-store.ts +1 -1
  394. package/src/memory/attachments-store.ts +70 -0
  395. package/src/memory/auto-analysis-enqueue.ts +127 -0
  396. package/src/memory/auto-analysis-guard.ts +27 -0
  397. package/src/memory/cleanup-schedule-state.ts +37 -0
  398. package/src/memory/conversation-analyze-job.ts +73 -0
  399. package/src/memory/conversation-crud.ts +99 -0
  400. package/src/memory/conversation-disk-view.ts +7 -0
  401. package/src/memory/conversation-group-migration.ts +34 -2
  402. package/src/memory/conversation-queries.ts +6 -5
  403. package/src/memory/db-init.ts +6 -0
  404. package/src/memory/db-maintenance.ts +108 -0
  405. package/src/memory/db.ts +1 -0
  406. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  407. package/src/memory/graph/extraction.test.ts +23 -0
  408. package/src/memory/graph/extraction.ts +8 -0
  409. package/src/memory/graph/retriever.ts +27 -18
  410. package/src/memory/graph/scoring.test.ts +186 -0
  411. package/src/memory/graph/scoring.ts +31 -1
  412. package/src/memory/graph/tools.ts +1 -1
  413. package/src/memory/group-crud.ts +6 -1
  414. package/src/memory/indexer.ts +95 -16
  415. package/src/memory/job-handlers/cleanup.ts +11 -8
  416. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  417. package/src/memory/jobs-store.ts +64 -4
  418. package/src/memory/jobs-worker.ts +22 -9
  419. package/src/memory/llm-usage-store.ts +92 -56
  420. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  421. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  422. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  423. package/src/memory/migrations/index.ts +6 -0
  424. package/src/memory/migrations/registry.ts +8 -0
  425. package/src/memory/qdrant-manager.ts +43 -16
  426. package/src/memory/schema/conversations.ts +2 -0
  427. package/src/memory/schema/oauth.ts +3 -0
  428. package/src/memory/usage-buckets.ts +396 -0
  429. package/src/messaging/providers/gmail/client.ts +57 -6
  430. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  431. package/src/messaging/providers/slack/adapter.ts +143 -38
  432. package/src/messaging/providers/slack/client.ts +16 -0
  433. package/src/messaging/providers/slack/types.ts +4 -0
  434. package/src/notifications/decision-engine.ts +3 -3
  435. package/src/notifications/signal.ts +5 -0
  436. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  437. package/src/oauth/byo-connection.test.ts +18 -1
  438. package/src/oauth/byo-connection.ts +3 -1
  439. package/src/oauth/connect-orchestrator.ts +2 -0
  440. package/src/oauth/connection-resolver.ts +6 -2
  441. package/src/oauth/connection.ts +2 -0
  442. package/src/oauth/oauth-store.ts +9 -0
  443. package/src/oauth/platform-connection.test.ts +98 -0
  444. package/src/oauth/platform-connection.ts +52 -31
  445. package/src/oauth/seed-providers.ts +7 -0
  446. package/src/permissions/checker.ts +16 -6
  447. package/src/permissions/defaults.ts +49 -1
  448. package/src/permissions/trust-store.ts +3 -3
  449. package/src/permissions/workspace-policy.ts +3 -0
  450. package/src/platform/client.test.ts +10 -0
  451. package/src/platform/sync-identity.ts +129 -0
  452. package/src/prompts/persona-resolver.ts +126 -2
  453. package/src/prompts/system-prompt.ts +59 -18
  454. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  455. package/src/prompts/templates/SOUL.md +3 -1
  456. package/src/prompts/templates/UPDATES.md +12 -0
  457. package/src/prompts/templates/channels/slack.md +20 -0
  458. package/src/prompts/update-bulletin-format.ts +26 -9
  459. package/src/prompts/update-bulletin.ts +34 -23
  460. package/src/prompts/user-reference.ts +20 -17
  461. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  462. package/src/providers/anthropic/client.ts +157 -61
  463. package/src/providers/fireworks/client.ts +2 -2
  464. package/src/providers/gemini/client.ts +9 -1
  465. package/src/providers/model-catalog.ts +6 -0
  466. package/src/providers/model-intents.ts +4 -4
  467. package/src/providers/ollama/client.ts +2 -2
  468. package/src/providers/openai/chat-completions-provider.ts +474 -0
  469. package/src/providers/openai/client.ts +25 -440
  470. package/src/providers/openai/responses-provider.ts +502 -0
  471. package/src/providers/openrouter/client.ts +101 -4
  472. package/src/providers/provider-secret-catalog.ts +139 -0
  473. package/src/providers/registry.ts +2 -2
  474. package/src/providers/retry.ts +14 -3
  475. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  476. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  477. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  478. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  479. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  480. package/src/providers/speech-to-text/deepgram.ts +115 -0
  481. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  482. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  483. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  484. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  485. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  486. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  487. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  488. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  489. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  490. package/src/providers/speech-to-text/resolve.ts +386 -6
  491. package/src/providers/types.ts +9 -0
  492. package/src/runtime/AGENTS.md +43 -1
  493. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  494. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  495. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  496. package/src/runtime/agent-wake.ts +512 -0
  497. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  498. package/src/runtime/auth/route-policy.ts +30 -5
  499. package/src/runtime/auth/token-service.ts +56 -1
  500. package/src/runtime/btw-sidechain.ts +2 -0
  501. package/src/runtime/capability-tokens.ts +10 -10
  502. package/src/runtime/channel-invite-transport.ts +1 -1
  503. package/src/runtime/channel-invite-transports/email.ts +14 -6
  504. package/src/runtime/channel-readiness-service.ts +12 -22
  505. package/src/runtime/chrome-extension-registry.ts +38 -2
  506. package/src/runtime/http-server.ts +395 -10
  507. package/src/runtime/http-types.ts +6 -2
  508. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  509. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  510. package/src/runtime/migrations/migration-transport.ts +1 -0
  511. package/src/runtime/migrations/migration-wizard.ts +1 -0
  512. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  513. package/src/runtime/migrations/vbundle-importer.ts +34 -0
  514. package/src/runtime/pending-interactions.ts +0 -11
  515. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  516. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  517. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  518. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  519. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  520. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  521. package/src/runtime/routes/app-management-routes.ts +12 -18
  522. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  523. package/src/runtime/routes/attachment-routes.ts +216 -17
  524. package/src/runtime/routes/backup-routes.ts +519 -0
  525. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  526. package/src/runtime/routes/btw-routes.ts +8 -6
  527. package/src/runtime/routes/contact-routes.test.ts +298 -0
  528. package/src/runtime/routes/contact-routes.ts +132 -5
  529. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  530. package/src/runtime/routes/conversation-management-routes.ts +115 -0
  531. package/src/runtime/routes/conversation-routes.ts +367 -146
  532. package/src/runtime/routes/filing-routes.ts +93 -0
  533. package/src/runtime/routes/home-feed-routes.ts +334 -0
  534. package/src/runtime/routes/home-state-routes.ts +138 -0
  535. package/src/runtime/routes/host-browser-routes.ts +3 -14
  536. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  537. package/src/runtime/routes/identity-routes.ts +3 -17
  538. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  539. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  540. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  541. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  542. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  543. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  544. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  545. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  546. package/src/runtime/routes/migration-routes.ts +40 -5
  547. package/src/runtime/routes/settings-routes.ts +22 -5
  548. package/src/runtime/routes/skills-routes.ts +76 -7
  549. package/src/runtime/routes/stt-routes.ts +233 -0
  550. package/src/runtime/routes/surface-action-routes.ts +41 -2
  551. package/src/runtime/routes/tts-routes.ts +108 -24
  552. package/src/runtime/routes/usage-routes.ts +30 -2
  553. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  554. package/src/runtime/routes/user-routes.ts +13 -1
  555. package/src/runtime/routes/work-items-routes.ts +8 -1
  556. package/src/runtime/runtime-mode.ts +33 -0
  557. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  558. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  559. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  560. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  561. package/src/runtime/services/analyze-conversation.ts +344 -0
  562. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  563. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  564. package/src/runtime/skill-route-registry.ts +49 -0
  565. package/src/runtime/slack-block-formatting.ts +437 -10
  566. package/src/schedule/scheduler.ts +50 -0
  567. package/src/security/oauth2.ts +26 -4
  568. package/src/security/secure-keys.ts +25 -2
  569. package/src/security/token-manager.ts +8 -0
  570. package/src/sequence/engine.ts +23 -0
  571. package/src/sequence/types.ts +1 -1
  572. package/src/skills/catalog-files.ts +64 -2
  573. package/src/skills/category-inference.ts +122 -0
  574. package/src/skills/clawhub-files.ts +213 -0
  575. package/src/skills/clawhub.ts +84 -23
  576. package/src/skills/skill-file-provider.ts +40 -0
  577. package/src/skills/skillssh-files.ts +395 -0
  578. package/src/skills/skillssh-registry.ts +4 -4
  579. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  580. package/src/stt/__tests__/types.test.ts +89 -0
  581. package/src/stt/daemon-batch-transcriber.ts +195 -0
  582. package/src/stt/stt-stream-session.ts +499 -0
  583. package/src/stt/types.ts +330 -0
  584. package/src/stt/wav-encoder.test.ts +373 -0
  585. package/src/stt/wav-encoder.ts +175 -0
  586. package/src/subagent/manager.ts +38 -14
  587. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  588. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  589. package/src/tools/browser/browser-execution.ts +1163 -23
  590. package/src/tools/browser/browser-manager.ts +45 -0
  591. package/src/tools/browser/browser-mode-constants.ts +12 -0
  592. package/src/tools/browser/browser-mode.ts +92 -0
  593. package/src/tools/browser/browser-status-constants.ts +33 -0
  594. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  595. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  596. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  597. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  598. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
  599. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  600. package/src/tools/browser/cdp-client/errors.ts +15 -0
  601. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  602. package/src/tools/browser/cdp-client/factory.ts +797 -87
  603. package/src/tools/browser/cdp-client/index.ts +16 -2
  604. package/src/tools/browser/cdp-client/types.ts +68 -0
  605. package/src/tools/credentials/vault.ts +35 -6
  606. package/src/tools/network/web-fetch.ts +5 -2
  607. package/src/tools/network/web-search.ts +5 -2
  608. package/src/tools/shared/shell-output.ts +3 -1
  609. package/src/tools/side-effects.ts +2 -0
  610. package/src/tools/skills/sandbox-runner.ts +3 -2
  611. package/src/tools/terminal/safe-env.ts +10 -2
  612. package/src/tools/terminal/shell.ts +15 -4
  613. package/src/tools/tool-manifest.ts +21 -0
  614. package/src/tools/types.ts +17 -0
  615. package/src/tools/ui-surface/definitions.ts +6 -1
  616. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  617. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  618. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  619. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  620. package/src/tts/provider-catalog.ts +201 -0
  621. package/src/tts/provider-registry.ts +73 -0
  622. package/src/tts/providers/deepgram-provider.ts +219 -0
  623. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  624. package/src/tts/providers/fish-audio-provider.ts +183 -0
  625. package/src/tts/providers/index.ts +42 -0
  626. package/src/tts/providers/register-builtins.ts +130 -0
  627. package/src/tts/synthesize-text.ts +110 -0
  628. package/src/tts/tts-config-resolver.ts +78 -0
  629. package/src/tts/types.ts +153 -0
  630. package/src/types/onboarding-context.ts +7 -0
  631. package/src/util/abort-reasons.ts +58 -0
  632. package/src/util/device-id.ts +32 -16
  633. package/src/util/errors.ts +9 -1
  634. package/src/util/platform.ts +54 -10
  635. package/src/util/pricing.ts +66 -3
  636. package/src/util/spawn.ts +1 -1
  637. package/src/util/truncate.ts +4 -2
  638. package/src/util/unicode.ts +201 -0
  639. package/src/version.ts +19 -24
  640. package/src/watcher/engine.ts +23 -0
  641. package/src/watcher/watcher-store.ts +31 -0
  642. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  643. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  644. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  645. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  646. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  647. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  648. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  649. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  650. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  651. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  652. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  653. package/src/workspace/migrations/registry.ts +16 -0
  654. package/src/workspace/top-level-renderer.ts +13 -1
  655. package/src/workspace/turn-commit.ts +31 -0
  656. package/src/__tests__/email-cli.test.ts +0 -297
  657. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  658. package/src/cli/commands/browser-relay.ts +0 -466
  659. package/src/email/guardrails.ts +0 -221
  660. package/src/email/provider.ts +0 -117
  661. package/src/email/providers/agentmail.ts +0 -361
  662. package/src/email/providers/index.ts +0 -65
  663. package/src/email/service.ts +0 -384
  664. package/src/email/types.ts +0 -126
  665. package/src/prompts/templates/USER.md +0 -13
  666. package/src/providers/speech-to-text/types.ts +0 -17
  667. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
@@ -114,6 +114,30 @@ export class MessageQueue {
114
114
  return item;
115
115
  }
116
116
 
117
+ /**
118
+ * Read-only access to a queued message by index without mutating the queue.
119
+ * Returns `undefined` when the index is out of range.
120
+ */
121
+ peek(index: number = 0): QueuedMessage | undefined {
122
+ return this.items[index];
123
+ }
124
+
125
+ /**
126
+ * Pop up to `count` messages FIFO and return them in order.
127
+ * Decrements the byte budget for each popped item using the same
128
+ * accounting as `shift` / `removeByRequestId`, keeping the bookkeeping
129
+ * centralized here rather than at call sites.
130
+ */
131
+ shiftN(count: number): QueuedMessage[] {
132
+ const n = Math.min(Math.max(0, count), this.items.length);
133
+ if (n === 0) return [];
134
+ const removed = this.items.splice(0, n);
135
+ for (const item of removed) {
136
+ this.currentBytes -= estimateItemBytes(item);
137
+ }
138
+ return removed;
139
+ }
140
+
117
141
  clear(): void {
118
142
  this.items = [];
119
143
  this.currentBytes = 0;
@@ -611,7 +611,8 @@ const PKB_SYSTEM_REMINDER =
611
611
  "<system_reminder>" +
612
612
  "\n**CRITICAL:** you MUST read any PKB files that might be relevant to this conversation — " +
613
613
  "INDEX.md is your table of contents. Don't wait to be asked. " +
614
- "Use `remember` OFTEN for EVERY new fact you learn IMMEDIATELY, don't wait for the next turn." +
614
+ "Use `remember` OFTEN for EVERY new fact you learn IMMEDIATELY, don't wait for the next turn. " +
615
+ "Corrections to things you had wrong are the highest-priority remembers — never skip them." +
615
616
  "\n</system_reminder>";
616
617
 
617
618
  /**
@@ -876,6 +877,12 @@ export interface UnifiedTurnContextOptions {
876
877
  interfaceName?: string;
877
878
  channelName?: string;
878
879
  actorContext?: InboundActorContext | null;
880
+ /**
881
+ * Human-readable duration since the previous user message (e.g. "14h ago",
882
+ * "yesterday", "3d ago"). Only populated when the gap exceeds 12 hours so
883
+ * the model can acknowledge long absences; otherwise omitted.
884
+ */
885
+ timeSinceLastMessage?: string | null;
879
886
  }
880
887
 
881
888
  /**
@@ -908,6 +915,9 @@ export function buildUnifiedTurnContextBlock(
908
915
 
909
916
  const lines: string[] = ["<turn_context>"];
910
917
  lines.push(`current_time: ${options.timestamp}`);
918
+ if (options.timeSinceLastMessage) {
919
+ lines.push(`time_since_last_message: ${options.timeSinceLastMessage}`);
920
+ }
911
921
  if (options.interfaceName) {
912
922
  lines.push(`interface: ${options.interfaceName}`);
913
923
  }
@@ -172,6 +172,42 @@ function resolveCommandsList(context?: SlashContext): string[] {
172
172
  ];
173
173
  }
174
174
 
175
+ /**
176
+ * Pure classifier: returns the kind of slash resolution `resolveSlash` would
177
+ * produce for `content`, without triggering any side effects.
178
+ *
179
+ * Queue-drain lookahead (`buildPassthroughBatch`) uses this to decide whether
180
+ * to include a queued message in a contiguous passthrough batch. `resolveSlash`
181
+ * itself runs side effects (e.g. `/pair` registers a pairing request and
182
+ * writes a QR PNG), so calling it during lookahead and then again in the real
183
+ * drain would execute those side effects twice — the second call sees the
184
+ * first registration and fails with "active pairing already in progress".
185
+ */
186
+ export function classifySlash(
187
+ content: string,
188
+ ): "passthrough" | "compact" | "unknown" {
189
+ const trimmed = content.trim();
190
+ if (
191
+ trimmed === "/model" ||
192
+ (trimmed.startsWith("/model ") && trimmed !== "/models")
193
+ ) {
194
+ return "unknown";
195
+ }
196
+ const shortcutMatch = trimmed.match(/^\/([a-z0-9-]+)(\s|$)/i);
197
+ if (
198
+ shortcutMatch &&
199
+ DEPRECATED_MODEL_SHORTCUTS.has(shortcutMatch[1].toLowerCase())
200
+ ) {
201
+ return "unknown";
202
+ }
203
+ if (trimmed === "/models") return "unknown";
204
+ if (trimmed === "/pair") return "unknown";
205
+ if (trimmed === "/compact") return "compact";
206
+ if (trimmed === "/status") return "unknown";
207
+ if (trimmed === "/commands") return "unknown";
208
+ return "passthrough";
209
+ }
210
+
175
211
  /**
176
212
  * Resolve built-in slash commands (/models, /status, /commands, /compact, /pair).
177
213
  * Returns `unknown` with a deterministic message, `compact` for forced compaction,
@@ -17,6 +17,8 @@ import type { ToolExecutionResult } from "../tools/types.js";
17
17
  import { getLogger } from "../util/logger.js";
18
18
  import { isPlainObject } from "../util/object.js";
19
19
  import { buildConversationErrorMessage } from "./conversation-error.js";
20
+ import { launchConversation } from "./conversation-launch.js";
21
+ import type { TrustContext } from "./conversation-runtime-assembly.js";
20
22
  import type {
21
23
  CardSurfaceData,
22
24
  DynamicPageSurfaceData,
@@ -234,6 +236,10 @@ function normalizeTaskProgressCardPatch(
234
236
  */
235
237
  export interface SurfaceConversationContext {
236
238
  readonly conversationId: string;
239
+ /** Assistant id (if known) — used when publishing launch-triggered events. */
240
+ readonly assistantId?: string;
241
+ /** Inherited to spawned conversations in the `launch_conversation` action path. */
242
+ readonly trustContext?: TrustContext;
237
243
  readonly channelCapabilities?: {
238
244
  channel: string;
239
245
  supportsDynamicUi: boolean;
@@ -278,6 +284,7 @@ export interface SurfaceConversationContext {
278
284
  data?: Record<string, unknown>;
279
285
  }>;
280
286
  display?: string;
287
+ persistent?: boolean;
281
288
  }>;
282
289
  /** Optional proxy for delegating computer-use actions to a connected desktop client. */
283
290
  hostCuProxy?: import("./host-cu-proxy.js").HostCuProxy;
@@ -645,12 +652,75 @@ export function buildDeselectionDescription(
645
652
  return "";
646
653
  }
647
654
 
648
- export function handleSurfaceAction(
655
+ export type SurfaceActionResult =
656
+ | { accepted: true; conversationId: string }
657
+ | { accepted: false; error: string }
658
+ | void;
659
+
660
+ export async function handleSurfaceAction(
649
661
  ctx: SurfaceConversationContext,
650
662
  surfaceId: string,
651
663
  actionId: string,
652
664
  data?: Record<string, unknown>,
653
- ): void {
665
+ ): Promise<SurfaceActionResult> {
666
+ // `launch_conversation` actions spawn a fresh conversation inline instead
667
+ // of round-tripping through the LLM with a `[User action on card surface:
668
+ // ...]` chat message. This dispatch must run BEFORE the pending-vs-not
669
+ // branching below: `ui_show` unconditionally calls
670
+ // `pendingSurfaceActions.set(...)` for any interactive card (regardless of
671
+ // the `persistent` flag), so on the very first click of a freshly-rendered
672
+ // launcher card `pending` is already set. Without this hoist the launch
673
+ // branch would fall through into the pending path and the LLM round-trip
674
+ // would happen on every click.
675
+ if (
676
+ data &&
677
+ typeof data === "object" &&
678
+ (data as Record<string, unknown>)._action === "launch_conversation"
679
+ ) {
680
+ const payload = data as Record<string, unknown>;
681
+ const title = typeof payload.title === "string" ? payload.title : "";
682
+ const seedPrompt =
683
+ typeof payload.seedPrompt === "string" ? payload.seedPrompt : "";
684
+ const anchorMessageId =
685
+ typeof payload.anchorMessageId === "string"
686
+ ? payload.anchorMessageId
687
+ : undefined;
688
+ if (!title || !seedPrompt) {
689
+ return { accepted: false, error: "missing_title_or_seedPrompt" };
690
+ }
691
+ // Launch actions don't consume the surface — persistent launcher cards
692
+ // keep accepting clicks afterward. Drop the pending entry (if any) so
693
+ // sibling button presses on the same card aren't blocked behind a stale
694
+ // expectation that this surface still owes an answer to the LLM.
695
+ ctx.pendingSurfaceActions.delete(surfaceId);
696
+ // `ctx` is the origin Conversation — inherit its trust context so the
697
+ // spawned conversation keeps guardian / trust-class state.
698
+ //
699
+ // `launchConversation` is the sole emitter of `open_conversation` for
700
+ // this path. We pass `focus: false` so the client registers a sidebar
701
+ // entry for the spawned conversation without switching focus away from
702
+ // the origin — critical for fan-out UX where one click launches
703
+ // multiple conversations.
704
+ //
705
+ // The helper also kicks off the seed turn fire-and-forget, so this
706
+ // `await` resolves as soon as the conversation is created + titled +
707
+ // published to the event hub. The HTTP POST /v1/surface-actions
708
+ // response returns promptly — the seed turn runs in the background.
709
+ const originTrustContext = ctx.trustContext;
710
+ const { conversationId } = await launchConversation({
711
+ title,
712
+ seedPrompt,
713
+ focus: false,
714
+ ...(anchorMessageId ? { anchorMessageId } : {}),
715
+ ...(originTrustContext ? { originTrustContext } : {}),
716
+ });
717
+ log.info(
718
+ { originConversationId: ctx.conversationId, conversationId, surfaceId },
719
+ "launch_conversation dispatched inline from surface action",
720
+ );
721
+ return { accepted: true, conversationId };
722
+ }
723
+
654
724
  const pending = ctx.pendingSurfaceActions.get(surfaceId);
655
725
 
656
726
  // When surfaces are restored from history (e.g. onboarding cards), there is
@@ -1202,7 +1272,13 @@ export function buildCompletionSummary(
1202
1272
  : undefined;
1203
1273
  return cancelLabel ? `User chose: "${cancelLabel}"` : "Cancelled";
1204
1274
  }
1205
- if (actionId === "confirm") return "Confirmed";
1275
+ if (actionId === "confirm") {
1276
+ const confirmLabel =
1277
+ typeof surfaceData?.confirmLabel === "string"
1278
+ ? surfaceData.confirmLabel
1279
+ : undefined;
1280
+ return confirmLabel ? `User chose: "${confirmLabel}"` : "Confirmed";
1281
+ }
1206
1282
  // Preserve the actual action ID so the LLM knows the user's exact choice
1207
1283
  // (e.g. "deny", "no", "reject") rather than misreporting it as confirmed.
1208
1284
  return `User selected: ${actionId}`;
@@ -1249,7 +1325,13 @@ export function buildUserFacingLabel(
1249
1325
  : undefined;
1250
1326
  return cancelLabel ?? "Cancelled";
1251
1327
  }
1252
- if (actionId === "confirm") return "Confirmed";
1328
+ if (actionId === "confirm") {
1329
+ const confirmLabel =
1330
+ typeof surfaceData?.confirmLabel === "string"
1331
+ ? surfaceData.confirmLabel
1332
+ : undefined;
1333
+ return confirmLabel ?? "Confirmed";
1334
+ }
1253
1335
  return `Selected: ${actionId}`;
1254
1336
  }
1255
1337
  if (surfaceType === "form") return "Submitted";
@@ -1378,6 +1460,11 @@ export async function surfaceProxyResolver(
1378
1460
  }
1379
1461
 
1380
1462
  const display = (input.display as string) === "panel" ? "panel" : "inline";
1463
+ // `persistent: true` keeps the card visible through action clicks (only
1464
+ // marks the clicked action as spent). Forward the flag so
1465
+ // `SurfaceManager.showSurface` on the client sees it — without this the
1466
+ // field is dropped and every card dismisses on first click.
1467
+ const persistent = input.persistent === true ? true : undefined;
1381
1468
 
1382
1469
  const mappedActions = actions?.map((a) => ({
1383
1470
  id: a.id,
@@ -1406,6 +1493,7 @@ export async function surfaceProxyResolver(
1406
1493
  dataKeys: Object.keys(data),
1407
1494
  actionCount: mappedActions?.length ?? 0,
1408
1495
  display,
1496
+ persistent: persistent ?? false,
1409
1497
  conversationId: ctx.conversationId,
1410
1498
  },
1411
1499
  "Sending ui_surface_show to client",
@@ -1420,6 +1508,7 @@ export async function surfaceProxyResolver(
1420
1508
  data,
1421
1509
  actions: mappedActions,
1422
1510
  display,
1511
+ ...(persistent ? { persistent: true } : {}),
1423
1512
  } as unknown as UiSurfaceShow);
1424
1513
 
1425
1514
  // Track surface for persistence with the message
@@ -1430,6 +1519,7 @@ export async function surfaceProxyResolver(
1430
1519
  data,
1431
1520
  actions: mappedActions,
1432
1521
  display,
1522
+ ...(persistent ? { persistent: true } : {}),
1433
1523
  });
1434
1524
 
1435
1525
  if (awaitAction) {
@@ -30,6 +30,7 @@ import { isAllowDecision } from "../permissions/types.js";
30
30
  import { isPermissionControlsV2Enabled } from "../permissions/v2-consent-policy.js";
31
31
  import type { Message, ToolDefinition } from "../providers/types.js";
32
32
  import type { TrustClass } from "../runtime/actor-trust-resolver.js";
33
+ import { getTaskRunRules } from "../tasks/ephemeral-permissions.js";
33
34
  import { coreAppProxyTools } from "../tools/apps/definitions.js";
34
35
  import { registerConversationSender } from "../tools/browser/browser-screencast.js";
35
36
  import type { ToolExecutor } from "../tools/executor.js";
@@ -118,6 +119,8 @@ export interface ToolSetupContext extends SurfaceConversationContext {
118
119
  hostFileProxy?: import("./host-file-proxy.js").HostFileProxy;
119
120
  /** CES RPC client for credential execution operations. Injected when CES tools are enabled and the CES process is available. */
120
121
  cesClient?: CesClient;
122
+ /** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */
123
+ readonly transportInterface?: InterfaceId;
121
124
  }
122
125
 
123
126
  // ── buildToolDefinitions ─────────────────────────────────────────────
@@ -170,6 +173,15 @@ export function createToolExecutor(
170
173
  markDoordashStepInProgress(ctx, input);
171
174
  }
172
175
 
176
+ // Unwrap skill_execute dispatch so downstream context (notably
177
+ // batchAuthorizedByTask) is keyed on the tool that will actually run.
178
+ // Task rules in required_tools contain underlying tool names (e.g.
179
+ // "gmail_archive"), never the outer "skill_execute" dispatcher.
180
+ const effectiveToolName =
181
+ name === "skill_execute" && typeof input.tool === "string" && input.tool
182
+ ? input.tool
183
+ : name;
184
+
173
185
  // Build the context object shared by both the skill_execute interception
174
186
  // path and the regular executor path.
175
187
  const toolContext: ToolContext = {
@@ -183,6 +195,17 @@ export function createToolExecutor(
183
195
  callSessionId: ctx.callSessionId,
184
196
  triggeredBySurfaceAction:
185
197
  ctx.surfaceActionRequestIds?.has(ctx.currentRequestId ?? "") ?? false,
198
+ // A task without required_tools entries (e.g. ad-hoc tasks created with
199
+ // omitted/empty required_tools, or legacy rows where it was never
200
+ // populated) correctly gets no batch authorization — that's the
201
+ // intended stricter contract this check enforces, not a regression to
202
+ // paper over. Batch tools gate themselves via this flag; callers that
203
+ // never declared the tool shouldn't get blanket authorization.
204
+ batchAuthorizedByTask:
205
+ ctx.taskRunId != null &&
206
+ getTaskRunRules(ctx.taskRunId).some(
207
+ (r) => r.tool === effectiveToolName,
208
+ ),
186
209
  requesterExternalUserId: ctx.trustContext?.requesterExternalUserId,
187
210
  requesterChatId: ctx.trustContext?.requesterChatId,
188
211
  requesterIdentifier: ctx.trustContext?.requesterIdentifier,
@@ -202,6 +225,7 @@ export function createToolExecutor(
202
225
  hostFileProxy: ctx.hostFileProxy,
203
226
  isPlatformHosted: getIsPlatform(),
204
227
  cesClient: ctx.cesClient,
228
+ transportInterface: ctx.transportInterface,
205
229
  onToolLifecycleEvent: handleToolLifecycleEvent,
206
230
  sendToClient: (msg) => {
207
231
  // Tool context's sendToClient uses a loose { type: string; [key: string]: unknown }
@@ -216,6 +240,7 @@ export function createToolExecutor(
216
240
  data: s.data,
217
241
  actions: s.actions,
218
242
  display: s.display,
243
+ ...(s.persistent ? { persistent: true } : {}),
219
244
  });
220
245
  }
221
246
  },
@@ -8,7 +8,10 @@ import type {
8
8
  PricingUsage,
9
9
  } from "../usage/types.js";
10
10
  import { getLogger } from "../util/logger.js";
11
- import { resolvePricingForUsageWithOverrides } from "../util/pricing.js";
11
+ import {
12
+ resolvePricingForUsageWithOverrides,
13
+ usesAnthropicPricingRules,
14
+ } from "../util/pricing.js";
12
15
  import type { ServerMessage, UsageStats } from "./message-protocol.js";
13
16
 
14
17
  const log = getLogger("conversation-usage");
@@ -142,16 +145,16 @@ export function recordUsage(
142
145
  0,
143
146
  );
144
147
 
145
- const isAnthropic = ctx.providerName === "anthropic";
148
+ const useAnthropicRules = usesAnthropicPricingRules(ctx.providerName, model);
146
149
  const pricingUsage: PricingUsage = {
147
150
  directInputTokens,
148
151
  outputTokens,
149
152
  cacheCreationInputTokens: normalizedCacheCreationInputTokens,
150
153
  cacheReadInputTokens: normalizedCacheReadInputTokens,
151
- anthropicCacheCreation: isAnthropic
154
+ anthropicCacheCreation: useAnthropicRules
152
155
  ? extractAnthropicCacheCreation(rawResponse)
153
156
  : null,
154
- speed: isAnthropic ? extractAnthropicSpeed(rawResponse) : null,
157
+ speed: useAnthropicRules ? extractAnthropicSpeed(rawResponse) : null,
155
158
  };
156
159
  const pricing = resolveStructuredPricing(
157
160
  ctx.providerName,
@@ -28,6 +28,7 @@ import type { Speed } from "../config/schemas/inference.js";
28
28
  import {
29
29
  ContextWindowManager,
30
30
  type ContextWindowResult,
31
+ getSummaryFromContextMessage,
31
32
  } from "../context/window-manager.js";
32
33
  import type { CesClient } from "../credential-execution/client.js";
33
34
  import { EventBus } from "../events/bus.js";
@@ -43,6 +44,7 @@ import {
43
44
  } from "../events/tool-profiling-listener.js";
44
45
  import { registerToolTraceListener } from "../events/tool-trace-listener.js";
45
46
  import { getHookManager } from "../hooks/manager.js";
47
+ import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
46
48
  import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
47
49
  import {
48
50
  updateConversationContextWindow,
@@ -60,13 +62,16 @@ import {
60
62
  } from "../permissions/v2-consent-policy.js";
61
63
  import { resolvePersonaContext } from "../prompts/persona-resolver.js";
62
64
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
63
- import type { Message } from "../providers/types.js";
65
+ import { resolveModelIntent } from "../providers/model-intents.js";
66
+ import type { Message, ModelIntent } from "../providers/types.js";
64
67
  import type { Provider } from "../providers/types.js";
65
68
  import type { TrustClass } from "../runtime/actor-trust-resolver.js";
66
69
  import type { AuthContext } from "../runtime/auth/types.js";
67
70
  import * as approvalOverrides from "../runtime/conversation-approval-overrides.js";
68
71
  import * as pendingInteractions from "../runtime/pending-interactions.js";
69
72
  import { ToolExecutor } from "../tools/executor.js";
73
+ import type { OnboardingContext } from "../types/onboarding-context.js";
74
+ import type { AbortReason } from "../util/abort-reasons.js";
70
75
  import { getLogger } from "../util/logger.js";
71
76
  import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
72
77
  import { runAgentLoopImpl } from "./conversation-agent-loop.js";
@@ -104,6 +109,7 @@ import {
104
109
  createSurfaceMutex,
105
110
  handleSurfaceAction as handleSurfaceActionImpl,
106
111
  handleSurfaceUndo as handleSurfaceUndoImpl,
112
+ type SurfaceActionResult,
107
113
  } from "./conversation-surfaces.js";
108
114
  import type { ToolSetupContext } from "./conversation-tool-setup.js";
109
115
  import {
@@ -196,15 +202,15 @@ export class Conversation {
196
202
  /** @internal */ hostFileProxy?: HostFileProxy;
197
203
  /**
198
204
  * Optional override sender used by `restoreBrowserProxyAvailability` so
199
- * non-SSE transports (e.g. chrome-extension, whose host_browser_request
200
- * frames flow through the ChromeExtensionRegistry WebSocket rather than
201
- * the SSE hub) can preserve their registry-routed sender across drain
202
- * queue restores. When set, `restoreBrowserProxyAvailability()` uses this
205
+ * registry-routed transports can preserve their sender across drain queue
206
+ * restores. When set, `restoreBrowserProxyAvailability()` uses this
203
207
  * function instead of `sendToClient` so the drain-queue path doesn't
204
- * clobber the chrome-extension sender with the SSE hub emitter.
208
+ * clobber the registry-routed sender with the SSE hub emitter.
205
209
  *
206
- * Populated by the POST /messages handler for chrome-extension turns and
207
- * cleared when an unrelated interface takes over (see `updateClient`).
210
+ * Populated by the POST /messages handler when the guardian has an active
211
+ * extension connection in the `ChromeExtensionRegistry`, regardless of
212
+ * interface (chrome-extension, macOS, etc.). Cleared when a turn without
213
+ * an active extension connection takes over.
208
214
  */
209
215
  /** @internal */ hostBrowserSenderOverride?: (msg: ServerMessage) => void;
210
216
  /** @internal */ cesClient?: CesClient;
@@ -268,6 +274,7 @@ export class Conversation {
268
274
  data: SurfaceData;
269
275
  actions?: Array<{ id: string; label: string; style?: string }>;
270
276
  display?: string;
277
+ persistent?: boolean;
271
278
  }> = [];
272
279
  /** @internal */ workspaceTopLevelContext: string | null = null;
273
280
  /** @internal */ workspaceTopLevelDirty = true;
@@ -297,6 +304,14 @@ export class Conversation {
297
304
  /** @internal */ turnCount = 0;
298
305
  public lastAssistantAttachments: AssistantAttachmentDraft[] = [];
299
306
  public lastAttachmentWarnings: string[] = [];
307
+ /**
308
+ * Pre-chat onboarding context provided by the native client.
309
+ * In-memory only — not persisted to the DB. Only relevant for the first
310
+ * turn of a brand-new conversation so the system prompt can personalize
311
+ * the opener and skip redundant discovery.
312
+ * @internal
313
+ */
314
+ private onboardingContext?: OnboardingContext;
300
315
  /** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
301
316
  /** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
302
317
  null;
@@ -323,6 +338,8 @@ export class Conversation {
323
338
  sharedCesClient?: CesClient,
324
339
  speedOverride?: Speed,
325
340
  cacheTtl?: "5m" | "1h",
341
+ modelIntent?: ModelIntent,
342
+ modelOverride?: string,
326
343
  ) {
327
344
  this.conversationId = conversationId;
328
345
  this.systemPrompt = systemPrompt;
@@ -424,10 +441,18 @@ export class Conversation {
424
441
  const hasSystemPromptOverride = systemPrompt !== buildSystemPrompt();
425
442
  this.hasSystemPromptOverride = hasSystemPromptOverride;
426
443
 
444
+ // If an explicit modelOverride is supplied, use it verbatim. Otherwise,
445
+ // if modelIntent is set, resolve it against the active provider's
446
+ // intent → model mapping. The AgentLoop passes the resulting string
447
+ // through to `providerConfig.model` on every turn.
448
+ const resolvedModel: string | undefined =
449
+ modelOverride ??
450
+ (modelIntent ? resolveModelIntent(provider.name, modelIntent) : undefined);
451
+
427
452
  const resolveSystemPromptCallback = (
428
453
  _history: import("../providers/types.js").Message[],
429
454
  ): ResolvedSystemPrompt => {
430
- const resolved = {
455
+ const resolved: ResolvedSystemPrompt = {
431
456
  systemPrompt: this.hasSystemPromptOverride
432
457
  ? systemPrompt
433
458
  : (() => {
@@ -440,10 +465,14 @@ export class Conversation {
440
465
  userPersona: persona.userPersona,
441
466
  channelPersona: persona.channelPersona,
442
467
  userSlug: persona.userSlug,
468
+ onboardingContext: this.getOnboardingContext(),
443
469
  });
444
470
  })(),
445
471
  maxTokens: configuredMaxTokens,
446
472
  };
473
+ if (resolvedModel !== undefined) {
474
+ resolved.model = resolvedModel;
475
+ }
447
476
  return resolved;
448
477
  };
449
478
 
@@ -481,6 +510,16 @@ export class Conversation {
481
510
  });
482
511
  }
483
512
 
513
+ // ── Onboarding context ───────────────────────────────────────────
514
+
515
+ setOnboardingContext(ctx: OnboardingContext): void {
516
+ this.onboardingContext = ctx;
517
+ }
518
+
519
+ getOnboardingContext(): OnboardingContext | undefined {
520
+ return this.onboardingContext;
521
+ }
522
+
484
523
  // ── Lifecycle ────────────────────────────────────────────────────
485
524
 
486
525
  async loadFromDb(): Promise<void> {
@@ -574,21 +613,31 @@ export class Conversation {
574
613
  this.hostFileProxy?.updateSender(this.sendToClient, false);
575
614
  }
576
615
 
577
- /** Restore host proxy availability based on whether a real client is connected. */
578
- restoreProxyAvailability(): void {
616
+ /**
617
+ * Restore host proxy availability based on whether a real client is connected.
618
+ * When `skipBrowser` is true, the browser proxy is left untouched — use this
619
+ * when `restoreBrowserProxyAvailability()` will handle the browser proxy
620
+ * separately with the correct registry-routed sender.
621
+ */
622
+ restoreProxyAvailability(options?: { skipBrowser?: boolean }): void {
579
623
  if (!this.hasNoClient) {
580
624
  this.hostBashProxy?.updateSender(this.sendToClient, true);
581
- this.hostBrowserProxy?.updateSender(this.sendToClient, true);
625
+ if (!options?.skipBrowser) {
626
+ this.hostBrowserProxy?.updateSender(this.sendToClient, true);
627
+ }
582
628
  this.hostCuProxy?.updateSender(this.sendToClient, true);
583
629
  this.hostFileProxy?.updateSender(this.sendToClient, true);
584
630
  }
585
631
  }
586
632
 
587
633
  /**
588
- * Restore host browser proxy availability only. Used for non-desktop
589
- * interfaces (e.g. chrome-extension) that support host_browser but not
590
- * the full desktop proxy set, so calling restoreProxyAvailability() would
591
- * incorrectly re-enable bash/file/CU proxies that should stay disabled.
634
+ * Restore host browser proxy availability only. Used for interfaces that
635
+ * support host_browser but not the full desktop proxy set, so calling
636
+ * restoreProxyAvailability() would incorrectly re-enable bash/file/CU
637
+ * proxies that should stay disabled. Applicable to chrome-extension turns
638
+ * (which only support host_browser) and macOS turns with an active
639
+ * extension connection (which route browser tools through the extension
640
+ * registry instead of cdp-inspect/local).
592
641
  *
593
642
  * Unlike `restoreProxyAvailability()`, this helper does NOT gate on
594
643
  * `hasNoClient`. The chrome-extension interface is non-interactive (so
@@ -599,16 +648,16 @@ export class Conversation {
599
648
  * incorrectly enable host_bash/host_file/host_cu tool gating downstream.
600
649
  *
601
650
  * When `hostBrowserSenderOverride` is set, that function is used as the
602
- * sender instead of `sendToClient`. This is required for the
603
- * chrome-extension interface whose host_browser frames route through the
604
- * ChromeExtensionRegistry WebSocket rather than the SSE hub: if the
605
- * queue-drain path called this helper with `sendToClient`, the
606
- * registry-routed sender established at turn-start would be clobbered by
607
- * the SSE hub emitter and host_browser_request frames would stop
608
- * reaching the extension.
651
+ * sender instead of `sendToClient`. This is required for any interface
652
+ * whose host_browser frames route through the ChromeExtensionRegistry
653
+ * WebSocket rather than the SSE hub: if the queue-drain path called this
654
+ * helper with `sendToClient`, the registry-routed sender established at
655
+ * turn-start would be clobbered by the SSE hub emitter and
656
+ * host_browser_request frames would stop reaching the extension.
609
657
  *
610
658
  * Callers must only invoke this when they know the current interface
611
- * supports host_browser (see `supportsHostProxy(id, "host_browser")`).
659
+ * supports host_browser (see `supportsHostProxy(id, "host_browser")`)
660
+ * or has an active extension connection with a registry-routed sender.
612
661
  */
613
662
  restoreBrowserProxyAvailability(): void {
614
663
  const sender = this.hostBrowserSenderOverride ?? this.sendToClient;
@@ -642,6 +691,8 @@ export class Conversation {
642
691
  }
643
692
  this.messages = [...messages];
644
693
  this.contextWindowManager.nonPersistedPrefixCount = messages.length;
694
+ this.contextWindowManager.summaryIsInjected =
695
+ getSummaryFromContextMessage(messages[0]) != null;
645
696
  }
646
697
 
647
698
  /**
@@ -667,8 +718,8 @@ export class Conversation {
667
718
  return this.stale;
668
719
  }
669
720
 
670
- abort(): void {
671
- abortConversation(this);
721
+ abort(reason?: AbortReason): void {
722
+ abortConversation(this, reason);
672
723
  }
673
724
 
674
725
  dispose(): void {
@@ -1130,6 +1181,13 @@ export class Conversation {
1130
1181
  result.summaryText,
1131
1182
  this.contextCompactedMessageCount,
1132
1183
  );
1184
+ // Fire auto-analysis on compaction so the reflective agent can
1185
+ // crystallize anything worth remembering before the context window
1186
+ // narrows further.
1187
+ enqueueAutoAnalysisOnCompaction(
1188
+ this.conversationId,
1189
+ this.trustContext?.trustClass,
1190
+ );
1133
1191
  }
1134
1192
  return result;
1135
1193
  }
@@ -1334,8 +1392,8 @@ export class Conversation {
1334
1392
  surfaceId: string,
1335
1393
  actionId: string,
1336
1394
  data?: Record<string, unknown>,
1337
- ): void {
1338
- handleSurfaceActionImpl(this, surfaceId, actionId, data);
1395
+ ): Promise<SurfaceActionResult> {
1396
+ return handleSurfaceActionImpl(this, surfaceId, actionId, data);
1339
1397
  }
1340
1398
 
1341
1399
  handleSurfaceUndo(surfaceId: string): void {