@vellumai/assistant 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (667) hide show
  1. package/ARCHITECTURE.md +273 -10
  2. package/Dockerfile +2 -3
  3. package/bun.lock +5 -13
  4. package/docs/backup-troubleshooting.md +52 -0
  5. package/docs/browser-use-architecture-phase2.md +174 -0
  6. package/docs/stt-provider-onboarding.md +120 -0
  7. package/knip.json +12 -2
  8. package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
  9. package/node_modules/@vellumai/ces-contracts/package.json +3 -3
  10. package/openapi.yaml +982 -72
  11. package/package.json +4 -6
  12. package/scripts/generate-openapi.ts +0 -1
  13. package/scripts/test.sh +73 -18
  14. package/src/__tests__/agent-image-optimize.test.ts +28 -0
  15. package/src/__tests__/agent-loop.test.ts +123 -0
  16. package/src/__tests__/anthropic-provider.test.ts +263 -10
  17. package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
  18. package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
  19. package/src/__tests__/browser-fill-credential.test.ts +11 -0
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/browser-skill-endstate.test.ts +31 -7
  22. package/src/__tests__/btw-routes.test.ts +7 -0
  23. package/src/__tests__/call-controller.test.ts +581 -20
  24. package/src/__tests__/catalog-files.test.ts +138 -0
  25. package/src/__tests__/channel-invite-transport.test.ts +2 -2
  26. package/src/__tests__/channel-readiness-routes.test.ts +16 -20
  27. package/src/__tests__/channel-readiness-service.test.ts +12 -7
  28. package/src/__tests__/checker.test.ts +157 -10
  29. package/src/__tests__/clawhub-files.test.ts +347 -0
  30. package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
  31. package/src/__tests__/config-analysis.test.ts +100 -0
  32. package/src/__tests__/config-schema.test.ts +1013 -66
  33. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
  34. package/src/__tests__/config-watcher.test.ts +43 -8
  35. package/src/__tests__/contact-store-user-file.test.ts +512 -0
  36. package/src/__tests__/contacts-write.test.ts +197 -0
  37. package/src/__tests__/context-window-manager.test.ts +88 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  40. package/src/__tests__/conversation-agent-loop.test.ts +98 -2
  41. package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
  42. package/src/__tests__/conversation-error.test.ts +70 -0
  43. package/src/__tests__/conversation-history-web-search.test.ts +11 -4
  44. package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
  45. package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
  46. package/src/__tests__/conversation-list-source.test.ts +145 -0
  47. package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
  48. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  49. package/src/__tests__/conversation-queue.test.ts +901 -60
  50. package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
  51. package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
  52. package/src/__tests__/conversation-skill-tools.test.ts +7 -4
  53. package/src/__tests__/conversation-slash-commands.test.ts +33 -0
  54. package/src/__tests__/conversation-slash-queue.test.ts +89 -18
  55. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  56. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  59. package/src/__tests__/credential-health-service.test.ts +352 -0
  60. package/src/__tests__/credential-security-invariants.test.ts +5 -3
  61. package/src/__tests__/credential-vault-unit.test.ts +379 -3
  62. package/src/__tests__/credentials-cli.test.ts +40 -16
  63. package/src/__tests__/cross-provider-web-search.test.ts +146 -35
  64. package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
  65. package/src/__tests__/device-id.test.ts +112 -0
  66. package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
  67. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
  68. package/src/__tests__/email-html-renderer.test.ts +71 -0
  69. package/src/__tests__/email-invite-adapter.test.ts +36 -32
  70. package/src/__tests__/emit-event-signal.test.ts +71 -0
  71. package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
  72. package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
  73. package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
  74. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  75. package/src/__tests__/gemini-provider.test.ts +64 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
  77. package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
  78. package/src/__tests__/gmail-archive-gate.test.ts +246 -0
  79. package/src/__tests__/gmail-preferences.test.ts +117 -0
  80. package/src/__tests__/headless-browser-interactions.test.ts +43 -0
  81. package/src/__tests__/headless-browser-mode.test.ts +614 -0
  82. package/src/__tests__/headless-browser-navigate.test.ts +142 -5
  83. package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
  84. package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
  85. package/src/__tests__/heartbeat-service.test.ts +70 -17
  86. package/src/__tests__/home-state-routes.test.ts +162 -0
  87. package/src/__tests__/host-bash-proxy.test.ts +0 -5
  88. package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
  89. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
  90. package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
  91. package/src/__tests__/host-cu-proxy.test.ts +0 -5
  92. package/src/__tests__/identity-intro-cache.test.ts +40 -10
  93. package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
  94. package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
  95. package/src/__tests__/llm-context-normalization.test.ts +488 -0
  96. package/src/__tests__/llm-context-route-provider.test.ts +86 -5
  97. package/src/__tests__/llm-usage-store.test.ts +363 -0
  98. package/src/__tests__/media-stream-output.test.ts +555 -0
  99. package/src/__tests__/media-stream-parser.test.ts +374 -0
  100. package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
  101. package/src/__tests__/media-stream-stt-session.test.ts +588 -0
  102. package/src/__tests__/media-turn-detector.test.ts +440 -0
  103. package/src/__tests__/message-queue.test.ts +125 -0
  104. package/src/__tests__/migration-export-http.test.ts +6 -6
  105. package/src/__tests__/migration-import-commit-http.test.ts +8 -6
  106. package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
  107. package/src/__tests__/migration-validate-http.test.ts +3 -3
  108. package/src/__tests__/mock-gateway-ipc.ts +151 -0
  109. package/src/__tests__/model-intents.test.ts +2 -2
  110. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  111. package/src/__tests__/oauth-cli.test.ts +2 -0
  112. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +2 -0
  115. package/src/__tests__/oauth-store.test.ts +85 -0
  116. package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
  117. package/src/__tests__/onboarding-template-contract.test.ts +6 -13
  118. package/src/__tests__/openai-provider.test.ts +176 -0
  119. package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
  120. package/src/__tests__/openai-responses-provider.test.ts +1105 -0
  121. package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
  122. package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
  123. package/src/__tests__/persona-resolver.test.ts +251 -0
  124. package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
  125. package/src/__tests__/platform.test.ts +92 -1
  126. package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
  127. package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
  128. package/src/__tests__/pricing.test.ts +174 -0
  129. package/src/__tests__/qdrant-manager.test.ts +29 -8
  130. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
  131. package/src/__tests__/relationship-state-contract.test.ts +175 -0
  132. package/src/__tests__/relay-server.test.ts +423 -5
  133. package/src/__tests__/search-skills-unified.test.ts +118 -0
  134. package/src/__tests__/secret-scanner-executor.test.ts +4 -0
  135. package/src/__tests__/secure-keys.test.ts +107 -0
  136. package/src/__tests__/send-endpoint-busy.test.ts +5 -1
  137. package/src/__tests__/sequence-store.test.ts +1 -1
  138. package/src/__tests__/server-history-render.test.ts +49 -0
  139. package/src/__tests__/settings-routes.test.ts +201 -0
  140. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  141. package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
  142. package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
  143. package/src/__tests__/skills.test.ts +5 -2
  144. package/src/__tests__/skillssh-files.test.ts +446 -0
  145. package/src/__tests__/slack-block-formatting.test.ts +110 -0
  146. package/src/__tests__/slack-channel-config.test.ts +564 -1
  147. package/src/__tests__/stt-catalog-parity.test.ts +282 -0
  148. package/src/__tests__/stt-stream-session.test.ts +535 -0
  149. package/src/__tests__/system-prompt.test.ts +112 -26
  150. package/src/__tests__/telephony-stt-routing.test.ts +329 -0
  151. package/src/__tests__/terminal-tools.test.ts +18 -7
  152. package/src/__tests__/test-preload.ts +18 -0
  153. package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
  155. package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
  156. package/src/__tests__/tool-executor.test.ts +33 -24
  157. package/src/__tests__/tool-result-truncation.test.ts +36 -0
  158. package/src/__tests__/trust-store.test.ts +7 -1
  159. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
  160. package/src/__tests__/tts-catalog-parity.test.ts +345 -0
  161. package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
  162. package/src/__tests__/twilio-routes.test.ts +376 -0
  163. package/src/__tests__/unicode.test.ts +293 -0
  164. package/src/__tests__/update-bulletin-format.test.ts +59 -0
  165. package/src/__tests__/update-bulletin.test.ts +206 -5
  166. package/src/__tests__/usage-routes.test.ts +25 -4
  167. package/src/__tests__/user-reference.test.ts +46 -61
  168. package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
  169. package/src/__tests__/voice-config-update.test.ts +403 -0
  170. package/src/__tests__/voice-quality.test.ts +434 -19
  171. package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
  172. package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
  173. package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
  174. package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
  175. package/src/__tests__/workspace-migration-meets.test.ts +244 -0
  176. package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
  177. package/src/__tests__/workspace-policy.test.ts +2 -0
  178. package/src/agent/image-optimize.ts +24 -12
  179. package/src/agent/loop.ts +43 -3
  180. package/src/backup/__tests__/backup-key.test.ts +152 -0
  181. package/src/backup/__tests__/backup-worker.test.ts +767 -0
  182. package/src/backup/__tests__/list-snapshots.test.ts +87 -0
  183. package/src/backup/__tests__/local-writer.test.ts +218 -0
  184. package/src/backup/__tests__/offsite-writer.test.ts +641 -0
  185. package/src/backup/__tests__/paths.test.ts +300 -0
  186. package/src/backup/__tests__/restore.test.ts +498 -0
  187. package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
  188. package/src/backup/__tests__/stream-crypt.test.ts +228 -0
  189. package/src/backup/backup-key.ts +137 -0
  190. package/src/backup/backup-worker.ts +459 -0
  191. package/src/backup/list-snapshots.ts +147 -0
  192. package/src/backup/local-writer.ts +133 -0
  193. package/src/backup/offsite-writer.ts +222 -0
  194. package/src/backup/paths.ts +226 -0
  195. package/src/backup/restore.ts +322 -0
  196. package/src/backup/snapshot-lock.ts +431 -0
  197. package/src/backup/stream-crypt.ts +263 -0
  198. package/src/bundler/package-resolver.ts +4 -0
  199. package/src/calls/audio-store.ts +11 -5
  200. package/src/calls/call-controller.ts +226 -71
  201. package/src/calls/call-domain.ts +9 -0
  202. package/src/calls/call-speech-output.ts +190 -0
  203. package/src/calls/call-transport.ts +77 -0
  204. package/src/calls/media-stream-audio-transcode.ts +173 -0
  205. package/src/calls/media-stream-output.ts +660 -0
  206. package/src/calls/media-stream-parser.ts +300 -0
  207. package/src/calls/media-stream-protocol.ts +166 -0
  208. package/src/calls/media-stream-server.ts +592 -0
  209. package/src/calls/media-stream-stt-session.ts +460 -0
  210. package/src/calls/media-turn-detector.ts +230 -0
  211. package/src/calls/relay-server.ts +90 -75
  212. package/src/calls/resolve-call-tts-provider.ts +136 -0
  213. package/src/calls/telephony-stt-routing.ts +145 -0
  214. package/src/calls/tts-call-strategy.ts +161 -0
  215. package/src/calls/tts-text-sanitizer.ts +32 -16
  216. package/src/calls/twilio-routes.ts +281 -17
  217. package/src/calls/voice-quality.ts +78 -35
  218. package/src/calls/voice-session-bridge.ts +8 -1
  219. package/src/channels/types.ts +16 -0
  220. package/src/cli/__tests__/run-assistant-command.ts +11 -1
  221. package/src/cli/commands/__tests__/backup.test.ts +1165 -0
  222. package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
  223. package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
  224. package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
  225. package/src/cli/commands/__tests__/email-download.test.ts +16 -1
  226. package/src/cli/commands/__tests__/email-list.test.ts +22 -4
  227. package/src/cli/commands/__tests__/email-register.test.ts +4 -4
  228. package/src/cli/commands/__tests__/email-send.test.ts +37 -4
  229. package/src/cli/commands/__tests__/email-status.test.ts +5 -1
  230. package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
  231. package/src/cli/commands/backup.ts +993 -0
  232. package/src/cli/commands/conversations.ts +77 -0
  233. package/src/cli/commands/credentials.ts +0 -1
  234. package/src/cli/commands/domain.ts +210 -0
  235. package/src/cli/commands/email.ts +255 -3
  236. package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
  237. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
  238. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
  239. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
  240. package/src/cli/commands/oauth/mode.ts +12 -3
  241. package/src/cli/commands/oauth/providers.ts +15 -0
  242. package/src/cli/commands/oauth/shared.ts +2 -1
  243. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
  244. package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
  245. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  246. package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
  247. package/src/cli/program.ts +30 -4
  248. package/src/config/__tests__/backup-schema.test.ts +134 -0
  249. package/src/config/assistant-feature-flags.ts +61 -62
  250. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
  251. package/src/config/bundled-skills/browser/SKILL.md +30 -5
  252. package/src/config/bundled-skills/browser/TOOLS.json +123 -0
  253. package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
  254. package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
  255. package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
  256. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +2 -2
  258. package/src/config/bundled-skills/gmail/SKILL.md +53 -7
  259. package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
  260. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
  261. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
  262. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
  263. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
  264. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
  265. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
  266. package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
  267. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
  268. package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
  269. package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
  270. package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
  271. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
  272. package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
  273. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
  274. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  275. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  276. package/src/config/bundled-skills/outlook/SKILL.md +2 -2
  277. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
  278. package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
  279. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
  280. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
  281. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  282. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
  283. package/src/config/bundled-skills/slack/SKILL.md +1 -0
  284. package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
  285. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
  286. package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
  287. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
  288. package/src/config/bundled-tool-registry.ts +8 -0
  289. package/src/config/env-registry.ts +24 -0
  290. package/src/config/env.ts +34 -10
  291. package/src/config/feature-flag-registry.json +46 -14
  292. package/src/config/loader.ts +26 -12
  293. package/src/config/schema.ts +35 -10
  294. package/src/config/schemas/__tests__/stt.test.ts +43 -0
  295. package/src/config/schemas/analysis.ts +51 -0
  296. package/src/config/schemas/backup.ts +72 -0
  297. package/src/config/schemas/calls.ts +1 -26
  298. package/src/config/schemas/elevenlabs.ts +0 -59
  299. package/src/config/schemas/filing.ts +47 -7
  300. package/src/config/schemas/heartbeat.ts +27 -5
  301. package/src/config/schemas/host-browser.ts +47 -1
  302. package/src/config/schemas/inference.ts +1 -1
  303. package/src/config/schemas/memory-lifecycle.ts +14 -2
  304. package/src/config/schemas/services.ts +44 -0
  305. package/src/config/schemas/stt.ts +59 -0
  306. package/src/config/schemas/tts.ts +230 -0
  307. package/src/config/schemas/updates.ts +14 -0
  308. package/src/config/skills.ts +4 -0
  309. package/src/config/types.ts +4 -0
  310. package/src/contacts/contact-store.ts +56 -11
  311. package/src/contacts/contacts-write.ts +38 -1
  312. package/src/context/post-turn-tool-result-truncation.ts +3 -2
  313. package/src/context/tool-result-truncation.ts +2 -1
  314. package/src/context/window-manager.ts +45 -12
  315. package/src/credential-execution/executable-discovery.ts +12 -2
  316. package/src/credential-execution/process-manager.ts +33 -2
  317. package/src/credential-health/credential-health-service.ts +366 -0
  318. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
  319. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
  320. package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
  321. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
  322. package/src/daemon/config-watcher.ts +99 -5
  323. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  324. package/src/daemon/conversation-agent-loop.ts +101 -24
  325. package/src/daemon/conversation-error.ts +11 -0
  326. package/src/daemon/conversation-history.ts +40 -6
  327. package/src/daemon/conversation-launch.ts +220 -0
  328. package/src/daemon/conversation-lifecycle.ts +59 -9
  329. package/src/daemon/conversation-messaging.ts +37 -3
  330. package/src/daemon/conversation-notifiers.ts +5 -0
  331. package/src/daemon/conversation-process.ts +581 -19
  332. package/src/daemon/conversation-queue-manager.ts +24 -0
  333. package/src/daemon/conversation-runtime-assembly.ts +11 -1
  334. package/src/daemon/conversation-slash.ts +36 -0
  335. package/src/daemon/conversation-surfaces.ts +94 -4
  336. package/src/daemon/conversation-tool-setup.ts +25 -0
  337. package/src/daemon/conversation-usage.ts +7 -4
  338. package/src/daemon/conversation.ts +86 -28
  339. package/src/daemon/handlers/config-slack-channel.ts +269 -94
  340. package/src/daemon/handlers/conversations.ts +4 -1
  341. package/src/daemon/handlers/shared.ts +22 -0
  342. package/src/daemon/handlers/skills.ts +321 -77
  343. package/src/daemon/host-browser-proxy.ts +2 -1
  344. package/src/daemon/lifecycle.ts +122 -25
  345. package/src/daemon/message-protocol.ts +6 -0
  346. package/src/daemon/message-types/conversations.ts +34 -1
  347. package/src/daemon/message-types/home.ts +40 -0
  348. package/src/daemon/message-types/meet.ts +143 -0
  349. package/src/daemon/message-types/messages.ts +14 -0
  350. package/src/daemon/message-types/schedules.ts +34 -2
  351. package/src/daemon/message-types/skills.ts +16 -0
  352. package/src/daemon/message-types/surfaces.ts +2 -0
  353. package/src/daemon/server.ts +347 -2
  354. package/src/daemon/shutdown-handlers.ts +32 -4
  355. package/src/daemon/shutdown-registry.ts +40 -0
  356. package/src/daemon/tool-side-effects.ts +9 -0
  357. package/src/email/html-renderer.ts +76 -0
  358. package/src/heartbeat/heartbeat-service.ts +93 -7
  359. package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
  360. package/src/home/__tests__/emit-feed-event.test.ts +169 -0
  361. package/src/home/__tests__/feed-scheduler.test.ts +194 -0
  362. package/src/home/__tests__/feed-types.test.ts +275 -0
  363. package/src/home/__tests__/feed-writer.test.ts +688 -0
  364. package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
  365. package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
  366. package/src/home/__tests__/progress-formula.test.ts +213 -0
  367. package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
  368. package/src/home/__tests__/rollup-producer.test.ts +398 -0
  369. package/src/home/assistant-feed-authoring.ts +124 -0
  370. package/src/home/emit-feed-event.ts +158 -0
  371. package/src/home/feed-scheduler.ts +247 -0
  372. package/src/home/feed-types.ts +181 -0
  373. package/src/home/feed-writer.ts +469 -0
  374. package/src/home/platform-gmail-digest.ts +163 -0
  375. package/src/home/progress-formula.ts +86 -0
  376. package/src/home/relationship-state-writer.ts +824 -0
  377. package/src/home/relationship-state.ts +143 -0
  378. package/src/home/rollup-producer.ts +384 -0
  379. package/src/hooks/runner.ts +7 -0
  380. package/src/inbound/platform-callback-registration.ts +12 -3
  381. package/src/inbound/public-ingress-urls.ts +12 -0
  382. package/src/instrument.ts +1 -1
  383. package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
  384. package/src/ipc/cli-client.ts +151 -0
  385. package/src/ipc/cli-server.ts +234 -0
  386. package/src/ipc/gateway-client.ts +180 -0
  387. package/src/ipc/routes/index.ts +5 -0
  388. package/src/ipc/routes/wake-conversation.ts +19 -0
  389. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
  390. package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
  391. package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
  392. package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
  393. package/src/memory/app-store.ts +1 -1
  394. package/src/memory/attachments-store.ts +70 -0
  395. package/src/memory/auto-analysis-enqueue.ts +127 -0
  396. package/src/memory/auto-analysis-guard.ts +27 -0
  397. package/src/memory/cleanup-schedule-state.ts +37 -0
  398. package/src/memory/conversation-analyze-job.ts +73 -0
  399. package/src/memory/conversation-crud.ts +99 -0
  400. package/src/memory/conversation-disk-view.ts +7 -0
  401. package/src/memory/conversation-group-migration.ts +34 -2
  402. package/src/memory/conversation-queries.ts +6 -5
  403. package/src/memory/db-init.ts +6 -0
  404. package/src/memory/db-maintenance.ts +108 -0
  405. package/src/memory/db.ts +1 -0
  406. package/src/memory/graph/conversation-graph-memory.ts +15 -0
  407. package/src/memory/graph/extraction.test.ts +23 -0
  408. package/src/memory/graph/extraction.ts +8 -0
  409. package/src/memory/graph/retriever.ts +27 -18
  410. package/src/memory/graph/scoring.test.ts +186 -0
  411. package/src/memory/graph/scoring.ts +31 -1
  412. package/src/memory/graph/tools.ts +1 -1
  413. package/src/memory/group-crud.ts +6 -1
  414. package/src/memory/indexer.ts +95 -16
  415. package/src/memory/job-handlers/cleanup.ts +11 -8
  416. package/src/memory/job-handlers/conversation-starters.ts +16 -10
  417. package/src/memory/jobs-store.ts +64 -4
  418. package/src/memory/jobs-worker.ts +22 -9
  419. package/src/memory/llm-usage-store.ts +92 -56
  420. package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
  421. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
  422. package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
  423. package/src/memory/migrations/index.ts +6 -0
  424. package/src/memory/migrations/registry.ts +8 -0
  425. package/src/memory/qdrant-manager.ts +43 -16
  426. package/src/memory/schema/conversations.ts +2 -0
  427. package/src/memory/schema/oauth.ts +3 -0
  428. package/src/memory/usage-buckets.ts +396 -0
  429. package/src/messaging/providers/gmail/client.ts +57 -6
  430. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
  431. package/src/messaging/providers/slack/adapter.ts +143 -38
  432. package/src/messaging/providers/slack/client.ts +16 -0
  433. package/src/messaging/providers/slack/types.ts +4 -0
  434. package/src/notifications/decision-engine.ts +3 -3
  435. package/src/notifications/signal.ts +5 -0
  436. package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
  437. package/src/oauth/byo-connection.test.ts +18 -1
  438. package/src/oauth/byo-connection.ts +3 -1
  439. package/src/oauth/connect-orchestrator.ts +2 -0
  440. package/src/oauth/connection-resolver.ts +6 -2
  441. package/src/oauth/connection.ts +2 -0
  442. package/src/oauth/oauth-store.ts +9 -0
  443. package/src/oauth/platform-connection.test.ts +98 -0
  444. package/src/oauth/platform-connection.ts +52 -31
  445. package/src/oauth/seed-providers.ts +7 -0
  446. package/src/permissions/checker.ts +16 -6
  447. package/src/permissions/defaults.ts +49 -1
  448. package/src/permissions/trust-store.ts +3 -3
  449. package/src/permissions/workspace-policy.ts +3 -0
  450. package/src/platform/client.test.ts +10 -0
  451. package/src/platform/sync-identity.ts +129 -0
  452. package/src/prompts/persona-resolver.ts +126 -2
  453. package/src/prompts/system-prompt.ts +59 -18
  454. package/src/prompts/templates/BOOTSTRAP.md +5 -5
  455. package/src/prompts/templates/SOUL.md +3 -1
  456. package/src/prompts/templates/UPDATES.md +12 -0
  457. package/src/prompts/templates/channels/slack.md +20 -0
  458. package/src/prompts/update-bulletin-format.ts +26 -9
  459. package/src/prompts/update-bulletin.ts +34 -23
  460. package/src/prompts/user-reference.ts +20 -17
  461. package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
  462. package/src/providers/anthropic/client.ts +157 -61
  463. package/src/providers/fireworks/client.ts +2 -2
  464. package/src/providers/gemini/client.ts +9 -1
  465. package/src/providers/model-catalog.ts +6 -0
  466. package/src/providers/model-intents.ts +4 -4
  467. package/src/providers/ollama/client.ts +2 -2
  468. package/src/providers/openai/chat-completions-provider.ts +474 -0
  469. package/src/providers/openai/client.ts +25 -440
  470. package/src/providers/openai/responses-provider.ts +502 -0
  471. package/src/providers/openrouter/client.ts +101 -4
  472. package/src/providers/provider-secret-catalog.ts +139 -0
  473. package/src/providers/registry.ts +2 -2
  474. package/src/providers/retry.ts +14 -3
  475. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
  476. package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
  477. package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
  478. package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
  479. package/src/providers/speech-to-text/deepgram.test.ts +332 -0
  480. package/src/providers/speech-to-text/deepgram.ts +115 -0
  481. package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
  482. package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
  483. package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
  484. package/src/providers/speech-to-text/google-gemini.ts +101 -0
  485. package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
  486. package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
  487. package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
  488. package/src/providers/speech-to-text/openai-whisper.ts +63 -33
  489. package/src/providers/speech-to-text/provider-catalog.ts +306 -0
  490. package/src/providers/speech-to-text/resolve.ts +386 -6
  491. package/src/providers/types.ts +9 -0
  492. package/src/runtime/AGENTS.md +43 -1
  493. package/src/runtime/__tests__/agent-wake.test.ts +831 -0
  494. package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
  495. package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
  496. package/src/runtime/agent-wake.ts +512 -0
  497. package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
  498. package/src/runtime/auth/route-policy.ts +30 -5
  499. package/src/runtime/auth/token-service.ts +56 -1
  500. package/src/runtime/btw-sidechain.ts +2 -0
  501. package/src/runtime/capability-tokens.ts +10 -10
  502. package/src/runtime/channel-invite-transport.ts +1 -1
  503. package/src/runtime/channel-invite-transports/email.ts +14 -6
  504. package/src/runtime/channel-readiness-service.ts +12 -22
  505. package/src/runtime/chrome-extension-registry.ts +38 -2
  506. package/src/runtime/http-server.ts +395 -10
  507. package/src/runtime/http-types.ts +6 -2
  508. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
  509. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
  510. package/src/runtime/migrations/migration-transport.ts +1 -0
  511. package/src/runtime/migrations/migration-wizard.ts +1 -0
  512. package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
  513. package/src/runtime/migrations/vbundle-importer.ts +34 -0
  514. package/src/runtime/pending-interactions.ts +0 -11
  515. package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
  516. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
  517. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
  518. package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
  519. package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
  520. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
  521. package/src/runtime/routes/app-management-routes.ts +12 -18
  522. package/src/runtime/routes/attachment-routes.test.ts +9 -3
  523. package/src/runtime/routes/attachment-routes.ts +216 -17
  524. package/src/runtime/routes/backup-routes.ts +519 -0
  525. package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
  526. package/src/runtime/routes/btw-routes.ts +8 -6
  527. package/src/runtime/routes/contact-routes.test.ts +298 -0
  528. package/src/runtime/routes/contact-routes.ts +132 -5
  529. package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
  530. package/src/runtime/routes/conversation-management-routes.ts +115 -0
  531. package/src/runtime/routes/conversation-routes.ts +367 -146
  532. package/src/runtime/routes/filing-routes.ts +93 -0
  533. package/src/runtime/routes/home-feed-routes.ts +334 -0
  534. package/src/runtime/routes/home-state-routes.ts +138 -0
  535. package/src/runtime/routes/host-browser-routes.ts +3 -14
  536. package/src/runtime/routes/identity-intro-cache.ts +7 -3
  537. package/src/runtime/routes/identity-routes.ts +3 -17
  538. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
  539. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
  540. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
  541. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
  542. package/src/runtime/routes/integrations/slack/channel.ts +11 -3
  543. package/src/runtime/routes/integrations/slack/share.ts +45 -7
  544. package/src/runtime/routes/llm-context-normalization.ts +303 -0
  545. package/src/runtime/routes/memory-item-routes.test.ts +3 -2
  546. package/src/runtime/routes/migration-routes.ts +40 -5
  547. package/src/runtime/routes/settings-routes.ts +22 -5
  548. package/src/runtime/routes/skills-routes.ts +76 -7
  549. package/src/runtime/routes/stt-routes.ts +233 -0
  550. package/src/runtime/routes/surface-action-routes.ts +41 -2
  551. package/src/runtime/routes/tts-routes.ts +108 -24
  552. package/src/runtime/routes/usage-routes.ts +30 -2
  553. package/src/runtime/routes/user-route-dispatcher.ts +50 -5
  554. package/src/runtime/routes/user-routes.ts +13 -1
  555. package/src/runtime/routes/work-items-routes.ts +8 -1
  556. package/src/runtime/runtime-mode.ts +33 -0
  557. package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
  558. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
  559. package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
  560. package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
  561. package/src/runtime/services/analyze-conversation.ts +344 -0
  562. package/src/runtime/services/analyze-deps-singleton.ts +32 -0
  563. package/src/runtime/services/auto-analysis-prompt.ts +55 -0
  564. package/src/runtime/skill-route-registry.ts +49 -0
  565. package/src/runtime/slack-block-formatting.ts +437 -10
  566. package/src/schedule/scheduler.ts +50 -0
  567. package/src/security/oauth2.ts +26 -4
  568. package/src/security/secure-keys.ts +25 -2
  569. package/src/security/token-manager.ts +8 -0
  570. package/src/sequence/engine.ts +23 -0
  571. package/src/sequence/types.ts +1 -1
  572. package/src/skills/catalog-files.ts +64 -2
  573. package/src/skills/category-inference.ts +122 -0
  574. package/src/skills/clawhub-files.ts +213 -0
  575. package/src/skills/clawhub.ts +84 -23
  576. package/src/skills/skill-file-provider.ts +40 -0
  577. package/src/skills/skillssh-files.ts +395 -0
  578. package/src/skills/skillssh-registry.ts +4 -4
  579. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
  580. package/src/stt/__tests__/types.test.ts +89 -0
  581. package/src/stt/daemon-batch-transcriber.ts +195 -0
  582. package/src/stt/stt-stream-session.ts +499 -0
  583. package/src/stt/types.ts +330 -0
  584. package/src/stt/wav-encoder.test.ts +373 -0
  585. package/src/stt/wav-encoder.ts +175 -0
  586. package/src/subagent/manager.ts +38 -14
  587. package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
  588. package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
  589. package/src/tools/browser/browser-execution.ts +1163 -23
  590. package/src/tools/browser/browser-manager.ts +45 -0
  591. package/src/tools/browser/browser-mode-constants.ts +12 -0
  592. package/src/tools/browser/browser-mode.ts +92 -0
  593. package/src/tools/browser/browser-status-constants.ts +33 -0
  594. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
  595. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
  596. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
  597. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
  598. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
  599. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
  600. package/src/tools/browser/cdp-client/errors.ts +15 -0
  601. package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
  602. package/src/tools/browser/cdp-client/factory.ts +797 -87
  603. package/src/tools/browser/cdp-client/index.ts +16 -2
  604. package/src/tools/browser/cdp-client/types.ts +68 -0
  605. package/src/tools/credentials/vault.ts +35 -6
  606. package/src/tools/network/web-fetch.ts +5 -2
  607. package/src/tools/network/web-search.ts +5 -2
  608. package/src/tools/shared/shell-output.ts +3 -1
  609. package/src/tools/side-effects.ts +2 -0
  610. package/src/tools/skills/sandbox-runner.ts +3 -2
  611. package/src/tools/terminal/safe-env.ts +10 -2
  612. package/src/tools/terminal/shell.ts +15 -4
  613. package/src/tools/tool-manifest.ts +21 -0
  614. package/src/tools/types.ts +17 -0
  615. package/src/tools/ui-surface/definitions.ts +6 -1
  616. package/src/tts/__tests__/provider-adapters.test.ts +834 -0
  617. package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
  618. package/src/tts/__tests__/provider-catalog.test.ts +183 -0
  619. package/src/tts/__tests__/provider-registry.test.ts +90 -0
  620. package/src/tts/provider-catalog.ts +201 -0
  621. package/src/tts/provider-registry.ts +73 -0
  622. package/src/tts/providers/deepgram-provider.ts +219 -0
  623. package/src/tts/providers/elevenlabs-provider.ts +211 -0
  624. package/src/tts/providers/fish-audio-provider.ts +183 -0
  625. package/src/tts/providers/index.ts +42 -0
  626. package/src/tts/providers/register-builtins.ts +130 -0
  627. package/src/tts/synthesize-text.ts +110 -0
  628. package/src/tts/tts-config-resolver.ts +78 -0
  629. package/src/tts/types.ts +153 -0
  630. package/src/types/onboarding-context.ts +7 -0
  631. package/src/util/abort-reasons.ts +58 -0
  632. package/src/util/device-id.ts +32 -16
  633. package/src/util/errors.ts +9 -1
  634. package/src/util/platform.ts +54 -10
  635. package/src/util/pricing.ts +66 -3
  636. package/src/util/spawn.ts +1 -1
  637. package/src/util/truncate.ts +4 -2
  638. package/src/util/unicode.ts +201 -0
  639. package/src/version.ts +19 -24
  640. package/src/watcher/engine.ts +23 -0
  641. package/src/watcher/watcher-store.ts +31 -0
  642. package/src/workspace/migrations/003-seed-device-id.ts +9 -3
  643. package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
  644. package/src/workspace/migrations/029-seed-pkb.ts +1 -1
  645. package/src/workspace/migrations/031-drop-user-md.ts +317 -0
  646. package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
  647. package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
  648. package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
  649. package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
  650. package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
  651. package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
  652. package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
  653. package/src/workspace/migrations/registry.ts +16 -0
  654. package/src/workspace/top-level-renderer.ts +13 -1
  655. package/src/workspace/turn-commit.ts +31 -0
  656. package/src/__tests__/email-cli.test.ts +0 -297
  657. package/src/__tests__/email-service-config-fallback.test.ts +0 -102
  658. package/src/cli/commands/browser-relay.ts +0 -466
  659. package/src/email/guardrails.ts +0 -221
  660. package/src/email/provider.ts +0 -117
  661. package/src/email/providers/agentmail.ts +0 -361
  662. package/src/email/providers/index.ts +0 -65
  663. package/src/email/service.ts +0 -384
  664. package/src/email/types.ts +0 -126
  665. package/src/prompts/templates/USER.md +0 -13
  666. package/src/providers/speech-to-text/types.ts +0 -17
  667. package/src/runtime/routes/browser-cdp-routes.ts +0 -229
@@ -0,0 +1,141 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Mocks — must be declared before the subject import
5
+ // ---------------------------------------------------------------------------
6
+
7
+ let mockTranscribeResult: string = "";
8
+
9
+ mock.module("../services/audio-transcribe.js", () => ({
10
+ transcribeSegmentAudio: async () => mockTranscribeResult,
11
+ }));
12
+
13
+ let spawnExitCode = 0;
14
+
15
+ mock.module("../../../../util/spawn.js", () => ({
16
+ spawnWithTimeout: async () => ({
17
+ exitCode: spawnExitCode,
18
+ stdout: "",
19
+ stderr: "",
20
+ }),
21
+ FFMPEG_PALETTE_TIMEOUT_MS: 10_000,
22
+ FFMPEG_PREPROCESS_TIMEOUT_MS: 60_000,
23
+ }));
24
+
25
+ mock.module("../../../../memory/media-store.js", () => ({
26
+ getMediaAssetById: (id: string) => ({
27
+ id,
28
+ mediaType: "video",
29
+ filePath: "/tmp/videos/test.mp4",
30
+ durationSeconds: 30,
31
+ }),
32
+ getProcessingStagesForAsset: () => [],
33
+ createProcessingStage: () => ({ id: "stage-1" }),
34
+ updateProcessingStage: () => {},
35
+ deleteKeyframesForAsset: () => {},
36
+ insertKeyframesBatch: () => {},
37
+ }));
38
+
39
+ // Mock fs — readdir must return frame filenames to produce segments with frames
40
+ let mockReaddirFiles: string[] = ["frame-000001.jpg", "frame-000002.jpg"];
41
+
42
+ mock.module("node:fs/promises", () => ({
43
+ mkdir: async () => {},
44
+ readdir: async () => mockReaddirFiles,
45
+ readFile: async () => "[]",
46
+ rename: async () => {},
47
+ rm: async () => {},
48
+ writeFile: async () => {},
49
+ }));
50
+
51
+ mock.module("../../../../util/silently.js", () => ({
52
+ silentlyWithLog: async () => {},
53
+ }));
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Subject import (after mocks)
57
+ // ---------------------------------------------------------------------------
58
+
59
+ import { preprocessForAsset } from "../services/preprocess.js";
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Tests
63
+ // ---------------------------------------------------------------------------
64
+
65
+ describe("preprocessForAsset — audio transcript enrichment", () => {
66
+ beforeEach(() => {
67
+ mockTranscribeResult = "";
68
+ spawnExitCode = 0;
69
+ mockReaddirFiles = ["frame-000001.jpg", "frame-000002.jpg"];
70
+ });
71
+
72
+ test("attaches transcript to segments when transcription returns text", async () => {
73
+ mockTranscribeResult = "Hello world, this is a transcript.";
74
+
75
+ const manifest = await preprocessForAsset("asset-1", {
76
+ includeAudio: true,
77
+ segmentDuration: 30,
78
+ });
79
+
80
+ expect(manifest.segments.length).toBeGreaterThan(0);
81
+ for (const seg of manifest.segments) {
82
+ expect(seg.transcript).toBe("Hello world, this is a transcript.");
83
+ }
84
+ });
85
+
86
+ test("omits transcript field when transcription returns empty string", async () => {
87
+ mockTranscribeResult = "";
88
+
89
+ const manifest = await preprocessForAsset("asset-1", {
90
+ includeAudio: true,
91
+ segmentDuration: 30,
92
+ });
93
+
94
+ expect(manifest.segments.length).toBeGreaterThan(0);
95
+ for (const seg of manifest.segments) {
96
+ expect(seg.transcript).toBeUndefined();
97
+ }
98
+ });
99
+
100
+ test("does not set transcript when includeAudio is false", async () => {
101
+ mockTranscribeResult = "Should not appear";
102
+
103
+ const manifest = await preprocessForAsset("asset-1", {
104
+ includeAudio: false,
105
+ segmentDuration: 30,
106
+ });
107
+
108
+ expect(manifest.segments.length).toBeGreaterThan(0);
109
+ for (const seg of manifest.segments) {
110
+ expect(seg.transcript).toBeUndefined();
111
+ }
112
+ });
113
+
114
+ test("does not set transcript when includeAudio is omitted", async () => {
115
+ mockTranscribeResult = "Should not appear";
116
+
117
+ const manifest = await preprocessForAsset("asset-1", {
118
+ segmentDuration: 30,
119
+ });
120
+
121
+ expect(manifest.segments.length).toBeGreaterThan(0);
122
+ for (const seg of manifest.segments) {
123
+ expect(seg.transcript).toBeUndefined();
124
+ }
125
+ });
126
+
127
+ test("does not throw when transcription returns empty for all segments", async () => {
128
+ mockTranscribeResult = "";
129
+
130
+ const manifest = await preprocessForAsset("asset-1", {
131
+ includeAudio: true,
132
+ segmentDuration: 15,
133
+ });
134
+
135
+ // Should complete successfully with segments but no transcripts
136
+ expect(manifest.segments.length).toBeGreaterThan(0);
137
+ expect(manifest.segments.every((s) => s.transcript === undefined)).toBe(
138
+ true,
139
+ );
140
+ });
141
+ });
@@ -1,34 +1,50 @@
1
1
  /**
2
2
  * Per-segment audio transcription for the video processing pipeline.
3
- * Extracts audio for a time range and transcribes it via OpenAI Whisper API
4
- * or local whisper.cpp, returning the transcript text.
3
+ * Extracts audio for a time range and transcribes it via the configured
4
+ * STT service (resolved through `resolveBatchTranscriber`), returning the
5
+ * transcript text.
5
6
  */
6
7
 
7
8
  import { randomUUID } from "node:crypto";
8
- import { access, readFile, unlink } from "node:fs/promises";
9
+ import { readFile, unlink } from "node:fs/promises";
9
10
  import { tmpdir } from "node:os";
10
11
  import { join } from "node:path";
11
12
 
13
+ import { resolveBatchTranscriber } from "../../../../providers/speech-to-text/resolve.js";
14
+ import type { BatchTranscriber } from "../../../../stt/types.js";
12
15
  import { spawnWithTimeout } from "../../../../util/spawn.js";
13
16
 
14
17
  const FFMPEG_TIMEOUT_MS = 60_000;
15
- const API_REQUEST_TIMEOUT_MS = 120_000;
16
- const LOCAL_CHUNK_TIMEOUT_MS = 120_000;
18
+ const STT_REQUEST_TIMEOUT_MS = 120_000;
17
19
 
18
20
  /**
19
21
  * Transcribe the audio from a specific time range of a video file.
20
22
  * Returns the transcript text, or empty string on failure (graceful degradation).
23
+ *
24
+ * Accepts an optional pre-resolved `BatchTranscriber` to avoid repeated
25
+ * credential lookups when transcribing multiple segments in a loop. When
26
+ * omitted, resolves the transcriber on demand via `resolveBatchTranscriber()`.
27
+ *
28
+ * Returns empty string when no provider is configured, the provider call
29
+ * fails, or ffmpeg extraction fails — this preserves preprocess resilience.
21
30
  */
22
31
  export async function transcribeSegmentAudio(
23
32
  videoPath: string,
24
33
  startSeconds: number,
25
34
  durationSeconds: number,
26
- mode: "api" | "local",
27
- options?: { apiKey?: string },
35
+ transcriber?: BatchTranscriber | null,
28
36
  ): Promise<string> {
29
37
  const tmpWav = join(tmpdir(), `vellum-seg-audio-${randomUUID()}.wav`);
30
38
 
31
39
  try {
40
+ // Use the provided transcriber or resolve on demand.
41
+ // null = "already resolved, no provider"; only re-resolve when undefined (not passed).
42
+ const resolved =
43
+ transcriber === undefined ? await resolveBatchTranscriber() : transcriber;
44
+ if (!resolved) {
45
+ return "";
46
+ }
47
+
32
48
  // Extract audio for the time range as 16kHz mono WAV
33
49
  const extractResult = await spawnWithTimeout(
34
50
  [
@@ -56,10 +72,15 @@ export async function transcribeSegmentAudio(
56
72
  return "";
57
73
  }
58
74
 
59
- if (mode === "api") {
60
- return await transcribeViaApi(tmpWav, options?.apiKey);
61
- }
62
- return await transcribeViaLocal(tmpWav);
75
+ // Send extracted WAV through the provider-agnostic transcriber
76
+ const audioBuffer = await readFile(tmpWav);
77
+ const result = await resolved.transcribe({
78
+ audio: audioBuffer,
79
+ mimeType: "audio/wav",
80
+ signal: AbortSignal.timeout(STT_REQUEST_TIMEOUT_MS),
81
+ });
82
+
83
+ return result.text?.trim() ?? "";
63
84
  } catch {
64
85
  return "";
65
86
  } finally {
@@ -70,79 +91,3 @@ export async function transcribeSegmentAudio(
70
91
  }
71
92
  }
72
93
  }
73
-
74
- async function transcribeViaApi(
75
- audioPath: string,
76
- apiKey?: string,
77
- ): Promise<string> {
78
- if (!apiKey) return "";
79
-
80
- const audioData = await readFile(audioPath);
81
- const formData = new FormData();
82
- formData.append(
83
- "file",
84
- new Blob([audioData], { type: "audio/wav" }),
85
- "audio.wav",
86
- );
87
- formData.append("model", "whisper-1");
88
-
89
- const response = await fetch(
90
- "https://api.openai.com/v1/audio/transcriptions",
91
- {
92
- method: "POST",
93
- headers: { Authorization: `Bearer ${apiKey}` },
94
- body: formData,
95
- signal: AbortSignal.timeout(API_REQUEST_TIMEOUT_MS),
96
- },
97
- );
98
-
99
- if (!response.ok) return "";
100
-
101
- const result = (await response.json()) as { text?: string };
102
- return result.text?.trim() ?? "";
103
- }
104
-
105
- async function transcribeViaLocal(audioPath: string): Promise<string> {
106
- // Check if whisper-cpp is available
107
- const whichResult = await spawnWithTimeout(["which", "whisper-cpp"], 5_000);
108
- if (whichResult.exitCode !== 0) return "";
109
-
110
- // Resolve model path
111
- const modelPath = await resolveWhisperModel();
112
- if (!modelPath) return "";
113
-
114
- const result = await spawnWithTimeout(
115
- ["whisper-cpp", "-m", modelPath, "-f", audioPath, "--no-timestamps"],
116
- LOCAL_CHUNK_TIMEOUT_MS,
117
- );
118
-
119
- if (result.exitCode !== 0) return "";
120
-
121
- return result.stdout
122
- .split("\n")
123
- .map((l) => l.trim())
124
- .filter((l) => l.length > 0)
125
- .join(" ")
126
- .trim();
127
- }
128
-
129
- async function resolveWhisperModel(): Promise<string | null> {
130
- const homeDir = process.env.HOME ?? "/tmp";
131
- const candidates = [
132
- join(homeDir, ".vellum", "models", "ggml-base.en.bin"),
133
- join(homeDir, ".vellum", "models", "ggml-base.bin"),
134
- "/usr/local/share/whisper-cpp/models/ggml-base.en.bin",
135
- "/opt/homebrew/share/whisper-cpp/models/ggml-base.en.bin",
136
- ];
137
-
138
- for (const p of candidates) {
139
- try {
140
- await access(p);
141
- return p;
142
- } catch {
143
- /* next */
144
- }
145
- }
146
-
147
- return null;
148
- }
@@ -18,6 +18,7 @@ import {
18
18
  type ProcessingStage,
19
19
  updateProcessingStage,
20
20
  } from "../../../../memory/media-store.js";
21
+ import { resolveBatchTranscriber } from "../../../../providers/speech-to-text/resolve.js";
21
22
  import { silentlyWithLog } from "../../../../util/silently.js";
22
23
  import {
23
24
  FFMPEG_PALETTE_TIMEOUT_MS,
@@ -92,8 +93,6 @@ export interface PreprocessOptions {
92
93
  detectDeadTime?: boolean;
93
94
  shortEdge?: number;
94
95
  includeAudio?: boolean;
95
- transcriptionMode?: "api" | "local";
96
- openaiApiKey?: string;
97
96
  }
98
97
 
99
98
  // ---------------------------------------------------------------------------
@@ -453,6 +452,12 @@ export async function preprocessForAsset(
453
452
  const segments: Segment[] = [];
454
453
  const allFramePaths: string[] = [];
455
454
 
455
+ // Resolve the STT transcriber once for all segments to avoid repeated
456
+ // credential lookups in the per-segment loop.
457
+ const transcriber = options.includeAudio
458
+ ? await resolveBatchTranscriber()
459
+ : null;
460
+
456
461
  const scaleFilter = `scale='if(gt(iw,ih),-1,${config.shortEdge})':'if(gt(iw,ih),${config.shortEdge},-1)'`;
457
462
 
458
463
  for (let i = 0; i < rawSegments.length; i++) {
@@ -529,8 +534,7 @@ export async function preprocessForAsset(
529
534
  asset.filePath,
530
535
  seg.startSeconds,
531
536
  seg.endSeconds - seg.startSeconds,
532
- options.transcriptionMode ?? "local",
533
- { apiKey: options.openaiApiKey },
537
+ transcriber,
534
538
  );
535
539
  if (transcript) {
536
540
  segment.transcript = transcript;
@@ -4,7 +4,6 @@ import {
4
4
  getKeyframesForAsset,
5
5
  getMediaAssetById,
6
6
  } from "../../../../memory/media-store.js";
7
- import { getProviderKeyAsync } from "../../../../security/secure-keys.js";
8
7
  import type {
9
8
  ToolContext,
10
9
  ToolExecutionResult,
@@ -26,13 +25,6 @@ export async function run(
26
25
  }
27
26
 
28
27
  const includeAudio = Boolean(input.include_audio);
29
- const transcriptionMode =
30
- (input.transcription_mode as "api" | "local") || undefined;
31
-
32
- let openaiApiKey: string | undefined;
33
- if (includeAudio && (!transcriptionMode || transcriptionMode === "api")) {
34
- openaiApiKey = await getProviderKeyAsync("openai");
35
- }
36
28
 
37
29
  const options: PreprocessOptions = {
38
30
  intervalSeconds: (input.interval_seconds as number) || undefined,
@@ -45,8 +37,6 @@ export async function run(
45
37
  : undefined,
46
38
  shortEdge: (input.short_edge as number) || undefined,
47
39
  includeAudio,
48
- transcriptionMode,
49
- openaiApiKey,
50
40
  };
51
41
 
52
42
  try {
@@ -17,15 +17,15 @@ You are a unified messaging assistant with access to multiple platforms (Gmail,
17
17
 
18
18
  ## External Identity
19
19
 
20
- When composing messages on behalf of your user to external recipients, refer to yourself as an "assistant" (not "AI assistant"). Use your user's name and pronouns from USER.md. Don't volunteer that you are an AI unless directly asked.
20
+ When composing messages on behalf of your user to external recipients, refer to yourself as an "assistant" (not "AI assistant"). Use your user's name and pronouns from their user persona file (`users/<slug>.md`). Don't volunteer that you are an AI unless directly asked.
21
21
 
22
22
  For Email management (archive, label, triage, declutter), load the **gmail** or **outlook** skill. For email sequences, load the **sequences** skill.
23
23
 
24
24
  ## Email Routing Priority
25
25
 
26
- When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Gmail or Outlook, not the assistant's AgentMail address.
26
+ When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Gmail or Outlook, not the assistant's @vellum.me address.
27
27
 
28
- Do not offer AgentMail as an option or mention it unless the user specifically asks. If Gmail and Outlookk are not connected, guide them through setup - do not suggest AgentMail as an alternative.
28
+ Do not offer the assistant's own email as an option unless the user specifically asks. If Gmail and Outlook are not connected, guide them through setup.
29
29
 
30
30
  ## Communication Style
31
31
 
@@ -8,9 +8,9 @@ export async function run(
8
8
  input: Record<string, unknown>,
9
9
  context: ToolContext,
10
10
  ): Promise<ToolExecutionResult> {
11
- if (!context.triggeredBySurfaceAction) {
11
+ if (!context.triggeredBySurfaceAction && !context.batchAuthorizedByTask) {
12
12
  return err(
13
- "This tool requires user confirmation via a surface action. Present results in a selection table with action buttons and wait for the user to click before proceeding.",
13
+ "This tool requires either a surface action or a scheduled task run with this tool in required_tools. Present results in a selection table with action buttons and wait for the user to click before proceeding.",
14
14
  );
15
15
  }
16
16
 
@@ -31,9 +31,9 @@ All tools above are Outlook-specific. For shared operations (send, read, search,
31
31
 
32
32
  ## Email Routing Priority
33
33
 
34
- When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email (Outlook)** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Outlook, not the assistant's AgentMail address.
34
+ When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email (Outlook)** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Outlook, not the assistant's @vellum.me address.
35
35
 
36
- Do not offer AgentMail as an option or mention it unless the user specifically asks. If Outlook is not connected, guide them through Outlook setup - do not suggest AgentMail as an alternative.
36
+ Do not offer the assistant's own email as an option unless the user specifically asks. If Outlook is not connected, guide them through Outlook setup.
37
37
 
38
38
  ## Connection Setup
39
39
 
@@ -23,9 +23,9 @@ export async function run(
23
23
  context: ToolContext,
24
24
  ): Promise<ToolExecutionResult> {
25
25
  const account = input.account as string | undefined;
26
- if (!context.triggeredBySurfaceAction) {
26
+ if (!context.triggeredBySurfaceAction && !context.batchAuthorizedByTask) {
27
27
  return err(
28
- "This tool requires user confirmation via a surface action. Present results in a selection table with action buttons and wait for the user to click before proceeding.",
28
+ "This tool requires either a surface action or a scheduled task run with this tool in required_tools. Present results in a selection table with action buttons and wait for the user to click before proceeding.",
29
29
  );
30
30
  }
31
31
 
@@ -21,11 +21,11 @@ You are helping the user set up and manage phone calls via Twilio. This skill co
21
21
 
22
22
  ## External Identity
23
23
 
24
- When speaking on behalf of your user during calls, refer to yourself as an "assistant" (not "AI assistant"). Use your user's name and pronouns from USER.md. Don't volunteer that you are an AI unless directly asked.
24
+ When speaking on behalf of your user during calls, refer to yourself as an "assistant" (not "AI assistant"). Use your user's name and pronouns from their user persona file (`users/<slug>.md`). Don't volunteer that you are an AI unless directly asked.
25
25
 
26
26
  # Overview
27
27
 
28
- The calling system uses Twilio's ConversationRelay for both **outbound** and **inbound** voice calls with **ElevenLabs** providing the text-to-speech voice. After Twilio setup, the assistant configures ElevenLabs as the TTS provider and prompts the user to choose a voice from a curated list of supported options.
28
+ The calling system uses Twilio's ConversationRelay for both **outbound** and **inbound** voice calls. The text-to-speech voice is provided by the globally configured TTS provider (set via `services.tts.provider`, default: ElevenLabs). After Twilio setup, the assistant prompts the user to choose a voice from a curated list of supported options.
29
29
 
30
30
  # Initial Setup
31
31
 
@@ -2,24 +2,33 @@
2
2
 
3
3
  All call-related settings can be managed via `assistant config`:
4
4
 
5
- | Setting | Description | Default |
6
- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
7
- | `calls.enabled` | Master switch for the calling feature | `false` |
8
- | `calls.provider` | Voice provider (currently only `twilio`) | `twilio` |
9
- | `calls.maxDurationSeconds` | Maximum call length in seconds | `3600` (1 hour) |
10
- | `calls.userConsultTimeoutSeconds` | How long to wait for user answers | `120` (2 min) |
11
- | `calls.disclosure.enabled` | Whether the AI announces itself at call start | `true` |
12
- | `calls.disclosure.text` | The disclosure message spoken at call start | `"At the very beginning of the call, introduce yourself as an assistant calling on behalf of my human."` |
13
- | `calls.model` | Override LLM model for call orchestration | _(uses default model)_ |
14
- | `calls.callerIdentity.allowPerCallOverride` | Allow per-call caller identity selection | `true` |
15
- | `calls.callerIdentity.userNumber` | E.164 phone number for user-number mode | _(empty)_ |
16
- | `calls.voice.language` | Language code for TTS and transcription | `en-US` |
17
- | `calls.voice.transcriptionProvider` | Speech-to-text provider (`Deepgram`, `Google`) | `Deepgram` |
18
- | `elevenlabs.voiceId` | ElevenLabs voice ID used by both in-app TTS and phone calls. Set during setup from the curated voice list. Defaults to Amelia | `ZF6FPAbjXT4488VcRRnw` |
19
- | `elevenlabs.voiceModelId` | Optional Twilio ConversationRelay model suffix. Leave empty to send bare `voiceId` | _(empty)_ |
20
- | `elevenlabs.speed` | Playback speed (`0.7` – `1.2`) | `1.0` |
21
- | `elevenlabs.stability` | Voice stability (`0.0` – `1.0`) | `0.5` |
22
- | `elevenlabs.similarityBoost` | Voice similarity boost (`0.0` – `1.0`) | `0.75` |
5
+ | Setting | Description | Default |
6
+ | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
7
+ | `calls.enabled` | Master switch for the calling feature | `true` |
8
+ | `calls.provider` | Voice provider (currently only `twilio`) | `twilio` |
9
+ | `calls.maxDurationSeconds` | Maximum call length in seconds | `3600` (1 hour) |
10
+ | `calls.userConsultTimeoutSeconds` | How long to wait for user answers | `120` (2 min) |
11
+ | `calls.disclosure.enabled` | Whether the AI announces itself at call start | `true` |
12
+ | `calls.disclosure.text` | The disclosure message spoken at call start | `"At the very beginning of the call, introduce yourself as an assistant calling on behalf of my human."` |
13
+ | `calls.model` | Override LLM model for call orchestration | _(uses default model)_ |
14
+ | `calls.callerIdentity.allowPerCallOverride` | Allow per-call caller identity selection | `true` |
15
+ | `calls.callerIdentity.userNumber` | E.164 phone number for user-number mode | _(empty)_ |
16
+ | `calls.voice.language` | Language code for TTS and transcription | `en-US` |
17
+ | `services.stt.provider` | STT provider for transcription and telephony. Determines the Twilio integration path at call setup time (Deepgram/Google use native ConversationRelay; OpenAI Whisper uses media-stream). | `deepgram` |
18
+ | `services.tts.provider` | Active TTS provider for speech synthesis. Must be a provider ID from the catalog (`elevenlabs`, `fish-audio`, `deepgram`). New providers can be added via the catalog without code changes to call routing. | `elevenlabs` |
19
+ | `services.tts.providers.<id>.*` | Provider-specific settings block. Each catalog provider has its own settings namespace under `services.tts.providers.<id>`. See voice settings in the desktop/iOS app or run `assistant config list` for available settings per provider. | _(per-provider defaults)_ |
20
+
21
+ ## TTS provider call-path behavior
22
+
23
+ Each TTS provider uses one of two call-path modes during phone calls:
24
+
25
+ | Provider | Call mode | Description |
26
+ | ------------ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | `elevenlabs` | `native-twilio` | Text tokens are forwarded to Twilio's ConversationRelay, which synthesizes audio via its built-in ElevenLabs integration. |
28
+ | `fish-audio` | `synthesized-play` | The assistant synthesizes audio server-side via Fish Audio's HTTP API and streams chunks to Twilio via play messages. |
29
+ | `deepgram` | `synthesized-play` | The assistant synthesizes audio server-side via Deepgram's HTTP API and streams chunks to Twilio via play messages. Uses the same API key as Deepgram speech-to-text. |
30
+
31
+ Providers using `synthesized-play` add a small amount of latency compared to `native-twilio` because audio must be synthesized server-side before playback. The assistant handles chunk buffering and streaming automatically.
23
32
 
24
33
  ## Adjusting settings
25
34
 
@@ -56,12 +56,12 @@ The system has a 30-second silence timeout. If nobody speaks for 30 seconds duri
56
56
 
57
57
  ## Call quality sounds off
58
58
 
59
- - Verify `elevenlabs.voiceId` is set to a valid ElevenLabs voice ID
59
+ - Verify `services.tts.providers.elevenlabs.voiceId` is set to a valid ElevenLabs voice ID
60
60
  - Ask for the desired voice style again and try a different voice selection
61
61
 
62
62
  ## Twilio says "application error" right after answer
63
63
 
64
64
  - This often means ConversationRelay rejected voice configuration after TwiML fetch
65
- - Keep `elevenlabs.voiceModelId` empty first (bare `voiceId` mode)
65
+ - Keep `services.tts.providers.elevenlabs.voiceModelId` empty first (bare `voiceId` mode)
66
66
  - If you set `voiceModelId`, try clearing it and retesting:
67
- `assistant config set elevenlabs.voiceModelId ""`
67
+ `assistant config set services.tts.providers.elevenlabs.voiceModelId ""`
@@ -3,7 +3,7 @@
3
3
  "tools": [
4
4
  {
5
5
  "name": "voice_config_update",
6
- "description": "Update a voice configuration setting (TTS provider, TTS voice ID, Fish Audio reference ID, PTT activation key, conversation timeout). Changes take effect immediately.",
6
+ "description": "Update a voice configuration setting. Use tts_provider to switch the global TTS provider (valid providers: elevenlabs, fish-audio, deepgram — defined by the provider catalog). Use tts_voice_id to set the ElevenLabs voice ID, fish_audio_reference_id for Fish Audio voice reference. Deepgram uses the same API key as speech-to-text and requires no additional voice config. Changes persist to services.tts config and take effect immediately.",
7
7
  "category": "system",
8
8
  "risk": "low",
9
9
  "input_schema": {
@@ -18,10 +18,10 @@
18
18
  "tts_provider",
19
19
  "tts_voice_id"
20
20
  ],
21
- "description": "The voice setting to change"
21
+ "description": "The voice setting to change. tts_provider selects the global TTS provider from the provider catalog (elevenlabs, fish-audio, deepgram). tts_voice_id sets the ElevenLabs voice. fish_audio_reference_id sets the Fish Audio voice reference. Deepgram uses its default model and shares the STT API key."
22
22
  },
23
23
  "value": {
24
- "description": "The new value for the setting (type depends on setting)"
24
+ "description": "The new value for the setting. For tts_provider: a valid provider ID from the provider catalog (elevenlabs, fish-audio, deepgram). For tts_voice_id: an alphanumeric ElevenLabs voice ID. For fish_audio_reference_id: a Fish Audio voice reference ID. For conversation_timeout: seconds (5, 10, 15, 30, or 60). For activation_key: key identifier string."
25
25
  },
26
26
  "activity": {
27
27
  "type": "string",