@vellumai/assistant 0.6.2 → 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 (895) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +41 -49
  4. package/bunfig.toml +3 -0
  5. package/docs/architecture/memory.md +1 -1
  6. package/docs/backup-troubleshooting.md +52 -0
  7. package/docs/browser-use-architecture-phase2.md +174 -0
  8. package/docs/stt-provider-onboarding.md +120 -0
  9. package/knip.json +12 -2
  10. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  11. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  12. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  13. package/openapi.yaml +1111 -86
  14. package/package.json +40 -42
  15. package/scripts/generate-openapi.ts +0 -2
  16. package/scripts/test.sh +73 -18
  17. package/src/__tests__/acp-session.test.ts +43 -0
  18. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  19. package/src/__tests__/agent-loop.test.ts +123 -0
  20. package/src/__tests__/anthropic-provider.test.ts +263 -10
  21. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  22. package/src/__tests__/app-executors.test.ts +1 -0
  23. package/src/__tests__/app-source-watcher.test.ts +37 -11
  24. package/src/__tests__/approval-routes-http.test.ts +178 -1
  25. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  26. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  27. package/src/__tests__/browser-fill-credential.test.ts +240 -94
  28. package/src/__tests__/browser-manager.test.ts +40 -27
  29. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  30. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  31. package/src/__tests__/btw-routes.test.ts +7 -0
  32. package/src/__tests__/call-controller.test.ts +581 -20
  33. package/src/__tests__/catalog-files.test.ts +1000 -0
  34. package/src/__tests__/channel-approvals.test.ts +53 -0
  35. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  36. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  37. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  38. package/src/__tests__/checker.test.ts +157 -10
  39. package/src/__tests__/clawhub-files.test.ts +347 -0
  40. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  41. package/src/__tests__/config-analysis.test.ts +100 -0
  42. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  43. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  44. package/src/__tests__/config-schema.test.ts +1248 -224
  45. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  46. package/src/__tests__/config-watcher.test.ts +43 -8
  47. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  48. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  49. package/src/__tests__/contacts-write.test.ts +197 -0
  50. package/src/__tests__/context-overflow-approval.test.ts +16 -1
  51. package/src/__tests__/context-window-manager.test.ts +88 -0
  52. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  54. package/src/__tests__/conversation-agent-loop.test.ts +99 -3
  55. package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
  56. package/src/__tests__/conversation-attachments.test.ts +80 -4
  57. package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
  58. package/src/__tests__/conversation-error.test.ts +70 -0
  59. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  60. package/src/__tests__/conversation-history-web-search.test.ts +12 -4
  61. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  62. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  63. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  64. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  65. package/src/__tests__/conversation-list-source.test.ts +145 -0
  66. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  67. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  68. package/src/__tests__/conversation-queue.test.ts +946 -62
  69. package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  72. package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
  73. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  74. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  75. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  76. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  77. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  78. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  79. package/src/__tests__/conversation-store.test.ts +195 -0
  80. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  81. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  82. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  83. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  84. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
  85. package/src/__tests__/credential-health-service.test.ts +352 -0
  86. package/src/__tests__/credential-security-invariants.test.ts +6 -3
  87. package/src/__tests__/credential-vault-unit.test.ts +383 -7
  88. package/src/__tests__/credential-vault.test.ts +152 -13
  89. package/src/__tests__/credentials-cli.test.ts +42 -18
  90. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  91. package/src/__tests__/date-context.test.ts +4 -4
  92. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  93. package/src/__tests__/device-id.test.ts +112 -0
  94. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  95. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  96. package/src/__tests__/email-html-renderer.test.ts +71 -0
  97. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  98. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  99. package/src/__tests__/emit-event-signal.test.ts +71 -0
  100. package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
  101. package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
  102. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  103. package/src/__tests__/gateway-only-guard.test.ts +2 -0
  104. package/src/__tests__/gemini-provider.test.ts +66 -2
  105. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  106. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  107. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  108. package/src/__tests__/gmail-preferences.test.ts +117 -0
  109. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  110. package/src/__tests__/headless-browser-interactions.test.ts +738 -359
  111. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  112. package/src/__tests__/headless-browser-navigate.test.ts +528 -49
  113. package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
  114. package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
  115. package/src/__tests__/heartbeat-service.test.ts +70 -17
  116. package/src/__tests__/home-state-routes.test.ts +162 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +145 -1
  118. package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
  119. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  120. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  121. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  122. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  123. package/src/__tests__/host-browser-routes.test.ts +198 -0
  124. package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
  125. package/src/__tests__/host-cu-proxy.test.ts +166 -1
  126. package/src/__tests__/host-file-proxy.test.ts +185 -1
  127. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  128. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  129. package/src/__tests__/host-shell-tool.test.ts +1 -11
  130. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  131. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  132. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  133. package/src/__tests__/integration-status.test.ts +6 -7
  134. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  135. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  136. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  137. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  138. package/src/__tests__/llm-usage-store.test.ts +363 -0
  139. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  140. package/src/__tests__/mcp-health-check.test.ts +10 -3
  141. package/src/__tests__/media-stream-output.test.ts +555 -0
  142. package/src/__tests__/media-stream-parser.test.ts +374 -0
  143. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  144. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  145. package/src/__tests__/media-turn-detector.test.ts +440 -0
  146. package/src/__tests__/message-queue.test.ts +125 -0
  147. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  148. package/src/__tests__/migration-export-http.test.ts +67 -8
  149. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  150. package/src/__tests__/migration-import-commit-http.test.ts +109 -7
  151. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  152. package/src/__tests__/migration-validate-http.test.ts +3 -3
  153. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  154. package/src/__tests__/model-intents.test.ts +2 -2
  155. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  156. package/src/__tests__/oauth-apps-routes.test.ts +18 -12
  157. package/src/__tests__/oauth-cli.test.ts +709 -60
  158. package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  160. package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
  161. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  162. package/src/__tests__/oauth-providers-routes.test.ts +52 -14
  163. package/src/__tests__/oauth-store.test.ts +1465 -176
  164. package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
  165. package/src/__tests__/onboarding-template-contract.test.ts +81 -70
  166. package/src/__tests__/openai-provider.test.ts +178 -2
  167. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  168. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  169. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  170. package/src/__tests__/outlook-categories.test.ts +1 -1
  171. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  172. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  173. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  174. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  175. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  176. package/src/__tests__/outlook-trash.test.ts +1 -1
  177. package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
  178. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  179. package/src/__tests__/permission-mode.test.ts +28 -56
  180. package/src/__tests__/persona-resolver.test.ts +251 -0
  181. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  182. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  183. package/src/__tests__/platform.test.ts +92 -1
  184. package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
  185. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  186. package/src/__tests__/pricing.test.ts +174 -0
  187. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  188. package/src/__tests__/qdrant-manager.test.ts +29 -8
  189. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  190. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  191. package/src/__tests__/relay-server.test.ts +423 -5
  192. package/src/__tests__/require-fresh-approval.test.ts +40 -1
  193. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  194. package/src/__tests__/schedule-routes.test.ts +162 -0
  195. package/src/__tests__/search-skills-unified.test.ts +118 -0
  196. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  197. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  198. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  199. package/src/__tests__/secure-keys.test.ts +107 -0
  200. package/src/__tests__/send-endpoint-busy.test.ts +8 -1
  201. package/src/__tests__/sequence-store.test.ts +1 -1
  202. package/src/__tests__/server-history-render.test.ts +49 -0
  203. package/src/__tests__/set-permission-mode.test.ts +13 -250
  204. package/src/__tests__/settings-routes.test.ts +201 -0
  205. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  206. package/src/__tests__/skills-file-content-endpoint.test.ts +801 -0
  207. package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
  208. package/src/__tests__/skills.test.ts +5 -2
  209. package/src/__tests__/skillssh-files.test.ts +446 -0
  210. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  211. package/src/__tests__/slack-channel-config.test.ts +576 -16
  212. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  213. package/src/__tests__/stt-stream-session.test.ts +535 -0
  214. package/src/__tests__/subagent-detail.test.ts +44 -2
  215. package/src/__tests__/subagent-disposal.test.ts +1 -0
  216. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  217. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  218. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  219. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  220. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  221. package/src/__tests__/subagent-tools.test.ts +1 -0
  222. package/src/__tests__/subagent-types.test.ts +1 -0
  223. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  224. package/src/__tests__/system-prompt.test.ts +184 -27
  225. package/src/__tests__/task-scheduler.test.ts +32 -6
  226. package/src/__tests__/telegram-config.test.ts +10 -13
  227. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  228. package/src/__tests__/terminal-tools.test.ts +25 -5
  229. package/src/__tests__/test-preload.ts +18 -0
  230. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  231. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  232. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  233. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  234. package/src/__tests__/tool-executor.test.ts +33 -24
  235. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  236. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  237. package/src/__tests__/top-level-renderer.test.ts +73 -1
  238. package/src/__tests__/transport-hints-queue.test.ts +14 -29
  239. package/src/__tests__/trust-store.test.ts +7 -1
  240. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  241. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  242. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  243. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  244. package/src/__tests__/twilio-routes.test.ts +376 -0
  245. package/src/__tests__/unicode.test.ts +293 -0
  246. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  247. package/src/__tests__/update-bulletin.test.ts +206 -5
  248. package/src/__tests__/usage-routes.test.ts +25 -4
  249. package/src/__tests__/user-reference.test.ts +46 -61
  250. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  251. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  252. package/src/__tests__/voice-config-update.test.ts +403 -0
  253. package/src/__tests__/voice-quality.test.ts +434 -19
  254. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  255. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  256. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  257. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  258. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  259. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  260. package/src/__tests__/workspace-policy.test.ts +2 -0
  261. package/src/acp/client-handler.ts +30 -4
  262. package/src/agent/image-optimize.ts +24 -12
  263. package/src/agent/loop.ts +55 -9
  264. package/src/approvals/guardian-request-resolvers.ts +21 -15
  265. package/src/backup/__tests__/backup-key.test.ts +152 -0
  266. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  267. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  268. package/src/backup/__tests__/local-writer.test.ts +218 -0
  269. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  270. package/src/backup/__tests__/paths.test.ts +300 -0
  271. package/src/backup/__tests__/restore.test.ts +498 -0
  272. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  273. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  274. package/src/backup/backup-key.ts +137 -0
  275. package/src/backup/backup-worker.ts +459 -0
  276. package/src/backup/list-snapshots.ts +147 -0
  277. package/src/backup/local-writer.ts +133 -0
  278. package/src/backup/offsite-writer.ts +222 -0
  279. package/src/backup/paths.ts +226 -0
  280. package/src/backup/restore.ts +322 -0
  281. package/src/backup/snapshot-lock.ts +431 -0
  282. package/src/backup/stream-crypt.ts +263 -0
  283. package/src/browser-session/__tests__/manager.test.ts +297 -0
  284. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  285. package/src/browser-session/backends/extension.ts +26 -0
  286. package/src/browser-session/backends/local.ts +24 -0
  287. package/src/browser-session/events.ts +164 -0
  288. package/src/browser-session/index.ts +27 -0
  289. package/src/browser-session/manager.ts +159 -0
  290. package/src/browser-session/types.ts +28 -0
  291. package/src/bundler/package-resolver.ts +4 -0
  292. package/src/calls/audio-store.ts +11 -5
  293. package/src/calls/call-controller.ts +226 -71
  294. package/src/calls/call-domain.ts +9 -0
  295. package/src/calls/call-speech-output.ts +190 -0
  296. package/src/calls/call-transport.ts +77 -0
  297. package/src/calls/media-stream-audio-transcode.ts +173 -0
  298. package/src/calls/media-stream-output.ts +660 -0
  299. package/src/calls/media-stream-parser.ts +300 -0
  300. package/src/calls/media-stream-protocol.ts +166 -0
  301. package/src/calls/media-stream-server.ts +592 -0
  302. package/src/calls/media-stream-stt-session.ts +460 -0
  303. package/src/calls/media-turn-detector.ts +230 -0
  304. package/src/calls/relay-server.ts +90 -75
  305. package/src/calls/resolve-call-tts-provider.ts +136 -0
  306. package/src/calls/telephony-stt-routing.ts +145 -0
  307. package/src/calls/tts-call-strategy.ts +161 -0
  308. package/src/calls/tts-text-sanitizer.ts +32 -16
  309. package/src/calls/twilio-routes.ts +281 -17
  310. package/src/calls/voice-quality.ts +78 -35
  311. package/src/calls/voice-session-bridge.ts +8 -1
  312. package/src/channels/__tests__/types.test.ts +134 -0
  313. package/src/channels/types.ts +69 -3
  314. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  315. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  316. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  317. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  318. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  319. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  320. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  321. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  322. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  323. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  324. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  325. package/src/cli/commands/backup.ts +993 -0
  326. package/src/cli/commands/conversations.ts +77 -0
  327. package/src/cli/commands/credentials.ts +3 -4
  328. package/src/cli/commands/domain.ts +210 -0
  329. package/src/cli/commands/email.ts +273 -16
  330. package/src/cli/commands/mcp.ts +16 -4
  331. package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
  332. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  333. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  334. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  335. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
  336. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
  337. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
  338. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  339. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  340. package/src/cli/commands/oauth/apps.ts +7 -4
  341. package/src/cli/commands/oauth/connect.ts +6 -3
  342. package/src/cli/commands/oauth/disconnect.ts +1 -1
  343. package/src/cli/commands/oauth/mode.ts +12 -3
  344. package/src/cli/commands/oauth/providers.ts +215 -36
  345. package/src/cli/commands/oauth/shared.ts +7 -6
  346. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
  347. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  348. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  349. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  350. package/src/cli/commands/platform/index.ts +107 -10
  351. package/src/cli/commands/usage.ts +10 -9
  352. package/src/cli/lib/daemon-credential-client.ts +4 -0
  353. package/src/cli/program.ts +30 -4
  354. package/src/config/__tests__/backup-schema.test.ts +134 -0
  355. package/src/config/assistant-feature-flags.ts +61 -62
  356. package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
  357. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
  358. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  359. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  360. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  361. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  362. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  363. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  364. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  365. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  366. package/src/config/bundled-skills/contacts/SKILL.md +5 -2
  367. package/src/config/bundled-skills/document/SKILL.md +4 -0
  368. package/src/config/bundled-skills/gmail/SKILL.md +54 -8
  369. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  370. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  371. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  372. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  373. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  374. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  375. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  376. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  377. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  378. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  379. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  380. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  381. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  382. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  383. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  384. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  385. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  386. package/src/config/bundled-skills/outlook/SKILL.md +9 -2
  387. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  388. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  389. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  390. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  391. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  392. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  393. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  394. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  395. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  396. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  397. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  398. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  399. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  400. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  401. package/src/config/bundled-tool-registry.ts +8 -0
  402. package/src/config/env-registry.ts +38 -0
  403. package/src/config/env.ts +49 -4
  404. package/src/config/feature-flag-registry.json +85 -14
  405. package/src/config/loader.ts +82 -13
  406. package/src/config/sanitize-for-transfer.ts +47 -0
  407. package/src/config/schema.ts +81 -15
  408. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  409. package/src/config/schemas/analysis.ts +51 -0
  410. package/src/config/schemas/backup.ts +72 -0
  411. package/src/config/schemas/calls.ts +1 -26
  412. package/src/config/schemas/elevenlabs.ts +0 -59
  413. package/src/config/schemas/filing.ts +47 -7
  414. package/src/config/schemas/heartbeat.ts +27 -5
  415. package/src/config/schemas/host-browser.ts +112 -0
  416. package/src/config/schemas/inference.ts +1 -1
  417. package/src/config/schemas/memory-lifecycle.ts +14 -2
  418. package/src/config/schemas/memory-retrieval.ts +103 -0
  419. package/src/config/schemas/security.ts +0 -6
  420. package/src/config/schemas/services.ts +52 -0
  421. package/src/config/schemas/stt.ts +59 -0
  422. package/src/config/schemas/tts.ts +230 -0
  423. package/src/config/schemas/updates.ts +14 -0
  424. package/src/config/skills.ts +4 -0
  425. package/src/config/types.ts +4 -1
  426. package/src/contacts/contact-store.ts +56 -11
  427. package/src/contacts/contacts-write.ts +38 -1
  428. package/src/context/post-turn-tool-result-truncation.ts +177 -0
  429. package/src/context/tool-result-truncation.ts +2 -1
  430. package/src/context/window-manager.ts +61 -10
  431. package/src/credential-execution/approval-bridge.ts +49 -15
  432. package/src/credential-execution/executable-discovery.ts +12 -2
  433. package/src/credential-execution/process-manager.ts +33 -2
  434. package/src/credential-health/credential-health-service.ts +366 -0
  435. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  436. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  437. package/src/daemon/__tests__/conversation-tool-setup.test.ts +195 -0
  438. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  439. package/src/daemon/app-source-watcher.ts +35 -0
  440. package/src/daemon/config-watcher.ts +99 -5
  441. package/src/daemon/context-overflow-approval.ts +5 -0
  442. package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
  443. package/src/daemon/conversation-agent-loop.ts +153 -42
  444. package/src/daemon/conversation-attachments.ts +40 -0
  445. package/src/daemon/conversation-error.ts +11 -0
  446. package/src/daemon/conversation-history.ts +40 -6
  447. package/src/daemon/conversation-launch.ts +220 -0
  448. package/src/daemon/conversation-lifecycle.ts +59 -9
  449. package/src/daemon/conversation-messaging.ts +37 -3
  450. package/src/daemon/conversation-notifiers.ts +5 -0
  451. package/src/daemon/conversation-process.ts +622 -13
  452. package/src/daemon/conversation-queue-manager.ts +24 -0
  453. package/src/daemon/conversation-runtime-assembly.ts +128 -36
  454. package/src/daemon/conversation-slash.ts +36 -0
  455. package/src/daemon/conversation-surfaces.ts +131 -40
  456. package/src/daemon/conversation-tool-setup.ts +99 -8
  457. package/src/daemon/conversation-usage.ts +7 -4
  458. package/src/daemon/conversation-workspace.ts +12 -0
  459. package/src/daemon/conversation.ts +292 -16
  460. package/src/daemon/date-context.ts +10 -10
  461. package/src/daemon/first-greeting.ts +3 -2
  462. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  463. package/src/daemon/handlers/conversations.ts +13 -141
  464. package/src/daemon/handlers/shared.ts +80 -0
  465. package/src/daemon/handlers/skills.ts +483 -44
  466. package/src/daemon/host-bash-proxy.ts +48 -13
  467. package/src/daemon/host-browser-proxy.ts +192 -0
  468. package/src/daemon/host-cu-proxy.ts +36 -11
  469. package/src/daemon/host-file-proxy.ts +57 -9
  470. package/src/daemon/lifecycle.ts +179 -28
  471. package/src/daemon/message-protocol.ts +13 -0
  472. package/src/daemon/message-types/conversations.ts +89 -14
  473. package/src/daemon/message-types/home.ts +40 -0
  474. package/src/daemon/message-types/host-browser.ts +100 -0
  475. package/src/daemon/message-types/meet.ts +143 -0
  476. package/src/daemon/message-types/messages.ts +19 -5
  477. package/src/daemon/message-types/schedules.ts +34 -2
  478. package/src/daemon/message-types/skills.ts +26 -0
  479. package/src/daemon/message-types/subagents.ts +2 -0
  480. package/src/daemon/message-types/surfaces.ts +2 -0
  481. package/src/daemon/server.ts +439 -14
  482. package/src/daemon/shutdown-handlers.ts +32 -4
  483. package/src/daemon/shutdown-registry.ts +40 -0
  484. package/src/daemon/tool-side-effects.ts +15 -0
  485. package/src/daemon/transport-hints.ts +5 -24
  486. package/src/email/html-renderer.ts +76 -0
  487. package/src/heartbeat/heartbeat-service.ts +93 -7
  488. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  489. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  490. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  491. package/src/home/__tests__/feed-types.test.ts +275 -0
  492. package/src/home/__tests__/feed-writer.test.ts +688 -0
  493. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  494. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  495. package/src/home/__tests__/progress-formula.test.ts +213 -0
  496. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  497. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  498. package/src/home/assistant-feed-authoring.ts +124 -0
  499. package/src/home/emit-feed-event.ts +158 -0
  500. package/src/home/feed-scheduler.ts +247 -0
  501. package/src/home/feed-types.ts +181 -0
  502. package/src/home/feed-writer.ts +469 -0
  503. package/src/home/platform-gmail-digest.ts +163 -0
  504. package/src/home/progress-formula.ts +86 -0
  505. package/src/home/relationship-state-writer.ts +824 -0
  506. package/src/home/relationship-state.ts +143 -0
  507. package/src/home/rollup-producer.ts +384 -0
  508. package/src/hooks/runner.ts +7 -0
  509. package/src/inbound/platform-callback-registration.ts +30 -20
  510. package/src/inbound/public-ingress-urls.ts +12 -0
  511. package/src/instrument.ts +1 -1
  512. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  513. package/src/ipc/cli-client.ts +151 -0
  514. package/src/ipc/cli-server.ts +234 -0
  515. package/src/ipc/gateway-client.ts +180 -0
  516. package/src/ipc/routes/index.ts +5 -0
  517. package/src/ipc/routes/wake-conversation.ts +19 -0
  518. package/src/mcp/client.ts +59 -24
  519. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  520. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  521. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  522. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  523. package/src/memory/app-store.ts +31 -1
  524. package/src/memory/attachments-store.ts +70 -0
  525. package/src/memory/auto-analysis-enqueue.ts +127 -0
  526. package/src/memory/auto-analysis-guard.ts +27 -0
  527. package/src/memory/cleanup-schedule-state.ts +37 -0
  528. package/src/memory/conversation-analyze-job.ts +73 -0
  529. package/src/memory/conversation-crud.ts +122 -0
  530. package/src/memory/conversation-disk-view.ts +7 -0
  531. package/src/memory/conversation-group-migration.ts +34 -2
  532. package/src/memory/conversation-queries.ts +6 -5
  533. package/src/memory/conversation-starters-cadence.ts +76 -0
  534. package/src/memory/conversation-title-service.ts +5 -2
  535. package/src/memory/db-init.ts +18 -0
  536. package/src/memory/db-maintenance.ts +108 -0
  537. package/src/memory/db.ts +1 -0
  538. package/src/memory/embedding-backend.test.ts +75 -0
  539. package/src/memory/embedding-backend.ts +131 -5
  540. package/src/memory/embedding-gemini.test.ts +54 -0
  541. package/src/memory/embedding-gemini.ts +20 -9
  542. package/src/memory/embedding-local.ts +176 -17
  543. package/src/memory/graph/consolidation.ts +10 -23
  544. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  545. package/src/memory/graph/extraction-job.ts +15 -0
  546. package/src/memory/graph/extraction.test.ts +23 -0
  547. package/src/memory/graph/extraction.ts +8 -0
  548. package/src/memory/graph/retriever.ts +67 -40
  549. package/src/memory/graph/scoring.test.ts +186 -0
  550. package/src/memory/graph/scoring.ts +31 -1
  551. package/src/memory/graph/store.test.ts +7 -3
  552. package/src/memory/graph/store.ts +47 -12
  553. package/src/memory/graph/tools.ts +1 -1
  554. package/src/memory/group-crud.ts +6 -1
  555. package/src/memory/indexer.ts +95 -16
  556. package/src/memory/job-handlers/cleanup.ts +11 -8
  557. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  558. package/src/memory/jobs-store.ts +64 -4
  559. package/src/memory/jobs-worker.ts +22 -9
  560. package/src/memory/llm-usage-store.ts +137 -60
  561. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  562. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  563. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  564. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  565. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  566. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  567. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  568. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  569. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  570. package/src/memory/migrations/index.ts +12 -0
  571. package/src/memory/migrations/registry.ts +16 -0
  572. package/src/memory/qdrant-manager.ts +43 -16
  573. package/src/memory/schema/conversations.ts +3 -0
  574. package/src/memory/schema/oauth.ts +21 -13
  575. package/src/memory/usage-buckets.ts +396 -0
  576. package/src/messaging/providers/gmail/client.ts +57 -6
  577. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  578. package/src/messaging/providers/slack/adapter.ts +143 -38
  579. package/src/messaging/providers/slack/client.ts +16 -0
  580. package/src/messaging/providers/slack/types.ts +4 -0
  581. package/src/notifications/decision-engine.ts +3 -3
  582. package/src/notifications/signal.ts +5 -0
  583. package/src/oauth/AGENTS.md +76 -0
  584. package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
  585. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  586. package/src/oauth/byo-connection.test.ts +26 -9
  587. package/src/oauth/byo-connection.ts +10 -8
  588. package/src/oauth/connect-orchestrator.ts +25 -21
  589. package/src/oauth/connect-types.ts +3 -3
  590. package/src/oauth/connection-resolver.test.ts +17 -4
  591. package/src/oauth/connection-resolver.ts +22 -18
  592. package/src/oauth/connection.ts +3 -1
  593. package/src/oauth/manual-token-connection.ts +13 -13
  594. package/src/oauth/oauth-store.ts +223 -100
  595. package/src/oauth/platform-connection.test.ts +101 -3
  596. package/src/oauth/platform-connection.ts +56 -35
  597. package/src/oauth/provider-serializer.ts +31 -5
  598. package/src/oauth/revoke.ts +76 -0
  599. package/src/oauth/seed-providers.ts +133 -87
  600. package/src/oauth/token-persistence.ts +1 -1
  601. package/src/permissions/checker.ts +16 -6
  602. package/src/permissions/defaults.ts +49 -1
  603. package/src/permissions/permission-mode.ts +4 -11
  604. package/src/permissions/prompter.ts +13 -1
  605. package/src/permissions/trust-store.ts +3 -3
  606. package/src/permissions/v2-consent-policy.ts +87 -0
  607. package/src/permissions/workspace-policy.ts +3 -0
  608. package/src/platform/client.test.ts +10 -0
  609. package/src/platform/sync-identity.ts +129 -0
  610. package/src/prompts/persona-resolver.ts +126 -2
  611. package/src/prompts/system-prompt.ts +76 -38
  612. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  613. package/src/prompts/templates/BOOTSTRAP.md +59 -105
  614. package/src/prompts/templates/SOUL.md +3 -1
  615. package/src/prompts/templates/UPDATES.md +12 -0
  616. package/src/prompts/templates/channels/slack.md +20 -0
  617. package/src/prompts/update-bulletin-format.ts +26 -9
  618. package/src/prompts/update-bulletin.ts +34 -23
  619. package/src/prompts/user-reference.ts +20 -17
  620. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  621. package/src/providers/anthropic/client.ts +157 -60
  622. package/src/providers/fireworks/client.ts +2 -2
  623. package/src/providers/gemini/client.ts +9 -1
  624. package/src/providers/model-catalog.ts +6 -0
  625. package/src/providers/model-intents.ts +4 -4
  626. package/src/providers/ollama/client.ts +2 -2
  627. package/src/providers/openai/chat-completions-provider.ts +474 -0
  628. package/src/providers/openai/client.ts +25 -440
  629. package/src/providers/openai/responses-provider.ts +502 -0
  630. package/src/providers/openrouter/client.ts +101 -4
  631. package/src/providers/provider-secret-catalog.ts +139 -0
  632. package/src/providers/registry.ts +2 -2
  633. package/src/providers/retry.ts +14 -3
  634. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  635. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  636. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  637. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  638. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  639. package/src/providers/speech-to-text/deepgram.ts +115 -0
  640. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  641. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  642. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  643. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  644. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  645. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  646. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  647. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  648. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  649. package/src/providers/speech-to-text/resolve.ts +386 -6
  650. package/src/providers/types.ts +10 -1
  651. package/src/runtime/AGENTS.md +65 -0
  652. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  653. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  654. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  655. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  656. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  657. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  658. package/src/runtime/agent-wake.ts +512 -0
  659. package/src/runtime/assistant-event-hub.ts +2 -2
  660. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  661. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  662. package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
  663. package/src/runtime/auth/middleware.ts +98 -0
  664. package/src/runtime/auth/route-policy.ts +33 -9
  665. package/src/runtime/auth/token-service.ts +56 -1
  666. package/src/runtime/btw-sidechain.ts +2 -0
  667. package/src/runtime/capability-tokens.ts +414 -0
  668. package/src/runtime/channel-approvals.ts +18 -5
  669. package/src/runtime/channel-invite-transport.ts +1 -1
  670. package/src/runtime/channel-invite-transports/email.ts +14 -6
  671. package/src/runtime/channel-readiness-service.ts +12 -22
  672. package/src/runtime/chrome-extension-registry.ts +368 -0
  673. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  674. package/src/runtime/guardian-decision-types.ts +7 -0
  675. package/src/runtime/http-server.ts +815 -75
  676. package/src/runtime/http-types.ts +6 -2
  677. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  678. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  679. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
  680. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  681. package/src/runtime/migrations/migration-transport.ts +7 -0
  682. package/src/runtime/migrations/migration-wizard.ts +23 -2
  683. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  684. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  685. package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
  686. package/src/runtime/migrations/vbundle-importer.ts +89 -5
  687. package/src/runtime/pending-interactions.ts +18 -13
  688. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  689. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  690. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  691. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  692. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  693. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  694. package/src/runtime/routes/app-management-routes.ts +12 -18
  695. package/src/runtime/routes/approval-routes.ts +90 -16
  696. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  697. package/src/runtime/routes/attachment-routes.ts +216 -17
  698. package/src/runtime/routes/backup-routes.ts +519 -0
  699. package/src/runtime/routes/browser-extension-pair-routes.ts +556 -0
  700. package/src/runtime/routes/btw-routes.ts +8 -6
  701. package/src/runtime/routes/contact-routes.test.ts +298 -0
  702. package/src/runtime/routes/contact-routes.ts +132 -5
  703. package/src/runtime/routes/conversation-analysis-routes.ts +22 -141
  704. package/src/runtime/routes/conversation-management-routes.ts +223 -0
  705. package/src/runtime/routes/conversation-routes.ts +598 -103
  706. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  707. package/src/runtime/routes/filing-routes.ts +93 -0
  708. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  709. package/src/runtime/routes/home-feed-routes.ts +334 -0
  710. package/src/runtime/routes/home-state-routes.ts +138 -0
  711. package/src/runtime/routes/host-browser-routes.ts +268 -0
  712. package/src/runtime/routes/host-file-routes.ts +9 -1
  713. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  714. package/src/runtime/routes/identity-routes.ts +262 -33
  715. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  716. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  717. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  718. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  719. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  720. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  721. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  722. package/src/runtime/routes/log-export-routes.ts +42 -22
  723. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  724. package/src/runtime/routes/memory-item-routes.ts +1 -7
  725. package/src/runtime/routes/migration-routes.ts +122 -2
  726. package/src/runtime/routes/oauth-apps.ts +15 -17
  727. package/src/runtime/routes/oauth-providers.ts +4 -0
  728. package/src/runtime/routes/schedule-routes.ts +24 -11
  729. package/src/runtime/routes/settings-routes.ts +31 -102
  730. package/src/runtime/routes/skills-routes.ts +128 -9
  731. package/src/runtime/routes/stt-routes.ts +233 -0
  732. package/src/runtime/routes/subagents-routes.ts +14 -10
  733. package/src/runtime/routes/surface-action-routes.ts +41 -2
  734. package/src/runtime/routes/tts-routes.ts +108 -24
  735. package/src/runtime/routes/usage-routes.ts +38 -9
  736. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  737. package/src/runtime/routes/user-routes.ts +13 -1
  738. package/src/runtime/routes/work-items-routes.ts +8 -1
  739. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  740. package/src/runtime/routes/workspace-routes.ts +8 -1
  741. package/src/runtime/routes/workspace-utils.ts +2 -0
  742. package/src/runtime/runtime-mode.ts +33 -0
  743. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  744. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  745. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  746. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  747. package/src/runtime/services/analyze-conversation.ts +344 -0
  748. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  749. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  750. package/src/runtime/skill-route-registry.ts +49 -0
  751. package/src/runtime/slack-block-formatting.ts +437 -10
  752. package/src/schedule/scheduler.ts +57 -5
  753. package/src/security/ces-credential-client.ts +20 -0
  754. package/src/security/ces-rpc-credential-backend.ts +17 -0
  755. package/src/security/credential-backend.ts +5 -0
  756. package/src/security/oauth2.ts +68 -29
  757. package/src/security/secure-keys.ts +143 -27
  758. package/src/security/token-manager.ts +31 -10
  759. package/src/sequence/engine.ts +23 -0
  760. package/src/sequence/types.ts +1 -1
  761. package/src/skills/catalog-files.ts +554 -0
  762. package/src/skills/category-inference.ts +122 -0
  763. package/src/skills/clawhub-files.ts +213 -0
  764. package/src/skills/clawhub.ts +84 -23
  765. package/src/skills/skill-file-provider.ts +40 -0
  766. package/src/skills/skillssh-files.ts +395 -0
  767. package/src/skills/skillssh-registry.ts +4 -4
  768. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  769. package/src/stt/__tests__/types.test.ts +89 -0
  770. package/src/stt/daemon-batch-transcriber.ts +195 -0
  771. package/src/stt/stt-stream-session.ts +499 -0
  772. package/src/stt/types.ts +330 -0
  773. package/src/stt/wav-encoder.test.ts +373 -0
  774. package/src/stt/wav-encoder.ts +175 -0
  775. package/src/subagent/manager.ts +169 -40
  776. package/src/subagent/types.ts +19 -0
  777. package/src/tools/apps/executors.ts +11 -2
  778. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  779. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  780. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  781. package/src/tools/browser/auth-detector.ts +43 -12
  782. package/src/tools/browser/browser-execution.ts +1787 -342
  783. package/src/tools/browser/browser-manager.ts +81 -12
  784. package/src/tools/browser/browser-mode-constants.ts +12 -0
  785. package/src/tools/browser/browser-mode.ts +92 -0
  786. package/src/tools/browser/browser-status-constants.ts +33 -0
  787. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  788. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  789. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
  790. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
  791. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
  792. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  793. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  794. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  795. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  796. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  797. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  798. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
  799. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  800. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
  801. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  802. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
  803. package/src/tools/browser/cdp-client/errors.ts +49 -0
  804. package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
  805. package/src/tools/browser/cdp-client/factory.ts +914 -0
  806. package/src/tools/browser/cdp-client/index.ts +28 -0
  807. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  808. package/src/tools/browser/cdp-client/types.ts +120 -0
  809. package/src/tools/credentials/vault.ts +35 -6
  810. package/src/tools/filesystem/edit.ts +1 -1
  811. package/src/tools/filesystem/list.ts +1 -1
  812. package/src/tools/filesystem/read.ts +1 -1
  813. package/src/tools/filesystem/write.ts +2 -1
  814. package/src/tools/host-filesystem/edit.ts +1 -1
  815. package/src/tools/host-filesystem/read.ts +12 -15
  816. package/src/tools/host-filesystem/write.ts +1 -1
  817. package/src/tools/host-terminal/host-shell.ts +21 -16
  818. package/src/tools/network/web-fetch.ts +5 -2
  819. package/src/tools/network/web-search.ts +5 -2
  820. package/src/tools/permission-checker.ts +77 -82
  821. package/src/tools/registry.ts +0 -2
  822. package/src/tools/secret-detection-handler.ts +34 -0
  823. package/src/tools/shared/filesystem/image-read.ts +61 -40
  824. package/src/tools/shared/shell-output.ts +3 -1
  825. package/src/tools/side-effects.ts +2 -0
  826. package/src/tools/skills/sandbox-runner.ts +3 -2
  827. package/src/tools/subagent/spawn.ts +47 -3
  828. package/src/tools/subagent/status.ts +2 -0
  829. package/src/tools/system/register.ts +2 -16
  830. package/src/tools/terminal/safe-env.ts +15 -0
  831. package/src/tools/terminal/shell.ts +36 -20
  832. package/src/tools/tool-approval-handler.ts +48 -2
  833. package/src/tools/tool-manifest.ts +21 -0
  834. package/src/tools/types.ts +19 -0
  835. package/src/tools/ui-surface/definitions.ts +6 -1
  836. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  837. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  838. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  839. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  840. package/src/tts/provider-catalog.ts +201 -0
  841. package/src/tts/provider-registry.ts +73 -0
  842. package/src/tts/providers/deepgram-provider.ts +219 -0
  843. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  844. package/src/tts/providers/fish-audio-provider.ts +183 -0
  845. package/src/tts/providers/index.ts +42 -0
  846. package/src/tts/providers/register-builtins.ts +130 -0
  847. package/src/tts/synthesize-text.ts +110 -0
  848. package/src/tts/tts-config-resolver.ts +78 -0
  849. package/src/tts/types.ts +153 -0
  850. package/src/types/onboarding-context.ts +7 -0
  851. package/src/util/abort-reasons.ts +58 -0
  852. package/src/util/device-id.ts +32 -16
  853. package/src/util/errors.ts +9 -1
  854. package/src/util/platform.ts +63 -24
  855. package/src/util/pricing.ts +66 -3
  856. package/src/util/spawn.ts +1 -1
  857. package/src/util/truncate.ts +4 -2
  858. package/src/util/unicode.ts +201 -0
  859. package/src/version.ts +19 -24
  860. package/src/watcher/engine.ts +23 -0
  861. package/src/watcher/watcher-store.ts +31 -0
  862. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  863. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  864. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  865. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  866. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  867. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  868. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  869. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  870. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  871. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  872. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  873. package/src/workspace/migrations/registry.ts +16 -0
  874. package/src/workspace/top-level-renderer.ts +31 -1
  875. package/src/workspace/turn-commit.ts +31 -0
  876. package/src/__tests__/chrome-cdp.test.ts +0 -419
  877. package/src/__tests__/email-cli.test.ts +0 -297
  878. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  879. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  880. package/src/__tests__/permission-mode-store.test.ts +0 -277
  881. package/src/browser-extension-relay/protocol.ts +0 -63
  882. package/src/browser-extension-relay/server.ts +0 -203
  883. package/src/cli/commands/browser-relay.ts +0 -536
  884. package/src/config/schemas/sandbox.ts +0 -14
  885. package/src/email/guardrails.ts +0 -221
  886. package/src/email/provider.ts +0 -117
  887. package/src/email/providers/agentmail.ts +0 -361
  888. package/src/email/providers/index.ts +0 -65
  889. package/src/email/service.ts +0 -384
  890. package/src/email/types.ts +0 -126
  891. package/src/permissions/permission-mode-store.ts +0 -180
  892. package/src/prompts/templates/USER.md +0 -13
  893. package/src/providers/speech-to-text/types.ts +0 -17
  894. package/src/tools/browser/chrome-cdp.ts +0 -239
  895. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -42,18 +42,35 @@ export function appendReleaseBlock(
42
42
  }
43
43
 
44
44
  /**
45
- * Extracts content-level markers (non-version feature markers) from the
46
- * template body. These are markers like `schedule-reminder-unification`
47
- * that identify the _content_ rather than the release version.
45
+ * Filters template content to only include content blocks whose opening
46
+ * markers are not already present in the existing workspace content.
47
+ *
48
+ * Each content block is delimited by opening/closing marker pairs:
49
+ * <!-- vellum-update-release:id --> ... <!-- /vellum-update-release:id -->
50
+ *
51
+ * If the template has no block structure (no matched open/close pairs),
52
+ * returns the original body unchanged for backward compatibility.
53
+ * Returns empty string when all blocks are already present.
48
54
  */
49
- export function extractContentMarkers(body: string): string[] {
50
- const ids: string[] = [];
51
- const regex = /<!-- vellum-update-release:(.+?) -->/g;
55
+ export function filterNewContentBlocks(
56
+ body: string,
57
+ existing: string,
58
+ ): string {
59
+ const blockRegex =
60
+ /(<!-- vellum-update-release:(.+?) -->[\s\S]*?<!-- \/vellum-update-release:\2 -->)/g;
61
+ const blocks: Array<{ full: string; id: string }> = [];
52
62
  let match: RegExpExecArray | null;
53
- while ((match = regex.exec(body)) !== null) {
54
- ids.push(match[1]);
63
+ while ((match = blockRegex.exec(body)) !== null) {
64
+ blocks.push({ full: match[1], id: match[2] });
55
65
  }
56
- return ids;
66
+
67
+ if (blocks.length === 0) return body;
68
+
69
+ const newBlocks = blocks.filter((b) => !hasReleaseBlock(existing, b.id));
70
+
71
+ if (newBlocks.length === 0) return "";
72
+
73
+ return newBlocks.map((b) => b.full).join("\n\n");
57
74
  }
58
75
 
59
76
  /** Extracts all version strings from release markers found in `content`. */
@@ -8,14 +8,14 @@ import {
8
8
  writeFileSync,
9
9
  } from "node:fs";
10
10
 
11
+ import { getConfig } from "../config/loader.js";
11
12
  import { getWorkspacePromptPath } from "../util/platform.js";
12
13
  import { stripCommentLines } from "../util/strip-comment-lines.js";
13
14
  import { APP_VERSION } from "../version.js";
14
15
  import {
15
16
  appendReleaseBlock,
16
- extractContentMarkers,
17
+ filterNewContentBlocks,
17
18
  hasReleaseBlock,
18
- releaseMarker,
19
19
  } from "./update-bulletin-format.js";
20
20
  import {
21
21
  addActiveRelease,
@@ -67,25 +67,43 @@ function atomicWriteFileSync(filePath: string, content: string): void {
67
67
  /**
68
68
  * Materializes the current release's update bulletin on startup.
69
69
  *
70
- * First checks for deletion-completion: if the workspace UPDATES.md was
71
- * deleted while releases were active, those releases are marked completed
72
- * (the assistant signals "done" by deleting the file).
70
+ * First checks for dismissal: if the workspace UPDATES.md was deleted or
71
+ * emptied after we'd previously materialized it, that's an explicit signal
72
+ * (from the user or the assistant) that the current release has been handled.
73
+ * Mark any active releases plus the current release as completed and return
74
+ * without recreating the file.
73
75
  *
74
- * Then reads the bundled UPDATES.md template, strips comment lines, and
75
- * appends a release block to the workspace UPDATES.md if one doesn't
76
- * already exist for this version. Skips completed releases entirely.
76
+ * Otherwise reads the bundled UPDATES.md template, strips comment lines, and
77
+ * appends a release block to the workspace UPDATES.md if one doesn't already
78
+ * exist for this version. Skips completed releases entirely.
77
79
  */
78
80
  export function syncUpdateBulletinOnStartup(): void {
81
+ if (!getConfig().updates.enabled) return;
82
+
79
83
  const currentReleaseId = APP_VERSION;
80
84
  const workspacePath = getWorkspacePromptPath("UPDATES.md");
81
85
 
82
- // --- Deletion completion ---
83
- // If UPDATES.md was deleted and there are active releases, the assistant
84
- // has signaled it is done with those updates. Mark them completed.
86
+ // --- Dismissal detection ---
87
+ // If UPDATES.md is missing or empty AND the CURRENT release has been
88
+ // materialized before (i.e. it's in the active set, or already marked
89
+ // completed), treat it as a dismissal: mark the active set plus the
90
+ // current release completed and stop. Scoping to the current release is
91
+ // critical — a prior release having been completed must NOT cause a new
92
+ // version's bulletin to be suppressed as "already dismissed". It also
93
+ // preserves fresh-install semantics: on a brand-new DB we want to create
94
+ // the file, not treat its absence as dismissal.
85
95
  const activeReleases = getActiveReleases();
86
- if (!existsSync(workspacePath) && activeReleases.length > 0) {
87
- markReleasesCompleted(activeReleases);
96
+ const fileMissing = !existsSync(workspacePath);
97
+ const fileEmpty =
98
+ !fileMissing && readFileSync(workspacePath, "utf-8").trim().length === 0;
99
+ const currentReleaseMaterialized =
100
+ activeReleases.includes(currentReleaseId) ||
101
+ isReleaseCompleted(currentReleaseId);
102
+
103
+ if ((fileMissing || fileEmpty) && currentReleaseMaterialized) {
104
+ markReleasesCompleted([...activeReleases, currentReleaseId]);
88
105
  setActiveReleases([]);
106
+ return;
89
107
  }
90
108
 
91
109
  // --- Template materialization ---
@@ -105,19 +123,12 @@ export function syncUpdateBulletinOnStartup(): void {
105
123
  } else {
106
124
  const existing = readFileSync(workspacePath, "utf-8");
107
125
  if (!hasReleaseBlock(existing, currentReleaseId)) {
108
- // Guard: skip if the template's content markers already exist in the
109
- // workspace file. This prevents the same update notes from being
110
- // appended on every version bump when the template isn't cleared.
111
- const contentMarkers = extractContentMarkers(templateContent);
112
- const allContentAlreadyPresent =
113
- contentMarkers.length > 0 &&
114
- contentMarkers.every((m) => existing.includes(releaseMarker(m)));
115
-
116
- if (!allContentAlreadyPresent) {
126
+ const contentToAppend = filterNewContentBlocks(templateContent, existing);
127
+ if (contentToAppend.length > 0) {
117
128
  const updated = appendReleaseBlock(
118
129
  existing,
119
130
  currentReleaseId,
120
- templateContent,
131
+ contentToAppend,
121
132
  );
122
133
  atomicWriteFileSync(workspacePath, updated);
123
134
  }
@@ -1,16 +1,18 @@
1
- import { readTextFileSync } from "../util/fs.js";
2
- import { getWorkspacePromptPath } from "../util/platform.js";
1
+ import { resolveGuardianPersonaStrict } from "./persona-resolver.js";
3
2
 
4
3
  export const DEFAULT_USER_REFERENCE = "my human";
5
4
  export const DECLINED_BY_USER_SENTINEL = "declined_by_user";
6
5
 
7
6
  /**
8
- * Read the raw "Preferred name/reference:" value from USER.md.
9
- * Returns the trimmed value when present, or `null` when the file
10
- * is missing, unreadable, or the field is empty.
7
+ * Read the raw "Preferred name/reference:" value from the guardian's
8
+ * per-user persona file (`users/<slug>.md`).
9
+ *
10
+ * Returns the trimmed value when present, or `null` when no guardian
11
+ * is resolvable, the persona file is missing / empty, or the field
12
+ * itself is blank.
11
13
  */
12
14
  function readPreferredNameFromUserMd(): string | null {
13
- const content = readTextFileSync(getWorkspacePromptPath("USER.md"));
15
+ const content = resolveGuardianPersonaStrict();
14
16
  if (content != null) {
15
17
  const match = content.match(/Preferred name\/reference:[ \t]*(.*)/);
16
18
  if (match && match[1].trim()) {
@@ -24,9 +26,9 @@ function readPreferredNameFromUserMd(): string | null {
24
26
  * Resolve the name/reference the assistant uses when referring to
25
27
  * the human it represents in external communications.
26
28
  *
27
- * Reads the "Preferred name/reference:" field from USER.md.
28
- * Falls back to "my human" when the file is missing, unreadable,
29
- * or the field is empty.
29
+ * Reads the "Preferred name/reference:" field from the guardian's
30
+ * persona file. Falls back to "my human" when the file is missing,
31
+ * unreadable, or the field is empty.
30
32
  */
31
33
  export function resolveUserReference(): string {
32
34
  const preferredName = readPreferredNameFromUserMd();
@@ -37,9 +39,9 @@ export function resolveUserReference(): string {
37
39
  }
38
40
 
39
41
  /**
40
- * Resolve the user's pronouns from USER.md. Returns `null` when the
41
- * file is missing, the field is empty, or the value is a sentinel like
42
- * `declined_by_user`.
42
+ * Resolve the user's pronouns from the guardian's per-user persona file.
43
+ * Returns `null` when no guardian is resolvable, the file is missing,
44
+ * the field is empty, or the value is a sentinel like `declined_by_user`.
43
45
  *
44
46
  * When a legacy `## Onboarding Snapshot` section exists, a `Pronouns:`
45
47
  * line *above* that section takes priority (explicit post-onboarding edit).
@@ -47,7 +49,7 @@ export function resolveUserReference(): string {
47
49
  * in the file.
48
50
  */
49
51
  export function resolveUserPronouns(): string | null {
50
- const content = readTextFileSync(getWorkspacePromptPath("USER.md"));
52
+ const content = resolveGuardianPersonaStrict();
51
53
  if (content == null) return null;
52
54
 
53
55
  const snapshotIdx = content.indexOf("## Onboarding Snapshot");
@@ -82,10 +84,11 @@ function cleanPronounValue(raw: string): string | null {
82
84
  * Resolve the guardian's display name.
83
85
  *
84
86
  * Priority:
85
- * 1. USER.md "Preferred name/reference:" — the user-editable, actively
86
- * maintained source of truth.
87
- * 2. guardianDisplayName (fallback for when USER.md is missing or empty,
88
- * e.g. pre-onboarding). Callers pass in Contact.displayName.
87
+ * 1. Guardian persona file "Preferred name/reference:" — the
88
+ * user-editable, actively maintained source of truth.
89
+ * 2. guardianDisplayName (fallback for when the persona file is
90
+ * missing or empty, e.g. pre-onboarding). Callers pass in
91
+ * Contact.displayName.
89
92
  * 3. DEFAULT_USER_REFERENCE ("my human").
90
93
  */
91
94
  export function resolveGuardianName(
@@ -0,0 +1,42 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { API_KEY_PROVIDERS } from "../provider-secret-catalog.js";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // API_KEY_PROVIDERS derivation invariants
7
+ // ---------------------------------------------------------------------------
8
+
9
+ describe("API_KEY_PROVIDERS", () => {
10
+ test("includes deepgram (shared by STT and TTS catalogs)", () => {
11
+ expect(API_KEY_PROVIDERS).toContain("deepgram");
12
+ });
13
+
14
+ test("includes deepgram exactly once despite appearing in both STT and TTS catalogs", () => {
15
+ const occurrences = API_KEY_PROVIDERS.filter((p) => p === "deepgram");
16
+ expect(occurrences.length).toBe(1);
17
+ });
18
+
19
+ test("includes openai exactly once (shared by LLM and STT)", () => {
20
+ const occurrences = API_KEY_PROVIDERS.filter((p) => p === "openai");
21
+ expect(occurrences.length).toBe(1);
22
+ });
23
+
24
+ test("contains no duplicate entries", () => {
25
+ const unique = new Set(API_KEY_PROVIDERS);
26
+ expect(API_KEY_PROVIDERS.length).toBe(unique.size);
27
+ });
28
+
29
+ test("is deterministic across calls", () => {
30
+ // Re-import would return the same module-level constant, but this
31
+ // validates that the composition does not introduce non-determinism.
32
+ const first = [...API_KEY_PROVIDERS];
33
+ const second = [...API_KEY_PROVIDERS];
34
+ expect(first).toEqual(second);
35
+ });
36
+
37
+ test("includes core LLM providers", () => {
38
+ expect(API_KEY_PROVIDERS).toContain("anthropic");
39
+ expect(API_KEY_PROVIDERS).toContain("openai");
40
+ expect(API_KEY_PROVIDERS).toContain("gemini");
41
+ });
42
+ });
@@ -1,9 +1,11 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
 
3
3
  import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/system-prompt.js";
4
+ import { isAbortReason } from "../../util/abort-reasons.js";
4
5
  import { ProviderError } from "../../util/errors.js";
5
6
  import { getLogger } from "../../util/logger.js";
6
7
  import { extractRetryAfterMs } from "../../util/retry.js";
8
+ import { stripOrphanedSurrogatesDeep } from "../../util/unicode.js";
7
9
  import { createStreamTimeout } from "../stream-timeout.js";
8
10
  import type {
9
11
  ContentBlock,
@@ -19,6 +21,35 @@ const log = getLogger("anthropic-client");
19
21
  /** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
20
22
  const VALIDATION_TIMEOUT_MS = 10_000;
21
23
 
24
+ /** Rate-limit the orphaned-surrogate warning so a single bad stream can't flood logs. */
25
+ const ORPHAN_WARNING_THROTTLE_MS = 60_000;
26
+ let lastOrphanWarningMs = 0;
27
+
28
+ function logOrphanedSurrogateWarning(
29
+ fixedStringCount: number,
30
+ messages: Anthropic.MessageParam[],
31
+ ): void {
32
+ const now = Date.now();
33
+ if (now - lastOrphanWarningMs < ORPHAN_WARNING_THROTTLE_MS) return;
34
+ lastOrphanWarningMs = now;
35
+ const blockTypes = new Set<string>();
36
+ for (const msg of messages) {
37
+ if (!Array.isArray(msg.content)) continue;
38
+ for (const block of msg.content) {
39
+ if (typeof block !== "object" || block == null) continue;
40
+ const type = (block as { type?: string }).type;
41
+ if (type) blockTypes.add(type);
42
+ }
43
+ }
44
+ log.warn(
45
+ {
46
+ fixedStringCount,
47
+ blockTypes: Array.from(blockTypes),
48
+ },
49
+ "stripped orphaned UTF-16 surrogates from outbound Anthropic request — upstream truncation is not surrogate-aware",
50
+ );
51
+ }
52
+
22
53
  /**
23
54
  * Validate an Anthropic API key by making a lightweight GET /v1/models call.
24
55
  * Returns `{ valid: true }` on success or `{ valid: false, reason: string }` on failure.
@@ -361,7 +392,10 @@ function repairOrphanedServerToolUse(
361
392
  repairedContent.push({
362
393
  type: "web_search_tool_result",
363
394
  tool_use_id: block.id,
364
- content: [],
395
+ content: {
396
+ type: "web_search_tool_result_error",
397
+ error_code: "unavailable",
398
+ },
365
399
  } as unknown as Anthropic.ContentBlockParam);
366
400
  }
367
401
  }
@@ -564,9 +598,22 @@ export class AnthropicProvider implements Provider {
564
598
  useNativeWebSearch?: boolean;
565
599
  streamTimeoutMs?: number;
566
600
  baseURL?: string;
601
+ /**
602
+ * Authenticate via `Authorization: Bearer <token>` instead of
603
+ * `x-api-key`. Required for proxies that front the Anthropic Messages
604
+ * API with their own Bearer scheme (e.g. OpenRouter). When set, the
605
+ * positional `apiKey` argument is ignored on the wire.
606
+ */
607
+ authToken?: string;
567
608
  } = {},
568
609
  ) {
569
- this.client = new Anthropic({ apiKey, baseURL: options.baseURL });
610
+ this.client = options.authToken
611
+ ? new Anthropic({
612
+ apiKey: null,
613
+ authToken: options.authToken,
614
+ baseURL: options.baseURL,
615
+ })
616
+ : new Anthropic({ apiKey, baseURL: options.baseURL });
570
617
  this.model = model;
571
618
  this.useNativeWebSearch = options.useNativeWebSearch ?? false;
572
619
  this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
@@ -579,7 +626,10 @@ export class AnthropicProvider implements Provider {
579
626
  options?: SendMessageOptions,
580
627
  ): Promise<ProviderResponse> {
581
628
  const { config, onEvent, signal } = options ?? {};
582
- const cacheTtl: "5m" | "1h" = ((config as Record<string, unknown> | undefined)?.cacheTtl as "5m" | "1h") ?? "1h";
629
+ const cacheTtl: "5m" | "1h" =
630
+ ((config as Record<string, unknown> | undefined)?.cacheTtl as
631
+ | "5m"
632
+ | "1h") ?? "1h";
583
633
  let sentMessages: Anthropic.MessageParam[] | undefined;
584
634
  try {
585
635
  const formatted = messages
@@ -689,25 +739,49 @@ export class AnthropicProvider implements Provider {
689
739
  // — the API accepts them. No provider-side stripping needed.
690
740
 
691
741
  sentMessages = ensureToolPairing(repairOrphanedServerToolUse(formatted));
692
- const { effort, speed, output_config, cacheTtl: _cacheTtl, ...restConfig } = (config ??
693
- {}) as Record<string, unknown> & {
742
+ const {
743
+ effort,
744
+ speed,
745
+ output_config,
746
+ cacheTtl: _cacheTtl,
747
+ max_tokens: callerMaxTokens,
748
+ ...restConfig
749
+ } = (config ?? {}) as Record<string, unknown> & {
694
750
  effort?: Anthropic.OutputConfig["effort"];
695
751
  speed?: "standard" | "fast";
696
752
  output_config?: Record<string, unknown>;
697
753
  };
698
- // Haiku does not support the effort / output_config parameter.
754
+ // Haiku does not support the effort / output_config parameter,
755
+ // extended cache TTL betas, 1M context, or 64K output tokens.
699
756
  // Determine the effective model (per-call override or provider default)
700
- // and strip effort when the model doesn't support it.
757
+ // and gate features accordingly.
701
758
  const effectiveModel =
702
759
  (restConfig as Record<string, unknown>).model?.toString() ?? this.model;
703
- const supportsEffort = !effectiveModel.includes("haiku");
760
+ const isHaiku = effectiveModel.includes("haiku");
761
+ const supportsEffort = !isHaiku;
704
762
  const mergedOutputConfig = {
705
763
  ...(output_config ?? {}),
706
764
  ...(effort && supportsEffort ? { effort } : {}),
707
765
  };
708
- const params: Anthropic.MessageStreamParams = {
766
+ // Build cache_control objects: Haiku doesn't support the extended
767
+ // cache TTL beta, so omit the ttl field for Haiku models.
768
+ const cacheControl = isHaiku
769
+ ? { type: "ephemeral" as const }
770
+ : { type: "ephemeral" as const, ttl: cacheTtl };
771
+ const tailCacheControl = isHaiku
772
+ ? { type: "ephemeral" as const }
773
+ : { type: "ephemeral" as const, ttl: "5m" as const };
774
+
775
+ let params: Anthropic.MessageStreamParams = {
709
776
  model: this.model,
710
- max_tokens: 64000,
777
+ max_tokens: isHaiku
778
+ ? Math.min(
779
+ typeof callerMaxTokens === "number" ? callerMaxTokens : 8192,
780
+ 8192,
781
+ )
782
+ : typeof callerMaxTokens === "number"
783
+ ? callerMaxTokens
784
+ : 64000,
711
785
  messages: sentMessages,
712
786
  ...restConfig,
713
787
  ...(Object.keys(mergedOutputConfig).length > 0
@@ -733,12 +807,12 @@ export class AnthropicProvider implements Provider {
733
807
  {
734
808
  type: "text" as const,
735
809
  text: staticBlock,
736
- cache_control: { type: "ephemeral" as const, ttl: cacheTtl },
810
+ cache_control: cacheControl,
737
811
  },
738
812
  {
739
813
  type: "text" as const,
740
814
  text: dynamicBlock,
741
- cache_control: { type: "ephemeral" as const, ttl: cacheTtl },
815
+ cache_control: cacheControl,
742
816
  },
743
817
  ];
744
818
  } else {
@@ -746,7 +820,7 @@ export class AnthropicProvider implements Provider {
746
820
  {
747
821
  type: "text" as const,
748
822
  text: systemPrompt,
749
- cache_control: { type: "ephemeral" as const, ttl: cacheTtl },
823
+ cache_control: cacheControl,
750
824
  },
751
825
  ];
752
826
  }
@@ -763,12 +837,7 @@ export class AnthropicProvider implements Provider {
763
837
  description: t.description,
764
838
  input_schema: t.input_schema as Anthropic.Tool["input_schema"],
765
839
  ...(i === otherTools.length - 1
766
- ? {
767
- cache_control: {
768
- type: "ephemeral" as const,
769
- ttl: cacheTtl,
770
- },
771
- }
840
+ ? { cache_control: cacheControl }
772
841
  : {}),
773
842
  }));
774
843
  const webSearchTool: Anthropic.WebSearchTool20250305 = {
@@ -782,14 +851,7 @@ export class AnthropicProvider implements Provider {
782
851
  name: t.name,
783
852
  description: t.description,
784
853
  input_schema: t.input_schema as Anthropic.Tool["input_schema"],
785
- ...(i === tools.length - 1
786
- ? {
787
- cache_control: {
788
- type: "ephemeral" as const,
789
- ttl: cacheTtl,
790
- },
791
- }
792
- : {}),
854
+ ...(i === tools.length - 1 ? { cache_control: cacheControl } : {}),
793
855
  }));
794
856
  }
795
857
  }
@@ -813,10 +875,8 @@ export class AnthropicProvider implements Provider {
813
875
  if (!hasText) continue;
814
876
  const lastBlock = msg.content[msg.content.length - 1];
815
877
  if (typeof lastBlock !== "string") {
816
- (lastBlock as unknown as Record<string, unknown>).cache_control = {
817
- type: "ephemeral",
818
- ttl: cacheTtl,
819
- };
878
+ (lastBlock as unknown as Record<string, unknown>).cache_control =
879
+ cacheControl;
820
880
  }
821
881
  turnStartIdx = i;
822
882
  break;
@@ -832,7 +892,10 @@ export class AnthropicProvider implements Provider {
832
892
  if (turnStartIdx >= 0 && turnStartIdx < sentMessages.length - 1) {
833
893
  const lastMsg = sentMessages[sentMessages.length - 1];
834
894
  if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {
835
- const NON_CACHEABLE_TYPES = new Set(["thinking", "redacted_thinking"]);
895
+ const NON_CACHEABLE_TYPES = new Set([
896
+ "thinking",
897
+ "redacted_thinking",
898
+ ]);
836
899
  let tailBlock: (typeof lastMsg.content)[number] | undefined;
837
900
  for (let j = lastMsg.content.length - 1; j >= 0; j--) {
838
901
  const block = lastMsg.content[j];
@@ -845,10 +908,8 @@ export class AnthropicProvider implements Provider {
845
908
  }
846
909
  }
847
910
  if (tailBlock && typeof tailBlock !== "string") {
848
- (tailBlock as unknown as Record<string, unknown>).cache_control = {
849
- type: "ephemeral",
850
- ttl: "5m",
851
- };
911
+ (tailBlock as unknown as Record<string, unknown>).cache_control =
912
+ tailCacheControl;
852
913
  tailBreakpointApplied = true;
853
914
  }
854
915
  }
@@ -872,7 +933,17 @@ export class AnthropicProvider implements Provider {
872
933
  params.system.length === 2 &&
873
934
  hasToolCacheBreakpoint
874
935
  ) {
875
- delete (params.system[0] as unknown as Record<string, unknown>).cache_control;
936
+ delete (params.system[0] as unknown as Record<string, unknown>)
937
+ .cache_control;
938
+ }
939
+
940
+ // Strip orphaned UTF-16 surrogates so the Anthropic JSON parser never
941
+ // sees invalid strings produced by upstream surrogate-splitting `.slice()` calls.
942
+ const sanitized = stripOrphanedSurrogatesDeep(params);
943
+ if (sanitized.changed) {
944
+ logOrphanedSurrogateWarning(sanitized.fixedStringCount, sentMessages);
945
+ params = sanitized.value;
946
+ sentMessages = params.messages;
876
947
  }
877
948
 
878
949
  const { signal: timeoutSignal, cleanup: cleanupTimeout } =
@@ -890,15 +961,15 @@ export class AnthropicProvider implements Provider {
890
961
  finalMessage(): Promise<Anthropic.Message>;
891
962
  }
892
963
 
893
- // Fast mode: use the beta endpoint with speed: "fast" for Opus 4.6
964
+ // Fast mode: use the beta endpoint with speed: "fast" for Opus models (4.6, 4.7)
894
965
  const useFastMode = speed === "fast" && effectiveModel.includes("opus");
895
966
 
896
967
  // Collect required betas: extended cache TTL for 1h system prompt caching,
897
968
  // 1M context window, and fast-mode when applicable.
898
- const betas: string[] = [
899
- "extended-cache-ttl-2025-04-11",
900
- "context-1m-2025-08-07",
901
- ];
969
+ // Haiku doesn't support the extended cache TTL or 1M context betas.
970
+ const betas: string[] = isHaiku
971
+ ? []
972
+ : ["extended-cache-ttl-2025-04-11", "context-1m-2025-08-07"];
902
973
  if (useFastMode) {
903
974
  betas.push("fast-mode-2026-02-01");
904
975
  }
@@ -915,14 +986,18 @@ export class AnthropicProvider implements Provider {
915
986
  Anthropic.Beta.Messages.MessageCreateParamsStreaming,
916
987
  { signal: timeoutSignal },
917
988
  ) as unknown as UnifiedStream)
918
- : (this.client.beta.messages.stream(
919
- {
920
- ...(params as Record<string, unknown>),
921
- betas,
922
- } as Anthropic.Beta.Messages.MessageCreateParamsNonStreaming &
923
- Anthropic.Beta.Messages.MessageCreateParamsStreaming,
924
- { signal: timeoutSignal },
925
- ) as unknown as UnifiedStream);
989
+ : betas.length > 0
990
+ ? (this.client.beta.messages.stream(
991
+ {
992
+ ...(params as Record<string, unknown>),
993
+ betas,
994
+ } as Anthropic.Beta.Messages.MessageCreateParamsNonStreaming &
995
+ Anthropic.Beta.Messages.MessageCreateParamsStreaming,
996
+ { signal: timeoutSignal },
997
+ ) as unknown as UnifiedStream)
998
+ : (this.client.messages.stream(params, {
999
+ signal: timeoutSignal,
1000
+ }) as unknown as UnifiedStream);
926
1001
 
927
1002
  stream.on("text", (text) => {
928
1003
  onEvent?.({ type: "text_delta", text });
@@ -982,6 +1057,9 @@ export class AnthropicProvider implements Provider {
982
1057
  type: "server_tool_complete",
983
1058
  toolUseId: block.tool_use_id,
984
1059
  isError: !!isError,
1060
+ ...(Array.isArray(block.content)
1061
+ ? { content: block.content }
1062
+ : {}),
985
1063
  });
986
1064
  }
987
1065
  if (event.type === "content_block_stop") {
@@ -1063,6 +1141,12 @@ export class AnthropicProvider implements Provider {
1063
1141
  rawResponse: response,
1064
1142
  };
1065
1143
  } catch (error) {
1144
+ // Propagate a tagged AbortReason (set by the daemon at controller.abort())
1145
+ // so wrapped errors can be classified as user cancellation downstream.
1146
+ const abortReason =
1147
+ signal?.aborted && isAbortReason(signal.reason)
1148
+ ? signal.reason
1149
+ : undefined;
1066
1150
  if (error instanceof Anthropic.APIError) {
1067
1151
  // Log detailed message structure for tool_use/tool_result ordering errors
1068
1152
  if (
@@ -1078,20 +1162,33 @@ export class AnthropicProvider implements Provider {
1078
1162
  "Anthropic 400: tool_use/tool_result pairing error — dumping message structure",
1079
1163
  );
1080
1164
  }
1081
- log.error(
1082
- {
1083
- status: error.status,
1084
- message: error.message,
1085
- headers: Object.fromEntries(error.headers?.entries() ?? []),
1086
- },
1087
- `Anthropic API error (${error.status})`,
1088
- );
1165
+ if (abortReason) {
1166
+ log.info(
1167
+ { abortReason, message: error.message },
1168
+ "Anthropic request aborted by daemon",
1169
+ );
1170
+ } else {
1171
+ log.error(
1172
+ {
1173
+ status: error.status,
1174
+ message: error.message,
1175
+ headers: Object.fromEntries(error.headers?.entries() ?? []),
1176
+ },
1177
+ `Anthropic API error (${error.status})`,
1178
+ );
1179
+ }
1089
1180
  const retryAfterMs = extractRetryAfterMs(error.headers);
1181
+ const errorOptions: {
1182
+ retryAfterMs?: number;
1183
+ abortReason?: unknown;
1184
+ } = {};
1185
+ if (retryAfterMs !== undefined) errorOptions.retryAfterMs = retryAfterMs;
1186
+ if (abortReason) errorOptions.abortReason = abortReason;
1090
1187
  throw new ProviderError(
1091
1188
  `Anthropic API error (${error.status}): ${error.message}`,
1092
1189
  "anthropic",
1093
1190
  error.status,
1094
- retryAfterMs !== undefined ? { retryAfterMs } : undefined,
1191
+ Object.keys(errorOptions).length > 0 ? errorOptions : undefined,
1095
1192
  );
1096
1193
  }
1097
1194
  throw new ProviderError(
@@ -1100,7 +1197,7 @@ export class AnthropicProvider implements Provider {
1100
1197
  }`,
1101
1198
  "anthropic",
1102
1199
  undefined,
1103
- { cause: error },
1200
+ abortReason ? { cause: error, abortReason } : { cause: error },
1104
1201
  );
1105
1202
  }
1106
1203
  }
@@ -1,4 +1,4 @@
1
- import { OpenAIProvider } from "../openai/client.js";
1
+ import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
2
2
 
3
3
  export interface FireworksProviderOptions {
4
4
  apiKey?: string;
@@ -8,7 +8,7 @@ export interface FireworksProviderOptions {
8
8
 
9
9
  const DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1";
10
10
 
11
- export class FireworksProvider extends OpenAIProvider {
11
+ export class FireworksProvider extends OpenAIChatCompletionsProvider {
12
12
  constructor(
13
13
  apiKey: string,
14
14
  model: string,