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