@agent-native/core 0.110.3 → 0.111.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 (380) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +11 -0
  3. package/corpus/core/docs/content/components.mdx +7 -0
  4. package/corpus/core/docs/content/locales/ar-SA/components.mdx +4 -2
  5. package/corpus/core/docs/content/locales/de-DE/components.mdx +4 -2
  6. package/corpus/core/docs/content/locales/es-ES/components.mdx +4 -2
  7. package/corpus/core/docs/content/locales/fr-FR/components.mdx +4 -2
  8. package/corpus/core/docs/content/locales/hi-IN/components.mdx +3 -2
  9. package/corpus/core/docs/content/locales/ja-JP/components.mdx +3 -2
  10. package/corpus/core/docs/content/locales/ko-KR/components.mdx +3 -2
  11. package/corpus/core/docs/content/locales/pt-BR/components.mdx +4 -2
  12. package/corpus/core/docs/content/locales/zh-CN/components.mdx +3 -2
  13. package/corpus/core/docs/content/locales/zh-TW/components.mdx +3 -2
  14. package/corpus/core/docs/content/toolkit-agent-ux.mdx +8 -3
  15. package/corpus/core/migration-manifest.json +133 -266
  16. package/corpus/core/package.json +32 -33
  17. package/corpus/core/scripts/check-dist-imports.mjs +25 -1
  18. package/corpus/core/scripts/finalize-build.mjs +59 -2
  19. package/corpus/core/src/client/AgentAskPopover.tsx +1 -1
  20. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  21. package/corpus/core/src/client/AssistantChat.tsx +12 -14
  22. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +1 -1
  23. package/corpus/core/src/client/agent-chat-adapter.ts +1 -1
  24. package/corpus/core/src/client/blocks/RegistryBlockDataProvider.tsx +121 -0
  25. package/corpus/core/src/client/blocks/index.ts +6 -0
  26. package/corpus/core/src/client/chat/attachment-adapters.ts +4 -5
  27. package/corpus/core/src/client/chat/index.ts +0 -1
  28. package/corpus/core/src/client/chat/message-components.tsx +2 -2
  29. package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -2
  30. package/corpus/core/src/client/collab/index.ts +0 -22
  31. package/corpus/core/src/client/composer/index.ts +5 -66
  32. package/corpus/core/src/client/composer/runtime-adapters.tsx +123 -0
  33. package/corpus/core/src/client/composer/use-mention-search.ts +2 -79
  34. package/corpus/core/src/client/composer/wired-components.tsx +53 -0
  35. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +1 -1
  36. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +1 -1
  37. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +1 -1
  38. package/corpus/core/src/client/index.ts +0 -156
  39. package/corpus/core/src/client/resources/ResourceEditor.tsx +29 -681
  40. package/corpus/core/src/client/resources/ResourcesPanel.tsx +1 -1
  41. package/corpus/core/src/client/settings/AutomationsSection.tsx +1 -1
  42. package/corpus/core/src/client/sharing/index.ts +0 -4
  43. package/corpus/core/src/client/tombstone/agent-presence-chip.ts +17 -0
  44. package/corpus/core/src/client/tombstone/editor.ts +265 -0
  45. package/corpus/core/src/client/tombstone/live-cursor-overlay.ts +21 -0
  46. package/corpus/core/src/client/tombstone/presence-bar.ts +17 -0
  47. package/corpus/core/src/client/tombstone/recent-edit-highlights.ts +17 -0
  48. package/corpus/core/src/client/tombstone/remote-selection-rings.ts +21 -0
  49. package/corpus/core/src/client/tombstone/rich-markdown-editor.ts +265 -0
  50. package/corpus/core/src/client/tombstone/ui-dialog.ts +49 -0
  51. package/corpus/core/src/client/tombstone/ui-dropdown-menu.ts +69 -0
  52. package/corpus/core/src/client/tombstone/ui-hover-card.ts +21 -0
  53. package/corpus/core/src/client/tombstone/ui-popover.ts +25 -0
  54. package/corpus/core/src/client/tombstone/ui-sheet.ts +49 -0
  55. package/corpus/core/src/client/tombstone/ui-tooltip.ts +29 -0
  56. package/corpus/core/src/client/tombstone/visual-style-controls.ts +61 -0
  57. package/corpus/core/src/client/uploads/index.ts +5 -0
  58. package/corpus/core/src/client/{rich-markdown-editor/uploadEditorImage.ts → uploads/upload-editor-image.ts} +11 -4
  59. package/corpus/core/src/package-lifecycle/tombstone.ts +16 -2
  60. package/corpus/core/src/package-lifecycle/upgrade-error.ts +23 -5
  61. package/corpus/core/src/testing.ts +1 -4
  62. package/corpus/core/src/vite/client.ts +62 -22
  63. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +2 -4
  64. package/corpus/templates/content/app/components/editor/extensions/registryBlocks.ts +1 -1
  65. package/corpus/templates/content/app/components/editor/registrySlashItems.ts +53 -52
  66. package/corpus/templates/plan/app/components/editor/PlanBlockNode.tsx +2 -2
  67. package/corpus/templates/plan/app/components/editor/planSlashCommands.ts +1 -1
  68. package/corpus/templates/plan/app/components/plan/DocumentArea.tsx +1 -1
  69. package/corpus/templates/plan/app/components/plan/PlanImageNode.tsx +1 -1
  70. package/corpus/templates/plan/app/components/plan/PlanMarkdownEditor.tsx +1 -1
  71. package/dist/catalog.json +1 -0
  72. package/dist/client/AgentAskPopover.js +1 -1
  73. package/dist/client/AgentAskPopover.js.map +1 -1
  74. package/dist/client/AgentPanel.js +1 -1
  75. package/dist/client/AgentPanel.js.map +1 -1
  76. package/dist/client/AssistantChat.d.ts +2 -2
  77. package/dist/client/AssistantChat.d.ts.map +1 -1
  78. package/dist/client/AssistantChat.js +5 -6
  79. package/dist/client/AssistantChat.js.map +1 -1
  80. package/dist/client/NewWorkspaceAppFlow.js +1 -1
  81. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  82. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  83. package/dist/client/agent-chat-adapter.js +1 -1
  84. package/dist/client/agent-chat-adapter.js.map +1 -1
  85. package/dist/client/blocks/RegistryBlockDataProvider.d.ts +7 -0
  86. package/dist/client/blocks/RegistryBlockDataProvider.d.ts.map +1 -0
  87. package/dist/client/blocks/RegistryBlockDataProvider.js +54 -0
  88. package/dist/client/blocks/RegistryBlockDataProvider.js.map +1 -0
  89. package/dist/client/blocks/index.d.ts +2 -0
  90. package/dist/client/blocks/index.d.ts.map +1 -1
  91. package/dist/client/blocks/index.js +1 -0
  92. package/dist/client/blocks/index.js.map +1 -1
  93. package/dist/client/chat/attachment-adapters.d.ts.map +1 -1
  94. package/dist/client/chat/attachment-adapters.js +1 -1
  95. package/dist/client/chat/attachment-adapters.js.map +1 -1
  96. package/dist/client/chat/index.d.ts +0 -1
  97. package/dist/client/chat/index.d.ts.map +1 -1
  98. package/dist/client/chat/index.js +0 -1
  99. package/dist/client/chat/index.js.map +1 -1
  100. package/dist/client/chat/message-components.d.ts.map +1 -1
  101. package/dist/client/chat/message-components.js +2 -2
  102. package/dist/client/chat/message-components.js.map +1 -1
  103. package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
  104. package/dist/client/code-agent-chat-adapter.js +1 -1
  105. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  106. package/dist/client/collab/index.d.ts +0 -5
  107. package/dist/client/collab/index.d.ts.map +1 -1
  108. package/dist/client/collab/index.js +0 -5
  109. package/dist/client/collab/index.js.map +1 -1
  110. package/dist/client/composer/index.d.ts +3 -11
  111. package/dist/client/composer/index.d.ts.map +1 -1
  112. package/dist/client/composer/index.js +3 -10
  113. package/dist/client/composer/index.js.map +1 -1
  114. package/dist/client/composer/runtime-adapters.d.ts +5 -0
  115. package/dist/client/composer/runtime-adapters.d.ts.map +1 -0
  116. package/dist/client/composer/runtime-adapters.js +85 -0
  117. package/dist/client/composer/runtime-adapters.js.map +1 -0
  118. package/dist/client/composer/use-mention-search.d.ts +1 -2
  119. package/dist/client/composer/use-mention-search.d.ts.map +1 -1
  120. package/dist/client/composer/use-mention-search.js +2 -69
  121. package/dist/client/composer/use-mention-search.js.map +1 -1
  122. package/dist/client/composer/wired-components.d.ts +10 -0
  123. package/dist/client/composer/wired-components.d.ts.map +1 -0
  124. package/dist/client/composer/wired-components.js +20 -0
  125. package/dist/client/composer/wired-components.js.map +1 -0
  126. package/dist/client/extensions/ExtensionViewer.js +1 -1
  127. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  128. package/dist/client/extensions/ExtensionsListPage.js +1 -1
  129. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  130. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  131. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  132. package/dist/client/index.d.ts +0 -10
  133. package/dist/client/index.d.ts.map +1 -1
  134. package/dist/client/index.js +0 -26
  135. package/dist/client/index.js.map +1 -1
  136. package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
  137. package/dist/client/resources/ResourceEditor.js +14 -532
  138. package/dist/client/resources/ResourceEditor.js.map +1 -1
  139. package/dist/client/resources/ResourcesPanel.js +1 -1
  140. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  141. package/dist/client/settings/AutomationsSection.js +1 -1
  142. package/dist/client/settings/AutomationsSection.js.map +1 -1
  143. package/dist/client/sharing/index.d.ts +0 -1
  144. package/dist/client/sharing/index.d.ts.map +1 -1
  145. package/dist/client/sharing/index.js +0 -1
  146. package/dist/client/sharing/index.js.map +1 -1
  147. package/dist/client/tombstone/agent-presence-chip.d.ts +6 -0
  148. package/dist/client/tombstone/agent-presence-chip.d.ts.map +1 -0
  149. package/dist/client/tombstone/agent-presence-chip.js +5 -0
  150. package/dist/client/tombstone/agent-presence-chip.js.map +1 -0
  151. package/dist/client/tombstone/editor.d.ts +128 -0
  152. package/dist/client/tombstone/editor.d.ts.map +1 -0
  153. package/dist/client/tombstone/editor.js +76 -0
  154. package/dist/client/tombstone/editor.js.map +1 -0
  155. package/dist/client/tombstone/live-cursor-overlay.d.ts +8 -0
  156. package/dist/client/tombstone/live-cursor-overlay.d.ts.map +1 -0
  157. package/dist/client/tombstone/live-cursor-overlay.js +5 -0
  158. package/dist/client/tombstone/live-cursor-overlay.js.map +1 -0
  159. package/dist/client/tombstone/presence-bar.d.ts +6 -0
  160. package/dist/client/tombstone/presence-bar.d.ts.map +1 -0
  161. package/dist/client/tombstone/presence-bar.js +5 -0
  162. package/dist/client/tombstone/presence-bar.js.map +1 -0
  163. package/dist/client/tombstone/recent-edit-highlights.d.ts +6 -0
  164. package/dist/client/tombstone/recent-edit-highlights.d.ts.map +1 -0
  165. package/dist/client/tombstone/recent-edit-highlights.js +5 -0
  166. package/dist/client/tombstone/recent-edit-highlights.js.map +1 -0
  167. package/dist/client/tombstone/remote-selection-rings.d.ts +8 -0
  168. package/dist/client/tombstone/remote-selection-rings.d.ts.map +1 -0
  169. package/dist/client/tombstone/remote-selection-rings.js +5 -0
  170. package/dist/client/tombstone/remote-selection-rings.js.map +1 -0
  171. package/dist/client/tombstone/rich-markdown-editor.d.ts +128 -0
  172. package/dist/client/tombstone/rich-markdown-editor.d.ts.map +1 -0
  173. package/dist/client/tombstone/rich-markdown-editor.js +76 -0
  174. package/dist/client/tombstone/rich-markdown-editor.js.map +1 -0
  175. package/dist/client/tombstone/ui-dialog.d.ts +22 -0
  176. package/dist/client/tombstone/ui-dialog.d.ts.map +1 -0
  177. package/dist/client/tombstone/ui-dialog.js +23 -0
  178. package/dist/client/tombstone/ui-dialog.js.map +1 -0
  179. package/dist/client/tombstone/ui-dropdown-menu.d.ts +32 -0
  180. package/dist/client/tombstone/ui-dropdown-menu.d.ts.map +1 -0
  181. package/dist/client/tombstone/ui-dropdown-menu.js +33 -0
  182. package/dist/client/tombstone/ui-dropdown-menu.js.map +1 -0
  183. package/dist/client/tombstone/ui-hover-card.d.ts +8 -0
  184. package/dist/client/tombstone/ui-hover-card.d.ts.map +1 -0
  185. package/dist/client/tombstone/ui-hover-card.js +9 -0
  186. package/dist/client/tombstone/ui-hover-card.js.map +1 -0
  187. package/dist/client/tombstone/ui-popover.d.ts +10 -0
  188. package/dist/client/tombstone/ui-popover.d.ts.map +1 -0
  189. package/dist/client/tombstone/ui-popover.js +11 -0
  190. package/dist/client/tombstone/ui-popover.js.map +1 -0
  191. package/dist/client/tombstone/ui-sheet.d.ts +22 -0
  192. package/dist/client/tombstone/ui-sheet.d.ts.map +1 -0
  193. package/dist/client/tombstone/ui-sheet.js +23 -0
  194. package/dist/client/tombstone/ui-sheet.js.map +1 -0
  195. package/dist/client/tombstone/ui-tooltip.d.ts +12 -0
  196. package/dist/client/tombstone/ui-tooltip.d.ts.map +1 -0
  197. package/dist/client/tombstone/ui-tooltip.js +13 -0
  198. package/dist/client/tombstone/ui-tooltip.js.map +1 -0
  199. package/dist/client/tombstone/visual-style-controls.d.ts +28 -0
  200. package/dist/client/tombstone/visual-style-controls.d.ts.map +1 -0
  201. package/dist/client/tombstone/visual-style-controls.js +23 -0
  202. package/dist/client/tombstone/visual-style-controls.js.map +1 -0
  203. package/dist/client/uploads/index.d.ts +1 -0
  204. package/dist/client/uploads/index.d.ts.map +1 -1
  205. package/dist/client/uploads/index.js +1 -0
  206. package/dist/client/uploads/index.js.map +1 -1
  207. package/dist/client/{rich-markdown-editor/uploadEditorImage.d.ts → uploads/upload-editor-image.d.ts} +8 -4
  208. package/dist/client/uploads/upload-editor-image.d.ts.map +1 -0
  209. package/dist/client/{rich-markdown-editor/uploadEditorImage.js → uploads/upload-editor-image.js} +2 -2
  210. package/dist/client/uploads/upload-editor-image.js.map +1 -0
  211. package/dist/collab/awareness.d.ts +2 -2
  212. package/dist/collab/awareness.d.ts.map +1 -1
  213. package/dist/notifications/routes.d.ts +3 -3
  214. package/dist/package-lifecycle/tombstone.d.ts.map +1 -1
  215. package/dist/package-lifecycle/tombstone.js +13 -3
  216. package/dist/package-lifecycle/tombstone.js.map +1 -1
  217. package/dist/package-lifecycle/upgrade-error.d.ts +2 -2
  218. package/dist/package-lifecycle/upgrade-error.d.ts.map +1 -1
  219. package/dist/package-lifecycle/upgrade-error.js +8 -5
  220. package/dist/package-lifecycle/upgrade-error.js.map +1 -1
  221. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  222. package/dist/server/transcribe-voice.d.ts +1 -1
  223. package/dist/testing.d.ts +1 -3
  224. package/dist/testing.d.ts.map +1 -1
  225. package/dist/testing.js +1 -3
  226. package/dist/testing.js.map +1 -1
  227. package/dist/vite/client.d.ts.map +1 -1
  228. package/dist/vite/client.js +26 -22
  229. package/dist/vite/client.js.map +1 -1
  230. package/docs/content/components.mdx +7 -0
  231. package/docs/content/locales/ar-SA/components.mdx +4 -2
  232. package/docs/content/locales/de-DE/components.mdx +4 -2
  233. package/docs/content/locales/es-ES/components.mdx +4 -2
  234. package/docs/content/locales/fr-FR/components.mdx +4 -2
  235. package/docs/content/locales/hi-IN/components.mdx +3 -2
  236. package/docs/content/locales/ja-JP/components.mdx +3 -2
  237. package/docs/content/locales/ko-KR/components.mdx +3 -2
  238. package/docs/content/locales/pt-BR/components.mdx +4 -2
  239. package/docs/content/locales/zh-CN/components.mdx +3 -2
  240. package/docs/content/locales/zh-TW/components.mdx +3 -2
  241. package/docs/content/toolkit-agent-ux.mdx +8 -3
  242. package/migration-manifest.json +133 -266
  243. package/package.json +31 -32
  244. package/corpus/core/src/client/composer/AgentComposerFrame.tsx +0 -59
  245. package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +0 -988
  246. package/corpus/core/src/client/composer/MentionPopover.tsx +0 -412
  247. package/corpus/core/src/client/composer/PastedTextChip.tsx +0 -150
  248. package/corpus/core/src/client/composer/PromptComposer.tsx +0 -714
  249. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +0 -860
  250. package/corpus/core/src/client/composer/TiptapComposer.tsx +0 -2928
  251. package/corpus/core/src/client/composer/VoiceButton.tsx +0 -262
  252. package/corpus/core/src/client/composer/asset-picker-url.ts +0 -80
  253. package/corpus/core/src/client/composer/attachment-accept.ts +0 -71
  254. package/corpus/core/src/client/composer/draft-key.ts +0 -7
  255. package/corpus/core/src/client/composer/extensions/FileReference.tsx +0 -55
  256. package/corpus/core/src/client/composer/extensions/MentionReference.tsx +0 -93
  257. package/corpus/core/src/client/composer/extensions/SkillReference.tsx +0 -56
  258. package/corpus/core/src/client/composer/pasted-text.ts +0 -160
  259. package/corpus/core/src/client/composer/prompt-attachments.ts +0 -70
  260. package/corpus/core/src/client/composer/realtime-voice-audio-level.ts +0 -64
  261. package/corpus/core/src/client/composer/realtime-voice-transcript.ts +0 -134
  262. package/corpus/core/src/client/composer/types.ts +0 -66
  263. package/corpus/core/src/client/composer/use-file-search.ts +0 -63
  264. package/corpus/core/src/client/composer/use-skills.ts +0 -44
  265. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +0 -2095
  266. package/corpus/core/src/client/composer/useVoiceDictation.ts +0 -1155
  267. package/corpus/core/src/client/editor/index.ts +0 -1
  268. package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +0 -799
  269. package/corpus/core/src/client/rich-markdown-editor/index.ts +0 -70
  270. package/corpus/core/src/client/rich-markdown-editor/registrySlashCommands.ts +0 -112
  271. package/dist/client/composer/AgentComposerFrame.d.ts +0 -19
  272. package/dist/client/composer/AgentComposerFrame.d.ts.map +0 -1
  273. package/dist/client/composer/AgentComposerFrame.js +0 -14
  274. package/dist/client/composer/AgentComposerFrame.js.map +0 -1
  275. package/dist/client/composer/ComposerPlusMenu.d.ts +0 -17
  276. package/dist/client/composer/ComposerPlusMenu.d.ts.map +0 -1
  277. package/dist/client/composer/ComposerPlusMenu.js +0 -501
  278. package/dist/client/composer/ComposerPlusMenu.js.map +0 -1
  279. package/dist/client/composer/MentionPopover.d.ts +0 -29
  280. package/dist/client/composer/MentionPopover.d.ts.map +0 -1
  281. package/dist/client/composer/MentionPopover.js +0 -180
  282. package/dist/client/composer/MentionPopover.js.map +0 -1
  283. package/dist/client/composer/PastedTextChip.d.ts +0 -9
  284. package/dist/client/composer/PastedTextChip.d.ts.map +0 -1
  285. package/dist/client/composer/PastedTextChip.js +0 -47
  286. package/dist/client/composer/PastedTextChip.js.map +0 -1
  287. package/dist/client/composer/PromptComposer.d.ts +0 -115
  288. package/dist/client/composer/PromptComposer.d.ts.map +0 -1
  289. package/dist/client/composer/PromptComposer.js +0 -299
  290. package/dist/client/composer/PromptComposer.js.map +0 -1
  291. package/dist/client/composer/RealtimeVoiceMode.d.ts +0 -104
  292. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +0 -1
  293. package/dist/client/composer/RealtimeVoiceMode.js +0 -245
  294. package/dist/client/composer/RealtimeVoiceMode.js.map +0 -1
  295. package/dist/client/composer/TiptapComposer.d.ts +0 -222
  296. package/dist/client/composer/TiptapComposer.d.ts.map +0 -1
  297. package/dist/client/composer/TiptapComposer.js +0 -1834
  298. package/dist/client/composer/TiptapComposer.js.map +0 -1
  299. package/dist/client/composer/VoiceButton.d.ts +0 -23
  300. package/dist/client/composer/VoiceButton.d.ts.map +0 -1
  301. package/dist/client/composer/VoiceButton.js +0 -100
  302. package/dist/client/composer/VoiceButton.js.map +0 -1
  303. package/dist/client/composer/asset-picker-url.d.ts +0 -16
  304. package/dist/client/composer/asset-picker-url.d.ts.map +0 -1
  305. package/dist/client/composer/asset-picker-url.js +0 -64
  306. package/dist/client/composer/asset-picker-url.js.map +0 -1
  307. package/dist/client/composer/attachment-accept.d.ts +0 -9
  308. package/dist/client/composer/attachment-accept.d.ts.map +0 -1
  309. package/dist/client/composer/attachment-accept.js +0 -65
  310. package/dist/client/composer/attachment-accept.js.map +0 -1
  311. package/dist/client/composer/draft-key.d.ts +0 -2
  312. package/dist/client/composer/draft-key.d.ts.map +0 -1
  313. package/dist/client/composer/draft-key.js +0 -8
  314. package/dist/client/composer/draft-key.js.map +0 -1
  315. package/dist/client/composer/extensions/FileReference.d.ts +0 -3
  316. package/dist/client/composer/extensions/FileReference.d.ts.map +0 -1
  317. package/dist/client/composer/extensions/FileReference.js +0 -36
  318. package/dist/client/composer/extensions/FileReference.js.map +0 -1
  319. package/dist/client/composer/extensions/MentionReference.d.ts +0 -3
  320. package/dist/client/composer/extensions/MentionReference.d.ts.map +0 -1
  321. package/dist/client/composer/extensions/MentionReference.js +0 -66
  322. package/dist/client/composer/extensions/MentionReference.js.map +0 -1
  323. package/dist/client/composer/extensions/SkillReference.d.ts +0 -3
  324. package/dist/client/composer/extensions/SkillReference.d.ts.map +0 -1
  325. package/dist/client/composer/extensions/SkillReference.js +0 -40
  326. package/dist/client/composer/extensions/SkillReference.js.map +0 -1
  327. package/dist/client/composer/pasted-text.d.ts +0 -31
  328. package/dist/client/composer/pasted-text.d.ts.map +0 -1
  329. package/dist/client/composer/pasted-text.js +0 -130
  330. package/dist/client/composer/pasted-text.js.map +0 -1
  331. package/dist/client/composer/prompt-attachments.d.ts +0 -11
  332. package/dist/client/composer/prompt-attachments.d.ts.map +0 -1
  333. package/dist/client/composer/prompt-attachments.js +0 -45
  334. package/dist/client/composer/prompt-attachments.js.map +0 -1
  335. package/dist/client/composer/realtime-voice-audio-level.d.ts +0 -14
  336. package/dist/client/composer/realtime-voice-audio-level.d.ts.map +0 -1
  337. package/dist/client/composer/realtime-voice-audio-level.js +0 -47
  338. package/dist/client/composer/realtime-voice-audio-level.js.map +0 -1
  339. package/dist/client/composer/realtime-voice-transcript.d.ts +0 -26
  340. package/dist/client/composer/realtime-voice-transcript.d.ts.map +0 -1
  341. package/dist/client/composer/realtime-voice-transcript.js +0 -103
  342. package/dist/client/composer/realtime-voice-transcript.js.map +0 -1
  343. package/dist/client/composer/types.d.ts +0 -60
  344. package/dist/client/composer/types.d.ts.map +0 -1
  345. package/dist/client/composer/types.js +0 -2
  346. package/dist/client/composer/types.js.map +0 -1
  347. package/dist/client/composer/use-file-search.d.ts +0 -6
  348. package/dist/client/composer/use-file-search.d.ts.map +0 -1
  349. package/dist/client/composer/use-file-search.js +0 -52
  350. package/dist/client/composer/use-file-search.js.map +0 -1
  351. package/dist/client/composer/use-skills.d.ts +0 -7
  352. package/dist/client/composer/use-skills.d.ts.map +0 -1
  353. package/dist/client/composer/use-skills.js +0 -39
  354. package/dist/client/composer/use-skills.js.map +0 -1
  355. package/dist/client/composer/useRealtimeVoiceMode.d.ts +0 -172
  356. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +0 -1
  357. package/dist/client/composer/useRealtimeVoiceMode.js +0 -1648
  358. package/dist/client/composer/useRealtimeVoiceMode.js.map +0 -1
  359. package/dist/client/composer/useVoiceDictation.d.ts +0 -57
  360. package/dist/client/composer/useVoiceDictation.d.ts.map +0 -1
  361. package/dist/client/composer/useVoiceDictation.js +0 -975
  362. package/dist/client/composer/useVoiceDictation.js.map +0 -1
  363. package/dist/client/editor/index.d.ts +0 -2
  364. package/dist/client/editor/index.d.ts.map +0 -1
  365. package/dist/client/editor/index.js +0 -2
  366. package/dist/client/editor/index.js.map +0 -1
  367. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +0 -130
  368. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +0 -1
  369. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +0 -426
  370. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +0 -1
  371. package/dist/client/rich-markdown-editor/index.d.ts +0 -5
  372. package/dist/client/rich-markdown-editor/index.d.ts.map +0 -1
  373. package/dist/client/rich-markdown-editor/index.js +0 -5
  374. package/dist/client/rich-markdown-editor/index.js.map +0 -1
  375. package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts +0 -60
  376. package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts.map +0 -1
  377. package/dist/client/rich-markdown-editor/registrySlashCommands.js +0 -51
  378. package/dist/client/rich-markdown-editor/registrySlashCommands.js.map +0 -1
  379. package/dist/client/rich-markdown-editor/uploadEditorImage.d.ts.map +0 -1
  380. package/dist/client/rich-markdown-editor/uploadEditorImage.js.map +0 -1
@@ -1,975 +0,0 @@
1
- /**
2
- * Voice dictation hook for the agent composer.
3
- *
4
- * Wires voice providers behind a single state machine:
5
- * - "auto" / "openai" / "builder" / "builder-gemini" / "gemini" / "groq"
6
- * — MediaRecorder → POST /_agent-native/transcribe-voice
7
- * - "google-realtime"
8
- * — MediaRecorder chunks → POST /_agent-native/transcribe-stream/session
9
- * → managed WebSocket → Google Speech-to-Text streaming
10
- * - "browser" — Web Speech API (low quality, offline capable)
11
- *
12
- * Provider preference lives in application_state under
13
- * `voice-transcription-prefs` (`{ transcriptionMode, provider, instructions }`).
14
- * The composer reads it on every start so settings changes take effect
15
- * immediately without unmounting the composer.
16
- *
17
- * The hook exposes amplitude (0..1) and duration (ms) so the composer can
18
- * render the Lovable-style live waveform + MM:SS timer.
19
- */
20
- import { useCallback, useEffect, useRef, useState } from "react";
21
- import { applyVoiceContextReplacements, } from "../../voice/index.js";
22
- import { agentNativePath } from "../api-path.js";
23
- const PREFS_KEY = "voice-transcription-prefs";
24
- const CLEANUP_PREFS_KEY = "voice-cleanup-prefs";
25
- const PREFS_URL = agentNativePath(`/_agent-native/application-state/${PREFS_KEY}`);
26
- const CLEANUP_PREFS_URL = agentNativePath(`/_agent-native/application-state/${CLEANUP_PREFS_KEY}`);
27
- const TRANSCRIBE_URL = agentNativePath("/_agent-native/transcribe-voice");
28
- const GOOGLE_REALTIME_SESSION_URL = agentNativePath("/_agent-native/transcribe-stream/session");
29
- const GOOGLE_REALTIME_WS_PROTOCOL = "google-realtime.v1";
30
- function isVoiceProvider(value) {
31
- return (value === "auto" ||
32
- value === "openai" ||
33
- value === "browser" ||
34
- value === "google-realtime" ||
35
- value === "builder-gemini" ||
36
- value === "builder" ||
37
- value === "gemini" ||
38
- value === "groq");
39
- }
40
- function isTranscriptionMode(value) {
41
- return (value === "mac-native" || value === "google-realtime" || value === "batch");
42
- }
43
- async function defaultProvider() {
44
- return "auto";
45
- }
46
- function normalizeProviderForMode(mode, provider) {
47
- if (mode === "mac-native")
48
- return "browser";
49
- if (mode === "google-realtime")
50
- return "google-realtime";
51
- if (mode === "batch") {
52
- if (!provider || provider === "browser")
53
- return "auto";
54
- return provider === "builder" ? "builder-gemini" : provider;
55
- }
56
- if (!provider)
57
- return null;
58
- return provider === "builder" ? "builder-gemini" : provider;
59
- }
60
- async function readVoicePrefs() {
61
- const cleanupPrefs = await readVoiceCleanupPrefs();
62
- try {
63
- const res = await fetch(PREFS_URL);
64
- if (!res.ok) {
65
- return {
66
- provider: await defaultProvider(),
67
- cleanupEnabled: cleanupPrefs.enabled,
68
- };
69
- }
70
- const body = (await res.json());
71
- const value = body?.value ??
72
- body;
73
- const mode = isTranscriptionMode(value?.transcriptionMode)
74
- ? value.transcriptionMode
75
- : undefined;
76
- const p = body?.provider ??
77
- body?.value?.provider;
78
- const instructions = body?.instructions ??
79
- body?.value?.instructions;
80
- const provider = normalizeProviderForMode(mode, isVoiceProvider(p) ? p : null);
81
- if (provider) {
82
- return {
83
- transcriptionMode: mode,
84
- provider,
85
- cleanupEnabled: cleanupPrefs.enabled,
86
- instructions: typeof instructions === "string" ? instructions.trim() : undefined,
87
- };
88
- }
89
- }
90
- catch {
91
- /* fall through */
92
- }
93
- return {
94
- provider: await defaultProvider(),
95
- cleanupEnabled: cleanupPrefs.enabled,
96
- };
97
- }
98
- async function readVoiceCleanupPrefs() {
99
- try {
100
- const res = await fetch(CLEANUP_PREFS_URL);
101
- if (!res.ok)
102
- return {};
103
- const body = (await res.json());
104
- const value = body?.value ??
105
- body;
106
- return { enabled: value?.enabled === true };
107
- }
108
- catch {
109
- return {};
110
- }
111
- }
112
- function getSpeechRecognitionCtor() {
113
- if (typeof window === "undefined")
114
- return null;
115
- return (window.SpeechRecognition ||
116
- window.webkitSpeechRecognition ||
117
- null);
118
- }
119
- function pickMimeType() {
120
- if (typeof MediaRecorder === "undefined")
121
- return "audio/webm";
122
- const candidates = [
123
- "audio/webm;codecs=opus",
124
- "audio/webm",
125
- "audio/mp4",
126
- "audio/ogg;codecs=opus",
127
- ];
128
- for (const mime of candidates) {
129
- try {
130
- if (MediaRecorder.isTypeSupported(mime))
131
- return mime;
132
- }
133
- catch {
134
- /* ignore */
135
- }
136
- }
137
- return "audio/webm";
138
- }
139
- async function resolveVoiceContextPack(source) {
140
- try {
141
- const value = typeof source === "function" ? await source() : source;
142
- return value && typeof value === "object" ? value : undefined;
143
- }
144
- catch {
145
- return undefined;
146
- }
147
- }
148
- function appendVoiceContext(form, contextPack) {
149
- if (!contextPack)
150
- return;
151
- try {
152
- form.append("voiceContext", JSON.stringify(contextPack));
153
- }
154
- catch {
155
- /* best effort */
156
- }
157
- }
158
- export function providerForTextCleanup(provider) {
159
- return provider === "google-realtime" ? "auto" : provider;
160
- }
161
- async function cleanupRecognizedText({ text, provider, instructions, contextPack, }) {
162
- if (provider === "browser") {
163
- return applyVoiceContextReplacements(text, contextPack);
164
- }
165
- const form = new FormData();
166
- form.append("text", text);
167
- form.append("provider", providerForTextCleanup(provider));
168
- if (instructions?.trim()) {
169
- form.append("instructions", instructions.trim());
170
- }
171
- appendVoiceContext(form, contextPack);
172
- const res = await fetch(TRANSCRIBE_URL, {
173
- method: "POST",
174
- body: form,
175
- });
176
- if (!res.ok) {
177
- const body = await res
178
- .json()
179
- .catch(() => ({ error: `HTTP ${res.status}` }));
180
- throw new Error(body.error || `Transcript cleanup failed (${res.status})`);
181
- }
182
- const data = (await res.json());
183
- return (data.text ?? "").trim() || text;
184
- }
185
- function microphoneBlockedByPermissionsPolicy() {
186
- if (typeof document === "undefined")
187
- return false;
188
- const doc = document;
189
- const policy = doc.permissionsPolicy ?? doc.featurePolicy ?? null;
190
- if (!policy?.allowsFeature)
191
- return false;
192
- try {
193
- return !policy.allowsFeature("microphone");
194
- }
195
- catch {
196
- return false;
197
- }
198
- }
199
- export function voiceDictationStartErrorMessage(error) {
200
- const name = typeof error?.name === "string"
201
- ? error.name
202
- : "";
203
- const message = typeof error?.message === "string"
204
- ? error.message
205
- : "";
206
- if (microphoneBlockedByPermissionsPolicy() ||
207
- /permissions[- ]policy|feature policy/i.test(message)) {
208
- return "This app is blocking microphone access through its browser permissions policy. Reload the app, or open it directly in a browser tab.";
209
- }
210
- if (name === "NotAllowedError" ||
211
- name === "SecurityError" ||
212
- /permission|denied|not allowed/i.test(message)) {
213
- return "Microphone access is blocked. Click the site controls icon in the address bar, set Microphone to Allow for this app, then try again.";
214
- }
215
- if (name === "NotFoundError" || name === "DevicesNotFoundError") {
216
- return "No microphone was found. Plug one in or choose a different input, then try again.";
217
- }
218
- if (name === "NotReadableError" || name === "TrackStartError") {
219
- return "Your microphone is busy in another app. Close the other app or choose a different input, then try again.";
220
- }
221
- return message || "Could not start recording";
222
- }
223
- function voiceDictationSpeechErrorMessage(error) {
224
- if (error === "not-allowed" || error === "service-not-allowed") {
225
- return voiceDictationStartErrorMessage({
226
- name: "NotAllowedError",
227
- message: error,
228
- });
229
- }
230
- if (error === "audio-capture") {
231
- return "No microphone was found. Plug one in or choose a different input, then try again.";
232
- }
233
- return `Speech recognition error: ${error ?? "unknown"}`;
234
- }
235
- export function useVoiceDictation(options) {
236
- const { onTranscript, onError, onLiveUpdate, contextPack } = options;
237
- const onTranscriptRef = useRef(onTranscript);
238
- const onErrorRef = useRef(onError);
239
- const onLiveUpdateRef = useRef(onLiveUpdate);
240
- const contextPackRef = useRef(contextPack);
241
- onTranscriptRef.current = onTranscript;
242
- onErrorRef.current = onError;
243
- onLiveUpdateRef.current = onLiveUpdate;
244
- contextPackRef.current = contextPack;
245
- const [state, setState] = useState("idle");
246
- const [amplitude, setAmplitude] = useState(0);
247
- const [durationMs, setDurationMs] = useState(0);
248
- const [errorMessage, setErrorMessage] = useState(null);
249
- const [provider, setProvider] = useState("auto");
250
- // Keep refs for teardown / cross-branch access.
251
- const mediaStreamRef = useRef(null);
252
- const mediaRecorderRef = useRef(null);
253
- const chunksRef = useRef([]);
254
- const audioContextRef = useRef(null);
255
- const analyserRef = useRef(null);
256
- const rafRef = useRef(null);
257
- const timerRef = useRef(null);
258
- const startedAtRef = useRef(0);
259
- const cancelledRef = useRef(false);
260
- const speechRef = useRef(null);
261
- const speechTranscriptRef = useRef("");
262
- const activeProviderRef = useRef("browser");
263
- // Parallel live recognition for OpenAI mode (provides instant preview while MediaRecorder captures)
264
- const liveSpeechRef = useRef(null);
265
- const liveTextRef = useRef("");
266
- const realtimeSocketRef = useRef(null);
267
- const realtimeFinalRef = useRef("");
268
- const realtimeInterimRef = useRef("");
269
- const realtimeStopTimeoutRef = useRef(null);
270
- const mediaRecorderSupported = typeof window !== "undefined" &&
271
- typeof navigator !== "undefined" &&
272
- !!navigator.mediaDevices?.getUserMedia &&
273
- typeof window.MediaRecorder !== "undefined";
274
- const speechSupported = !!getSpeechRecognitionCtor();
275
- const supported = mediaRecorderSupported || speechSupported;
276
- const teardown = useCallback(() => {
277
- if (rafRef.current != null) {
278
- cancelAnimationFrame(rafRef.current);
279
- rafRef.current = null;
280
- }
281
- if (timerRef.current != null) {
282
- clearInterval(timerRef.current);
283
- timerRef.current = null;
284
- }
285
- if (mediaStreamRef.current) {
286
- for (const track of mediaStreamRef.current.getTracks()) {
287
- track.stop();
288
- }
289
- mediaStreamRef.current = null;
290
- }
291
- if (audioContextRef.current) {
292
- audioContextRef.current.close().catch(() => { });
293
- audioContextRef.current = null;
294
- }
295
- if (speechRef.current) {
296
- // Stop the Web Speech session before dropping the ref so the browser
297
- // releases the mic and stops dispatching onresult events into a stale
298
- // closure. abort() is fire-and-forget (no final result); stop() would
299
- // deliver remaining partials but we've already cleared state.
300
- try {
301
- speechRef.current.abort?.();
302
- }
303
- catch {
304
- /* ignore */
305
- }
306
- }
307
- if (liveSpeechRef.current) {
308
- try {
309
- liveSpeechRef.current.abort?.();
310
- }
311
- catch {
312
- /* ignore */
313
- }
314
- liveSpeechRef.current = null;
315
- }
316
- if (realtimeSocketRef.current) {
317
- const socket = realtimeSocketRef.current;
318
- realtimeSocketRef.current = null;
319
- try {
320
- socket.close();
321
- }
322
- catch {
323
- /* ignore */
324
- }
325
- }
326
- if (realtimeStopTimeoutRef.current) {
327
- clearTimeout(realtimeStopTimeoutRef.current);
328
- realtimeStopTimeoutRef.current = null;
329
- }
330
- analyserRef.current = null;
331
- mediaRecorderRef.current = null;
332
- chunksRef.current = [];
333
- speechRef.current = null;
334
- speechTranscriptRef.current = "";
335
- liveTextRef.current = "";
336
- realtimeFinalRef.current = "";
337
- realtimeInterimRef.current = "";
338
- setAmplitude(0);
339
- }, []);
340
- useEffect(() => teardown, [teardown]);
341
- const failWith = useCallback((message) => {
342
- setErrorMessage(message);
343
- setState("error");
344
- onErrorRef.current?.(message);
345
- teardown();
346
- }, [teardown]);
347
- const getVoiceContextPack = useCallback(() => resolveVoiceContextPack(contextPackRef.current), []);
348
- const startMeter = useCallback((stream) => {
349
- try {
350
- const AudioCtor = typeof window !== "undefined"
351
- ? window.AudioContext || window.webkitAudioContext || null
352
- : null;
353
- if (!AudioCtor)
354
- return;
355
- const ctx = new AudioCtor();
356
- const source = ctx.createMediaStreamSource(stream);
357
- const analyser = ctx.createAnalyser();
358
- analyser.fftSize = 512;
359
- source.connect(analyser);
360
- audioContextRef.current = ctx;
361
- analyserRef.current = analyser;
362
- const buffer = new Uint8Array(analyser.frequencyBinCount);
363
- const tick = () => {
364
- if (!analyserRef.current)
365
- return;
366
- analyserRef.current.getByteTimeDomainData(buffer);
367
- let sumSquares = 0;
368
- for (let i = 0; i < buffer.length; i++) {
369
- const n = (buffer[i] - 128) / 128;
370
- sumSquares += n * n;
371
- }
372
- const rms = Math.sqrt(sumSquares / buffer.length);
373
- setAmplitude(Math.min(1, rms * 2.5));
374
- rafRef.current = requestAnimationFrame(tick);
375
- };
376
- rafRef.current = requestAnimationFrame(tick);
377
- }
378
- catch {
379
- /* analyser is best-effort */
380
- }
381
- }, []);
382
- const startTimer = useCallback(() => {
383
- startedAtRef.current = Date.now();
384
- setDurationMs(0);
385
- timerRef.current = setInterval(() => {
386
- setDurationMs(Date.now() - startedAtRef.current);
387
- }, 100);
388
- }, []);
389
- const startOpenAi = useCallback(async (providerPref, instructions) => {
390
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
391
- // User may have pressed Escape (cancel) while the permission prompt was
392
- // open. If so, stop the stream and bail before we start recording.
393
- if (cancelledRef.current) {
394
- for (const track of stream.getTracks())
395
- track.stop();
396
- cancelledRef.current = false;
397
- setState("idle");
398
- return;
399
- }
400
- mediaStreamRef.current = stream;
401
- const mimeType = pickMimeType();
402
- const recorder = new MediaRecorder(stream, { mimeType });
403
- mediaRecorderRef.current = recorder;
404
- chunksRef.current = [];
405
- recorder.ondataavailable = (e) => {
406
- if (e.data && e.data.size > 0)
407
- chunksRef.current.push(e.data);
408
- };
409
- recorder.onstop = async () => {
410
- const localChunks = chunksRef.current.slice();
411
- const localMime = recorder.mimeType || mimeType;
412
- const liveSnapshot = liveTextRef.current;
413
- teardown();
414
- if (cancelledRef.current) {
415
- cancelledRef.current = false;
416
- setState("idle");
417
- return;
418
- }
419
- if (localChunks.length === 0) {
420
- if (liveSnapshot)
421
- onTranscriptRef.current?.(liveSnapshot.trim());
422
- setState("idle");
423
- return;
424
- }
425
- setState("transcribing");
426
- try {
427
- const audioBlob = new Blob(localChunks, { type: localMime });
428
- const form = new FormData();
429
- form.append("audio", audioBlob, `voice.${localMime.split("/")[1] ?? "webm"}`);
430
- form.append("provider", providerPref);
431
- if (instructions?.trim()) {
432
- form.append("instructions", instructions.trim());
433
- }
434
- appendVoiceContext(form, await getVoiceContextPack());
435
- const res = await fetch(TRANSCRIBE_URL, {
436
- method: "POST",
437
- body: form,
438
- });
439
- if (!res.ok) {
440
- const body = await res
441
- .json()
442
- .catch(() => ({ error: `HTTP ${res.status}` }));
443
- throw new Error(body.error || `Transcription failed (${res.status})`);
444
- }
445
- if (cancelledRef.current) {
446
- cancelledRef.current = false;
447
- setState("idle");
448
- return;
449
- }
450
- const data = (await res.json());
451
- const text = (data.text ?? "").trim();
452
- if (text) {
453
- onTranscriptRef.current?.(text);
454
- }
455
- else if (liveSnapshot) {
456
- onTranscriptRef.current?.(liveSnapshot.trim());
457
- }
458
- setState("idle");
459
- }
460
- catch (err) {
461
- if (cancelledRef.current) {
462
- cancelledRef.current = false;
463
- setState("idle");
464
- return;
465
- }
466
- if (liveSnapshot) {
467
- onTranscriptRef.current?.(liveSnapshot.trim());
468
- setState("idle");
469
- }
470
- else {
471
- failWith(err?.message ??
472
- "Transcription failed. Check your voice transcription provider in settings.");
473
- }
474
- }
475
- };
476
- startMeter(stream);
477
- startTimer();
478
- setState("recording");
479
- recorder.start();
480
- // Start parallel Web Speech recognition for live preview text.
481
- // This runs alongside MediaRecorder so the user sees words appear
482
- // immediately while the server provider processes the full recording later.
483
- const SpeechCtor = getSpeechRecognitionCtor();
484
- if (SpeechCtor) {
485
- const liveSpeech = new SpeechCtor();
486
- liveSpeech.continuous = true;
487
- liveSpeech.interimResults = true;
488
- liveSpeech.lang =
489
- (typeof navigator !== "undefined" && navigator.language) || "en-US";
490
- liveSpeechRef.current = liveSpeech;
491
- liveTextRef.current = "";
492
- liveSpeech.onresult = (event) => {
493
- let interim = "";
494
- for (let i = event.resultIndex; i < event.results.length; i++) {
495
- const result = event.results[i];
496
- const text = result[0]?.transcript ?? "";
497
- if (result.isFinal) {
498
- liveTextRef.current += text;
499
- }
500
- else {
501
- interim += text;
502
- }
503
- }
504
- onLiveUpdateRef.current?.(liveTextRef.current, interim);
505
- };
506
- liveSpeech.onend = () => {
507
- if (liveSpeechRef.current === liveSpeech) {
508
- try {
509
- liveSpeech.start();
510
- }
511
- catch {
512
- /* ignore */
513
- }
514
- }
515
- };
516
- liveSpeech.onerror = () => { };
517
- try {
518
- liveSpeech.start();
519
- }
520
- catch {
521
- /* best effort — live preview just won't appear */
522
- }
523
- }
524
- }, [startMeter, startTimer, teardown, failWith, getVoiceContextPack]);
525
- const startBrowser = useCallback(async (prefs) => {
526
- const Ctor = getSpeechRecognitionCtor();
527
- if (!Ctor) {
528
- throw new Error("Your browser doesn't support speech recognition. Add an OpenAI API key in settings for Whisper transcription.");
529
- }
530
- // Still request mic to drive the amplitude meter, so the UI doesn't look
531
- // dead while the user talks. SpeechRecognition manages its own capture
532
- // under the hood in most browsers.
533
- let stream = null;
534
- try {
535
- stream = await navigator.mediaDevices.getUserMedia({ audio: true });
536
- mediaStreamRef.current = stream;
537
- startMeter(stream);
538
- }
539
- catch {
540
- /* non-fatal — recognition can still work without our analyser */
541
- }
542
- if (cancelledRef.current) {
543
- if (stream)
544
- for (const track of stream.getTracks())
545
- track.stop();
546
- mediaStreamRef.current = null;
547
- cancelledRef.current = false;
548
- setState("idle");
549
- return;
550
- }
551
- const recognition = new Ctor();
552
- recognition.continuous = true;
553
- recognition.interimResults = true;
554
- recognition.lang =
555
- (typeof navigator !== "undefined" && navigator.language) || "en-US";
556
- speechRef.current = recognition;
557
- speechTranscriptRef.current = "";
558
- recognition.onresult = (event) => {
559
- let interim = "";
560
- for (let i = event.resultIndex; i < event.results.length; i++) {
561
- const result = event.results[i];
562
- const text = result[0]?.transcript ?? "";
563
- if (result.isFinal) {
564
- speechTranscriptRef.current += text;
565
- }
566
- else {
567
- interim += text;
568
- }
569
- }
570
- onLiveUpdateRef.current?.(speechTranscriptRef.current, interim);
571
- };
572
- recognition.onerror = (event) => {
573
- if (event?.error === "no-speech" || event?.error === "aborted")
574
- return;
575
- failWith(voiceDictationSpeechErrorMessage(event?.error));
576
- };
577
- recognition.onend = () => {
578
- const text = speechTranscriptRef.current.trim();
579
- const wasCancelled = cancelledRef.current;
580
- cancelledRef.current = false;
581
- teardown();
582
- if (wasCancelled || !text) {
583
- setState("idle");
584
- return;
585
- }
586
- void (async () => {
587
- let finalText = text;
588
- if (prefs.cleanupEnabled) {
589
- setState("transcribing");
590
- try {
591
- finalText = await cleanupRecognizedText({
592
- text,
593
- provider: prefs.provider,
594
- instructions: prefs.instructions,
595
- contextPack: await getVoiceContextPack(),
596
- });
597
- }
598
- catch {
599
- finalText = text;
600
- }
601
- }
602
- if (!cancelledRef.current && finalText) {
603
- onTranscriptRef.current?.(finalText);
604
- }
605
- cancelledRef.current = false;
606
- setState("idle");
607
- })();
608
- };
609
- startTimer();
610
- setState("recording");
611
- recognition.start();
612
- }, [startMeter, startTimer, teardown, failWith, getVoiceContextPack]);
613
- const startGoogleRealtime = useCallback(async (prefs) => {
614
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
615
- if (cancelledRef.current) {
616
- for (const track of stream.getTracks())
617
- track.stop();
618
- cancelledRef.current = false;
619
- setState("idle");
620
- return;
621
- }
622
- const sessionRes = await fetch(GOOGLE_REALTIME_SESSION_URL, {
623
- method: "POST",
624
- headers: { "Content-Type": "application/json" },
625
- body: JSON.stringify({
626
- language: (typeof navigator !== "undefined" && navigator.language) || "en-US",
627
- }),
628
- });
629
- const sessionBody = (await sessionRes
630
- .json()
631
- .catch(() => ({ error: `HTTP ${sessionRes.status}` })));
632
- if (!sessionRes.ok ||
633
- !sessionBody.websocketUrl ||
634
- !sessionBody.sessionToken) {
635
- for (const track of stream.getTracks())
636
- track.stop();
637
- throw new Error(sessionBody.error ||
638
- `Could not start Google realtime transcription (${sessionRes.status})`);
639
- }
640
- if (cancelledRef.current) {
641
- for (const track of stream.getTracks())
642
- track.stop();
643
- cancelledRef.current = false;
644
- setState("idle");
645
- return;
646
- }
647
- mediaStreamRef.current = stream;
648
- const mimeType = pickMimeType();
649
- const recorder = new MediaRecorder(stream, { mimeType });
650
- mediaRecorderRef.current = recorder;
651
- realtimeFinalRef.current = "";
652
- realtimeInterimRef.current = "";
653
- let finalized = false;
654
- let recorderStarted = false;
655
- const finish = (errorMessage) => {
656
- if (finalized)
657
- return;
658
- finalized = true;
659
- void (async () => {
660
- const finalText = realtimeFinalRef.current.trim();
661
- const interimText = realtimeInterimRef.current.trim();
662
- const text = [finalText, interimText]
663
- .filter(Boolean)
664
- .join(" ")
665
- .trim();
666
- teardown();
667
- if (cancelledRef.current) {
668
- cancelledRef.current = false;
669
- setState("idle");
670
- return;
671
- }
672
- if (text) {
673
- let cleanedText = text;
674
- if (prefs.cleanupEnabled) {
675
- setState("transcribing");
676
- try {
677
- cleanedText = await cleanupRecognizedText({
678
- text,
679
- provider: prefs.provider,
680
- instructions: prefs.instructions,
681
- contextPack: await getVoiceContextPack(),
682
- });
683
- }
684
- catch {
685
- cleanedText = text;
686
- }
687
- }
688
- if (!cancelledRef.current && cleanedText) {
689
- onTranscriptRef.current?.(cleanedText);
690
- }
691
- cancelledRef.current = false;
692
- setState("idle");
693
- return;
694
- }
695
- if (errorMessage) {
696
- failWith(errorMessage);
697
- return;
698
- }
699
- setState("idle");
700
- })();
701
- };
702
- recorder.ondataavailable = async (event) => {
703
- if (!event.data || event.data.size === 0)
704
- return;
705
- const socket = realtimeSocketRef.current;
706
- if (!socket || socket.readyState !== WebSocket.OPEN)
707
- return;
708
- try {
709
- socket.send(await event.data.arrayBuffer());
710
- }
711
- catch (err) {
712
- finish(err?.message ?? "Realtime audio upload failed");
713
- }
714
- };
715
- recorder.onstop = () => {
716
- const socket = realtimeSocketRef.current;
717
- if (!socket || socket.readyState !== WebSocket.OPEN) {
718
- finish();
719
- return;
720
- }
721
- setState("transcribing");
722
- try {
723
- socket.send(JSON.stringify({ type: "stop" }));
724
- }
725
- catch {
726
- finish();
727
- return;
728
- }
729
- realtimeStopTimeoutRef.current = window.setTimeout(() => {
730
- const activeSocket = realtimeSocketRef.current;
731
- if (activeSocket?.readyState === WebSocket.OPEN) {
732
- try {
733
- activeSocket.close();
734
- }
735
- catch {
736
- finish();
737
- }
738
- return;
739
- }
740
- finish();
741
- }, 10000);
742
- };
743
- const socket = new WebSocket(sessionBody.websocketUrl, [
744
- sessionBody.websocketProtocol || GOOGLE_REALTIME_WS_PROTOCOL,
745
- sessionBody.sessionToken,
746
- ]);
747
- socket.binaryType = "arraybuffer";
748
- realtimeSocketRef.current = socket;
749
- socket.onmessage = (event) => {
750
- if (cancelledRef.current) {
751
- finish();
752
- return;
753
- }
754
- const raw = typeof event.data === "string"
755
- ? event.data
756
- : event.data instanceof Blob
757
- ? null
758
- : new TextDecoder().decode(event.data);
759
- if (!raw)
760
- return;
761
- let message;
762
- try {
763
- message = JSON.parse(raw);
764
- }
765
- catch {
766
- return;
767
- }
768
- if (!message?.type)
769
- return;
770
- if (message.type === "ready") {
771
- if (!recorderStarted) {
772
- recorderStarted = true;
773
- startMeter(stream);
774
- startTimer();
775
- setState("recording");
776
- recorder.start(100);
777
- }
778
- return;
779
- }
780
- if (message.type === "partial") {
781
- realtimeInterimRef.current = (message.text ?? "").trim();
782
- onLiveUpdateRef.current?.(realtimeFinalRef.current, realtimeInterimRef.current);
783
- return;
784
- }
785
- if (message.type === "final") {
786
- const next = (message.text ?? "").trim();
787
- if (next) {
788
- realtimeFinalRef.current = [realtimeFinalRef.current.trim(), next]
789
- .filter(Boolean)
790
- .join(" ");
791
- }
792
- realtimeInterimRef.current = "";
793
- onLiveUpdateRef.current?.(realtimeFinalRef.current, "");
794
- return;
795
- }
796
- if (message.type === "error") {
797
- finish(message.error || "Google realtime transcription failed");
798
- return;
799
- }
800
- if (message.type === "end") {
801
- finish();
802
- }
803
- };
804
- socket.onerror = () => {
805
- finish("Google realtime transcription connection failed");
806
- };
807
- socket.onclose = () => {
808
- finish();
809
- };
810
- socket.onopen = () => {
811
- if (cancelledRef.current) {
812
- finish();
813
- return;
814
- }
815
- try {
816
- socket.send(JSON.stringify({
817
- type: "start",
818
- language: (typeof navigator !== "undefined" && navigator.language) ||
819
- "en-US",
820
- interimResults: true,
821
- mimeType,
822
- }));
823
- }
824
- catch (err) {
825
- finish(err?.message ?? "Could not start realtime stream");
826
- }
827
- };
828
- }, [startMeter, startTimer, teardown, failWith, getVoiceContextPack]);
829
- const start = useCallback(async () => {
830
- if (state === "recording" || state === "starting")
831
- return;
832
- setErrorMessage(null);
833
- setState("starting");
834
- cancelledRef.current = false;
835
- const prefs = await readVoicePrefs();
836
- const pref = prefs.provider;
837
- setProvider(pref);
838
- // In "auto" mode, prefer browser-native SpeechRecognition when available.
839
- // It requires no server-side API key, streams words incrementally into the
840
- // composer, and matches the macros-app record-button experience. Fall back
841
- // to the server upload path only when SpeechRecognition isn't supported.
842
- // Explicit server providers (builder, gemini, groq, openai) always use the
843
- // MediaRecorder → server upload path regardless.
844
- const resolvedProvider = pref === "auto" && speechSupported
845
- ? "browser"
846
- : pref === "auto" ||
847
- pref === "builder" ||
848
- pref === "builder-gemini" ||
849
- pref === "gemini" ||
850
- pref === "groq"
851
- ? "openai"
852
- : pref;
853
- activeProviderRef.current = resolvedProvider;
854
- try {
855
- if (resolvedProvider === "openai") {
856
- if (!mediaRecorderSupported) {
857
- throw new Error("Your browser doesn't support audio recording. Use the browser provider in Settings → Voice Transcription.");
858
- }
859
- await startOpenAi(pref, prefs.instructions);
860
- }
861
- else if (resolvedProvider === "google-realtime") {
862
- if (!mediaRecorderSupported) {
863
- throw new Error("Your browser doesn't support audio recording, so Google realtime transcription can't start.");
864
- }
865
- await startGoogleRealtime(prefs);
866
- }
867
- else {
868
- await startBrowser(prefs);
869
- }
870
- }
871
- catch (err) {
872
- if (cancelledRef.current) {
873
- cancelledRef.current = false;
874
- teardown();
875
- setState("idle");
876
- return;
877
- }
878
- failWith(voiceDictationStartErrorMessage(err));
879
- }
880
- }, [
881
- state,
882
- speechSupported,
883
- mediaRecorderSupported,
884
- startOpenAi,
885
- startGoogleRealtime,
886
- startBrowser,
887
- failWith,
888
- ]);
889
- const stop = useCallback(() => {
890
- if (state !== "recording")
891
- return;
892
- cancelledRef.current = false;
893
- if ((activeProviderRef.current === "openai" ||
894
- activeProviderRef.current === "google-realtime") &&
895
- mediaRecorderRef.current) {
896
- try {
897
- mediaRecorderRef.current.stop();
898
- }
899
- catch {
900
- teardown();
901
- setState("idle");
902
- }
903
- }
904
- else if (speechRef.current) {
905
- try {
906
- speechRef.current.stop();
907
- }
908
- catch {
909
- teardown();
910
- setState("idle");
911
- }
912
- }
913
- else {
914
- teardown();
915
- setState("idle");
916
- }
917
- }, [state, teardown]);
918
- const cancel = useCallback(() => {
919
- if (state !== "recording" &&
920
- state !== "starting" &&
921
- state !== "transcribing")
922
- return;
923
- cancelledRef.current = true;
924
- if ((activeProviderRef.current === "openai" ||
925
- activeProviderRef.current === "google-realtime") &&
926
- mediaRecorderRef.current) {
927
- try {
928
- mediaRecorderRef.current.stop();
929
- }
930
- catch {
931
- /* ignore */
932
- }
933
- }
934
- else if (speechRef.current) {
935
- try {
936
- speechRef.current.abort?.();
937
- }
938
- catch {
939
- /* ignore */
940
- }
941
- }
942
- teardown();
943
- setState("idle");
944
- }, [state, teardown]);
945
- // Auto-dismiss error after 8s so a stale "permission denied" message doesn't
946
- // sit forever after the user fixes the underlying permission. Manual dismiss
947
- // (via dismissError) and click-to-retry both also clear the error sooner.
948
- useEffect(() => {
949
- if (state !== "error")
950
- return;
951
- const handle = setTimeout(() => {
952
- setErrorMessage(null);
953
- setState("idle");
954
- }, 8000);
955
- return () => clearTimeout(handle);
956
- }, [state]);
957
- const dismissError = useCallback(() => {
958
- setErrorMessage(null);
959
- if (state === "error")
960
- setState("idle");
961
- }, [state]);
962
- return {
963
- state,
964
- amplitude,
965
- durationMs,
966
- errorMessage,
967
- provider,
968
- supported,
969
- start,
970
- stop,
971
- cancel,
972
- dismissError,
973
- };
974
- }
975
- //# sourceMappingURL=useVoiceDictation.js.map