@agent-native/core 0.8.2 → 0.10.0

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 (305) hide show
  1. package/README.md +4 -4
  2. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  3. package/dist/agent/engine/builder-engine.js +5 -4
  4. package/dist/agent/engine/builder-engine.js.map +1 -1
  5. package/dist/agent/engine/registry.d.ts +6 -3
  6. package/dist/agent/engine/registry.d.ts.map +1 -1
  7. package/dist/agent/engine/registry.js +8 -17
  8. package/dist/agent/engine/registry.js.map +1 -1
  9. package/dist/agent/production-agent.d.ts +1 -1
  10. package/dist/agent/production-agent.d.ts.map +1 -1
  11. package/dist/agent/production-agent.js +28 -11
  12. package/dist/agent/production-agent.js.map +1 -1
  13. package/dist/agent/run-manager.d.ts +10 -0
  14. package/dist/agent/run-manager.d.ts.map +1 -1
  15. package/dist/agent/run-manager.js +89 -7
  16. package/dist/agent/run-manager.js.map +1 -1
  17. package/dist/agent/run-store.d.ts +4 -1
  18. package/dist/agent/run-store.d.ts.map +1 -1
  19. package/dist/agent/run-store.js +6 -5
  20. package/dist/agent/run-store.js.map +1 -1
  21. package/dist/agent/thread-data-builder.d.ts +12 -0
  22. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  23. package/dist/agent/thread-data-builder.js +96 -0
  24. package/dist/agent/thread-data-builder.js.map +1 -1
  25. package/dist/cli/create.d.ts +9 -0
  26. package/dist/cli/create.d.ts.map +1 -1
  27. package/dist/cli/create.js +29 -11
  28. package/dist/cli/create.js.map +1 -1
  29. package/dist/cli/index.js +177 -22
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/workspace-dev.js +66 -5
  32. package/dist/cli/workspace-dev.js.map +1 -1
  33. package/dist/client/AgentPanel.d.ts.map +1 -1
  34. package/dist/client/AgentPanel.js +6 -20
  35. package/dist/client/AgentPanel.js.map +1 -1
  36. package/dist/client/AssistantChat.d.ts.map +1 -1
  37. package/dist/client/AssistantChat.js +146 -107
  38. package/dist/client/AssistantChat.js.map +1 -1
  39. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  40. package/dist/client/agent-chat-adapter.js +143 -22
  41. package/dist/client/agent-chat-adapter.js.map +1 -1
  42. package/dist/client/agent-sidebar-state.d.ts +3 -0
  43. package/dist/client/agent-sidebar-state.d.ts.map +1 -0
  44. package/dist/client/agent-sidebar-state.js +24 -0
  45. package/dist/client/agent-sidebar-state.js.map +1 -0
  46. package/dist/client/analytics.d.ts +39 -0
  47. package/dist/client/analytics.d.ts.map +1 -1
  48. package/dist/client/analytics.js +74 -0
  49. package/dist/client/analytics.js.map +1 -1
  50. package/dist/client/components/PresenceBar.d.ts.map +1 -1
  51. package/dist/client/components/PresenceBar.js +21 -15
  52. package/dist/client/components/PresenceBar.js.map +1 -1
  53. package/dist/client/components/ui/tooltip.d.ts +2 -1
  54. package/dist/client/components/ui/tooltip.d.ts.map +1 -1
  55. package/dist/client/components/ui/tooltip.js +9 -2
  56. package/dist/client/components/ui/tooltip.js.map +1 -1
  57. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  58. package/dist/client/composer/ComposerPlusMenu.js +51 -17
  59. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  60. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  61. package/dist/client/composer/PromptComposer.js +30 -0
  62. package/dist/client/composer/PromptComposer.js.map +1 -1
  63. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  64. package/dist/client/composer/TiptapComposer.js +31 -5
  65. package/dist/client/composer/TiptapComposer.js.map +1 -1
  66. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  67. package/dist/client/composer/VoiceButton.js +9 -8
  68. package/dist/client/composer/VoiceButton.js.map +1 -1
  69. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  70. package/dist/client/dev-overlay/DevOverlay.js +4 -3
  71. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  72. package/dist/client/error-format.d.ts.map +1 -1
  73. package/dist/client/error-format.js +6 -0
  74. package/dist/client/error-format.js.map +1 -1
  75. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  76. package/dist/client/extensions/EmbeddedExtension.js +14 -3
  77. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  78. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  79. package/dist/client/extensions/ExtensionEditor.js +6 -5
  80. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  81. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  82. package/dist/client/extensions/ExtensionSlot.js +2 -1
  83. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  84. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  85. package/dist/client/extensions/ExtensionViewer.js +40 -19
  86. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  87. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  88. package/dist/client/extensions/ExtensionsSidebarSection.js +52 -51
  89. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  90. package/dist/client/index.d.ts +2 -1
  91. package/dist/client/index.d.ts.map +1 -1
  92. package/dist/client/index.js +2 -1
  93. package/dist/client/index.js.map +1 -1
  94. package/dist/client/integrations/IntegrationCard.d.ts.map +1 -1
  95. package/dist/client/integrations/IntegrationCard.js +2 -1
  96. package/dist/client/integrations/IntegrationCard.js.map +1 -1
  97. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  98. package/dist/client/integrations/IntegrationsPanel.js +3 -2
  99. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  100. package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
  101. package/dist/client/notifications/NotificationsBell.js +42 -6
  102. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  103. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  104. package/dist/client/onboarding/OnboardingPanel.js +3 -2
  105. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  106. package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
  107. package/dist/client/onboarding/SetupButton.js +14 -13
  108. package/dist/client/onboarding/SetupButton.js.map +1 -1
  109. package/dist/client/org/InvitationBanner.d.ts +8 -2
  110. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  111. package/dist/client/org/InvitationBanner.js +28 -7
  112. package/dist/client/org/InvitationBanner.js.map +1 -1
  113. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  114. package/dist/client/org/OrgSwitcher.js +29 -5
  115. package/dist/client/org/OrgSwitcher.js.map +1 -1
  116. package/dist/client/org/TeamPage.d.ts.map +1 -1
  117. package/dist/client/org/TeamPage.js +9 -7
  118. package/dist/client/org/TeamPage.js.map +1 -1
  119. package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
  120. package/dist/client/resources/ResourceEditor.js +2 -1
  121. package/dist/client/resources/ResourceEditor.js.map +1 -1
  122. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  123. package/dist/client/resources/ResourcesPanel.js +48 -14
  124. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  125. package/dist/client/resources/use-mcp-servers.d.ts +2 -0
  126. package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
  127. package/dist/client/resources/use-mcp-servers.js +59 -3
  128. package/dist/client/resources/use-mcp-servers.js.map +1 -1
  129. package/dist/client/settings/AgentsSection.d.ts.map +1 -1
  130. package/dist/client/settings/AgentsSection.js +8 -7
  131. package/dist/client/settings/AgentsSection.js.map +1 -1
  132. package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
  133. package/dist/client/settings/AutomationsSection.js +4 -3
  134. package/dist/client/settings/AutomationsSection.js.map +1 -1
  135. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  136. package/dist/client/settings/SecretsSection.js +11 -1
  137. package/dist/client/settings/SecretsSection.js.map +1 -1
  138. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  139. package/dist/client/settings/SettingsPanel.js +15 -12
  140. package/dist/client/settings/SettingsPanel.js.map +1 -1
  141. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  142. package/dist/client/settings/VoiceTranscriptionSection.js +13 -30
  143. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  144. package/dist/client/settings/index.d.ts +1 -1
  145. package/dist/client/settings/index.d.ts.map +1 -1
  146. package/dist/client/settings/index.js.map +1 -1
  147. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  148. package/dist/client/settings/useBuilderStatus.js +27 -1
  149. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  150. package/dist/client/sharing/ShareButton.d.ts +4 -0
  151. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  152. package/dist/client/sharing/ShareButton.js +5 -1
  153. package/dist/client/sharing/ShareButton.js.map +1 -1
  154. package/dist/client/sse-event-processor.d.ts +1 -1
  155. package/dist/client/sse-event-processor.d.ts.map +1 -1
  156. package/dist/client/sse-event-processor.js +59 -11
  157. package/dist/client/sse-event-processor.js.map +1 -1
  158. package/dist/client/use-db-sync.d.ts.map +1 -1
  159. package/dist/client/use-db-sync.js +100 -19
  160. package/dist/client/use-db-sync.js.map +1 -1
  161. package/dist/client/use-session.d.ts.map +1 -1
  162. package/dist/client/use-session.js +14 -2
  163. package/dist/client/use-session.js.map +1 -1
  164. package/dist/collab/client.d.ts +1 -0
  165. package/dist/collab/client.d.ts.map +1 -1
  166. package/dist/collab/client.js +18 -1
  167. package/dist/collab/client.js.map +1 -1
  168. package/dist/deploy/build.d.ts.map +1 -1
  169. package/dist/deploy/build.js +5 -0
  170. package/dist/deploy/build.js.map +1 -1
  171. package/dist/deploy/route-discovery.d.ts.map +1 -1
  172. package/dist/deploy/route-discovery.js +1 -0
  173. package/dist/deploy/route-discovery.js.map +1 -1
  174. package/dist/deploy/workspace-core.d.ts +1 -1
  175. package/dist/deploy/workspace-core.d.ts.map +1 -1
  176. package/dist/deploy/workspace-core.js +1 -0
  177. package/dist/deploy/workspace-core.js.map +1 -1
  178. package/dist/extensions/actions.d.ts.map +1 -1
  179. package/dist/extensions/actions.js +17 -3
  180. package/dist/extensions/actions.js.map +1 -1
  181. package/dist/extensions/routes.js +1 -1
  182. package/dist/extensions/routes.js.map +1 -1
  183. package/dist/extensions/schema.d.ts +14 -14
  184. package/dist/extensions/schema.d.ts.map +1 -1
  185. package/dist/extensions/schema.js +4 -4
  186. package/dist/extensions/schema.js.map +1 -1
  187. package/dist/extensions/store.d.ts.map +1 -1
  188. package/dist/extensions/store.js +23 -0
  189. package/dist/extensions/store.js.map +1 -1
  190. package/dist/extensions/theme.d.ts +8 -1
  191. package/dist/extensions/theme.d.ts.map +1 -1
  192. package/dist/extensions/theme.js +43 -34
  193. package/dist/extensions/theme.js.map +1 -1
  194. package/dist/mcp-client/routes.d.ts +1 -0
  195. package/dist/mcp-client/routes.d.ts.map +1 -1
  196. package/dist/mcp-client/routes.js +28 -1
  197. package/dist/mcp-client/routes.js.map +1 -1
  198. package/dist/org/auto-join-domain.d.ts +28 -0
  199. package/dist/org/auto-join-domain.d.ts.map +1 -0
  200. package/dist/org/auto-join-domain.js +92 -0
  201. package/dist/org/auto-join-domain.js.map +1 -0
  202. package/dist/org/index.d.ts +2 -0
  203. package/dist/org/index.d.ts.map +1 -1
  204. package/dist/org/index.js +1 -0
  205. package/dist/org/index.js.map +1 -1
  206. package/dist/scripts/db/exec.d.ts.map +1 -1
  207. package/dist/scripts/db/exec.js +27 -1
  208. package/dist/scripts/db/exec.js.map +1 -1
  209. package/dist/scripts/db/index.d.ts.map +1 -1
  210. package/dist/scripts/db/index.js +1 -0
  211. package/dist/scripts/db/index.js.map +1 -1
  212. package/dist/scripts/db/reset-dev-owner.d.ts +27 -0
  213. package/dist/scripts/db/reset-dev-owner.d.ts.map +1 -0
  214. package/dist/scripts/db/reset-dev-owner.js +225 -0
  215. package/dist/scripts/db/reset-dev-owner.js.map +1 -0
  216. package/dist/scripts/db/scoping.d.ts.map +1 -1
  217. package/dist/scripts/db/scoping.js +15 -30
  218. package/dist/scripts/db/scoping.js.map +1 -1
  219. package/dist/scripts/dev-session.d.ts +46 -0
  220. package/dist/scripts/dev-session.d.ts.map +1 -0
  221. package/dist/scripts/dev-session.js +81 -0
  222. package/dist/scripts/dev-session.js.map +1 -0
  223. package/dist/scripts/runner.d.ts.map +1 -1
  224. package/dist/scripts/runner.js +21 -0
  225. package/dist/scripts/runner.js.map +1 -1
  226. package/dist/secrets/register.d.ts +1 -1
  227. package/dist/secrets/register.d.ts.map +1 -1
  228. package/dist/secrets/register.js +4 -2
  229. package/dist/secrets/register.js.map +1 -1
  230. package/dist/secrets/routes.d.ts.map +1 -1
  231. package/dist/secrets/routes.js +32 -0
  232. package/dist/secrets/routes.js.map +1 -1
  233. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  234. package/dist/server/agent-chat-plugin.js +77 -102
  235. package/dist/server/agent-chat-plugin.js.map +1 -1
  236. package/dist/server/auth.d.ts.map +1 -1
  237. package/dist/server/auth.js +33 -0
  238. package/dist/server/auth.js.map +1 -1
  239. package/dist/server/better-auth-instance.d.ts.map +1 -1
  240. package/dist/server/better-auth-instance.js +11 -0
  241. package/dist/server/better-auth-instance.js.map +1 -1
  242. package/dist/server/builder-browser.d.ts.map +1 -1
  243. package/dist/server/builder-browser.js +169 -68
  244. package/dist/server/builder-browser.js.map +1 -1
  245. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  246. package/dist/server/core-routes-plugin.js +56 -13
  247. package/dist/server/core-routes-plugin.js.map +1 -1
  248. package/dist/server/credential-provider.d.ts +49 -6
  249. package/dist/server/credential-provider.d.ts.map +1 -1
  250. package/dist/server/credential-provider.js +133 -38
  251. package/dist/server/credential-provider.js.map +1 -1
  252. package/dist/server/design-token-utils.d.ts +13 -2
  253. package/dist/server/design-token-utils.d.ts.map +1 -1
  254. package/dist/server/design-token-utils.js +48 -16
  255. package/dist/server/design-token-utils.js.map +1 -1
  256. package/dist/server/framework-request-handler.d.ts.map +1 -1
  257. package/dist/server/framework-request-handler.js +31 -0
  258. package/dist/server/framework-request-handler.js.map +1 -1
  259. package/dist/server/google-realtime-session.d.ts.map +1 -1
  260. package/dist/server/google-realtime-session.js +19 -6
  261. package/dist/server/google-realtime-session.js.map +1 -1
  262. package/dist/server/index.d.ts +2 -0
  263. package/dist/server/index.d.ts.map +1 -1
  264. package/dist/server/index.js +2 -0
  265. package/dist/server/index.js.map +1 -1
  266. package/dist/server/onboarding-html.d.ts.map +1 -1
  267. package/dist/server/onboarding-html.js +142 -14
  268. package/dist/server/onboarding-html.js.map +1 -1
  269. package/dist/server/request-context.d.ts +17 -0
  270. package/dist/server/request-context.d.ts.map +1 -1
  271. package/dist/server/request-context.js +40 -1
  272. package/dist/server/request-context.js.map +1 -1
  273. package/dist/server/sentry-plugin.d.ts +11 -0
  274. package/dist/server/sentry-plugin.d.ts.map +1 -0
  275. package/dist/server/sentry-plugin.js +116 -0
  276. package/dist/server/sentry-plugin.js.map +1 -0
  277. package/dist/server/sentry.d.ts +92 -0
  278. package/dist/server/sentry.d.ts.map +1 -0
  279. package/dist/server/sentry.js +287 -0
  280. package/dist/server/sentry.js.map +1 -0
  281. package/dist/server/transcribe-voice.d.ts +2 -4
  282. package/dist/server/transcribe-voice.d.ts.map +1 -1
  283. package/dist/server/transcribe-voice.js +4 -16
  284. package/dist/server/transcribe-voice.js.map +1 -1
  285. package/dist/server/voice-providers-status.d.ts.map +1 -1
  286. package/dist/server/voice-providers-status.js +19 -35
  287. package/dist/server/voice-providers-status.js.map +1 -1
  288. package/dist/styles/agent-native.css +15 -0
  289. package/docs/content/cloneable-saas.md +7 -9
  290. package/docs/content/deployment.md +6 -2
  291. package/docs/content/dispatch.md +1 -1
  292. package/docs/content/extensions.md +177 -142
  293. package/docs/content/faq.md +2 -2
  294. package/docs/content/getting-started.md +13 -11
  295. package/docs/content/multi-app-workspace.md +2 -2
  296. package/docs/content/observability.md +47 -0
  297. package/docs/content/pure-agent-apps.md +1 -1
  298. package/docs/content/template-clips.md +3 -3
  299. package/docs/content/template-design.md +3 -3
  300. package/docs/content/template-dispatch.md +1 -1
  301. package/docs/content/template-forms.md +1 -1
  302. package/docs/content/template-mail.md +1 -1
  303. package/docs/content/what-is-agent-native.md +4 -4
  304. package/docs/content/workspace.md +1 -1
  305. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"transcribe-voice.js","sourceRoot":"","sources":["../../src/server/transcribe-voice.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * POST /_agent-native/transcribe-voice\n *\n * Receives an audio blob from the agent sidebar composer and forwards it to\n * the configured transcription provider. Returns `{ text }` on success,\n * `{ error }` on failure.\n *\n * Key resolution order for BYOK providers:\n * 1. User-scoped encrypted secret (`readAppSecret` — set via the sidebar\n * settings UI).\n * 2. `resolveCredential(\"<PROVIDER>_API_KEY\")` — env var + SQL settings\n * store.\n *\n * If no server provider is configured, returns 400 with an error the\n * composer UI can surface (the client falls back to Web Speech when possible).\n *\n * This is a framework route rather than a `defineAction` because multipart\n * audio bodies aren't a clean fit for the action contract (actions are\n * typed JSON-in / JSON-out).\n */\n\nimport {\n defineEventHandler,\n getMethod,\n getRequestHeader,\n readMultipartFormData,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { readAppSecret } from \"../secrets/storage.js\";\nimport { resolveCredential } from \"../credentials/index.js\";\nimport { getSession } from \"./auth.js\";\nimport { appStateGet } from \"../application-state/store.js\";\nimport { resolveHasBuilderPrivateKey } from \"./credential-provider.js\";\nimport { transcribeWithBuilder } from \"../transcription/builder-transcription.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { createBuilderEngine } from \"../agent/engine/builder-engine.js\";\n\nconst WHISPER_URL = \"https://api.openai.com/v1/audio/transcriptions\";\nconst GROQ_URL = \"https://api.groq.com/openai/v1/audio/transcriptions\";\nconst GROQ_CHAT_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst GROQ_MODEL = \"whisper-large-v3-turbo\";\nconst GROQ_CLEANUP_MODEL = \"llama-3.3-70b-versatile\";\nconst OPENAI_MODEL = \"whisper-1\";\nconst OPENAI_CHAT_URL = \"https://api.openai.com/v1/chat/completions\";\nconst OPENAI_CLEANUP_MODEL = \"gpt-5.4-mini\";\nconst MAX_AUDIO_BYTES = 25 * 1024 * 1024; // Whisper hard limit.\nconst MAX_TRANSCRIPT_CHARS = 40_000;\n// Public Builder transcription model id. The Builder gateway maps this to\n// Gemini 3.1 Flash-Lite.\nconst BUILDER_GEMINI_TRANSCRIPTION_MODEL = \"gemini-3-1-flash-lite\";\n\n// Gemini Flash Lite BYOK path when GEMINI_API_KEY is configured.\n// Gemini accepts inline audio; we just give it the bytes and a \"transcribe\n// this\" prompt and it replies with text. 2.5x faster TTFT than 2.5 Flash\n// per Google's release notes, and noticeably snappier than the Whisper\n// round-trip even on a fast connection.\n// Keep the direct Google AI path on a stable public model id; Builder's\n// managed provider above handles the newer Gemini 3.1 Flash-Lite preview.\nconst GEMINI_MODEL = \"gemini-2.0-flash-lite\";\nconst GEMINI_URL = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent`;\n\n/**\n * Reject cross-site POSTs. Cookies are `SameSite=None; Secure` over HTTPS so\n * the browser would otherwise attach the session to a forged form submission\n * from evil.com, causing us to spend OpenAI credits on the user's behalf.\n * Same-origin browsers always send `Origin` on POST; if it's missing we fall\n * back to `Sec-Fetch-Site` so Safari's fetch-spec behavior still works.\n */\nfunction isSameOriginRequest(event: H3Event): boolean {\n const host = getRequestHeader(event, \"host\");\n const origin = getRequestHeader(event, \"origin\");\n if (origin && host) {\n try {\n const parsed = new URL(origin);\n if (parsed.host === host) return true;\n // Tauri desktop dev serves the tray WebView from localhost:1420 while\n // the app server lives on the template dev port. Production Tauri\n // WebViews can also send a tauri://localhost origin. Treat only those\n // desktop origins as trusted cross-origin callers; arbitrary websites\n // still fail the CSRF check.\n if (parsed.protocol === \"tauri:\" && parsed.hostname === \"localhost\") {\n return true;\n }\n if (\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n parsed.hostname === \"tauri.localhost\" &&\n (host.startsWith(\"localhost:\") || host.startsWith(\"127.0.0.1:\"))\n ) {\n return true;\n }\n if (\n parsed.protocol === \"http:\" &&\n (parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\") &&\n parsed.port === \"1420\" &&\n (host.startsWith(\"localhost:\") || host.startsWith(\"127.0.0.1:\"))\n ) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n }\n const fetchSite = getRequestHeader(event, \"sec-fetch-site\");\n if (fetchSite) return fetchSite === \"same-origin\" || fetchSite === \"none\";\n // No Origin and no Sec-Fetch-Site: likely a non-browser client (curl,\n // server-side) — safe to allow, CSRF requires a browser with ambient cookies.\n return true;\n}\n\nexport function createTranscribeVoiceHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!isSameOriginRequest(event)) {\n setResponseStatus(event, 403);\n return { error: \"Cross-origin request rejected\" };\n }\n\n const parts = await readMultipartFormData(event).catch(() => null);\n const audio = parts?.find((p) => p.name === \"audio\");\n const textPart = parts?.find((p) => p.name === \"text\");\n const transcriptText = textPart?.data\n ? sanitizeTranscriptText(textPart.data.toString(\"utf8\"))\n : undefined;\n if (!audio?.data?.length && !transcriptText) {\n setResponseStatus(event, 400);\n return { error: \"Missing audio or transcript payload\" };\n }\n if (audio?.data?.length && audio.data.length > MAX_AUDIO_BYTES) {\n setResponseStatus(event, 413);\n return { error: \"Audio too large (max 25 MB)\" };\n }\n\n const languagePart = parts?.find((p) => p.name === \"language\");\n const language = languagePart?.data\n ? languagePart.data.toString(\"utf8\").trim().slice(0, 8)\n : undefined;\n const instructionsPart = parts?.find((p) => p.name === \"instructions\");\n const instructions = instructionsPart?.data\n ? sanitizeInstructions(instructionsPart.data.toString(\"utf8\"))\n : undefined;\n\n // Resolve provider preference. Per-request \"provider\" form field takes\n // precedence (the desktop client sends it on every dictation press),\n // falling back to the user's stored `voice-transcription-prefs` app\n // state for the agent sidebar composer / web clients that don't send\n // it explicitly.\n const session = await getSession(event).catch(() => null);\n if (!session?.email && process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 401);\n return { error: \"Authentication required\" };\n }\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const requestContext = {\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n };\n const withRequestContext = async <T>(fn: () => Promise<T>): Promise<T> =>\n requestContext.userEmail\n ? runWithRequestContext(requestContext, fn)\n : fn();\n const hasBuilderPrivateKey = async () =>\n withRequestContext(() => resolveHasBuilderPrivateKey());\n const transcribeWithBuilderForRequest = (\n opts: Parameters<typeof transcribeWithBuilder>[0],\n ) => withRequestContext(() => transcribeWithBuilder(opts));\n const sessionId = session?.email ?? \"local\";\n let providerPref: string | undefined;\n // CRITICAL: presence of the \"provider\" form field is the explicit\n // signal that the client is making a per-request choice. Even if\n // the value is \"auto\" (→ undefined providerPref → fallback chain),\n // we must NOT fall back to app-state's stored preference — the\n // client just told us what it wants. Without this gate, a stale\n // `voice-transcription-prefs.provider = \"browser\"` in app-state\n // (from earlier testing) would override the client's \"auto\" and\n // 400 with \"Voice provider is set to browser\".\n const providerPart = parts?.find((p) => p.name === \"provider\");\n let providerExplicit = false;\n if (providerPart?.data) {\n const v = providerPart.data.toString(\"utf8\").trim().toLowerCase();\n if (\n v === \"auto\" ||\n v === \"browser\" ||\n v === \"builder\" ||\n v === \"builder-gemini\" ||\n v === \"gemini\" ||\n v === \"openai\" ||\n v === \"groq\"\n ) {\n providerExplicit = true;\n providerPref = v === \"auto\" ? undefined : v;\n }\n }\n if (!providerExplicit) {\n try {\n const prefs = await appStateGet(sessionId, \"voice-transcription-prefs\");\n providerPref = (\n prefs as { provider?: string; value?: { provider?: string } } | null\n )?.provider;\n providerPref ??= (prefs as { value?: { provider?: string } } | null)\n ?.value?.provider;\n } catch {\n /* fall through — default to fallback chain */\n }\n }\n\n // Respect explicit \"browser\" preference — user chose Web Speech API and\n // does not want audio uploaded to any external provider. The client\n // shouldn't hit this endpoint when \"browser\" is selected; this is a\n // defense-in-depth refusal.\n if (providerPref === \"browser\") {\n setResponseStatus(event, 400);\n return {\n error:\n 'Voice provider is set to \"browser\" (Web Speech API only). Change the preference in Settings → Voice Transcription to use a server-side provider.',\n };\n }\n\n // Per-user-or-fallback API key resolution. Hoisted up so the Gemini\n // path below can use it without duplicating logic.\n async function resolveApiKey(key: string): Promise<string | undefined> {\n const ctx = { userEmail: session?.email };\n if (!session?.email)\n return (await resolveCredential(key, ctx)) ?? undefined;\n const userSecret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: session.email,\n }).catch(() => null);\n return (\n userSecret?.value || (await resolveCredential(key, ctx)) || undefined\n );\n }\n\n if (transcriptText) {\n return await cleanupTranscriptText({\n event,\n text: transcriptText,\n instructions,\n providerPref,\n hasBuilderPrivateKey,\n withRequestContext,\n resolveApiKey,\n });\n }\n\n if (!audio?.data?.length) {\n setResponseStatus(event, 400);\n return { error: \"Missing audio payload\" };\n }\n\n const mime = audio.type || \"audio/webm\";\n const audioBytes = new Uint8Array(\n audio.data.buffer,\n audio.data.byteOffset,\n audio.data.byteLength,\n );\n\n let builderError: string | null = null;\n\n // ── Strict per-provider preferences ─────────────────────────────────\n // When the user explicitly picks a single provider (gemini / builder /\n // groq), we only try that provider and surface its error rather than\n // silently falling through. \"auto\" / undefined keeps the existing\n // fallback chain below. \"openai\" is handled by the chain (it skips\n // earlier providers and lands on the Whisper path).\n\n if (providerPref === \"gemini\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (!geminiKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Gemini is selected but GEMINI_API_KEY is not configured. Add it in Settings → API Keys, or change the provider preference.\",\n };\n }\n try {\n const text = await transcribeWithGemini({\n audioBytes,\n mimeType: mime,\n apiKey: geminiKey,\n language: language || undefined,\n instructions,\n });\n const trimmed = text.trim();\n if (!trimmed) {\n setResponseStatus(event, 502);\n return { error: \"Gemini returned an empty transcript.\" };\n }\n return { text: trimmed };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Gemini transcription failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"builder\" || providerPref === \"builder-gemini\") {\n const label =\n providerPref === \"builder-gemini\"\n ? \"Builder Gemini Flash-Lite\"\n : \"Builder\";\n if (!(await hasBuilderPrivateKey())) {\n setResponseStatus(event, 400);\n return {\n error: `${label} is selected but Builder.io is not connected. Connect Builder.io in Settings, or change the provider preference.`,\n };\n }\n try {\n const result = await transcribeWithBuilderForRequest({\n audioBytes,\n mimeType: mime,\n model:\n providerPref === \"builder-gemini\"\n ? BUILDER_GEMINI_TRANSCRIPTION_MODEL\n : undefined,\n language: language || undefined,\n instructions,\n });\n return { text: (result.text ?? \"\").trim() };\n } catch (err) {\n const message = (err as Error)?.message ?? String(err);\n if (message.includes(\"credits exhausted\")) {\n setResponseStatus(event, 402);\n return { error: message };\n }\n setResponseStatus(event, 502);\n return { error: `${label} transcription failed: ${message}` };\n }\n }\n\n if (providerPref === \"groq\") {\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (!groqKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Groq is selected but GROQ_API_KEY is not configured. Add it in Settings → API Keys, or change the provider preference.\",\n };\n }\n return await callWhisperCompat({\n event,\n provider: {\n name: \"groq\",\n endpoint: GROQ_URL,\n model: GROQ_MODEL,\n apiKey: groqKey,\n },\n audioBytes,\n mime,\n language,\n instructions,\n });\n }\n\n // ── Auto / undefined / openai fallback chain ────────────────────────\n\n // ── Builder Gemini Flash-Lite path ─────────────────────────────────\n // First-priority in auto mode when Builder is connected. This lets users\n // try Gemini 3.1 Flash-Lite without bringing their own Google key.\n if (providerPref !== \"openai\" && (await hasBuilderPrivateKey())) {\n try {\n const result = await transcribeWithBuilderForRequest({\n audioBytes,\n mimeType: mime,\n model: BUILDER_GEMINI_TRANSCRIPTION_MODEL,\n language: language || undefined,\n instructions,\n });\n return { text: (result.text ?? \"\").trim() };\n } catch (err) {\n const message = (err as Error)?.message ?? String(err);\n // Surface 402 (credits exhausted) as a 402 so the client can show\n // a specific upgrade prompt.\n if (message.includes(\"credits exhausted\")) {\n setResponseStatus(event, 402);\n return { error: message };\n }\n builderError = message;\n }\n }\n\n // ── Gemini Flash Lite BYOK path ────────────────────────────────────\n // If Builder is unavailable, try a user-provided Gemini key before\n // Whisper-compatible providers.\n if (providerPref !== \"openai\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (geminiKey) {\n try {\n const text = await transcribeWithGemini({\n audioBytes,\n mimeType: mime,\n apiKey: geminiKey,\n language: language || undefined,\n instructions,\n });\n const trimmed = text.trim();\n if (trimmed) {\n console.log(`[transcribe-voice] Gemini → ${trimmed.length} chars`);\n return { text: trimmed };\n }\n console.warn(\n \"[transcribe-voice] Gemini returned empty text — falling through to next provider\",\n );\n } catch (err) {\n console.warn(\n \"[transcribe-voice] Gemini path failed, falling through:\",\n (err as Error)?.message ?? err,\n );\n }\n }\n }\n\n // If Builder is unavailable, fall through to BYOK providers rather than\n // hard-failing. This mirrors Clips' batch transcription path.\n\n // ── Groq / OpenAI Whisper-compatible path ──────────────────────────\n // (resolveApiKey is hoisted above so the Gemini path can use it too.)\n\n let provider: {\n name: \"groq\" | \"openai\";\n endpoint: string;\n model: string;\n apiKey: string;\n } | null = null;\n\n if (providerPref !== \"openai\") {\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (groqKey) {\n provider = {\n name: \"groq\",\n endpoint: GROQ_URL,\n model: GROQ_MODEL,\n apiKey: groqKey,\n };\n }\n }\n if (!provider) {\n const openaiKey = await resolveApiKey(\"OPENAI_API_KEY\");\n if (openaiKey) {\n provider = {\n name: \"openai\",\n endpoint: WHISPER_URL,\n model: OPENAI_MODEL,\n apiKey: openaiKey,\n };\n }\n }\n\n if (!provider) {\n setResponseStatus(event, builderError ? 502 : 400);\n return {\n error: builderError\n ? `Builder transcription failed: ${builderError}. Add GEMINI_API_KEY, GROQ_API_KEY, or OPENAI_API_KEY in Settings → API Keys to enable a fallback provider.`\n : \"No voice transcription provider configured. Connect Builder.io or add GEMINI_API_KEY / GROQ_API_KEY / OPENAI_API_KEY in Settings → API Keys.\",\n };\n }\n\n return await callWhisperCompat({\n event,\n provider,\n audioBytes,\n mime,\n language,\n instructions,\n });\n });\n}\n\n/**\n * Posts the audio to a Whisper-compatible OpenAI-style endpoint (Groq or\n * OpenAI itself) and returns `{ text }` / `{ error }` shaped like the\n * other branches in `createTranscribeVoiceHandler`. Hoisted so the\n * strict-Groq preference path and the auto fallback chain share one\n * implementation.\n */\nasync function callWhisperCompat({\n event,\n provider,\n audioBytes,\n mime,\n language,\n instructions,\n}: {\n event: H3Event;\n provider: {\n name: \"groq\" | \"openai\";\n endpoint: string;\n model: string;\n apiKey: string;\n };\n audioBytes: Uint8Array;\n mime: string;\n language?: string;\n instructions?: string;\n}): Promise<{ text: string } | { error: string }> {\n const ext = pickExtension(mime);\n const filename = `composer-voice.${ext}`;\n\n const form = new FormData();\n form.append(\n \"file\",\n new Blob([audioBytes as BlobPart], { type: mime }),\n filename,\n );\n form.append(\"model\", provider.model);\n form.append(\"response_format\", \"json\");\n if (language) form.append(\"language\", language);\n if (instructions) form.append(\"prompt\", instructions);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 45_000);\n try {\n const res = await fetch(provider.endpoint, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${provider.apiKey}` },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n setResponseStatus(event, res.status === 401 ? 401 : 502);\n return {\n error:\n res.status === 401\n ? `${provider.name} rejected the API key. Update it in Settings → API Keys.`\n : `${provider.name} transcription error ${res.status}: ${text.slice(0, 300)}`,\n };\n }\n const data = (await res.json()) as { text?: string };\n return { text: (data.text ?? \"\").trim() };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error:\n (err as Error)?.name === \"AbortError\"\n ? `${provider.name} transcription timed out after 45 seconds.`\n : `Could not reach ${provider.name}: ${(err as Error)?.message ?? err}`,\n };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function cleanupTranscriptText({\n event,\n text,\n instructions,\n providerPref,\n hasBuilderPrivateKey,\n withRequestContext,\n resolveApiKey,\n}: {\n event: H3Event;\n text: string;\n instructions?: string;\n providerPref?: string;\n hasBuilderPrivateKey: () => Promise<boolean>;\n withRequestContext: <T>(fn: () => Promise<T>) => Promise<T>;\n resolveApiKey: (key: string) => Promise<string | undefined>;\n}): Promise<{ text: string } | { error: string }> {\n const original = text.trim();\n if (!original) return { text: \"\" };\n\n if (providerPref === \"browser\") {\n return { text: original };\n }\n\n if (providerPref === \"builder\" || providerPref === \"builder-gemini\") {\n if (!(await hasBuilderPrivateKey())) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Builder.io cleanup is selected but Builder.io is not connected. Connect Builder.io in Settings, or change the provider preference.\",\n };\n }\n try {\n const cleaned = await withRequestContext(() =>\n cleanupWithBuilder({ text: original, instructions }),\n );\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Builder.io cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"gemini\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (!geminiKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Gemini cleanup is selected but GEMINI_API_KEY is not configured.\",\n };\n }\n try {\n const cleaned = await cleanupWithGemini({\n text: original,\n apiKey: geminiKey,\n instructions,\n });\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Gemini cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"openai\" || providerPref === \"groq\") {\n const keyName =\n providerPref === \"openai\" ? \"OPENAI_API_KEY\" : \"GROQ_API_KEY\";\n const apiKey = await resolveApiKey(keyName);\n if (!apiKey) {\n setResponseStatus(event, 400);\n return {\n error: `${providerPref} cleanup is selected but ${keyName} is not configured.`,\n };\n }\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: providerPref,\n text: original,\n apiKey,\n instructions,\n });\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `${providerPref} cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (await hasBuilderPrivateKey()) {\n try {\n const cleaned = await withRequestContext(() =>\n cleanupWithBuilder({ text: original, instructions }),\n );\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through to BYOK providers, then raw text.\n }\n }\n\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (geminiKey) {\n try {\n const cleaned = await cleanupWithGemini({\n text: original,\n apiKey: geminiKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (groqKey) {\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: \"groq\",\n text: original,\n apiKey: groqKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n const openaiKey = await resolveApiKey(\"OPENAI_API_KEY\");\n if (openaiKey) {\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: \"openai\",\n text: original,\n apiKey: openaiKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n return { text: original };\n}\n\nasync function cleanupWithBuilder({\n text,\n instructions,\n}: {\n text: string;\n instructions?: string;\n}): Promise<string> {\n const engine = createBuilderEngine();\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n let streamedText = \"\";\n let finalText = \"\";\n let terminalError: string | undefined;\n try {\n for await (const event of engine.stream({\n model: BUILDER_GEMINI_TRANSCRIPTION_MODEL,\n systemPrompt: buildCleanupSystemPrompt(instructions),\n messages: [\n {\n role: \"user\",\n content: [{ type: \"text\", text: buildCleanupUserPrompt(text) }],\n },\n ],\n tools: [],\n abortSignal: controller.signal,\n maxOutputTokens: Math.min(4096, Math.max(512, text.length * 2)),\n temperature: 0,\n })) {\n if (event.type === \"text-delta\") streamedText += event.text;\n if (event.type === \"assistant-content\") {\n finalText = event.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim();\n }\n if (event.type === \"stop\" && event.reason === \"error\") {\n terminalError = event.error ?? \"Builder gateway returned an error\";\n }\n }\n } finally {\n clearTimeout(timeout);\n }\n if (terminalError) throw new Error(terminalError);\n return stripTranscriptEnvelope(finalText || streamedText);\n}\n\nasync function cleanupWithGemini({\n text,\n apiKey,\n instructions,\n}: {\n text: string;\n apiKey: string;\n instructions?: string;\n}): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n try {\n const res = await fetch(GEMINI_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n { text: buildCleanupSystemPrompt(instructions) },\n { text: buildCleanupUserPrompt(text) },\n ],\n },\n ],\n generationConfig: { temperature: 0 },\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Gemini ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: Array<{\n content?: { parts?: Array<{ text?: string }> };\n }>;\n };\n const cleaned = data.candidates?.[0]?.content?.parts\n ?.map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n return stripTranscriptEnvelope(cleaned ?? \"\");\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function cleanupWithChatProvider({\n provider,\n text,\n apiKey,\n instructions,\n}: {\n provider: \"openai\" | \"groq\";\n text: string;\n apiKey: string;\n instructions?: string;\n}): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n const endpoint = provider === \"openai\" ? OPENAI_CHAT_URL : GROQ_CHAT_URL;\n const model =\n provider === \"openai\" ? OPENAI_CLEANUP_MODEL : GROQ_CLEANUP_MODEL;\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model,\n messages: [\n { role: \"system\", content: buildCleanupSystemPrompt(instructions) },\n { role: \"user\", content: buildCleanupUserPrompt(text) },\n ],\n temperature: 0,\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`${provider} ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n return stripTranscriptEnvelope(\n data.choices?.[0]?.message?.content?.trim() ?? \"\",\n );\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction pickExtension(mime: string): string {\n const lower = mime.toLowerCase();\n if (lower.includes(\"mp4\") || lower.includes(\"m4a\")) return \"mp4\";\n if (lower.includes(\"mpeg\") || lower.includes(\"mp3\")) return \"mp3\";\n if (lower.includes(\"ogg\")) return \"ogg\";\n if (lower.includes(\"wav\")) return \"wav\";\n return \"webm\";\n}\n\nfunction sanitizeInstructions(value: string): string | undefined {\n const trimmed = value.replace(/\\0/g, \"\").trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, 3000);\n}\n\nfunction sanitizeTranscriptText(value: string): string | undefined {\n const trimmed = value.replace(/\\0/g, \"\").trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, MAX_TRANSCRIPT_CHARS);\n}\n\nfunction buildCleanupSystemPrompt(instructions?: string): string {\n const custom = instructions\n ? `\\n\\nUser's custom cleanup instructions:\\n${instructions}`\n : \"\";\n return `You clean up live speech-recognition transcripts before paste.\n\nRules:\n- Preserve the speaker's meaning and voice.\n- Fix obvious recognition mistakes, punctuation, capitalization, spacing, and casing.\n- Remove false starts and filler only when they are clearly not intentional.\n- Do not add facts, explanations, headings, bullets, quotes, or markdown.\n- Output only the cleaned transcript text.${custom}`;\n}\n\nfunction buildCleanupUserPrompt(text: string): string {\n return `Clean up this transcript and return only the final text:\\n\\n<transcript>\\n${text}\\n</transcript>`;\n}\n\nfunction stripTranscriptEnvelope(value: string): string {\n return value\n .trim()\n .replace(/^```(?:text)?\\s*/i, \"\")\n .replace(/\\s*```$/i, \"\")\n .replace(/^[\"“](.*)[\"”]$/s, \"$1\")\n .trim();\n}\n\nfunction buildGeminiTranscriptionPrompt({\n language,\n instructions,\n}: {\n language?: string;\n instructions?: string;\n}): string {\n const base = language\n ? `Transcribe the speech in this audio (language: ${language}).`\n : \"Transcribe the speech in this audio.\";\n const custom = instructions\n ? `\\n\\nAdditional user instructions for transcription cleanup:\\n${instructions}\\n\\nApply these only to formatting, casing, punctuation, vocabulary, and cleanup. Do not add content that is not present in the audio.`\n : \"\";\n return `${base} Output only the transcript text — no preamble, no quotes, no formatting.${custom}`;\n}\n\n/**\n * Transcribe audio via Gemini Flash Lite.\n *\n * Gemini accepts the audio inline as base64 alongside a text prompt; we\n * ask for just the transcript with no preamble. 30s timeout — Gemini is\n * fast and we'd rather fall through to Whisper than wait longer.\n *\n * Gemini's documented audio formats are WAV / MP3 / AIFF / AAC / OGG /\n * FLAC — webm/opus is not officially supported but in practice it\n * accepts webm too. If Gemini rejects it the caller falls through.\n */\nasync function transcribeWithGemini({\n audioBytes,\n mimeType,\n apiKey,\n language,\n instructions,\n}: {\n audioBytes: Uint8Array;\n mimeType: string;\n apiKey: string;\n language?: string;\n instructions?: string;\n}): Promise<string> {\n const base64 = uint8ArrayToBase64(audioBytes);\n const prompt = buildGeminiTranscriptionPrompt({ language, instructions });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const res = await fetch(GEMINI_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n { text: prompt },\n {\n inlineData: {\n mimeType: normalizeAudioMimeForGemini(mimeType),\n data: base64,\n },\n },\n ],\n },\n ],\n // Keep generation tight — we want the transcript verbatim, no\n // creative reinterpretation.\n generationConfig: { temperature: 0 },\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Gemini ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: Array<{\n content?: { parts?: Array<{ text?: string }> };\n }>;\n };\n const text = data.candidates?.[0]?.content?.parts\n ?.map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n return text ?? \"\";\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction normalizeAudioMimeForGemini(mime: string): string {\n // Strip codec parameters — Gemini doesn't need them and some variants\n // (e.g. \"audio/webm;codecs=opus\") are rejected as unknown.\n const lower = mime.toLowerCase().split(\";\")[0].trim();\n if (!lower) return \"audio/webm\";\n return lower;\n}\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n // Fallback for non-Node runtimes — chunk to avoid stack overflow.\n let binary = \"\";\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(\n ...bytes.subarray(i, Math.min(i + chunk, bytes.length)),\n );\n }\n return btoa(binary);\n}\n"]}
1
+ {"version":3,"file":"transcribe-voice.js","sourceRoot":"","sources":["../../src/server/transcribe-voice.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * POST /_agent-native/transcribe-voice\n *\n * Receives an audio blob from the agent sidebar composer and forwards it to\n * the configured transcription provider. Returns `{ text }` on success,\n * `{ error }` on failure.\n *\n * Key resolution order for BYOK providers:\n * 1. Request-scoped encrypted secret (`app_secrets`: user, org, workspace).\n * 2. Env var fallback only outside authenticated request contexts.\n *\n * If no server provider is configured, returns 400 with an error the\n * composer UI can surface (the client falls back to Web Speech when possible).\n *\n * This is a framework route rather than a `defineAction` because multipart\n * audio bodies aren't a clean fit for the action contract (actions are\n * typed JSON-in / JSON-out).\n */\n\nimport {\n defineEventHandler,\n getMethod,\n getRequestHeader,\n readMultipartFormData,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { getSession } from \"./auth.js\";\nimport { appStateGet } from \"../application-state/store.js\";\nimport {\n resolveHasBuilderPrivateKey,\n resolveSecret,\n} from \"./credential-provider.js\";\nimport { transcribeWithBuilder } from \"../transcription/builder-transcription.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { createBuilderEngine } from \"../agent/engine/builder-engine.js\";\n\nconst WHISPER_URL = \"https://api.openai.com/v1/audio/transcriptions\";\nconst GROQ_URL = \"https://api.groq.com/openai/v1/audio/transcriptions\";\nconst GROQ_CHAT_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst GROQ_MODEL = \"whisper-large-v3-turbo\";\nconst GROQ_CLEANUP_MODEL = \"llama-3.3-70b-versatile\";\nconst OPENAI_MODEL = \"whisper-1\";\nconst OPENAI_CHAT_URL = \"https://api.openai.com/v1/chat/completions\";\nconst OPENAI_CLEANUP_MODEL = \"gpt-5.4-mini\";\nconst MAX_AUDIO_BYTES = 25 * 1024 * 1024; // Whisper hard limit.\nconst MAX_TRANSCRIPT_CHARS = 40_000;\n// Public Builder transcription model id. The Builder gateway maps this to\n// Gemini 3.1 Flash-Lite.\nconst BUILDER_GEMINI_TRANSCRIPTION_MODEL = \"gemini-3-1-flash-lite\";\n\n// Gemini Flash Lite BYOK path when GEMINI_API_KEY is configured.\n// Gemini accepts inline audio; we just give it the bytes and a \"transcribe\n// this\" prompt and it replies with text. 2.5x faster TTFT than 2.5 Flash\n// per Google's release notes, and noticeably snappier than the Whisper\n// round-trip even on a fast connection.\n// Keep the direct Google AI path on a stable public model id; Builder's\n// managed provider above handles the newer Gemini 3.1 Flash-Lite preview.\nconst GEMINI_MODEL = \"gemini-2.0-flash-lite\";\nconst GEMINI_URL = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent`;\n\n/**\n * Reject cross-site POSTs. Cookies are `SameSite=None; Secure` over HTTPS so\n * the browser would otherwise attach the session to a forged form submission\n * from evil.com, causing us to spend OpenAI credits on the user's behalf.\n * Same-origin browsers always send `Origin` on POST; if it's missing we fall\n * back to `Sec-Fetch-Site` so Safari's fetch-spec behavior still works.\n */\nfunction isSameOriginRequest(event: H3Event): boolean {\n const host = getRequestHeader(event, \"host\");\n const origin = getRequestHeader(event, \"origin\");\n if (origin && host) {\n try {\n const parsed = new URL(origin);\n if (parsed.host === host) return true;\n // Tauri desktop dev serves the tray WebView from localhost:1420 while\n // the app server lives on the template dev port. Production Tauri\n // WebViews can also send a tauri://localhost origin. Treat only those\n // desktop origins as trusted cross-origin callers; arbitrary websites\n // still fail the CSRF check.\n if (parsed.protocol === \"tauri:\" && parsed.hostname === \"localhost\") {\n return true;\n }\n if (\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n parsed.hostname === \"tauri.localhost\" &&\n (host.startsWith(\"localhost:\") || host.startsWith(\"127.0.0.1:\"))\n ) {\n return true;\n }\n if (\n parsed.protocol === \"http:\" &&\n (parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\") &&\n parsed.port === \"1420\" &&\n (host.startsWith(\"localhost:\") || host.startsWith(\"127.0.0.1:\"))\n ) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n }\n const fetchSite = getRequestHeader(event, \"sec-fetch-site\");\n if (fetchSite) return fetchSite === \"same-origin\" || fetchSite === \"none\";\n // No Origin and no Sec-Fetch-Site: likely a non-browser client (curl,\n // server-side) — safe to allow, CSRF requires a browser with ambient cookies.\n return true;\n}\n\nexport function createTranscribeVoiceHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!isSameOriginRequest(event)) {\n setResponseStatus(event, 403);\n return { error: \"Cross-origin request rejected\" };\n }\n\n const parts = await readMultipartFormData(event).catch(() => null);\n const audio = parts?.find((p) => p.name === \"audio\");\n const textPart = parts?.find((p) => p.name === \"text\");\n const transcriptText = textPart?.data\n ? sanitizeTranscriptText(textPart.data.toString(\"utf8\"))\n : undefined;\n if (!audio?.data?.length && !transcriptText) {\n setResponseStatus(event, 400);\n return { error: \"Missing audio or transcript payload\" };\n }\n if (audio?.data?.length && audio.data.length > MAX_AUDIO_BYTES) {\n setResponseStatus(event, 413);\n return { error: \"Audio too large (max 25 MB)\" };\n }\n\n const languagePart = parts?.find((p) => p.name === \"language\");\n const language = languagePart?.data\n ? languagePart.data.toString(\"utf8\").trim().slice(0, 8)\n : undefined;\n const instructionsPart = parts?.find((p) => p.name === \"instructions\");\n const instructions = instructionsPart?.data\n ? sanitizeInstructions(instructionsPart.data.toString(\"utf8\"))\n : undefined;\n\n // Resolve provider preference. Per-request \"provider\" form field takes\n // precedence (the desktop client sends it on every dictation press),\n // falling back to the user's stored `voice-transcription-prefs` app\n // state for the agent sidebar composer / web clients that don't send\n // it explicitly.\n const session = await getSession(event).catch(() => null);\n if (!session?.email && process.env.NODE_ENV === \"production\") {\n setResponseStatus(event, 401);\n return { error: \"Authentication required\" };\n }\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const requestContext = {\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n };\n const withRequestContext = async <T>(fn: () => Promise<T>): Promise<T> =>\n requestContext.userEmail\n ? runWithRequestContext(requestContext, fn)\n : fn();\n const hasBuilderPrivateKey = async () =>\n withRequestContext(() => resolveHasBuilderPrivateKey());\n const transcribeWithBuilderForRequest = (\n opts: Parameters<typeof transcribeWithBuilder>[0],\n ) => withRequestContext(() => transcribeWithBuilder(opts));\n const sessionId = session?.email ?? \"local\";\n let providerPref: string | undefined;\n // CRITICAL: presence of the \"provider\" form field is the explicit\n // signal that the client is making a per-request choice. Even if\n // the value is \"auto\" (→ undefined providerPref → fallback chain),\n // we must NOT fall back to app-state's stored preference — the\n // client just told us what it wants. Without this gate, a stale\n // `voice-transcription-prefs.provider = \"browser\"` in app-state\n // (from earlier testing) would override the client's \"auto\" and\n // 400 with \"Voice provider is set to browser\".\n const providerPart = parts?.find((p) => p.name === \"provider\");\n let providerExplicit = false;\n if (providerPart?.data) {\n const v = providerPart.data.toString(\"utf8\").trim().toLowerCase();\n if (\n v === \"auto\" ||\n v === \"browser\" ||\n v === \"builder\" ||\n v === \"builder-gemini\" ||\n v === \"gemini\" ||\n v === \"openai\" ||\n v === \"groq\"\n ) {\n providerExplicit = true;\n providerPref = v === \"auto\" ? undefined : v;\n }\n }\n if (!providerExplicit) {\n try {\n const prefs = await appStateGet(sessionId, \"voice-transcription-prefs\");\n providerPref = (\n prefs as { provider?: string; value?: { provider?: string } } | null\n )?.provider;\n providerPref ??= (prefs as { value?: { provider?: string } } | null)\n ?.value?.provider;\n } catch {\n /* fall through — default to fallback chain */\n }\n }\n\n // Respect explicit \"browser\" preference — user chose Web Speech API and\n // does not want audio uploaded to any external provider. The client\n // shouldn't hit this endpoint when \"browser\" is selected; this is a\n // defense-in-depth refusal.\n if (providerPref === \"browser\") {\n setResponseStatus(event, 400);\n return {\n error:\n 'Voice provider is set to \"browser\" (Web Speech API only). Change the preference in Settings → Voice Transcription to use a server-side provider.',\n };\n }\n\n // Per-user-or-fallback API key resolution. Hoisted up so the Gemini\n // path below can use it without duplicating logic.\n async function resolveApiKey(key: string): Promise<string | undefined> {\n return (await withRequestContext(() => resolveSecret(key))) ?? undefined;\n }\n\n if (transcriptText) {\n return await cleanupTranscriptText({\n event,\n text: transcriptText,\n instructions,\n providerPref,\n hasBuilderPrivateKey,\n withRequestContext,\n resolveApiKey,\n });\n }\n\n if (!audio?.data?.length) {\n setResponseStatus(event, 400);\n return { error: \"Missing audio payload\" };\n }\n\n const mime = audio.type || \"audio/webm\";\n const audioBytes = new Uint8Array(\n audio.data.buffer,\n audio.data.byteOffset,\n audio.data.byteLength,\n );\n\n let builderError: string | null = null;\n\n // ── Strict per-provider preferences ─────────────────────────────────\n // When the user explicitly picks a single provider (gemini / builder /\n // groq), we only try that provider and surface its error rather than\n // silently falling through. \"auto\" / undefined keeps the existing\n // fallback chain below. \"openai\" is handled by the chain (it skips\n // earlier providers and lands on the Whisper path).\n\n if (providerPref === \"gemini\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (!geminiKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Gemini is selected but GEMINI_API_KEY is not configured. Add it in Settings → API Keys, or change the provider preference.\",\n };\n }\n try {\n const text = await transcribeWithGemini({\n audioBytes,\n mimeType: mime,\n apiKey: geminiKey,\n language: language || undefined,\n instructions,\n });\n const trimmed = text.trim();\n if (!trimmed) {\n setResponseStatus(event, 502);\n return { error: \"Gemini returned an empty transcript.\" };\n }\n return { text: trimmed };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Gemini transcription failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"builder\" || providerPref === \"builder-gemini\") {\n const label =\n providerPref === \"builder-gemini\"\n ? \"Builder Gemini Flash-Lite\"\n : \"Builder\";\n if (!(await hasBuilderPrivateKey())) {\n setResponseStatus(event, 400);\n return {\n error: `${label} is selected but Builder.io is not connected. Connect Builder.io in Settings, or change the provider preference.`,\n };\n }\n try {\n const result = await transcribeWithBuilderForRequest({\n audioBytes,\n mimeType: mime,\n model:\n providerPref === \"builder-gemini\"\n ? BUILDER_GEMINI_TRANSCRIPTION_MODEL\n : undefined,\n language: language || undefined,\n instructions,\n });\n return { text: (result.text ?? \"\").trim() };\n } catch (err) {\n const message = (err as Error)?.message ?? String(err);\n if (message.includes(\"credits exhausted\")) {\n setResponseStatus(event, 402);\n return { error: message };\n }\n setResponseStatus(event, 502);\n return { error: `${label} transcription failed: ${message}` };\n }\n }\n\n if (providerPref === \"groq\") {\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (!groqKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Groq is selected but GROQ_API_KEY is not configured. Add it in Settings → API Keys, or change the provider preference.\",\n };\n }\n return await callWhisperCompat({\n event,\n provider: {\n name: \"groq\",\n endpoint: GROQ_URL,\n model: GROQ_MODEL,\n apiKey: groqKey,\n },\n audioBytes,\n mime,\n language,\n instructions,\n });\n }\n\n // ── Auto / undefined / openai fallback chain ────────────────────────\n\n // ── Builder Gemini Flash-Lite path ─────────────────────────────────\n // First-priority in auto mode when Builder is connected. This lets users\n // try Gemini 3.1 Flash-Lite without bringing their own Google key.\n if (providerPref !== \"openai\" && (await hasBuilderPrivateKey())) {\n try {\n const result = await transcribeWithBuilderForRequest({\n audioBytes,\n mimeType: mime,\n model: BUILDER_GEMINI_TRANSCRIPTION_MODEL,\n language: language || undefined,\n instructions,\n });\n return { text: (result.text ?? \"\").trim() };\n } catch (err) {\n const message = (err as Error)?.message ?? String(err);\n // Surface 402 (credits exhausted) as a 402 so the client can show\n // a specific upgrade prompt.\n if (message.includes(\"credits exhausted\")) {\n setResponseStatus(event, 402);\n return { error: message };\n }\n builderError = message;\n }\n }\n\n // ── Gemini Flash Lite BYOK path ────────────────────────────────────\n // If Builder is unavailable, try a user-provided Gemini key before\n // Whisper-compatible providers.\n if (providerPref !== \"openai\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (geminiKey) {\n try {\n const text = await transcribeWithGemini({\n audioBytes,\n mimeType: mime,\n apiKey: geminiKey,\n language: language || undefined,\n instructions,\n });\n const trimmed = text.trim();\n if (trimmed) {\n console.log(`[transcribe-voice] Gemini → ${trimmed.length} chars`);\n return { text: trimmed };\n }\n console.warn(\n \"[transcribe-voice] Gemini returned empty text — falling through to next provider\",\n );\n } catch (err) {\n console.warn(\n \"[transcribe-voice] Gemini path failed, falling through:\",\n (err as Error)?.message ?? err,\n );\n }\n }\n }\n\n // If Builder is unavailable, fall through to BYOK providers rather than\n // hard-failing. This mirrors Clips' batch transcription path.\n\n // ── Groq / OpenAI Whisper-compatible path ──────────────────────────\n // (resolveApiKey is hoisted above so the Gemini path can use it too.)\n\n let provider: {\n name: \"groq\" | \"openai\";\n endpoint: string;\n model: string;\n apiKey: string;\n } | null = null;\n\n if (providerPref !== \"openai\") {\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (groqKey) {\n provider = {\n name: \"groq\",\n endpoint: GROQ_URL,\n model: GROQ_MODEL,\n apiKey: groqKey,\n };\n }\n }\n if (!provider) {\n const openaiKey = await resolveApiKey(\"OPENAI_API_KEY\");\n if (openaiKey) {\n provider = {\n name: \"openai\",\n endpoint: WHISPER_URL,\n model: OPENAI_MODEL,\n apiKey: openaiKey,\n };\n }\n }\n\n if (!provider) {\n setResponseStatus(event, builderError ? 502 : 400);\n return {\n error: builderError\n ? `Builder transcription failed: ${builderError}. Add GEMINI_API_KEY, GROQ_API_KEY, or OPENAI_API_KEY in Settings → API Keys to enable a fallback provider.`\n : \"No voice transcription provider configured. Connect Builder.io or add GEMINI_API_KEY / GROQ_API_KEY / OPENAI_API_KEY in Settings → API Keys.\",\n };\n }\n\n return await callWhisperCompat({\n event,\n provider,\n audioBytes,\n mime,\n language,\n instructions,\n });\n });\n}\n\n/**\n * Posts the audio to a Whisper-compatible OpenAI-style endpoint (Groq or\n * OpenAI itself) and returns `{ text }` / `{ error }` shaped like the\n * other branches in `createTranscribeVoiceHandler`. Hoisted so the\n * strict-Groq preference path and the auto fallback chain share one\n * implementation.\n */\nasync function callWhisperCompat({\n event,\n provider,\n audioBytes,\n mime,\n language,\n instructions,\n}: {\n event: H3Event;\n provider: {\n name: \"groq\" | \"openai\";\n endpoint: string;\n model: string;\n apiKey: string;\n };\n audioBytes: Uint8Array;\n mime: string;\n language?: string;\n instructions?: string;\n}): Promise<{ text: string } | { error: string }> {\n const ext = pickExtension(mime);\n const filename = `composer-voice.${ext}`;\n\n const form = new FormData();\n form.append(\n \"file\",\n new Blob([audioBytes as BlobPart], { type: mime }),\n filename,\n );\n form.append(\"model\", provider.model);\n form.append(\"response_format\", \"json\");\n if (language) form.append(\"language\", language);\n if (instructions) form.append(\"prompt\", instructions);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 45_000);\n try {\n const res = await fetch(provider.endpoint, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${provider.apiKey}` },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n setResponseStatus(event, res.status === 401 ? 401 : 502);\n return {\n error:\n res.status === 401\n ? `${provider.name} rejected the API key. Update it in Settings → API Keys.`\n : `${provider.name} transcription error ${res.status}: ${text.slice(0, 300)}`,\n };\n }\n const data = (await res.json()) as { text?: string };\n return { text: (data.text ?? \"\").trim() };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error:\n (err as Error)?.name === \"AbortError\"\n ? `${provider.name} transcription timed out after 45 seconds.`\n : `Could not reach ${provider.name}: ${(err as Error)?.message ?? err}`,\n };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function cleanupTranscriptText({\n event,\n text,\n instructions,\n providerPref,\n hasBuilderPrivateKey,\n withRequestContext,\n resolveApiKey,\n}: {\n event: H3Event;\n text: string;\n instructions?: string;\n providerPref?: string;\n hasBuilderPrivateKey: () => Promise<boolean>;\n withRequestContext: <T>(fn: () => Promise<T>) => Promise<T>;\n resolveApiKey: (key: string) => Promise<string | undefined>;\n}): Promise<{ text: string } | { error: string }> {\n const original = text.trim();\n if (!original) return { text: \"\" };\n\n if (providerPref === \"browser\") {\n return { text: original };\n }\n\n if (providerPref === \"builder\" || providerPref === \"builder-gemini\") {\n if (!(await hasBuilderPrivateKey())) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Builder.io cleanup is selected but Builder.io is not connected. Connect Builder.io in Settings, or change the provider preference.\",\n };\n }\n try {\n const cleaned = await withRequestContext(() =>\n cleanupWithBuilder({ text: original, instructions }),\n );\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Builder.io cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"gemini\") {\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (!geminiKey) {\n setResponseStatus(event, 400);\n return {\n error:\n \"Gemini cleanup is selected but GEMINI_API_KEY is not configured.\",\n };\n }\n try {\n const cleaned = await cleanupWithGemini({\n text: original,\n apiKey: geminiKey,\n instructions,\n });\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `Gemini cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (providerPref === \"openai\" || providerPref === \"groq\") {\n const keyName =\n providerPref === \"openai\" ? \"OPENAI_API_KEY\" : \"GROQ_API_KEY\";\n const apiKey = await resolveApiKey(keyName);\n if (!apiKey) {\n setResponseStatus(event, 400);\n return {\n error: `${providerPref} cleanup is selected but ${keyName} is not configured.`,\n };\n }\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: providerPref,\n text: original,\n apiKey,\n instructions,\n });\n return { text: cleaned || original };\n } catch (err) {\n setResponseStatus(event, 502);\n return {\n error: `${providerPref} cleanup failed: ${(err as Error)?.message ?? String(err)}`,\n };\n }\n }\n\n if (await hasBuilderPrivateKey()) {\n try {\n const cleaned = await withRequestContext(() =>\n cleanupWithBuilder({ text: original, instructions }),\n );\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through to BYOK providers, then raw text.\n }\n }\n\n const geminiKey = await resolveApiKey(\"GEMINI_API_KEY\");\n if (geminiKey) {\n try {\n const cleaned = await cleanupWithGemini({\n text: original,\n apiKey: geminiKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n const groqKey = await resolveApiKey(\"GROQ_API_KEY\");\n if (groqKey) {\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: \"groq\",\n text: original,\n apiKey: groqKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n const openaiKey = await resolveApiKey(\"OPENAI_API_KEY\");\n if (openaiKey) {\n try {\n const cleaned = await cleanupWithChatProvider({\n provider: \"openai\",\n text: original,\n apiKey: openaiKey,\n instructions,\n });\n if (cleaned) return { text: cleaned };\n } catch {\n // Fall through.\n }\n }\n\n return { text: original };\n}\n\nasync function cleanupWithBuilder({\n text,\n instructions,\n}: {\n text: string;\n instructions?: string;\n}): Promise<string> {\n const engine = createBuilderEngine();\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n let streamedText = \"\";\n let finalText = \"\";\n let terminalError: string | undefined;\n try {\n for await (const event of engine.stream({\n model: BUILDER_GEMINI_TRANSCRIPTION_MODEL,\n systemPrompt: buildCleanupSystemPrompt(instructions),\n messages: [\n {\n role: \"user\",\n content: [{ type: \"text\", text: buildCleanupUserPrompt(text) }],\n },\n ],\n tools: [],\n abortSignal: controller.signal,\n maxOutputTokens: Math.min(4096, Math.max(512, text.length * 2)),\n temperature: 0,\n })) {\n if (event.type === \"text-delta\") streamedText += event.text;\n if (event.type === \"assistant-content\") {\n finalText = event.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim();\n }\n if (event.type === \"stop\" && event.reason === \"error\") {\n terminalError = event.error ?? \"Builder gateway returned an error\";\n }\n }\n } finally {\n clearTimeout(timeout);\n }\n if (terminalError) throw new Error(terminalError);\n return stripTranscriptEnvelope(finalText || streamedText);\n}\n\nasync function cleanupWithGemini({\n text,\n apiKey,\n instructions,\n}: {\n text: string;\n apiKey: string;\n instructions?: string;\n}): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n try {\n const res = await fetch(GEMINI_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n { text: buildCleanupSystemPrompt(instructions) },\n { text: buildCleanupUserPrompt(text) },\n ],\n },\n ],\n generationConfig: { temperature: 0 },\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Gemini ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: Array<{\n content?: { parts?: Array<{ text?: string }> };\n }>;\n };\n const cleaned = data.candidates?.[0]?.content?.parts\n ?.map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n return stripTranscriptEnvelope(cleaned ?? \"\");\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function cleanupWithChatProvider({\n provider,\n text,\n apiKey,\n instructions,\n}: {\n provider: \"openai\" | \"groq\";\n text: string;\n apiKey: string;\n instructions?: string;\n}): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 8_000);\n const endpoint = provider === \"openai\" ? OPENAI_CHAT_URL : GROQ_CHAT_URL;\n const model =\n provider === \"openai\" ? OPENAI_CLEANUP_MODEL : GROQ_CLEANUP_MODEL;\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model,\n messages: [\n { role: \"system\", content: buildCleanupSystemPrompt(instructions) },\n { role: \"user\", content: buildCleanupUserPrompt(text) },\n ],\n temperature: 0,\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`${provider} ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n return stripTranscriptEnvelope(\n data.choices?.[0]?.message?.content?.trim() ?? \"\",\n );\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction pickExtension(mime: string): string {\n const lower = mime.toLowerCase();\n if (lower.includes(\"mp4\") || lower.includes(\"m4a\")) return \"mp4\";\n if (lower.includes(\"mpeg\") || lower.includes(\"mp3\")) return \"mp3\";\n if (lower.includes(\"ogg\")) return \"ogg\";\n if (lower.includes(\"wav\")) return \"wav\";\n return \"webm\";\n}\n\nfunction sanitizeInstructions(value: string): string | undefined {\n const trimmed = value.replace(/\\0/g, \"\").trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, 3000);\n}\n\nfunction sanitizeTranscriptText(value: string): string | undefined {\n const trimmed = value.replace(/\\0/g, \"\").trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, MAX_TRANSCRIPT_CHARS);\n}\n\nfunction buildCleanupSystemPrompt(instructions?: string): string {\n const custom = instructions\n ? `\\n\\nUser's custom cleanup instructions:\\n${instructions}`\n : \"\";\n return `You clean up live speech-recognition transcripts before paste.\n\nRules:\n- Preserve the speaker's meaning and voice.\n- Fix obvious recognition mistakes, punctuation, capitalization, spacing, and casing.\n- Remove false starts and filler only when they are clearly not intentional.\n- Do not add facts, explanations, headings, bullets, quotes, or markdown.\n- Output only the cleaned transcript text.${custom}`;\n}\n\nfunction buildCleanupUserPrompt(text: string): string {\n return `Clean up this transcript and return only the final text:\\n\\n<transcript>\\n${text}\\n</transcript>`;\n}\n\nfunction stripTranscriptEnvelope(value: string): string {\n return value\n .trim()\n .replace(/^```(?:text)?\\s*/i, \"\")\n .replace(/\\s*```$/i, \"\")\n .replace(/^[\"“](.*)[\"”]$/s, \"$1\")\n .trim();\n}\n\nfunction buildGeminiTranscriptionPrompt({\n language,\n instructions,\n}: {\n language?: string;\n instructions?: string;\n}): string {\n const base = language\n ? `Transcribe the speech in this audio (language: ${language}).`\n : \"Transcribe the speech in this audio.\";\n const custom = instructions\n ? `\\n\\nAdditional user instructions for transcription cleanup:\\n${instructions}\\n\\nApply these only to formatting, casing, punctuation, vocabulary, and cleanup. Do not add content that is not present in the audio.`\n : \"\";\n return `${base} Output only the transcript text — no preamble, no quotes, no formatting.${custom}`;\n}\n\n/**\n * Transcribe audio via Gemini Flash Lite.\n *\n * Gemini accepts the audio inline as base64 alongside a text prompt; we\n * ask for just the transcript with no preamble. 30s timeout — Gemini is\n * fast and we'd rather fall through to Whisper than wait longer.\n *\n * Gemini's documented audio formats are WAV / MP3 / AIFF / AAC / OGG /\n * FLAC — webm/opus is not officially supported but in practice it\n * accepts webm too. If Gemini rejects it the caller falls through.\n */\nasync function transcribeWithGemini({\n audioBytes,\n mimeType,\n apiKey,\n language,\n instructions,\n}: {\n audioBytes: Uint8Array;\n mimeType: string;\n apiKey: string;\n language?: string;\n instructions?: string;\n}): Promise<string> {\n const base64 = uint8ArrayToBase64(audioBytes);\n const prompt = buildGeminiTranscriptionPrompt({ language, instructions });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const res = await fetch(GEMINI_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": apiKey,\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n { text: prompt },\n {\n inlineData: {\n mimeType: normalizeAudioMimeForGemini(mimeType),\n data: base64,\n },\n },\n ],\n },\n ],\n // Keep generation tight — we want the transcript verbatim, no\n // creative reinterpretation.\n generationConfig: { temperature: 0 },\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Gemini ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: Array<{\n content?: { parts?: Array<{ text?: string }> };\n }>;\n };\n const text = data.candidates?.[0]?.content?.parts\n ?.map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n return text ?? \"\";\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction normalizeAudioMimeForGemini(mime: string): string {\n // Strip codec parameters — Gemini doesn't need them and some variants\n // (e.g. \"audio/webm;codecs=opus\") are rejected as unknown.\n const lower = mime.toLowerCase().split(\";\")[0].trim();\n if (!lower) return \"audio/webm\";\n return lower;\n}\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n // Fallback for non-Node runtimes — chunk to avoid stack overflow.\n let binary = \"\";\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(\n ...bytes.subarray(i, Math.min(i + chunk, bytes.length)),\n );\n }\n return btoa(binary);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"voice-providers-status.d.ts","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,6EAA6E;IAC7E,OAAO,EAAE,IAAI,CAAC;IACd;;;;;OAKG;IACH,MAAM,EAAE,IAAI,CAAC;CACd;AAED,wBAAgB,iCAAiC;;IA6EhD"}
1
+ {"version":3,"file":"voice-providers-status.d.ts","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,6EAA6E;IAC7E,OAAO,EAAE,IAAI,CAAC;IACd;;;;;OAKG;IACH,MAAM,EAAE,IAAI,CAAC;CACd;AAED,wBAAgB,iCAAiC;;IA+DhD"}
@@ -5,19 +5,16 @@
5
5
  * current user. The desktop Settings UI uses this to show "Connect" vs
6
6
  * "Connected" status pills next to each provider option.
7
7
  *
8
- * Resolution mirrors `transcribe-voice.ts`: we try the user-scoped
9
- * encrypted secret first (set via the sidebar settings UI) and fall back
10
- * to `resolveCredential()` (env var + SQL settings store). Each lookup is
11
- * wrapped in try/catch — one provider's failure must never break the
12
- * whole response.
8
+ * Resolution mirrors `transcribe-voice.ts`: we read request-scoped encrypted
9
+ * secrets (user, org, workspace), with env fallback only outside authenticated
10
+ * request contexts. Each lookup is wrapped in try/catch one provider's
11
+ * failure must never break the whole response.
13
12
  *
14
13
  * Returns booleans only — never the actual key material.
15
14
  */
16
15
  import { defineEventHandler, getMethod, setResponseStatus, } from "h3";
17
- import { readAppSecret } from "../secrets/storage.js";
18
- import { resolveCredential } from "../credentials/index.js";
19
16
  import { getSession } from "./auth.js";
20
- import { resolveHasBuilderPrivateKey } from "./credential-provider.js";
17
+ import { resolveHasBuilderPrivateKey, resolveSecret, } from "./credential-provider.js";
21
18
  import { getOrgContext } from "../org/context.js";
22
19
  import { runWithRequestContext } from "./request-context.js";
23
20
  import { resolveGoogleRealtimeCredentials } from "./google-realtime-session.js";
@@ -28,32 +25,27 @@ export function createVoiceProvidersStatusHandler() {
28
25
  return { error: "Method not allowed" };
29
26
  }
30
27
  const session = await getSession(event).catch(() => null);
28
+ const orgCtx = session?.email
29
+ ? await getOrgContext(event).catch(() => null)
30
+ : null;
31
+ const requestContext = {
32
+ userEmail: session?.email,
33
+ orgId: orgCtx?.orgId ?? undefined,
34
+ };
35
+ const withRequestContext = async (fn) => requestContext.userEmail
36
+ ? runWithRequestContext(requestContext, fn)
37
+ : fn();
31
38
  async function hasKey(key) {
32
39
  try {
33
40
  if (key === "GOOGLE_APPLICATION_CREDENTIALS") {
34
- const orgCtx = session?.email
35
- ? await getOrgContext(event).catch(() => null)
36
- : null;
37
41
  const resolved = await resolveGoogleRealtimeCredentials({
38
42
  userEmail: session?.email,
39
43
  orgId: orgCtx?.orgId ?? undefined,
40
44
  });
41
45
  return typeof resolved === "string" && resolved.length > 0;
42
46
  }
43
- const ctx = { userEmail: session?.email };
44
- if (!session?.email) {
45
- const v = await resolveCredential(key, ctx);
46
- return typeof v === "string" && v.length > 0;
47
- }
48
- const userSecret = await readAppSecret({
49
- key,
50
- scope: "user",
51
- scopeId: session.email,
52
- }).catch(() => null);
53
- if (userSecret?.value && userSecret.value.length > 0)
54
- return true;
55
- const fallback = await resolveCredential(key, ctx);
56
- return typeof fallback === "string" && fallback.length > 0;
47
+ const resolved = await withRequestContext(() => resolveSecret(key));
48
+ return typeof resolved === "string" && resolved.length > 0;
57
49
  }
58
50
  catch {
59
51
  return false;
@@ -61,17 +53,9 @@ export function createVoiceProvidersStatusHandler() {
61
53
  }
62
54
  let builder = false;
63
55
  try {
64
- const orgCtx = session?.email
65
- ? await getOrgContext(event).catch(() => null)
66
- : null;
67
- const resolve = () => resolveHasBuilderPrivateKey();
68
56
  builder =
69
- (session?.email
70
- ? await runWithRequestContext({
71
- userEmail: session.email,
72
- orgId: orgCtx?.orgId ?? undefined,
73
- }, resolve)
74
- : await resolve()) === true;
57
+ (await withRequestContext(() => resolveHasBuilderPrivateKey())) ===
58
+ true;
75
59
  }
76
60
  catch {
77
61
  builder = false;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-providers-status.js","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GET /_agent-native/voice-providers/status\n *\n * Reports which voice transcription providers are configured for the\n * current user. The desktop Settings UI uses this to show \"Connect\" vs\n * \"Connected\" status pills next to each provider option.\n *\n * Resolution mirrors `transcribe-voice.ts`: we try the user-scoped\n * encrypted secret first (set via the sidebar settings UI) and fall back\n * to `resolveCredential()` (env var + SQL settings store). Each lookup is\n * wrapped in try/catch — one provider's failure must never break the\n * whole response.\n *\n * Returns booleans only — never the actual key material.\n */\nimport {\n defineEventHandler,\n getMethod,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { readAppSecret } from \"../secrets/storage.js\";\nimport { resolveCredential } from \"../credentials/index.js\";\nimport { getSession } from \"./auth.js\";\nimport { resolveHasBuilderPrivateKey } from \"./credential-provider.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { resolveGoogleRealtimeCredentials } from \"./google-realtime-session.js\";\n\nexport interface VoiceProvidersStatus {\n builder: boolean;\n gemini: boolean;\n openai: boolean;\n groq: boolean;\n /**\n * Google Speech-to-Text realtime streaming is BYOK-only for v1. This reports\n * whether a service-account credential is configured; the actual stream runs\n * through the dedicated WebSocket -> StreamingRecognize path, not the batch\n * transcribe route.\n */\n googleRealtime: boolean;\n /** Always true — the Web Speech API is available in WebKit-based clients. */\n browser: true;\n /**\n * Apple's SFSpeechRecognizer + AVAudioEngine, exposed by the Tauri\n * desktop client. Always reported as `true` from the server — the\n * desktop client gates this on macOS at the Tauri-command boundary, so\n * non-macOS hosts return a clear error instead of attempting to use it.\n */\n native: true;\n}\n\nexport function createVoiceProvidersStatusHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const session = await getSession(event).catch(() => null);\n\n async function hasKey(key: string): Promise<boolean> {\n try {\n if (key === \"GOOGLE_APPLICATION_CREDENTIALS\") {\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const resolved = await resolveGoogleRealtimeCredentials({\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n });\n return typeof resolved === \"string\" && resolved.length > 0;\n }\n const ctx = { userEmail: session?.email };\n if (!session?.email) {\n const v = await resolveCredential(key, ctx);\n return typeof v === \"string\" && v.length > 0;\n }\n const userSecret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: session.email,\n }).catch(() => null);\n if (userSecret?.value && userSecret.value.length > 0) return true;\n const fallback = await resolveCredential(key, ctx);\n return typeof fallback === \"string\" && fallback.length > 0;\n } catch {\n return false;\n }\n }\n\n let builder = false;\n try {\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const resolve = () => resolveHasBuilderPrivateKey();\n builder =\n (session?.email\n ? await runWithRequestContext(\n {\n userEmail: session.email,\n orgId: orgCtx?.orgId ?? undefined,\n },\n resolve,\n )\n : await resolve()) === true;\n } catch {\n builder = false;\n }\n\n const [gemini, openai, groq, googleRealtime] = await Promise.all([\n hasKey(\"GEMINI_API_KEY\"),\n hasKey(\"OPENAI_API_KEY\"),\n hasKey(\"GROQ_API_KEY\"),\n hasKey(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n ]);\n\n const status: VoiceProvidersStatus = {\n builder,\n gemini,\n openai,\n groq,\n googleRealtime,\n browser: true,\n native: true,\n };\n return status;\n });\n}\n"]}
1
+ {"version":3,"file":"voice-providers-status.js","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,GAElB,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACL,2BAA2B,EAC3B,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAyBhF,MAAM,UAAU,iCAAiC;IAC/C,OAAO,kBAAkB,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QACjD,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;YAC/B,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK;YAC3B,CAAC,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YAC9C,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,cAAc,GAAG;YACrB,SAAS,EAAE,OAAO,EAAE,KAAK;YACzB,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,SAAS;SAClC,CAAC;QACF,MAAM,kBAAkB,GAAG,KAAK,EAAK,EAAoB,EAAc,EAAE,CACvE,cAAc,CAAC,SAAS;YACtB,CAAC,CAAC,qBAAqB,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3C,CAAC,CAAC,EAAE,EAAE,CAAC;QAEX,KAAK,UAAU,MAAM,CAAC,GAAW;YAC/B,IAAI,CAAC;gBACH,IAAI,GAAG,KAAK,gCAAgC,EAAE,CAAC;oBAC7C,MAAM,QAAQ,GAAG,MAAM,gCAAgC,CAAC;wBACtD,SAAS,EAAE,OAAO,EAAE,KAAK;wBACzB,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,SAAS;qBAClC,CAAC,CAAC;oBACH,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC7D,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;gBACpE,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7D,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC;YACH,OAAO;gBACL,CAAC,MAAM,kBAAkB,CAAC,GAAG,EAAE,CAAC,2BAA2B,EAAE,CAAC,CAAC;oBAC/D,IAAI,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;QAED,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC/D,MAAM,CAAC,gBAAgB,CAAC;YACxB,MAAM,CAAC,gBAAgB,CAAC;YACxB,MAAM,CAAC,cAAc,CAAC;YACtB,MAAM,CAAC,gCAAgC,CAAC;SACzC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAyB;YACnC,OAAO;YACP,MAAM;YACN,MAAM;YACN,IAAI;YACJ,cAAc;YACd,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;SACb,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * GET /_agent-native/voice-providers/status\n *\n * Reports which voice transcription providers are configured for the\n * current user. The desktop Settings UI uses this to show \"Connect\" vs\n * \"Connected\" status pills next to each provider option.\n *\n * Resolution mirrors `transcribe-voice.ts`: we read request-scoped encrypted\n * secrets (user, org, workspace), with env fallback only outside authenticated\n * request contexts. Each lookup is wrapped in try/catch — one provider's\n * failure must never break the whole response.\n *\n * Returns booleans only — never the actual key material.\n */\nimport {\n defineEventHandler,\n getMethod,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { getSession } from \"./auth.js\";\nimport {\n resolveHasBuilderPrivateKey,\n resolveSecret,\n} from \"./credential-provider.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { resolveGoogleRealtimeCredentials } from \"./google-realtime-session.js\";\n\nexport interface VoiceProvidersStatus {\n builder: boolean;\n gemini: boolean;\n openai: boolean;\n groq: boolean;\n /**\n * Google Speech-to-Text realtime streaming is BYOK-only for v1. This reports\n * whether a service-account credential is configured; the actual stream runs\n * through the dedicated WebSocket -> StreamingRecognize path, not the batch\n * transcribe route.\n */\n googleRealtime: boolean;\n /** Always true — the Web Speech API is available in WebKit-based clients. */\n browser: true;\n /**\n * Apple's SFSpeechRecognizer + AVAudioEngine, exposed by the Tauri\n * desktop client. Always reported as `true` from the server — the\n * desktop client gates this on macOS at the Tauri-command boundary, so\n * non-macOS hosts return a clear error instead of attempting to use it.\n */\n native: true;\n}\n\nexport function createVoiceProvidersStatusHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const session = await getSession(event).catch(() => null);\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const requestContext = {\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n };\n const withRequestContext = async <T>(fn: () => Promise<T>): Promise<T> =>\n requestContext.userEmail\n ? runWithRequestContext(requestContext, fn)\n : fn();\n\n async function hasKey(key: string): Promise<boolean> {\n try {\n if (key === \"GOOGLE_APPLICATION_CREDENTIALS\") {\n const resolved = await resolveGoogleRealtimeCredentials({\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n });\n return typeof resolved === \"string\" && resolved.length > 0;\n }\n const resolved = await withRequestContext(() => resolveSecret(key));\n return typeof resolved === \"string\" && resolved.length > 0;\n } catch {\n return false;\n }\n }\n\n let builder = false;\n try {\n builder =\n (await withRequestContext(() => resolveHasBuilderPrivateKey())) ===\n true;\n } catch {\n builder = false;\n }\n\n const [gemini, openai, groq, googleRealtime] = await Promise.all([\n hasKey(\"GEMINI_API_KEY\"),\n hasKey(\"OPENAI_API_KEY\"),\n hasKey(\"GROQ_API_KEY\"),\n hasKey(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n ]);\n\n const status: VoiceProvidersStatus = {\n builder,\n gemini,\n openai,\n groq,\n googleRealtime,\n browser: true,\n native: true,\n };\n return status;\n });\n}\n"]}
@@ -80,6 +80,7 @@
80
80
 
81
81
  --animate-accordion-down: accordion-down 0.2s ease-out;
82
82
  --animate-accordion-up: accordion-up 0.2s ease-out;
83
+ --animate-bounce-once: bounce-once 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
83
84
 
84
85
  @keyframes accordion-down {
85
86
  from {
@@ -97,6 +98,20 @@
97
98
  height: 0;
98
99
  }
99
100
  }
101
+ @keyframes bounce-once {
102
+ 0% {
103
+ transform: translateY(0);
104
+ }
105
+ 35% {
106
+ transform: translateY(-8px);
107
+ }
108
+ 65% {
109
+ transform: translateY(-2px);
110
+ }
111
+ 100% {
112
+ transform: translateY(0);
113
+ }
114
+ }
100
115
  }
101
116
 
102
117
  /* Border-color compatibility shim:
@@ -1,15 +1,13 @@
1
1
  ---
2
- title: "Cloneable SaaS"
2
+ title: "Templates"
3
3
  description: "Fork a working SaaS product and make it yours — agent included."
4
4
  ---
5
5
 
6
- # Cloneable SaaS
6
+ # Templates
7
7
 
8
8
  Want to ship your own AI-powered analytics tool? Mail client? Forms builder? Pick a template, and you've got a working SaaS in minutes — agent, database, auth, and deploy pipeline already wired up.
9
9
 
10
- Most templates give you a blank scaffold and a long TODO list. Agent-native flips that. Each template is a **complete, SaaS-grade product** — already runnable on day one, already shippable, and entirely yours to customize, brand, and deploy.
11
-
12
- We call them **cloneable SaaS**, not templates. You're not starting from scratch. You're forking a finished product.
10
+ Most "templates" give you a blank scaffold and a long TODO list. Agent-native flips that. Each one is a **complete, SaaS-grade product** — already runnable on day one, already shippable, and entirely yours to customize, brand, and deploy. Think of them as cloneable SaaS, not starter kits: you're forking a finished product, not staring at boilerplate.
13
11
 
14
12
  ## Templates available {#catalog}
15
13
 
@@ -33,7 +31,7 @@ See the full catalog under [Templates](/templates), or jump straight to one —
33
31
 
34
32
  ## What you get out of the box {#what-you-get}
35
33
 
36
- Every cloneable SaaS ships with the parts that normally take months to build:
34
+ Every template ships with the parts that normally take months to build:
37
35
 
38
36
  - **A working agent** — already wired into the app, already able to take actions on your data, already context-aware about what you're looking at. See [Messaging the agent](/docs/messaging) for how it works.
39
37
  - **Auth** — sign in, sessions, organizations, multi-tenant isolation. Already done.
@@ -72,9 +70,9 @@ You don't have to. Every template is also available as a hosted app on `agent-na
72
70
 
73
71
  - [**Getting Started**](/docs/getting-started) — clone your first template and run it locally
74
72
  - [**Messaging the agent**](/docs/messaging) — how users (and you) talk to the agent that ships with each template
75
- - [**Multi-App Workspace**](/docs/multi-app-workspace) — bundle several cloneable-SaaS apps into one workspace that shares auth, brand, and agent
73
+ - [**Multi-App Workspace**](/docs/multi-app-workspace) — bundle several templates into one workspace that shares auth, brand, and agent
76
74
  - [**Dispatch**](/docs/template-dispatch) — the workspace control plane template
77
- - [**Creating Templates**](/docs/creating-templates) — author and publish your own cloneable SaaS
75
+ - [**Creating Templates**](/docs/creating-templates) — author and publish your own template
78
76
 
79
77
  ### For developers {#dev-details}
80
78
 
@@ -90,4 +88,4 @@ Fill in `.env` (mostly `ANTHROPIC_API_KEY` and `DATABASE_URL`), `pnpm install`,
90
88
 
91
89
  Deploy targets: any Nitro-compatible host (Node, Cloudflare, Netlify, Vercel, Deno, Lambda, Bun) and any Drizzle-compatible SQL database (SQLite, Postgres, Turso, D1, Supabase, Neon). For workspaces, `agent-native deploy` builds every app at once and ships them behind a single origin. See [Deployment](/docs/deployment).
92
90
 
93
- To author and publish your own cloneable SaaS, see [Creating Templates](/docs/creating-templates).
91
+ To author and publish your own template, see [Creating Templates](/docs/creating-templates).
@@ -90,17 +90,21 @@ node .output/server/index.mjs
90
90
 
91
91
  Set `PORT` to configure the listen port (default: `3000`).
92
92
 
93
+ Use the current Node.js LTS line for production deploys. As of May 2026, that
94
+ is Node.js 24; Node.js 20 reached end-of-life on April 30, 2026 and no longer
95
+ receives upstream security updates.
96
+
93
97
  ### Docker {#docker}
94
98
 
95
99
  ```dockerfile
96
- FROM node:20-slim AS build
100
+ FROM node:24-slim AS build
97
101
  WORKDIR /app
98
102
  COPY package.json pnpm-lock.yaml ./
99
103
  RUN corepack enable && pnpm install --frozen-lockfile
100
104
  COPY . .
101
105
  RUN pnpm build
102
106
 
103
- FROM node:20-slim
107
+ FROM node:24-slim
104
108
  WORKDIR /app
105
109
  COPY --from=build /app/.output .output
106
110
  COPY --from=build /app/data data
@@ -81,7 +81,7 @@ Three short steps:
81
81
 
82
82
  1. **Scaffold a workspace that includes Dispatch.** Run `pnpm dlx @agent-native/core create my-company-platform` and pick `dispatch` alongside whatever domain templates you want. Dispatch lives at `apps/dispatch` and the rest of the apps sit beside it. See [Multi-App Workspace](/docs/multi-app-workspace).
83
83
  2. **Connect messaging.** Open **Settings → Messaging** in Dispatch and click connect for Slack, Email, Telegram, or WhatsApp. The form fields match the env vars in the [Messaging](/docs/messaging) doc — refer there for what each platform needs.
84
- 3. **Add other apps.** Run `agent-native add-app` from the workspace root for each domain app. They auto-appear as A2A peers in Dispatch's `list-workspace-apps` — no manual registration, no agent-card editing. Dispatch will start delegating to them as soon as their agent cards are reachable.
84
+ 3. **Add other apps.** Run `npx @agent-native/core add-app` from the workspace root for each domain app. They auto-appear as A2A peers in Dispatch's `list-workspace-apps` — no manual registration, no agent-card editing. Dispatch will start delegating to them as soon as their agent cards are reachable.
85
85
 
86
86
  Then add credentials to the vault, grant them to the apps that need them, and (optionally) author workspace skills under **Resources** and sync them out.
87
87