@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
@@ -50,7 +50,15 @@ mock.module("../tools/registry.js", () => ({
50
50
  // ---------------------------------------------------------------------------
51
51
 
52
52
  let mockRefreshOAuth2Token: ReturnType<
53
- typeof mock<() => Promise<{ accessToken: string; expiresIn: number }>>
53
+ typeof mock<
54
+ (
55
+ tokenExchangeUrl: string,
56
+ clientId: string,
57
+ refreshToken: string,
58
+ clientSecret?: string,
59
+ tokenEndpointAuthMethod?: string,
60
+ ) => Promise<{ accessToken: string; expiresIn: number }>
61
+ >
54
62
  >;
55
63
 
56
64
  mock.module("../security/oauth2.js", () => {
@@ -74,7 +82,7 @@ const mockConnections = new Map<
74
82
  string,
75
83
  {
76
84
  id: string;
77
- providerKey: string;
85
+ provider: string;
78
86
  oauthAppId: string;
79
87
  expiresAt: number | null;
80
88
  }
@@ -83,7 +91,7 @@ const mockApps = new Map<
83
91
  string,
84
92
  {
85
93
  id: string;
86
- providerKey: string;
94
+ provider: string;
87
95
  clientId: string;
88
96
  clientSecretCredentialPath: string;
89
97
  }
@@ -92,21 +100,22 @@ const mockProviders = new Map<
92
100
  string,
93
101
  {
94
102
  key: string;
95
- tokenUrl: string;
103
+ tokenExchangeUrl: string;
104
+ refreshUrl?: string | null;
96
105
  tokenEndpointAuthMethod?: string;
97
106
  }
98
107
  >();
99
108
 
100
109
  let mockDisconnectOAuthProvider: ReturnType<
101
110
  typeof mock<
102
- (providerKey: string) => Promise<"disconnected" | "not-found" | "error">
111
+ (provider: string) => Promise<"disconnected" | "not-found" | "error">
103
112
  >
104
113
  >;
105
114
 
106
115
  mock.module("../oauth/oauth-store.js", () => {
107
- mockDisconnectOAuthProvider = mock((providerKey: string) =>
116
+ mockDisconnectOAuthProvider = mock((provider: string) =>
108
117
  Promise.resolve(
109
- mockConnections.has(providerKey)
118
+ mockConnections.has(provider)
110
119
  ? ("disconnected" as const)
111
120
  : ("not-found" as const),
112
121
  ),
@@ -746,7 +755,7 @@ describe("credential_store tool", () => {
746
755
  // Simulate an active OAuth connection for this service
747
756
  mockConnections.set("google", {
748
757
  id: "conn-gmail",
749
- providerKey: "google",
758
+ provider: "google",
750
759
  oauthAppId: "app-gmail",
751
760
  expiresAt: Date.now() + 3600_000,
752
761
  });
@@ -1303,7 +1312,7 @@ describe("withValidToken refresh deduplication", () => {
1303
1312
  * Helper: set up a service with an access token, refresh token, and
1304
1313
  * mock DB data so that token refresh can proceed through doRefresh().
1305
1314
  *
1306
- * OAuth-specific fields (tokenUrl, clientId, expiresAt) are now stored
1315
+ * OAuth-specific fields (tokenExchangeUrl, clientId, expiresAt) are now stored
1307
1316
  * in the SQLite oauth-store. The mock maps simulate the DB layer.
1308
1317
  */
1309
1318
  async function setupService(
@@ -1324,17 +1333,18 @@ describe("withValidToken refresh deduplication", () => {
1324
1333
  );
1325
1334
  mockProviders.set(service, {
1326
1335
  key: service,
1327
- tokenUrl: "https://oauth.example.com/token",
1336
+ tokenExchangeUrl: "https://oauth.example.com/token",
1337
+ refreshUrl: null,
1328
1338
  });
1329
1339
  mockApps.set(appId, {
1330
1340
  id: appId,
1331
- providerKey: service,
1341
+ provider: service,
1332
1342
  clientId: "test-client-id",
1333
1343
  clientSecretCredentialPath: `oauth_app/${appId}/client_secret`,
1334
1344
  });
1335
1345
  mockConnections.set(service, {
1336
1346
  id: connId,
1337
- providerKey: service,
1347
+ provider: service,
1338
1348
  oauthAppId: appId,
1339
1349
  expiresAt: opts?.expired
1340
1350
  ? Date.now() - 60_000 // expired 1 minute ago
@@ -1428,7 +1438,7 @@ describe("withValidToken refresh deduplication", () => {
1428
1438
  let refreshCallCount = 0;
1429
1439
  mockRefreshOAuth2Token.mockImplementation(() => {
1430
1440
  refreshCallCount++;
1431
- // Both services use the same tokenUrl in this test, so we track by
1441
+ // Both services use the same tokenExchangeUrl in this test, so we track by
1432
1442
  // call order to return the correct deferred promise.
1433
1443
  if (refreshCallCount === 1) return gmailPromise;
1434
1444
  return slackPromise;
@@ -1527,4 +1537,133 @@ describe("withValidToken refresh deduplication", () => {
1527
1537
  // Only one actual refresh attempt
1528
1538
  expect(mockRefreshOAuth2Token).toHaveBeenCalledTimes(1);
1529
1539
  });
1540
+
1541
+ // -----------------------------------------------------------------------
1542
+ // refreshUrl resolution — provider.refreshUrl with fallback to tokenExchangeUrl
1543
+ // -----------------------------------------------------------------------
1544
+ describe("refreshUrl resolution", () => {
1545
+ test("uses provider.refreshUrl when set", async () => {
1546
+ await setupService("google");
1547
+ mockProviders.get("google")!.refreshUrl =
1548
+ "https://refresh.example.com/token";
1549
+
1550
+ mockRefreshOAuth2Token.mockImplementation(() =>
1551
+ Promise.resolve({
1552
+ accessToken: "new-token-from-refresh-url",
1553
+ expiresIn: 3600,
1554
+ }),
1555
+ );
1556
+
1557
+ const err401 = Object.assign(new Error("Unauthorized"), { status: 401 });
1558
+
1559
+ const callback = async (token: string) => {
1560
+ if (token === "old-access-token") throw err401;
1561
+ return `result-with-${token}`;
1562
+ };
1563
+
1564
+ const result = await withValidToken("google", callback);
1565
+
1566
+ expect(result).toBe("result-with-new-token-from-refresh-url");
1567
+ expect(mockRefreshOAuth2Token).toHaveBeenCalledTimes(1);
1568
+ // Assert the refresh endpoint passed in is provider.refreshUrl, not
1569
+ // the tokenExchangeUrl fallback.
1570
+ expect(mockRefreshOAuth2Token.mock.calls[0]?.[0]).toBe(
1571
+ "https://refresh.example.com/token",
1572
+ );
1573
+ });
1574
+
1575
+ test("falls back to provider.tokenExchangeUrl when refreshUrl is null", async () => {
1576
+ // setupService sets refreshUrl: null by default — this exercises the
1577
+ // fallback path explicitly.
1578
+ await setupService("google");
1579
+ expect(mockProviders.get("google")!.refreshUrl).toBeNull();
1580
+
1581
+ mockRefreshOAuth2Token.mockImplementation(() =>
1582
+ Promise.resolve({
1583
+ accessToken: "new-token-from-token-exchange-url",
1584
+ expiresIn: 3600,
1585
+ }),
1586
+ );
1587
+
1588
+ const err401 = Object.assign(new Error("Unauthorized"), { status: 401 });
1589
+
1590
+ const callback = async (token: string) => {
1591
+ if (token === "old-access-token") throw err401;
1592
+ return `result-with-${token}`;
1593
+ };
1594
+
1595
+ const result = await withValidToken("google", callback);
1596
+
1597
+ expect(result).toBe("result-with-new-token-from-token-exchange-url");
1598
+ expect(mockRefreshOAuth2Token).toHaveBeenCalledTimes(1);
1599
+ // Assert the refresh endpoint falls back to tokenExchangeUrl.
1600
+ expect(mockRefreshOAuth2Token.mock.calls[0]?.[0]).toBe(
1601
+ "https://oauth.example.com/token",
1602
+ );
1603
+ });
1604
+
1605
+ test("falls back to provider.tokenExchangeUrl when refreshUrl is undefined", async () => {
1606
+ await setupService("google");
1607
+ // Delete the refreshUrl field entirely so the property is `undefined`
1608
+ // rather than `null`. Both representations of "not set" must produce
1609
+ // the fallback behavior.
1610
+ delete mockProviders.get("google")!.refreshUrl;
1611
+ expect(mockProviders.get("google")!.refreshUrl).toBeUndefined();
1612
+
1613
+ mockRefreshOAuth2Token.mockImplementation(() =>
1614
+ Promise.resolve({
1615
+ accessToken: "new-token-from-token-exchange-url",
1616
+ expiresIn: 3600,
1617
+ }),
1618
+ );
1619
+
1620
+ const err401 = Object.assign(new Error("Unauthorized"), { status: 401 });
1621
+
1622
+ const callback = async (token: string) => {
1623
+ if (token === "old-access-token") throw err401;
1624
+ return `result-with-${token}`;
1625
+ };
1626
+
1627
+ const result = await withValidToken("google", callback);
1628
+
1629
+ expect(result).toBe("result-with-new-token-from-token-exchange-url");
1630
+ expect(mockRefreshOAuth2Token).toHaveBeenCalledTimes(1);
1631
+ // Assert the refresh endpoint falls back to tokenExchangeUrl.
1632
+ expect(mockRefreshOAuth2Token.mock.calls[0]?.[0]).toBe(
1633
+ "https://oauth.example.com/token",
1634
+ );
1635
+ });
1636
+
1637
+ test("falls back to provider.tokenExchangeUrl when refreshUrl is empty string", async () => {
1638
+ // Platform's Python `oauth_app.refresh_url or oauth_app.token_exchange_url`
1639
+ // treats an empty string as unset. We use `||` (not `??`) so empty
1640
+ // strings follow the same fallback path and never resolve to an empty
1641
+ // endpoint.
1642
+ await setupService("google");
1643
+ mockProviders.get("google")!.refreshUrl = "";
1644
+
1645
+ mockRefreshOAuth2Token.mockImplementation(() =>
1646
+ Promise.resolve({
1647
+ accessToken: "new-token-from-token-exchange-url",
1648
+ expiresIn: 3600,
1649
+ }),
1650
+ );
1651
+
1652
+ const err401 = Object.assign(new Error("Unauthorized"), { status: 401 });
1653
+
1654
+ const callback = async (token: string) => {
1655
+ if (token === "old-access-token") throw err401;
1656
+ return `result-with-${token}`;
1657
+ };
1658
+
1659
+ const result = await withValidToken("google", callback);
1660
+
1661
+ expect(result).toBe("result-with-new-token-from-token-exchange-url");
1662
+ expect(mockRefreshOAuth2Token).toHaveBeenCalledTimes(1);
1663
+ // Assert the refresh endpoint falls back to tokenExchangeUrl — NOT "".
1664
+ expect(mockRefreshOAuth2Token.mock.calls[0]?.[0]).toBe(
1665
+ "https://oauth.example.com/token",
1666
+ );
1667
+ });
1668
+ });
1530
1669
  });
@@ -20,40 +20,64 @@ function nextUUID(): string {
20
20
  }
21
21
 
22
22
  // ---------------------------------------------------------------------------
23
- // Mock secure-keys
23
+ // Mock daemon-credential-client
24
+ //
25
+ // The credentials CLI routes secret read/write through the daemon HTTP API
26
+ // (see src/cli/lib/daemon-credential-client.ts). Mocking the daemon client
27
+ // directly is the cleanest way to isolate the CLI from the real daemon or a
28
+ // running daemon on localhost (which would otherwise be reached via the HTTP
29
+ // healthz fallback in daemon-credential-client).
24
30
  // ---------------------------------------------------------------------------
25
31
 
26
- mock.module("../security/secure-keys.js", () => ({
27
- setSecureKeyAsync: async (
28
- account: string,
32
+ function normalizeCredentialAccount(
33
+ type: string,
34
+ name: string,
35
+ ): string {
36
+ if (type !== "credential") return name;
37
+ if (name.startsWith("credential/")) return name;
38
+ const colonIdx = name.lastIndexOf(":");
39
+ if (colonIdx > 0 && colonIdx < name.length - 1) {
40
+ return `credential/${name.slice(0, colonIdx)}/${name.slice(colonIdx + 1)}`;
41
+ }
42
+ return name;
43
+ }
44
+
45
+ mock.module("../cli/lib/daemon-credential-client.js", () => ({
46
+ setSecureKeyViaDaemon: async (
47
+ type: string,
48
+ name: string,
29
49
  value: string,
30
50
  ): Promise<boolean> => {
31
- secureKeyStore.set(account, value);
51
+ secureKeyStore.set(normalizeCredentialAccount(type, name), value);
32
52
  return true;
33
53
  },
34
- deleteSecureKeyAsync: async (
35
- account: string,
54
+ deleteSecureKeyViaDaemon: async (
55
+ type: string,
56
+ name: string,
36
57
  ): Promise<"deleted" | "not-found" | "error"> => {
37
- if (secureKeyStore.has(account)) {
38
- secureKeyStore.delete(account);
58
+ const key = normalizeCredentialAccount(type, name);
59
+ if (secureKeyStore.has(key)) {
60
+ secureKeyStore.delete(key);
39
61
  return "deleted";
40
62
  }
41
63
  return "not-found";
42
64
  },
43
- listSecureKeysAsync: async () => ({
44
- accounts: [...secureKeyStore.keys()],
45
- unreachable: false,
46
- }),
47
- getSecureKeyAsync: async (account: string): Promise<string | undefined> => {
65
+ getSecureKeyViaDaemon: async (
66
+ account: string,
67
+ ): Promise<string | undefined> => {
48
68
  return secureKeyStore.get(account);
49
69
  },
50
- getSecureKeyResultAsync: async (
70
+ getSecureKeyResultViaDaemon: async (
51
71
  account: string,
52
72
  ): Promise<{ value: string | undefined; unreachable: boolean }> => ({
53
73
  value: secureKeyStore.get(account),
54
74
  unreachable: mockBrokerUnreachable,
55
75
  }),
56
- _resetBackend: (): void => {},
76
+ getProviderKeyViaDaemon: async (
77
+ provider: string,
78
+ ): Promise<string | undefined> => {
79
+ return secureKeyStore.get(provider);
80
+ },
57
81
  }));
58
82
 
59
83
  // ---------------------------------------------------------------------------
@@ -148,9 +172,9 @@ let disconnectOAuthProviderResult: "disconnected" | "not-found" | "error" =
148
172
 
149
173
  mock.module("../oauth/oauth-store.js", () => ({
150
174
  disconnectOAuthProvider: async (
151
- providerKey: string,
175
+ provider: string,
152
176
  ): Promise<"disconnected" | "not-found" | "error"> => {
153
- disconnectOAuthProviderCalls.push(providerKey);
177
+ disconnectOAuthProviderCalls.push(provider);
154
178
  return disconnectOAuthProviderResult;
155
179
  },
156
180
  getConnectionByProvider: (): undefined => undefined,
@@ -89,7 +89,8 @@ function webSearchResultOnlyMessage(): Message[] {
89
89
  // Mock OpenAI SDK
90
90
  // ---------------------------------------------------------------------------
91
91
 
92
- let lastOpenAIParams: Record<string, unknown> | null = null;
92
+ let lastOpenAIResponsesParams: Record<string, unknown> | null = null;
93
+ let lastOpenAIChatParams: Record<string, unknown> | null = null;
93
94
 
94
95
  mock.module("openai", () => {
95
96
  class FakeAPIError extends Error {
@@ -110,7 +111,7 @@ mock.module("openai", () => {
110
111
  chat = {
111
112
  completions: {
112
113
  create: (params: Record<string, unknown>) => {
113
- lastOpenAIParams = JSON.parse(JSON.stringify(params));
114
+ lastOpenAIChatParams = JSON.parse(JSON.stringify(params));
114
115
  return (async function* () {
115
116
  yield {
116
117
  choices: [
@@ -126,6 +127,28 @@ mock.module("openai", () => {
126
127
  },
127
128
  },
128
129
  };
130
+ responses = {
131
+ stream: (params: Record<string, unknown>) => {
132
+ lastOpenAIResponsesParams = JSON.parse(JSON.stringify(params));
133
+ return (async function* () {
134
+ yield {
135
+ type: "response.output_text.delta",
136
+ delta: "OK",
137
+ };
138
+ yield {
139
+ type: "response.completed",
140
+ response: {
141
+ model: "gpt-4o",
142
+ status: "completed",
143
+ usage: {
144
+ input_tokens: 10,
145
+ output_tokens: 5,
146
+ },
147
+ },
148
+ };
149
+ })();
150
+ },
151
+ };
129
152
  },
130
153
  };
131
154
  });
@@ -172,60 +195,137 @@ mock.module("@google/genai", () => {
172
195
 
173
196
  // Import providers after mocking
174
197
  import { GeminiProvider } from "../providers/gemini/client.js";
175
- import { OpenAIProvider } from "../providers/openai/client.js";
198
+ import {
199
+ OpenAIChatCompletionsProvider,
200
+ OpenAIResponsesProvider,
201
+ } from "../providers/openai/client.js";
176
202
 
177
203
  // ---------------------------------------------------------------------------
178
- // OpenAI provider tests
204
+ // OpenAI Responses API provider tests
179
205
  // ---------------------------------------------------------------------------
180
206
 
181
- describe("Cross-Provider Web Search — OpenAI", () => {
207
+ describe("Cross-Provider Web Search — OpenAI (Responses API)", () => {
182
208
  beforeEach(() => {
183
- lastOpenAIParams = null;
209
+ lastOpenAIResponsesParams = null;
184
210
  });
185
211
 
186
- test("degrades server_tool_use in assistant message to text placeholder", async () => {
187
- const provider = new OpenAIProvider("sk-test", "gpt-4o");
212
+ test("degrades server_tool_use in assistant message to text placeholder in Responses input", async () => {
213
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o");
188
214
  await provider.sendMessage(webSearchConversation());
189
215
 
190
- const messages = lastOpenAIParams!.messages as Array<{
191
- role: string;
192
- content: unknown;
216
+ const input = lastOpenAIResponsesParams!.input as Array<{
217
+ type: string;
218
+ role?: string;
219
+ content?: Array<{ type: string; text?: string }>;
193
220
  }>;
194
221
 
195
- const assistantMsg = messages.find((m) => m.role === "assistant");
196
- expect(assistantMsg).toBeDefined();
197
- expect(assistantMsg!.content).toContain("[Web search: web_search]");
198
- expect(assistantMsg!.content).toContain("Here are the results.");
222
+ const assistantItems = input.filter(
223
+ (item) => item.type === "message" && item.role === "assistant",
224
+ );
225
+ const hasWebSearchPlaceholder = assistantItems.some((item) =>
226
+ item.content?.some(
227
+ (part) =>
228
+ part.type === "output_text" &&
229
+ part.text?.includes("[Web search: web_search]"),
230
+ ),
231
+ );
232
+ expect(hasWebSearchPlaceholder).toBe(true);
233
+
234
+ const hasResultsText = assistantItems.some((item) =>
235
+ item.content?.some(
236
+ (part) =>
237
+ part.type === "output_text" &&
238
+ part.text?.includes("Here are the results."),
239
+ ),
240
+ );
241
+ expect(hasResultsText).toBe(true);
199
242
  });
200
243
 
201
- test("degrades web_search_tool_result in user message to text placeholder", async () => {
202
- const provider = new OpenAIProvider("sk-test", "gpt-4o");
244
+ test("degrades web_search_tool_result in user message to text placeholder in Responses input", async () => {
245
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o");
203
246
  await provider.sendMessage(webSearchConversation());
204
247
 
205
- const messages = lastOpenAIParams!.messages as Array<{
206
- role: string;
207
- content: unknown;
248
+ const input = lastOpenAIResponsesParams!.input as Array<{
249
+ type: string;
250
+ role?: string;
251
+ content?: Array<{ type: string; text?: string }>;
208
252
  }>;
209
253
 
210
- const userMsgs = messages.filter((m) => m.role === "user");
211
- const hasWebSearchResult = userMsgs.some((m) => {
212
- if (typeof m.content === "string") return false;
213
- if (Array.isArray(m.content)) {
214
- return (m.content as Array<{ type: string; text?: string }>).some(
215
- (part) =>
216
- part.type === "text" && part.text === "[Web search results]",
217
- );
218
- }
219
- return false;
220
- });
254
+ const userItems = input.filter(
255
+ (item) => item.type === "message" && item.role === "user",
256
+ );
257
+ const hasWebSearchResult = userItems.some((item) =>
258
+ item.content?.some(
259
+ (part) =>
260
+ part.type === "input_text" && part.text === "[Web search results]",
261
+ ),
262
+ );
221
263
  expect(hasWebSearchResult).toBe(true);
222
264
  });
223
265
 
224
266
  test("handles message containing only web_search_tool_result", async () => {
225
- const provider = new OpenAIProvider("sk-test", "gpt-4o");
267
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o");
226
268
  await provider.sendMessage(webSearchResultOnlyMessage());
227
269
 
228
- const messages = lastOpenAIParams!.messages as Array<{
270
+ const input = lastOpenAIResponsesParams!.input as Array<{
271
+ type: string;
272
+ role?: string;
273
+ content?: Array<{ type: string; text?: string }>;
274
+ }>;
275
+
276
+ const assistantItems = input.filter(
277
+ (item) => item.type === "message" && item.role === "assistant",
278
+ );
279
+ const hasWebSearchPlaceholder = assistantItems.some((item) =>
280
+ item.content?.some(
281
+ (part) =>
282
+ part.type === "output_text" &&
283
+ part.text?.includes("[Web search: web_search]"),
284
+ ),
285
+ );
286
+ expect(hasWebSearchPlaceholder).toBe(true);
287
+
288
+ const userItems = input.filter(
289
+ (item) => item.type === "message" && item.role === "user",
290
+ );
291
+ const hasWebSearchResult = userItems.some((item) =>
292
+ item.content?.some(
293
+ (part) =>
294
+ part.type === "input_text" && part.text === "[Web search results]",
295
+ ),
296
+ );
297
+ expect(hasWebSearchResult).toBe(true);
298
+ });
299
+
300
+ test("does not produce function_call items for server_tool_use blocks", async () => {
301
+ const provider = new OpenAIResponsesProvider("sk-test", "gpt-4o");
302
+ await provider.sendMessage(webSearchConversation());
303
+
304
+ const input = lastOpenAIResponsesParams!.input as Array<{
305
+ type: string;
306
+ }>;
307
+
308
+ const functionCallItems = input.filter(
309
+ (item) => item.type === "function_call",
310
+ );
311
+ expect(functionCallItems).toHaveLength(0);
312
+ });
313
+ });
314
+
315
+ // ---------------------------------------------------------------------------
316
+ // OpenAI Chat Completions compatibility provider tests
317
+ // ---------------------------------------------------------------------------
318
+
319
+ describe("Cross-Provider Web Search — OpenAI Chat Completions (compatibility)", () => {
320
+ beforeEach(() => {
321
+ lastOpenAIChatParams = null;
322
+ });
323
+
324
+ test("degrades server_tool_use in assistant message to text placeholder", async () => {
325
+ const provider = new OpenAIChatCompletionsProvider("sk-test", "gpt-4o");
326
+ await provider.sendMessage(webSearchConversation());
327
+
328
+ const messages = lastOpenAIChatParams!.messages as Array<{
229
329
  role: string;
230
330
  content: unknown;
231
331
  }>;
@@ -233,6 +333,17 @@ describe("Cross-Provider Web Search — OpenAI", () => {
233
333
  const assistantMsg = messages.find((m) => m.role === "assistant");
234
334
  expect(assistantMsg).toBeDefined();
235
335
  expect(assistantMsg!.content).toContain("[Web search: web_search]");
336
+ expect(assistantMsg!.content).toContain("Here are the results.");
337
+ });
338
+
339
+ test("degrades web_search_tool_result in user message to text placeholder", async () => {
340
+ const provider = new OpenAIChatCompletionsProvider("sk-test", "gpt-4o");
341
+ await provider.sendMessage(webSearchConversation());
342
+
343
+ const messages = lastOpenAIChatParams!.messages as Array<{
344
+ role: string;
345
+ content: unknown;
346
+ }>;
236
347
 
237
348
  const userMsgs = messages.filter((m) => m.role === "user");
238
349
  const hasWebSearchResult = userMsgs.some((m) => {
@@ -249,10 +360,10 @@ describe("Cross-Provider Web Search — OpenAI", () => {
249
360
  });
250
361
 
251
362
  test("does not produce tool_calls for server_tool_use blocks", async () => {
252
- const provider = new OpenAIProvider("sk-test", "gpt-4o");
363
+ const provider = new OpenAIChatCompletionsProvider("sk-test", "gpt-4o");
253
364
  await provider.sendMessage(webSearchConversation());
254
365
 
255
- const messages = lastOpenAIParams!.messages as Array<{
366
+ const messages = lastOpenAIChatParams!.messages as Array<{
256
367
  role: string;
257
368
  tool_calls?: unknown[];
258
369
  }>;
@@ -115,7 +115,7 @@ describe("formatTurnTimestamp", () => {
115
115
  timeZone: "America/Chicago",
116
116
  });
117
117
  expect(result).toBe(
118
- "2026-04-02 (Thu) 01:52:33 -05:00 (America/Chicago)",
118
+ "2026-04-02 (Thursday) 01:52:33 -05:00 (America/Chicago)",
119
119
  );
120
120
  });
121
121
 
@@ -124,7 +124,7 @@ describe("formatTurnTimestamp", () => {
124
124
  nowMs: THU_APR_02_0652,
125
125
  hostTimeZone: "UTC",
126
126
  });
127
- expect(result).toBe("2026-04-02 (Thu) 06:52:33 +00:00 (UTC)");
127
+ expect(result).toBe("2026-04-02 (Thursday) 06:52:33 +00:00 (UTC)");
128
128
  });
129
129
 
130
130
  test("handles user timezone override", () => {
@@ -133,7 +133,7 @@ describe("formatTurnTimestamp", () => {
133
133
  hostTimeZone: "UTC",
134
134
  userTimeZone: "Asia/Tokyo",
135
135
  });
136
- expect(result).toBe("2026-04-02 (Thu) 15:52:33 +09:00 (Asia/Tokyo)");
136
+ expect(result).toBe("2026-04-02 (Thursday) 15:52:33 +09:00 (Asia/Tokyo)");
137
137
  });
138
138
 
139
139
  test("handles DST correctly", () => {
@@ -144,7 +144,7 @@ describe("formatTurnTimestamp", () => {
144
144
  timeZone: "America/New_York",
145
145
  });
146
146
  expect(result).toBe(
147
- "2026-07-01 (Wed) 08:00:30 -04:00 (America/New_York)",
147
+ "2026-07-01 (Wednesday) 08:00:30 -04:00 (America/New_York)",
148
148
  );
149
149
  });
150
150
 
@@ -31,6 +31,7 @@ mock.module("../config/env.js", () => ({
31
31
  // Imports (after mocks)
32
32
  // ---------------------------------------------------------------------------
33
33
 
34
+ import type { TwilioRelaySpeechConfig } from "../calls/twilio-routes.js";
34
35
  import { generateTwiML } from "../calls/twilio-routes.js";
35
36
  import { initializeDb } from "../memory/db-init.js";
36
37
  import {
@@ -100,9 +101,14 @@ describe("Channel verification reply templates", () => {
100
101
  describe("TwiML parameter propagation", () => {
101
102
  const defaultProfile = {
102
103
  language: "en-US",
103
- transcriptionProvider: "deepgram",
104
104
  ttsProvider: "google",
105
105
  voice: "en-US-Standard-A",
106
+ };
107
+
108
+ const defaultSpeechConfig: TwilioRelaySpeechConfig = {
109
+ transcriptionProvider: "deepgram",
110
+ speechModel: undefined,
111
+ hints: undefined,
106
112
  interruptSensitivity: "low",
107
113
  };
108
114
 
@@ -112,6 +118,7 @@ describe("TwiML parameter propagation", () => {
112
118
  "wss://example.com/v1/calls/relay",
113
119
  null,
114
120
  defaultProfile,
121
+ defaultSpeechConfig,
115
122
  undefined,
116
123
  { verificationSessionId: "gv-session-456" },
117
124
  );
@@ -126,6 +133,7 @@ describe("TwiML parameter propagation", () => {
126
133
  "wss://example.com/v1/calls/relay",
127
134
  null,
128
135
  defaultProfile,
136
+ defaultSpeechConfig,
129
137
  );
130
138
  expect(twiml).not.toContain("<Parameter");
131
139
  });
@@ -136,6 +144,7 @@ describe("TwiML parameter propagation", () => {
136
144
  "wss://example.com/v1/calls/relay",
137
145
  null,
138
146
  defaultProfile,
147
+ defaultSpeechConfig,
139
148
  "token123",
140
149
  undefined,
141
150
  );