@agent-native/core 0.110.2 → 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 +17 -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 -269
  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/struct-routes.d.ts +1 -1
  212. package/dist/notifications/routes.d.ts +3 -3
  213. package/dist/package-lifecycle/tombstone.d.ts.map +1 -1
  214. package/dist/package-lifecycle/tombstone.js +13 -3
  215. package/dist/package-lifecycle/tombstone.js.map +1 -1
  216. package/dist/package-lifecycle/upgrade-error.d.ts +2 -2
  217. package/dist/package-lifecycle/upgrade-error.d.ts.map +1 -1
  218. package/dist/package-lifecycle/upgrade-error.js +8 -5
  219. package/dist/package-lifecycle/upgrade-error.js.map +1 -1
  220. package/dist/secrets/routes.d.ts +9 -9
  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 -269
  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,860 +0,0 @@
1
- import { Button } from "@agent-native/toolkit/ui/button";
2
- import {
3
- Select,
4
- SelectContent,
5
- SelectGroup,
6
- SelectItem,
7
- SelectTrigger,
8
- } from "@agent-native/toolkit/ui/select";
9
- import {
10
- IconAlertTriangle,
11
- IconBrain,
12
- IconLanguage,
13
- IconLoader2,
14
- IconMicrophone,
15
- IconPhoneOff,
16
- IconSettings,
17
- IconVolume,
18
- } from "@tabler/icons-react";
19
- import {
20
- type MouseEvent,
21
- useCallback,
22
- useEffect,
23
- useId,
24
- useRef,
25
- useState,
26
- useSyncExternalStore,
27
- } from "react";
28
-
29
- import {
30
- Popover,
31
- PopoverAnchor,
32
- PopoverContent,
33
- PopoverTrigger,
34
- } from "../components/ui/popover.js";
35
- import {
36
- Tooltip,
37
- TooltipContent,
38
- TooltipTrigger,
39
- } from "../components/ui/tooltip.js";
40
- import { cn } from "../utils.js";
41
- import {
42
- createRealtimeVoiceAudioLevelStore,
43
- type RealtimeVoiceAudioLevelStore,
44
- } from "./realtime-voice-audio-level.js";
45
-
46
- export type RealtimeVoiceModeState =
47
- | "connecting"
48
- | "listening"
49
- | "speaking"
50
- | "working"
51
- | "error"
52
- | "ending";
53
-
54
- /**
55
- * User-visible copy stays outside the shared component so host catalogs remain
56
- * the source of truth. Callers should provide these values through `useT()`.
57
- */
58
- export interface RealtimeVoiceModeCopy {
59
- entryButtonLabel: string;
60
- promptTitle: string;
61
- promptDescription: string;
62
- setupTitle: string;
63
- setupDescription: string;
64
- connectBuilder: string;
65
- useOpenAiKey: string;
66
- startWithOpenAiKey: string;
67
- startVoiceMode: string;
68
- keepDictating: string;
69
- showChat: string;
70
- hideChat: string;
71
- endVoiceMode: string;
72
- voiceSettings: string;
73
- settings: {
74
- microphone: string;
75
- defaultMicrophone: string;
76
- microphoneSwitchFailed: string;
77
- language: string;
78
- autoLanguage: string;
79
- languages: Record<
80
- Exclude<
81
- import("./useRealtimeVoiceMode.js").RealtimeVoiceLanguage,
82
- "auto"
83
- >,
84
- string
85
- >;
86
- intelligence: string;
87
- intelligenceLevels: Record<
88
- import("./useRealtimeVoiceMode.js").RealtimeVoiceIntelligence,
89
- string
90
- >;
91
- voiceStyle: string;
92
- voiceChangePending: string;
93
- voiceDescriptions: Record<
94
- import("./useRealtimeVoiceMode.js").RealtimeVoice,
95
- string
96
- >;
97
- };
98
- status: Record<RealtimeVoiceModeState, string>;
99
- errors: {
100
- unsupported: string;
101
- responseFailed: string;
102
- sessionFailed: string;
103
- channelDisconnected: string;
104
- connectionTimedOut?: string;
105
- connectionFailed: string;
106
- offerFailed: string;
107
- };
108
- }
109
-
110
- export interface RealtimeVoiceModeEntryProps {
111
- copy: RealtimeVoiceModeCopy;
112
- disabled?: boolean;
113
- providerStatusPending?: boolean;
114
- open?: boolean;
115
- onOpenChange?: (open: boolean) => void;
116
- onStartVoiceMode: () => void;
117
- onKeepDictating: () => void;
118
- setupRequired?: boolean;
119
- openAiConfigured?: boolean;
120
- connectingBuilder?: boolean;
121
- onConnectBuilder?: () => void;
122
- onUseOpenAiKey?: () => void;
123
- className?: string;
124
- }
125
-
126
- /**
127
- * Composer mic entry point for apps that support a full-duplex voice session.
128
- * The first click offers voice mode without silently changing the existing
129
- * editable-dictation behavior.
130
- */
131
- export function RealtimeVoiceModeEntry({
132
- copy,
133
- disabled,
134
- providerStatusPending = false,
135
- open: controlledOpen,
136
- onOpenChange,
137
- onStartVoiceMode,
138
- onKeepDictating,
139
- setupRequired = false,
140
- openAiConfigured = false,
141
- connectingBuilder = false,
142
- onConnectBuilder,
143
- onUseOpenAiKey,
144
- className,
145
- }: RealtimeVoiceModeEntryProps) {
146
- const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
147
- const open = controlledOpen ?? uncontrolledOpen;
148
- const titleId = useId();
149
- const descriptionId = useId();
150
- const [collisionBoundary, setCollisionBoundary] =
151
- useState<HTMLElement | null>(null);
152
-
153
- const setTriggerNode = useCallback((node: HTMLButtonElement | null) => {
154
- const nextBoundary =
155
- node?.closest<HTMLElement>(".agent-panel-root") ?? null;
156
- setCollisionBoundary((currentBoundary) =>
157
- currentBoundary === nextBoundary ? currentBoundary : nextBoundary,
158
- );
159
- }, []);
160
-
161
- const setOpen = (nextOpen: boolean) => {
162
- if (controlledOpen === undefined) setUncontrolledOpen(nextOpen);
163
- onOpenChange?.(nextOpen);
164
- };
165
-
166
- const choose = (callback: () => void) => {
167
- setOpen(false);
168
- callback();
169
- };
170
-
171
- return (
172
- <Popover open={open} onOpenChange={setOpen}>
173
- <Tooltip>
174
- <TooltipTrigger asChild>
175
- <PopoverTrigger asChild>
176
- <Button
177
- ref={setTriggerNode}
178
- type="button"
179
- variant="ghost"
180
- size="icon"
181
- disabled={disabled}
182
- aria-label={copy.entryButtonLabel}
183
- aria-expanded={open}
184
- className={cn(
185
- "size-7 shrink-0 text-muted-foreground hover:text-foreground",
186
- className,
187
- )}
188
- >
189
- <IconMicrophone />
190
- </Button>
191
- </PopoverTrigger>
192
- </TooltipTrigger>
193
- <TooltipContent>{copy.entryButtonLabel}</TooltipContent>
194
- </Tooltip>
195
-
196
- <PopoverContent
197
- side="top"
198
- align="end"
199
- sideOffset={10}
200
- collisionBoundary={collisionBoundary ?? undefined}
201
- collisionPadding={16}
202
- data-collision-boundary={collisionBoundary ? "agent-panel" : "viewport"}
203
- className={cn(
204
- "p-4",
205
- setupRequired
206
- ? "w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,30rem),30rem)]"
207
- : "w-[min(calc(100vw-2rem),var(--radix-popover-content-available-width,22rem),22rem)]",
208
- )}
209
- aria-labelledby={titleId}
210
- aria-describedby={descriptionId}
211
- >
212
- <div className="grid gap-3">
213
- <div className="grid gap-1">
214
- <h2 id={titleId} className="text-sm font-semibold text-foreground">
215
- {setupRequired ? copy.setupTitle : copy.promptTitle}
216
- </h2>
217
- <p
218
- id={descriptionId}
219
- className="text-sm leading-relaxed text-muted-foreground"
220
- >
221
- {setupRequired ? copy.setupDescription : copy.promptDescription}
222
- </p>
223
- </div>
224
-
225
- <div className="flex flex-col-reverse gap-2 sm:flex-row sm:flex-wrap sm:justify-end">
226
- <Button
227
- type="button"
228
- variant="ghost"
229
- size="sm"
230
- onClick={() => choose(onKeepDictating)}
231
- >
232
- {copy.keepDictating}
233
- </Button>
234
- {setupRequired ? (
235
- <>
236
- <Button
237
- type="button"
238
- variant="outline"
239
- size="sm"
240
- onClick={() => choose(onUseOpenAiKey ?? onStartVoiceMode)}
241
- >
242
- {openAiConfigured
243
- ? copy.startWithOpenAiKey
244
- : copy.useOpenAiKey}
245
- </Button>
246
- <Button
247
- type="button"
248
- size="sm"
249
- className="whitespace-nowrap"
250
- disabled={connectingBuilder}
251
- onClick={() => choose(onConnectBuilder ?? onStartVoiceMode)}
252
- >
253
- {connectingBuilder ? (
254
- <IconLoader2 className="animate-spin" />
255
- ) : null}
256
- {copy.connectBuilder}
257
- </Button>
258
- </>
259
- ) : (
260
- <Button
261
- type="button"
262
- size="sm"
263
- disabled={providerStatusPending}
264
- onClick={() => choose(onStartVoiceMode)}
265
- >
266
- {providerStatusPending ? (
267
- <IconLoader2 className="animate-spin" />
268
- ) : (
269
- <IconMicrophone />
270
- )}
271
- {copy.startVoiceMode}
272
- </Button>
273
- )}
274
- </div>
275
- </div>
276
- </PopoverContent>
277
- </Popover>
278
- );
279
- }
280
-
281
- export interface RealtimeVoiceModeDockProps {
282
- state: RealtimeVoiceModeState;
283
- copy: RealtimeVoiceModeCopy;
284
- chatVisible: boolean;
285
- audioLevels?: RealtimeVoiceAudioLevelStore;
286
- onToggleChat: () => void;
287
- onEndVoiceMode: () => void;
288
- settings?: RealtimeVoiceModeInlineSettings;
289
- errorMessage?: string | null;
290
- className?: string;
291
- }
292
-
293
- export interface RealtimeVoiceModeSettingOption {
294
- value: string;
295
- label: string;
296
- description?: string;
297
- }
298
-
299
- export interface RealtimeVoiceModeSelectSetting {
300
- label: string;
301
- value: string;
302
- options: readonly RealtimeVoiceModeSettingOption[];
303
- onValueChange: (value: string) => void;
304
- disabled?: boolean;
305
- }
306
-
307
- export interface RealtimeVoiceModeInlineSettings {
308
- dialogLabel: string;
309
- appliesNextConversationNote?: string;
310
- microphoneError?: string;
311
- microphone: RealtimeVoiceModeSelectSetting;
312
- language: RealtimeVoiceModeSelectSetting;
313
- intelligence: RealtimeVoiceModeSelectSetting;
314
- voiceStyle: RealtimeVoiceModeSelectSetting;
315
- }
316
-
317
- const SILENT_AUDIO_LEVELS = createRealtimeVoiceAudioLevelStore();
318
- const WAVEFORM_WEIGHTS = [0.55, 0.82, 1, 0.82, 0.55];
319
- const AUDIO_ACTIVITY_THRESHOLD = 0.035;
320
-
321
- function usePrefersReducedMotion(): boolean {
322
- const [reduced, setReduced] = useState(false);
323
- useEffect(() => {
324
- if (typeof window === "undefined" || !window.matchMedia) return;
325
- const query = window.matchMedia("(prefers-reduced-motion: reduce)");
326
- const update = () => setReduced(query.matches);
327
- update();
328
- query.addEventListener?.("change", update);
329
- return () => query.removeEventListener?.("change", update);
330
- }, []);
331
- return reduced;
332
- }
333
-
334
- function VoiceWaveform({
335
- level,
336
- reducedMotion,
337
- activity,
338
- }: {
339
- level: number;
340
- reducedMotion: boolean;
341
- activity: "idle" | "user" | "assistant";
342
- }) {
343
- const visibleLevel = reducedMotion ? 0.45 : level;
344
- return (
345
- <span
346
- aria-hidden="true"
347
- className="flex h-6 items-center justify-center gap-0.5"
348
- data-realtime-voice-waveform="true"
349
- data-realtime-voice-waveform-activity={activity}
350
- >
351
- {WAVEFORM_WEIGHTS.map((weight, index) => (
352
- <span
353
- key={index}
354
- className="h-5 w-0.5 origin-center rounded-full bg-current transition-transform duration-75 ease-out motion-reduce:transition-none"
355
- style={{
356
- transform: `scaleY(${0.2 + visibleLevel * 0.8 * weight})`,
357
- }}
358
- />
359
- ))}
360
- </span>
361
- );
362
- }
363
-
364
- function VoiceConnectingIndicator() {
365
- return (
366
- <IconLoader2
367
- aria-hidden="true"
368
- className="size-6 animate-spin motion-reduce:animate-none"
369
- data-realtime-voice-connecting-indicator="true"
370
- />
371
- );
372
- }
373
-
374
- const ORB_STATE_CLASSES: Record<RealtimeVoiceModeState, string> = {
375
- connecting:
376
- "bg-background/65 text-foreground ring-border/60 hover:bg-background/75",
377
- listening:
378
- "bg-background/65 text-foreground ring-border/60 hover:bg-background/75",
379
- speaking:
380
- "bg-background/65 text-foreground ring-border/60 hover:bg-background/75",
381
- working:
382
- "bg-background/65 text-foreground ring-border/60 hover:bg-background/75",
383
- error:
384
- "bg-destructive/20 text-destructive ring-destructive/30 hover:bg-destructive/25",
385
- ending: "cursor-wait bg-background/65 text-muted-foreground ring-border/60",
386
- };
387
-
388
- function useChatPanelTranslation(chatVisible: boolean): number {
389
- const [translation, setTranslation] = useState(0);
390
-
391
- useEffect(() => {
392
- if (!chatVisible || typeof window === "undefined") {
393
- setTranslation(0);
394
- return;
395
- }
396
-
397
- const direction = window.getComputedStyle(
398
- document.documentElement,
399
- ).direction;
400
- const inlineEnd = direction === "rtl" ? "left" : "right";
401
-
402
- const update = () => {
403
- const panels = Array.from(
404
- document.querySelectorAll<HTMLElement>(
405
- `.agent-sidebar-panel[data-agent-sidebar-position="${inlineEnd}"][data-agent-sidebar-state="open"]`,
406
- ),
407
- );
408
- const panel = panels.find((candidate) => {
409
- const rect = candidate.getBoundingClientRect();
410
- return rect.width > 0 && rect.height > 0;
411
- });
412
-
413
- if (!panel) {
414
- setTranslation(0);
415
- return;
416
- }
417
-
418
- // A fullscreen chat has no unobscured side to move into. Keep the dock
419
- // at its normal edge so it stays reachable instead of pinning it to the
420
- // opposite side of the same overlay.
421
- if (panel.dataset.agentSidebarLayout === "fullscreen") {
422
- setTranslation(0);
423
- return;
424
- }
425
-
426
- const rect = panel.getBoundingClientRect();
427
- const overlap =
428
- inlineEnd === "right"
429
- ? Math.max(0, window.innerWidth - rect.left)
430
- : Math.max(0, rect.right);
431
- const maximumShift = Math.max(0, window.innerWidth - 96);
432
- const distance = Math.min(overlap, maximumShift);
433
- setTranslation(inlineEnd === "right" ? -distance : distance);
434
- };
435
-
436
- update();
437
- const frame = window.requestAnimationFrame(update);
438
- window.addEventListener("resize", update);
439
-
440
- const resizeObserver =
441
- typeof ResizeObserver === "undefined" ? null : new ResizeObserver(update);
442
- const observedPanels = new WeakSet<HTMLElement>();
443
- const observePanels = () => {
444
- document
445
- .querySelectorAll<HTMLElement>(".agent-sidebar-panel")
446
- .forEach((panel) => {
447
- if (!observedPanels.has(panel)) {
448
- observedPanels.add(panel);
449
- resizeObserver?.observe(panel);
450
- }
451
- });
452
- };
453
- observePanels();
454
-
455
- const mutationObserver = new MutationObserver(() => {
456
- observePanels();
457
- update();
458
- });
459
- mutationObserver.observe(document.body, {
460
- attributes: true,
461
- attributeFilter: [
462
- "data-agent-sidebar-layout",
463
- "data-agent-sidebar-state",
464
- "style",
465
- ],
466
- childList: true,
467
- subtree: true,
468
- });
469
-
470
- return () => {
471
- window.cancelAnimationFrame(frame);
472
- window.removeEventListener("resize", update);
473
- resizeObserver?.disconnect();
474
- mutationObserver.disconnect();
475
- };
476
- }, [chatVisible]);
477
-
478
- return translation;
479
- }
480
-
481
- function VoiceSettingRow({
482
- icon: Icon,
483
- setting,
484
- onSelectOpenChange,
485
- }: {
486
- icon: typeof IconLanguage;
487
- setting: RealtimeVoiceModeSelectSetting;
488
- onSelectOpenChange: (open: boolean) => void;
489
- }) {
490
- const selected = setting.options.find(
491
- (option) => option.value === setting.value,
492
- );
493
-
494
- return (
495
- <Select
496
- value={setting.value}
497
- onValueChange={setting.onValueChange}
498
- onOpenChange={onSelectOpenChange}
499
- disabled={setting.disabled}
500
- >
501
- <SelectTrigger
502
- aria-label={`${setting.label}: ${selected?.label ?? setting.value}`}
503
- className="h-11 rounded-none border-0 bg-transparent px-3 shadow-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
504
- >
505
- <div className="flex min-w-0 flex-1 items-center gap-2.5">
506
- <Icon className="size-4 shrink-0 text-muted-foreground" />
507
- <span className="shrink-0 text-sm font-medium text-foreground">
508
- {setting.label}
509
- </span>
510
- <span className="ms-auto min-w-0 truncate text-end text-sm text-muted-foreground">
511
- {selected?.label ?? setting.value}
512
- </span>
513
- </div>
514
- </SelectTrigger>
515
- <SelectContent
516
- align="end"
517
- className="min-w-56"
518
- data-realtime-voice-setting-options="true"
519
- >
520
- <SelectGroup>
521
- {setting.options.map((option) => (
522
- <SelectItem key={option.value} value={option.value}>
523
- <span className="grid gap-0.5">
524
- <span>{option.label}</span>
525
- {option.description ? (
526
- <span className="text-xs text-muted-foreground">
527
- {option.description}
528
- </span>
529
- ) : null}
530
- </span>
531
- </SelectItem>
532
- ))}
533
- </SelectGroup>
534
- </SelectContent>
535
- </Select>
536
- );
537
- }
538
-
539
- function VoiceInlineSettings({
540
- settings,
541
- disabled,
542
- onSelectOpenChange,
543
- }: {
544
- settings: RealtimeVoiceModeInlineSettings;
545
- disabled: boolean;
546
- onSelectOpenChange: (open: boolean) => void;
547
- }) {
548
- const selectedVoice = settings.voiceStyle.options.find(
549
- (option) => option.value === settings.voiceStyle.value,
550
- );
551
-
552
- return (
553
- <div data-realtime-voice-settings="true">
554
- <h2 className="sr-only">{settings.dialogLabel}</h2>
555
- <div className="grid gap-0.5 px-4 pb-3 pt-4 text-center">
556
- <div className="truncate text-base font-semibold text-foreground">
557
- {selectedVoice?.label ?? settings.voiceStyle.value}
558
- </div>
559
- {selectedVoice?.description ? (
560
- <div className="truncate text-xs text-muted-foreground">
561
- {selectedVoice.description}
562
- </div>
563
- ) : null}
564
- </div>
565
- <div className="mx-2 mb-2 overflow-hidden rounded-xl border border-border/70 bg-background/70">
566
- <VoiceSettingRow
567
- icon={IconMicrophone}
568
- setting={{
569
- ...settings.microphone,
570
- disabled: disabled || settings.microphone.disabled,
571
- }}
572
- onSelectOpenChange={onSelectOpenChange}
573
- />
574
- <div className="mx-3 h-px bg-border/70" />
575
- <VoiceSettingRow
576
- icon={IconLanguage}
577
- setting={{
578
- ...settings.language,
579
- disabled: disabled || settings.language.disabled,
580
- }}
581
- onSelectOpenChange={onSelectOpenChange}
582
- />
583
- <div className="mx-3 h-px bg-border/70" />
584
- <VoiceSettingRow
585
- icon={IconBrain}
586
- setting={{
587
- ...settings.intelligence,
588
- disabled: disabled || settings.intelligence.disabled,
589
- }}
590
- onSelectOpenChange={onSelectOpenChange}
591
- />
592
- <div className="mx-3 h-px bg-border/70" />
593
- <VoiceSettingRow
594
- icon={IconVolume}
595
- setting={{
596
- ...settings.voiceStyle,
597
- disabled: disabled || settings.voiceStyle.disabled,
598
- }}
599
- onSelectOpenChange={onSelectOpenChange}
600
- />
601
- </div>
602
- {settings.microphoneError ? (
603
- <p className="px-4 pb-3 text-center text-xs text-destructive">
604
- {settings.microphoneError}
605
- </p>
606
- ) : null}
607
- {settings.appliesNextConversationNote ? (
608
- <p className="px-4 pb-3 text-center text-xs text-muted-foreground">
609
- {settings.appliesNextConversationNote}
610
- </p>
611
- ) : null}
612
- </div>
613
- );
614
- }
615
-
616
- /**
617
- * Persistent voice-session control. Toggling the main orb only changes chat
618
- * visibility; ending the realtime session is intentionally a separate action.
619
- */
620
- export function RealtimeVoiceModeDock({
621
- state,
622
- copy,
623
- chatVisible,
624
- audioLevels = SILENT_AUDIO_LEVELS,
625
- onToggleChat,
626
- onEndVoiceMode,
627
- settings,
628
- errorMessage,
629
- className,
630
- }: RealtimeVoiceModeDockProps) {
631
- const statusId = useId();
632
- const controlsId = useId();
633
- const [controlsOpen, setControlsOpen] = useState(false);
634
- const [settingsOpen, setSettingsOpen] = useState(false);
635
- const selectInteractionRef = useRef(false);
636
- const selectInteractionFrameRef = useRef<number | null>(null);
637
- const levels = useSyncExternalStore(
638
- audioLevels.subscribe,
639
- audioLevels.getSnapshot,
640
- audioLevels.getSnapshot,
641
- );
642
- const reducedMotion = usePrefersReducedMotion();
643
- // Microphone metering begins while the SDP request is still in flight. Keep
644
- // the connecting affordance authoritative until WebRTC is established;
645
- // otherwise speaking into the mic replaces the loader with a waveform and
646
- // makes a stalled connection look like a live call.
647
- const connected =
648
- state === "listening" || state === "speaking" || state === "working";
649
- const activity = connected
650
- ? levels.output > AUDIO_ACTIVITY_THRESHOLD
651
- ? "assistant"
652
- : levels.input > AUDIO_ACTIVITY_THRESHOLD
653
- ? "user"
654
- : "idle"
655
- : "idle";
656
- const activityLevel = activity === "assistant" ? levels.output : levels.input;
657
- const toggleLabel = chatVisible ? copy.hideChat : copy.showChat;
658
- const ending = state === "ending";
659
- const errorDetailVisible = state === "error" && Boolean(errorMessage);
660
- const controlsVisible = controlsOpen || settingsOpen;
661
- const chatPanelTranslation = useChatPanelTranslation(chatVisible);
662
-
663
- const handleSelectOpenChange = useCallback((open: boolean) => {
664
- if (selectInteractionFrameRef.current !== null) {
665
- window.cancelAnimationFrame(selectInteractionFrameRef.current);
666
- selectInteractionFrameRef.current = null;
667
- }
668
- selectInteractionRef.current = true;
669
- if (!open) {
670
- // Radix closes the portalled Select before its focus/outside events have
671
- // fully settled. Keep the parent protected through the current frame.
672
- selectInteractionFrameRef.current = window.requestAnimationFrame(() => {
673
- selectInteractionRef.current = false;
674
- selectInteractionFrameRef.current = null;
675
- });
676
- }
677
- }, []);
678
-
679
- useEffect(
680
- () => () => {
681
- if (selectInteractionFrameRef.current !== null) {
682
- window.cancelAnimationFrame(selectInteractionFrameRef.current);
683
- }
684
- },
685
- [],
686
- );
687
-
688
- const closeControlsUnlessFocused = (event: MouseEvent<HTMLDivElement>) => {
689
- if (settingsOpen) return;
690
- if (!event.currentTarget.contains(document.activeElement)) {
691
- setControlsOpen(false);
692
- }
693
- };
694
-
695
- return (
696
- <div
697
- className={cn(
698
- "pointer-events-none fixed bottom-4 end-4 flex max-w-[calc(100vw-2rem)] flex-col items-end gap-2 transition-transform duration-200 ease-[var(--ease-collapse)] motion-reduce:transition-none",
699
- className,
700
- )}
701
- style={{
702
- zIndex: 270,
703
- transform: `translateX(${chatPanelTranslation}px)`,
704
- }}
705
- data-realtime-voice-state={state}
706
- data-realtime-voice-activity={activity}
707
- data-realtime-voice-chat-offset={chatPanelTranslation}
708
- >
709
- {errorDetailVisible ? (
710
- <div
711
- role="alert"
712
- className="pointer-events-auto max-w-xs rounded-lg border border-destructive/30 bg-background px-3 py-2 text-sm text-destructive shadow-md"
713
- >
714
- {errorMessage}
715
- </div>
716
- ) : null}
717
-
718
- <div
719
- className="group pointer-events-auto flex items-center gap-2"
720
- onMouseEnter={() => setControlsOpen(true)}
721
- onMouseLeave={closeControlsUnlessFocused}
722
- onFocusCapture={() => setControlsOpen(true)}
723
- onBlurCapture={(event) => {
724
- if (
725
- !event.currentTarget.contains(event.relatedTarget as Node | null)
726
- ) {
727
- setControlsOpen(false);
728
- }
729
- }}
730
- >
731
- <div
732
- id={controlsId}
733
- data-realtime-voice-controls={controlsVisible ? "open" : "closed"}
734
- className={cn(
735
- "flex items-center gap-1 rounded-full border border-border/70 bg-background/95 p-1 shadow-lg backdrop-blur-md transition-[transform,opacity] duration-150 ease-out motion-reduce:transition-none",
736
- controlsVisible
737
- ? "pointer-events-auto translate-x-0 opacity-100"
738
- : "pointer-events-none opacity-0 ltr:translate-x-2 rtl:-translate-x-2 group-hover:pointer-events-auto group-hover:translate-x-0 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:translate-x-0 group-focus-within:opacity-100",
739
- )}
740
- >
741
- <span
742
- id={statusId}
743
- role={state === "error" && !errorDetailVisible ? "alert" : "status"}
744
- aria-live={
745
- state === "error" && !errorDetailVisible ? "assertive" : "polite"
746
- }
747
- className="sr-only"
748
- >
749
- {copy.status[state]}
750
- </span>
751
-
752
- {settings ? (
753
- <Popover open={settingsOpen} onOpenChange={setSettingsOpen}>
754
- <Tooltip>
755
- <TooltipTrigger asChild>
756
- <PopoverAnchor asChild>
757
- <Button
758
- type="button"
759
- variant="ghost"
760
- size="icon"
761
- disabled={ending}
762
- onClick={() => setSettingsOpen((open) => !open)}
763
- aria-label={copy.voiceSettings}
764
- aria-expanded={settingsOpen}
765
- className="size-8 rounded-full text-muted-foreground transition-transform duration-150 ease-out active:scale-[0.97]"
766
- >
767
- <IconSettings />
768
- </Button>
769
- </PopoverAnchor>
770
- </TooltipTrigger>
771
- <TooltipContent>{copy.voiceSettings}</TooltipContent>
772
- </Tooltip>
773
- <PopoverContent
774
- side="top"
775
- align="end"
776
- sideOffset={10}
777
- className="w-[min(20rem,calc(100vw-2rem))] overflow-hidden p-0"
778
- onOpenAutoFocus={(event) => event.preventDefault()}
779
- onInteractOutside={(event) => {
780
- const target = event.target;
781
- if (
782
- selectInteractionRef.current ||
783
- (target instanceof Element &&
784
- target.closest(
785
- '[data-realtime-voice-setting-options="true"]',
786
- ))
787
- ) {
788
- event.preventDefault();
789
- }
790
- }}
791
- >
792
- <VoiceInlineSettings
793
- settings={settings}
794
- disabled={ending}
795
- onSelectOpenChange={handleSelectOpenChange}
796
- />
797
- </PopoverContent>
798
- </Popover>
799
- ) : null}
800
-
801
- <Tooltip>
802
- <TooltipTrigger asChild>
803
- <Button
804
- type="button"
805
- variant="ghost"
806
- size="icon"
807
- disabled={ending}
808
- onClick={onEndVoiceMode}
809
- aria-label={copy.endVoiceMode}
810
- className="size-8 rounded-full text-destructive transition-transform duration-150 ease-out hover:bg-destructive/10 hover:text-destructive active:scale-[0.97]"
811
- >
812
- <IconPhoneOff />
813
- </Button>
814
- </TooltipTrigger>
815
- <TooltipContent>{copy.endVoiceMode}</TooltipContent>
816
- </Tooltip>
817
- </div>
818
-
819
- <Tooltip>
820
- <TooltipTrigger asChild>
821
- <Button
822
- type="button"
823
- size="icon"
824
- disabled={ending}
825
- onClick={() => {
826
- setControlsOpen(true);
827
- onToggleChat();
828
- }}
829
- aria-label={toggleLabel}
830
- aria-pressed={chatVisible}
831
- data-realtime-voice-chat-toggle="orb"
832
- aria-describedby={statusId}
833
- aria-controls={controlsId}
834
- aria-expanded={controlsVisible}
835
- className={cn(
836
- "relative isolate size-16 overflow-visible rounded-full ring-1 backdrop-blur-xl transition-transform duration-150 ease-out focus-visible:ring-offset-2 active:scale-[0.97] motion-reduce:transition-none",
837
- ORB_STATE_CLASSES[state],
838
- )}
839
- >
840
- <span className="relative z-10 flex items-center justify-center">
841
- {state === "connecting" ? (
842
- <VoiceConnectingIndicator />
843
- ) : state !== "error" ? (
844
- <VoiceWaveform
845
- level={activityLevel}
846
- reducedMotion={reducedMotion}
847
- activity={activity}
848
- />
849
- ) : (
850
- <IconAlertTriangle />
851
- )}
852
- </span>
853
- </Button>
854
- </TooltipTrigger>
855
- <TooltipContent>{toggleLabel}</TooltipContent>
856
- </Tooltip>
857
- </div>
858
- </div>
859
- );
860
- }