@agent-native/core 0.97.0 → 0.98.1

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 (1019) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +56 -0
  3. package/corpus/core/docs/content/authentication.mdx +3 -3
  4. package/corpus/core/docs/content/doctor.mdx +170 -0
  5. package/corpus/core/docs/content/external-agents.mdx +8 -7
  6. package/corpus/core/docs/content/locales/ar-SA/authentication.mdx +2 -2
  7. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +8 -7
  8. package/corpus/core/docs/content/locales/ar-SA/mcp-protocol.mdx +1 -1
  9. package/corpus/core/docs/content/locales/ar-SA/security.mdx +2 -0
  10. package/corpus/core/docs/content/locales/de-DE/authentication.mdx +1 -1
  11. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +8 -7
  12. package/corpus/core/docs/content/locales/de-DE/mcp-protocol.mdx +1 -1
  13. package/corpus/core/docs/content/locales/de-DE/security.mdx +2 -0
  14. package/corpus/core/docs/content/locales/es-ES/authentication.mdx +2 -2
  15. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +8 -7
  16. package/corpus/core/docs/content/locales/es-ES/mcp-protocol.mdx +1 -1
  17. package/corpus/core/docs/content/locales/es-ES/security.mdx +2 -0
  18. package/corpus/core/docs/content/locales/fr-FR/authentication.mdx +1 -1
  19. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +8 -7
  20. package/corpus/core/docs/content/locales/fr-FR/mcp-protocol.mdx +1 -1
  21. package/corpus/core/docs/content/locales/fr-FR/security.mdx +2 -0
  22. package/corpus/core/docs/content/locales/hi-IN/authentication.mdx +2 -2
  23. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +8 -7
  24. package/corpus/core/docs/content/locales/hi-IN/mcp-protocol.mdx +1 -1
  25. package/corpus/core/docs/content/locales/hi-IN/security.mdx +2 -0
  26. package/corpus/core/docs/content/locales/ja-JP/authentication.mdx +2 -2
  27. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +8 -7
  28. package/corpus/core/docs/content/locales/ja-JP/mcp-protocol.mdx +1 -1
  29. package/corpus/core/docs/content/locales/ja-JP/security.mdx +2 -0
  30. package/corpus/core/docs/content/locales/ko-KR/authentication.mdx +2 -2
  31. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +8 -7
  32. package/corpus/core/docs/content/locales/ko-KR/mcp-protocol.mdx +1 -1
  33. package/corpus/core/docs/content/locales/ko-KR/security.mdx +2 -0
  34. package/corpus/core/docs/content/locales/pt-BR/authentication.mdx +2 -2
  35. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +8 -7
  36. package/corpus/core/docs/content/locales/pt-BR/mcp-protocol.mdx +1 -1
  37. package/corpus/core/docs/content/locales/pt-BR/security.mdx +2 -0
  38. package/corpus/core/docs/content/locales/zh-CN/authentication.mdx +2 -2
  39. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +8 -7
  40. package/corpus/core/docs/content/locales/zh-CN/mcp-protocol.mdx +1 -1
  41. package/corpus/core/docs/content/locales/zh-CN/security.mdx +2 -0
  42. package/corpus/core/docs/content/locales/zh-TW/authentication.mdx +2 -2
  43. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +8 -7
  44. package/corpus/core/docs/content/locales/zh-TW/mcp-protocol.mdx +1 -1
  45. package/corpus/core/docs/content/locales/zh-TW/security.mdx +2 -0
  46. package/corpus/core/docs/content/mcp-protocol.mdx +1 -1
  47. package/corpus/core/docs/content/security.mdx +2 -0
  48. package/corpus/core/package.json +6 -2
  49. package/corpus/core/scripts/finalize-build.mjs +63 -3
  50. package/corpus/core/scripts/materialize-source-corpus.mjs +101 -15
  51. package/corpus/core/src/action-change-marker.ts +8 -1
  52. package/corpus/core/src/action.ts +42 -0
  53. package/corpus/core/src/agent/engine/builder-engine.ts +3 -0
  54. package/corpus/core/src/agent/engine/context-directives-transform.ts +69 -0
  55. package/corpus/core/src/agent/engine/continuation-dispatch-retry.ts +168 -0
  56. package/corpus/core/src/agent/engine/tool-call-journal-seed.ts +85 -0
  57. package/corpus/core/src/agent/production-agent.ts +129 -244
  58. package/corpus/core/src/changelog/parse.ts +8 -3
  59. package/corpus/core/src/cli/doctor.ts +9 -3
  60. package/corpus/core/src/cli/plan-local.ts +10 -2
  61. package/corpus/core/src/cli/skills-content/assets-skill.ts +83 -0
  62. package/corpus/core/src/cli/skills-content/canvas.ts +153 -0
  63. package/corpus/core/src/cli/skills-content/connection.ts +52 -0
  64. package/corpus/core/src/cli/skills-content/content-skill.ts +109 -0
  65. package/corpus/core/src/cli/skills-content/design-exploration-skill.ts +118 -0
  66. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +228 -0
  67. package/corpus/core/src/cli/skills-content/document-quality.ts +196 -0
  68. package/corpus/core/src/cli/skills-content/exemplar.ts +69 -0
  69. package/corpus/core/src/cli/skills-content/help.ts +77 -0
  70. package/corpus/core/src/cli/skills-content/index.ts +22 -0
  71. package/corpus/core/src/cli/skills-content/local-files.ts +95 -0
  72. package/corpus/core/src/cli/skills-content/plan-setup-auth.ts +80 -0
  73. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +470 -0
  74. package/corpus/core/src/cli/skills-content/visual-recap-skill.ts +547 -0
  75. package/corpus/core/src/cli/skills-content/visualize-repo-skill.ts +93 -0
  76. package/corpus/core/src/cli/skills-content/wireframe.ts +349 -0
  77. package/corpus/core/src/cli/skills.ts +27 -2733
  78. package/corpus/core/src/client/AgentPanel.tsx +8 -8
  79. package/corpus/core/src/client/AssistantChat.tsx +83 -39
  80. package/corpus/core/src/client/CommandMenu.tsx +16 -5
  81. package/corpus/core/src/client/FeedbackButton.tsx +2 -2
  82. package/corpus/core/src/client/analytics.ts +29 -0
  83. package/corpus/core/src/client/app-providers.tsx +18 -5
  84. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +16 -2
  85. package/corpus/core/src/client/chat/tool-call-display.tsx +3 -3
  86. package/corpus/core/src/client/chat-model-groups.ts +28 -0
  87. package/corpus/core/src/client/composer/PastedTextChip.tsx +1 -1
  88. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +523 -68
  89. package/corpus/core/src/client/composer/TiptapComposer.tsx +47 -30
  90. package/corpus/core/src/client/composer/VoiceButton.tsx +22 -5
  91. package/corpus/core/src/client/composer/index.ts +5 -0
  92. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +1271 -35
  93. package/corpus/core/src/client/context-xray/ContextXRayPanel.tsx +5 -2
  94. package/corpus/core/src/client/extensions/ExtensionEditor.tsx +37 -4
  95. package/corpus/core/src/client/extensions/ExtensionQueryErrorState.tsx +47 -0
  96. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +39 -10
  97. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +44 -6
  98. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -3
  99. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +49 -11
  100. package/corpus/core/src/client/index.ts +5 -13
  101. package/corpus/core/src/client/progress/RunsTray.tsx +23 -4
  102. package/corpus/core/src/client/settings/SecretsSection.tsx +387 -266
  103. package/corpus/core/src/client/settings/SettingsPanel.tsx +117 -38
  104. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +7 -0
  105. package/corpus/core/src/client/settings/useBuilderStatus.ts +6 -0
  106. package/corpus/core/src/client/tool-cells/EditCell.tsx +19 -16
  107. package/corpus/core/src/client/tool-cells/FilesChangedSummary.tsx +26 -23
  108. package/corpus/core/src/client/tool-cells/WriteCell.tsx +19 -16
  109. package/corpus/core/src/client/use-action.ts +12 -0
  110. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +8 -1
  111. package/corpus/core/src/client/use-agent-engine-configured.ts +17 -3
  112. package/corpus/core/src/client/use-db-sync.ts +84 -34
  113. package/corpus/core/src/client/use-pausing-interval.ts +14 -4
  114. package/corpus/core/src/client/visual-style-controls.tsx +1 -1
  115. package/corpus/core/src/deploy/build.ts +36 -14
  116. package/corpus/core/src/integrations/google-docs-poller.ts +23 -2
  117. package/corpus/core/src/integrations/plugin.ts +10 -0
  118. package/corpus/core/src/integrations/scope-store.ts +1 -1
  119. package/corpus/core/src/integrations/usage-budget-store.ts +1 -1
  120. package/corpus/core/src/integrations/webhook-handler.ts +27 -2
  121. package/corpus/core/src/jobs/scheduler.ts +28 -2
  122. package/corpus/core/src/localization/default-messages.ts +51 -1
  123. package/corpus/core/src/mcp/oauth-token.ts +6 -1
  124. package/corpus/core/src/mcp-client/workspace-servers.ts +4 -4
  125. package/corpus/core/src/observability/routes.ts +36 -0
  126. package/corpus/core/src/observability/sentiment.ts +261 -0
  127. package/corpus/core/src/observability/store.ts +23 -0
  128. package/corpus/core/src/observability/traces.ts +49 -63
  129. package/corpus/core/src/observability/tracking-identity.ts +55 -0
  130. package/corpus/core/src/observability/types.ts +13 -0
  131. package/corpus/core/src/secrets/crypto.ts +28 -8
  132. package/corpus/core/src/secrets/storage.ts +67 -3
  133. package/corpus/core/src/server/action-change.ts +5 -1
  134. package/corpus/core/src/server/action-routes.ts +8 -0
  135. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +199 -0
  136. package/corpus/core/src/server/agent-chat/browser-team-tools.ts +510 -0
  137. package/corpus/core/src/server/agent-chat/context-tools.ts +595 -0
  138. package/corpus/core/src/server/agent-chat/framework-prompts.ts +470 -0
  139. package/corpus/core/src/server/agent-chat/lazy-fs.ts +11 -0
  140. package/corpus/core/src/server/agent-chat/mcp-glue.ts +91 -0
  141. package/corpus/core/src/server/agent-chat/plugin-options.ts +350 -0
  142. package/corpus/core/src/server/agent-chat/process-run-failure.ts +62 -0
  143. package/corpus/core/src/server/agent-chat/prompt-resources.ts +688 -0
  144. package/corpus/core/src/server/agent-chat/recurring-jobs-runtime.ts +80 -0
  145. package/corpus/core/src/server/agent-chat/request-surface.ts +71 -0
  146. package/corpus/core/src/server/agent-chat/run-code-tools.ts +67 -0
  147. package/corpus/core/src/server/agent-chat/script-entries.ts +779 -0
  148. package/corpus/core/src/server/agent-chat/shared-thread.ts +301 -0
  149. package/corpus/core/src/server/agent-chat/skill-frontmatter.ts +41 -0
  150. package/corpus/core/src/server/agent-chat-plugin.ts +364 -4182
  151. package/corpus/core/src/server/agent-teams.ts +26 -3
  152. package/corpus/core/src/server/auth.ts +55 -57
  153. package/corpus/core/src/server/credential-provider.ts +22 -25
  154. package/corpus/core/src/server/edge.ts +1 -0
  155. package/corpus/core/src/server/onboarding-html.ts +1 -16
  156. package/corpus/core/src/server/poll.ts +1 -0
  157. package/corpus/core/src/server/realtime-voice.ts +335 -14
  158. package/corpus/core/src/server/request-origin.ts +6 -2
  159. package/corpus/core/src/server/ssr-handler.ts +55 -2
  160. package/corpus/core/src/sharing/access.ts +155 -11
  161. package/corpus/core/src/sharing/registry.ts +7 -0
  162. package/corpus/core/src/styles/agent-native.css +17 -16
  163. package/corpus/core/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  164. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  165. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -0
  166. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -0
  167. package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -0
  168. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -0
  169. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -0
  170. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -0
  171. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -0
  172. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -0
  173. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -0
  174. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +6 -0
  175. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +6 -0
  176. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  177. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  178. package/corpus/core/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  179. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  180. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  181. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  182. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  183. package/corpus/core/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  184. package/corpus/core/src/templates/workspace-core/src/server/index.ts +4 -2
  185. package/corpus/core/src/testing.ts +26 -0
  186. package/corpus/core/src/triggers/dispatcher.ts +23 -2
  187. package/corpus/core/src/vite/client.ts +135 -3
  188. package/corpus/core/tsconfig.cli.json +1 -1
  189. package/corpus/core/tsconfig.json +5 -1
  190. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +2 -2
  191. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -1
  192. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +2 -2
  193. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +10 -5
  194. package/corpus/templates/analytics/AGENTS.md +15 -6
  195. package/corpus/templates/analytics/actions/install-dashboard-template.ts +79 -43
  196. package/corpus/templates/analytics/actions/list-explorer-dashboards.ts +3 -3
  197. package/corpus/templates/analytics/actions/list-sql-dashboards.ts +8 -3
  198. package/corpus/templates/analytics/actions/navigate.ts +59 -5
  199. package/corpus/templates/analytics/actions/rename-analysis.ts +8 -2
  200. package/corpus/templates/analytics/actions/rename-dashboard.ts +8 -7
  201. package/corpus/templates/analytics/actions/view-screen.ts +7 -29
  202. package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +20 -3
  203. package/corpus/templates/analytics/app/components/ResourceLoadError.tsx +42 -0
  204. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +2 -1
  205. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +85 -70
  206. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  207. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +128 -95
  208. package/corpus/templates/analytics/app/components/layout/SidebarLoadError.tsx +24 -0
  209. package/corpus/templates/analytics/app/global.css +19 -20
  210. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -5
  211. package/corpus/templates/analytics/app/i18n/zh-TW.ts +4 -0
  212. package/corpus/templates/analytics/app/i18n-data.ts +40 -0
  213. package/corpus/templates/analytics/app/lib/provider-corpus-job-sync.ts +26 -0
  214. package/corpus/templates/analytics/app/pages/Settings.tsx +41 -343
  215. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +36 -20
  216. package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +34 -20
  217. package/corpus/templates/analytics/app/pages/adhoc/explorer/use-explorer-config.ts +42 -41
  218. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +43 -36
  219. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewsMenu.tsx +11 -2
  220. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +38 -7
  221. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +1 -1
  222. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +3 -0
  223. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +333 -272
  224. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +72 -17
  225. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +297 -108
  226. package/corpus/templates/analytics/app/root.tsx +40 -8
  227. package/corpus/templates/analytics/app/routes/_index.tsx +14 -2
  228. package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +2 -1
  229. package/corpus/templates/analytics/changelog/2026-06-25-referrer-dashboard-panels-show-external-domains.md +2 -1
  230. package/corpus/templates/analytics/changelog/2026-07-03-agent-llm-observability-dashboard.md +1 -1
  231. package/corpus/templates/analytics/changelog/2026-07-06-mobile-chat-header-is-more-compact-and-the-menu-button-opens-navigation.md +1 -0
  232. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +1 -0
  233. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +1 -0
  234. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +1 -0
  235. package/corpus/templates/analytics/changelog/2026-07-11-agent-feedback-sentiment-dashboard.md +6 -0
  236. package/corpus/templates/analytics/changelog/2026-07-11-analytics-chats-now-start-faster-by-loading-metric-definitio.md +6 -0
  237. package/corpus/templates/analytics/changelog/2026-07-11-analytics-no-longer-repeatedly-restarts-background-requests-.md +6 -0
  238. package/corpus/templates/analytics/changelog/2026-07-11-analytics-only-asks-for-replay-storage-when-you-enable-sessi.md +6 -0
  239. package/corpus/templates/analytics/changelog/2026-07-11-charts-now-show-their-loading-skeleton-while-refreshing.md +6 -0
  240. package/corpus/templates/analytics/changelog/2026-07-11-command-and-sql-previews-now-respond-without-lag.md +6 -0
  241. package/corpus/templates/analytics/changelog/2026-07-11-command-search-now-reports-loading-failures-and-lets-you-ret.md +6 -0
  242. package/corpus/templates/analytics/changelog/2026-07-11-dashboard-navigation-now-loads-faster-and-reports-request-fa.md +6 -0
  243. package/corpus/templates/analytics/changelog/2026-07-11-inferred-message-sentiment-dashboard.md +6 -0
  244. package/corpus/templates/analytics/changelog/2026-07-11-microphone-settings-from-realtime-voice-mode-now-open-the-vo.md +6 -0
  245. package/corpus/templates/analytics/changelog/2026-07-11-more-dashboard-edit-paths-are-now-safe-against-simultaneous-.md +6 -0
  246. package/corpus/templates/analytics/changelog/2026-07-11-realtime-voice-now-shows-a-clear-connection-indicator-comple.md +6 -0
  247. package/corpus/templates/analytics/changelog/2026-07-11-renaming-a-dashboard-is-now-safe-against-simultaneous-agent-.md +6 -0
  248. package/corpus/templates/analytics/changelog/2026-07-11-renaming-an-analysis-is-now-safe-against-simultaneous-edits.md +6 -0
  249. package/corpus/templates/analytics/changelog/2026-07-11-replay-event-counts-stay-hidden-until-recordings-finish-load.md +6 -0
  250. package/corpus/templates/analytics/changelog/2026-07-11-replay-storage-key-mismatches-show-actionable-setup-guidance.md +6 -0
  251. package/corpus/templates/analytics/changelog/2026-07-11-replay-timelines-group-continuous-scrolling-and-dev-tools-co.md +6 -0
  252. package/corpus/templates/analytics/changelog/2026-07-11-session-filters-now-stay-compact-in-a-settings-menu-at-mediu.md +6 -0
  253. package/corpus/templates/analytics/changelog/2026-07-11-session-replay-console-errors-now-link-to-matching-issues-or.md +6 -0
  254. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-load-large-recordings-faster-and-surface-fai.md +6 -0
  255. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-preserve-recorded-styles-and-viewport-layout.md +6 -0
  256. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-stay-centered-instead-of-clipping-wide-recor.md +6 -0
  257. package/corpus/templates/analytics/changelog/2026-07-11-workspace-mounted-analytics-now-opens-ask-reliably-and-route.md +6 -0
  258. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +37 -3
  259. package/corpus/templates/analytics/package.json +1 -1
  260. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +37 -1
  261. package/corpus/templates/analytics/server/handlers/session-replay.ts +57 -0
  262. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -24
  263. package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +0 -5
  264. package/corpus/templates/analytics/server/lib/dashboards-store.ts +289 -20
  265. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +106 -34
  266. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +20 -4
  267. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +12 -0
  268. package/corpus/templates/analytics/server/lib/session-replay.ts +208 -2
  269. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -39
  270. package/corpus/templates/analytics/server/plugins/onboarding.ts +7 -79
  271. package/corpus/templates/analytics/server/routes/api/session-replay/recordings/[recordingId]/chunks.get.ts +1 -0
  272. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -1
  273. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +2 -2
  274. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +30 -4
  275. package/corpus/templates/assets/app/global.css +4 -4
  276. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +0 -1
  277. package/corpus/templates/assets/app/routes/library.tsx +49 -6
  278. package/corpus/templates/assets/changelog/2026-07-11-library-load-failures-now-show-a-retry-action.md +6 -0
  279. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -1
  280. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +2 -2
  281. package/corpus/templates/brain/app/global.css +5 -5
  282. package/corpus/templates/brain/app/root.tsx +0 -3
  283. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -1
  284. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +2 -2
  285. package/corpus/templates/calendar/.env.example +5 -0
  286. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +2 -2
  287. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  288. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  289. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +37 -1
  290. package/corpus/templates/calendar/app/pages/BookingsList.tsx +20 -3
  291. package/corpus/templates/calendar/app/root.tsx +1 -0
  292. package/corpus/templates/calendar/changelog/2026-07-11-booking-load-failures-now-show-a-retry-action.md +6 -0
  293. package/corpus/templates/calendar/changelog/2026-07-11-event-cards-give-subtle-press-feedback-and-smoother-hover.md +6 -0
  294. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -1
  295. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +2 -2
  296. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -1
  297. package/corpus/templates/clips/actions/decline-invite.ts +8 -0
  298. package/corpus/templates/clips/app/components/library/folder-tree.tsx +209 -187
  299. package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +2 -2
  300. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +17 -5
  301. package/corpus/templates/clips/app/components/player/scrubber.tsx +5 -3
  302. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +2 -2
  303. package/corpus/templates/clips/app/components/workspace/insights-hub.tsx +119 -95
  304. package/corpus/templates/clips/app/global.css +45 -0
  305. package/corpus/templates/clips/app/hooks/use-auto-title.ts +74 -8
  306. package/corpus/templates/clips/app/hooks/use-library.ts +12 -25
  307. package/corpus/templates/clips/app/root.tsx +4 -0
  308. package/corpus/templates/clips/app/routes/_app.notifications.tsx +23 -2
  309. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +20 -22
  310. package/corpus/templates/clips/app/routes/_app.trash.tsx +24 -2
  311. package/corpus/templates/clips/changelog/2026-07-11-controls-and-folders-now-move-more-smoothly.md +6 -0
  312. package/corpus/templates/clips/changelog/2026-07-11-declining-an-invitation-now-requires-being-its-recipient.md +6 -0
  313. package/corpus/templates/clips/changelog/2026-07-11-generated-titles-no-longer-cause-continuous-background-refreshes.md +6 -0
  314. package/corpus/templates/clips/changelog/2026-07-11-recording-overlays-are-lighter-weight-and-no-longer-cause-pa.md +6 -0
  315. package/corpus/templates/clips/changelog/2026-07-11-s3-storage-setup-stays-collapsed-until-you-choose-it-as-the-.md +6 -0
  316. package/corpus/templates/clips/changelog/2026-07-11-workspace-load-failures-now-show-a-retry-action.md +6 -0
  317. package/corpus/templates/clips/chrome-extension/src/overlay.css +34 -5
  318. package/corpus/templates/clips/chrome-extension/src/styles.css +2 -2
  319. package/corpus/templates/clips/desktop/src/styles.css +71 -26
  320. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -1
  321. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +2 -2
  322. package/corpus/templates/content/actions/move-document.ts +34 -18
  323. package/corpus/templates/content/app/components/QueryErrorState.tsx +39 -0
  324. package/corpus/templates/content/app/components/editor/LinkHoverPreview.tsx +1 -1
  325. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +225 -1435
  326. package/corpus/templates/content/app/components/editor/database/GalleryView.tsx +368 -0
  327. package/corpus/templates/content/app/components/editor/database/ListView.tsx +353 -0
  328. package/corpus/templates/content/app/components/editor/database/TimelineView.tsx +580 -0
  329. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -2
  330. package/corpus/templates/content/app/global.css +19 -19
  331. package/corpus/templates/content/app/hooks/use-comments.ts +0 -1
  332. package/corpus/templates/content/app/root.tsx +2 -2
  333. package/corpus/templates/content/app/routes/_app._index.tsx +11 -1
  334. package/corpus/templates/content/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  335. package/corpus/templates/content/changelog/2026-07-11-document-load-failures-now-show-a-retry-action.md +6 -0
  336. package/corpus/templates/content/changelog/2026-07-11-editor-toggle-feedback-now-feels-more-responsive.md +6 -0
  337. package/corpus/templates/content/changelog/2026-07-11-moving-documents-at-the-same-time-no-longer-scrambles-their-.md +6 -0
  338. package/corpus/templates/content/changelog/2026-07-11-public-document-chats-now-start-faster-while-keeping-full-do.md +6 -0
  339. package/corpus/templates/content/changelog/2026-07-11-reopening-a-comment-now-uses-consistent-permissions-everywhe.md +6 -0
  340. package/corpus/templates/content/changelog/2026-07-11-sidebar-resizing-now-tracks-your-cursor-instantly-instead-of.md +6 -0
  341. package/corpus/templates/content/server/lib/public-documents.ts +47 -10
  342. package/corpus/templates/content/server/routes/api/comments/[id].patch.ts +24 -24
  343. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -1
  344. package/corpus/templates/design/app/components/QueryErrorState.tsx +24 -0
  345. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +1 -1
  346. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +5 -2
  347. package/corpus/templates/design/app/components/design/EditPanel.tsx +326 -319
  348. package/corpus/templates/design/app/components/design/LayersPanel.tsx +198 -193
  349. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +11 -4
  350. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +1 -1
  351. package/corpus/templates/design/app/components/layout/Header.tsx +1 -1
  352. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
  353. package/corpus/templates/design/app/pages/DesignSystems.tsx +7 -1
  354. package/corpus/templates/design/app/pages/Index.tsx +14 -2
  355. package/corpus/templates/design/app/pages/Present.tsx +16 -3
  356. package/corpus/templates/design/app/pages/Templates.tsx +10 -4
  357. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +484 -0
  358. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +378 -0
  359. package/corpus/templates/design/app/pages/design-editor/design-data-geometry-utils.ts +138 -0
  360. package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +15 -0
  361. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +180 -0
  362. package/corpus/templates/design/app/pages/design-editor/html-layer-positioning.ts +226 -0
  363. package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +348 -0
  364. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +160 -0
  365. package/corpus/templates/design/app/pages/design-editor/text-edit-utils.ts +238 -0
  366. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +23 -1
  367. package/corpus/templates/design/app/pages/design-editor/types.ts +25 -0
  368. package/corpus/templates/design/app/root.tsx +10 -1
  369. package/corpus/templates/design/changelog/2026-07-11-canvas-context-menus-now-open-without-motion-jitter.md +6 -0
  370. package/corpus/templates/design/changelog/2026-07-11-design-load-failures-now-show-a-retry-action.md +6 -0
  371. package/corpus/templates/design/changelog/2026-07-11-inspector-tooltips-appear-instantly-as-you-sweep-across-icon.md +6 -0
  372. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -1
  373. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +10 -0
  374. package/corpus/templates/dispatch/app/i18n-data.ts +123 -0
  375. package/corpus/templates/dispatch/app/routes/integrations.tsx +163 -144
  376. package/corpus/templates/dispatch/changelog/2026-07-11-dispatch-mcp-connections-now-start-with-safer-app-access-and.md +6 -0
  377. package/corpus/templates/dispatch/changelog/2026-07-11-overview-and-chat-now-share-a-cleaner-more-stable-flow.md +6 -0
  378. package/corpus/templates/dispatch/changelog/2026-07-11-query-errors-now-show-a-retry-option.md +6 -0
  379. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -1
  380. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +2 -2
  381. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +3 -3
  382. package/corpus/templates/forms/app/root.tsx +34 -8
  383. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -1
  384. package/corpus/templates/macros/app/components/DailyProgress.tsx +25 -5
  385. package/corpus/templates/macros/app/components/QueryErrorState.tsx +31 -0
  386. package/corpus/templates/macros/app/components/WeightTracker.tsx +5 -1
  387. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -2
  388. package/corpus/templates/macros/app/components/ui/button.tsx +1 -1
  389. package/corpus/templates/macros/app/components/ui/progress.tsx +1 -1
  390. package/corpus/templates/macros/app/components/ui/tabs.tsx +1 -1
  391. package/corpus/templates/macros/app/i18n/ar-SA.ts +2 -0
  392. package/corpus/templates/macros/app/i18n/de-DE.ts +2 -0
  393. package/corpus/templates/macros/app/i18n/en-US.ts +2 -0
  394. package/corpus/templates/macros/app/i18n/es-ES.ts +2 -0
  395. package/corpus/templates/macros/app/i18n/fr-FR.ts +2 -0
  396. package/corpus/templates/macros/app/i18n/hi-IN.ts +2 -0
  397. package/corpus/templates/macros/app/i18n/ja-JP.ts +2 -0
  398. package/corpus/templates/macros/app/i18n/ko-KR.ts +2 -0
  399. package/corpus/templates/macros/app/i18n/pt-BR.ts +2 -0
  400. package/corpus/templates/macros/app/i18n/zh-CN.ts +2 -0
  401. package/corpus/templates/macros/app/i18n/zh-TW.ts +2 -0
  402. package/corpus/templates/macros/app/root.tsx +0 -3
  403. package/corpus/templates/macros/app/routes/_index.tsx +22 -12
  404. package/corpus/templates/macros/app/routes/analytics.tsx +31 -10
  405. package/corpus/templates/macros/changelog/2026-07-11-daily-tracking-now-loads-and-updates-more-quickly.md +6 -0
  406. package/corpus/templates/macros/changelog/2026-07-11-data-load-failures-now-show-a-clear-error-with-a-retry-actio.md +6 -0
  407. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -1
  408. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +2 -2
  409. package/corpus/templates/mail/.env.example +16 -11
  410. package/corpus/templates/mail/actions/list-emails.ts +39 -35
  411. package/corpus/templates/mail/app/components/email/ComposeModal.tsx +58 -6
  412. package/corpus/templates/mail/app/components/email/EmailListItem.tsx +35 -2
  413. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +113 -104
  414. package/corpus/templates/mail/app/hooks/use-compose-state.ts +1 -0
  415. package/corpus/templates/mail/app/root.tsx +9 -22
  416. package/corpus/templates/mail/changelog/2026-07-11-compose-and-navigation-motion-now-feel-faster-and-smoother.md +6 -0
  417. package/corpus/templates/mail/changelog/2026-07-11-swipe-to-archive-or-snooze-now-responds-to-quick-flicks-not-.md +6 -0
  418. package/corpus/templates/mail/changelog/2026-07-11-the-assistant-now-sees-the-same-inbox-you-do-snoozed-mail-st.md +6 -0
  419. package/corpus/templates/mail/server/handlers/emails.ts +25 -69
  420. package/corpus/templates/mail/server/lib/list-inbox-emails.ts +169 -0
  421. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -1
  422. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +2 -2
  423. package/corpus/templates/plan/.env.example +4 -0
  424. package/corpus/templates/plan/actions/create-plan-design.ts +89 -81
  425. package/corpus/templates/plan/actions/create-prototype-plan.ts +72 -59
  426. package/corpus/templates/plan/actions/create-ui-plan.ts +70 -55
  427. package/corpus/templates/plan/actions/create-visual-plan.ts +65 -51
  428. package/corpus/templates/plan/actions/update-local-plan-folder.ts +43 -30
  429. package/corpus/templates/plan/actions/update-visual-plan.ts +81 -64
  430. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +17 -0
  431. package/corpus/templates/plan/app/components/ui/tabs.tsx +1 -1
  432. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +5 -2
  433. package/corpus/templates/plan/app/hooks/use-plans.ts +6 -13
  434. package/corpus/templates/plan/app/i18n/ar-SA.ts +10 -0
  435. package/corpus/templates/plan/app/i18n/de-DE.ts +10 -0
  436. package/corpus/templates/plan/app/i18n/en-US.ts +10 -0
  437. package/corpus/templates/plan/app/i18n/es-ES.ts +10 -0
  438. package/corpus/templates/plan/app/i18n/fr-FR.ts +10 -0
  439. package/corpus/templates/plan/app/i18n/hi-IN.ts +10 -0
  440. package/corpus/templates/plan/app/i18n/ja-JP.ts +10 -0
  441. package/corpus/templates/plan/app/i18n/ko-KR.ts +10 -0
  442. package/corpus/templates/plan/app/i18n/pt-BR.ts +10 -0
  443. package/corpus/templates/plan/app/i18n/zh-CN.ts +10 -0
  444. package/corpus/templates/plan/app/i18n/zh-TW.ts +10 -0
  445. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +80 -1
  446. package/corpus/templates/plan/app/pages/PlansPage.tsx +157 -31
  447. package/corpus/templates/plan/app/root.tsx +11 -0
  448. package/corpus/templates/plan/changelog/2026-07-11-local-plans-now-explain-and-recover-from-browser-permission-.md +6 -0
  449. package/corpus/templates/plan/changelog/2026-07-11-plan-edits-now-save-atomically-and-can-no-longer-partially-a.md +6 -0
  450. package/corpus/templates/plan/changelog/2026-07-11-plan-lists-now-show-a-clear-error-with-a-retry-action-when-t.md +6 -0
  451. package/corpus/templates/plan/changelog/2026-07-11-plan-refreshes-only-when-content-changes.md +6 -0
  452. package/corpus/templates/plan/shared/plan-content.ts +546 -260
  453. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -1
  454. package/corpus/templates/slides/actions/delete-slide-comment.ts +49 -0
  455. package/corpus/templates/slides/actions/update-slide-comment.ts +93 -0
  456. package/corpus/templates/slides/actions/view-screen.ts +14 -6
  457. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +37 -11
  458. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +1 -1
  459. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +2 -2
  460. package/corpus/templates/slides/app/components/editor/GenerateSlidesDialog.tsx +2 -2
  461. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
  462. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +4 -2
  463. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +4 -3
  464. package/corpus/templates/slides/app/context/DeckContext.tsx +10 -0
  465. package/corpus/templates/slides/app/hooks/use-slide-comments.ts +7 -31
  466. package/corpus/templates/slides/app/i18n/ar-SA.ts +6 -0
  467. package/corpus/templates/slides/app/i18n/de-DE.ts +6 -0
  468. package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
  469. package/corpus/templates/slides/app/i18n/es-ES.ts +6 -0
  470. package/corpus/templates/slides/app/i18n/fr-FR.ts +6 -0
  471. package/corpus/templates/slides/app/i18n/hi-IN.ts +6 -0
  472. package/corpus/templates/slides/app/i18n/ja-JP.ts +6 -0
  473. package/corpus/templates/slides/app/i18n/ko-KR.ts +6 -0
  474. package/corpus/templates/slides/app/i18n/pt-BR.ts +6 -0
  475. package/corpus/templates/slides/app/i18n/zh-CN.ts +5 -0
  476. package/corpus/templates/slides/app/i18n/zh-TW.ts +5 -0
  477. package/corpus/templates/slides/app/pages/DesignSystems.tsx +23 -2
  478. package/corpus/templates/slides/app/pages/Index.tsx +29 -1
  479. package/corpus/templates/slides/changelog/2026-07-11-comment-load-failures-now-show-a-retry-action-instead-of-say.md +6 -0
  480. package/corpus/templates/slides/changelog/2026-07-11-comment-pins-now-clear-with-a-faster-smoother-confirmation.md +6 -0
  481. package/corpus/templates/slides/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  482. package/corpus/templates/slides/changelog/2026-07-11-deck-and-design-system-load-failures-now-show-a-retry-action.md +6 -0
  483. package/corpus/templates/slides/changelog/2026-07-11-editor-toggles-and-toolbar-menus-now-animate-smoothly.md +6 -0
  484. package/corpus/templates/slides/changelog/2026-07-11-the-assistant-can-now-resolve-reopen-and-delete-slide-commen.md +6 -0
  485. package/corpus/templates/slides/changelog/2026-07-11-viewing-slides-no-longer-loads-every-deck-s-full-contents-in.md +6 -0
  486. package/corpus/templates/slides/server/routes/api/comments/[id].delete.ts +29 -48
  487. package/corpus/templates/slides/server/routes/api/comments/[id].patch.ts +29 -65
  488. package/dist/action-change-marker.d.ts +1 -0
  489. package/dist/action-change-marker.d.ts.map +1 -1
  490. package/dist/action-change-marker.js +7 -1
  491. package/dist/action-change-marker.js.map +1 -1
  492. package/dist/action.d.ts +23 -0
  493. package/dist/action.d.ts.map +1 -1
  494. package/dist/action.js +13 -0
  495. package/dist/action.js.map +1 -1
  496. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  497. package/dist/agent/engine/builder-engine.js +3 -0
  498. package/dist/agent/engine/builder-engine.js.map +1 -1
  499. package/dist/agent/engine/context-directives-transform.d.ts +25 -0
  500. package/dist/agent/engine/context-directives-transform.d.ts.map +1 -0
  501. package/dist/agent/engine/context-directives-transform.js +53 -0
  502. package/dist/agent/engine/context-directives-transform.js.map +1 -0
  503. package/dist/agent/engine/continuation-dispatch-retry.d.ts +40 -0
  504. package/dist/agent/engine/continuation-dispatch-retry.d.ts.map +1 -0
  505. package/dist/agent/engine/continuation-dispatch-retry.js +109 -0
  506. package/dist/agent/engine/continuation-dispatch-retry.js.map +1 -0
  507. package/dist/agent/engine/tool-call-journal-seed.d.ts +46 -0
  508. package/dist/agent/engine/tool-call-journal-seed.d.ts.map +1 -0
  509. package/dist/agent/engine/tool-call-journal-seed.js +60 -0
  510. package/dist/agent/engine/tool-call-journal-seed.js.map +1 -0
  511. package/dist/agent/production-agent.d.ts +7 -0
  512. package/dist/agent/production-agent.d.ts.map +1 -1
  513. package/dist/agent/production-agent.js +102 -222
  514. package/dist/agent/production-agent.js.map +1 -1
  515. package/dist/changelog/parse.d.ts +4 -2
  516. package/dist/changelog/parse.d.ts.map +1 -1
  517. package/dist/changelog/parse.js +5 -3
  518. package/dist/changelog/parse.js.map +1 -1
  519. package/dist/cli/doctor.d.ts.map +1 -1
  520. package/dist/cli/doctor.js +7 -3
  521. package/dist/cli/doctor.js.map +1 -1
  522. package/dist/cli/plan-local.d.ts.map +1 -1
  523. package/dist/cli/plan-local.js +8 -2
  524. package/dist/cli/plan-local.js.map +1 -1
  525. package/dist/cli/skills-content/assets-skill.d.ts +2 -0
  526. package/dist/cli/skills-content/assets-skill.d.ts.map +1 -0
  527. package/dist/cli/skills-content/assets-skill.js +84 -0
  528. package/dist/cli/skills-content/assets-skill.js.map +1 -0
  529. package/dist/cli/skills-content/canvas.d.ts +4 -0
  530. package/dist/cli/skills-content/canvas.d.ts.map +1 -0
  531. package/dist/cli/skills-content/canvas.js +152 -0
  532. package/dist/cli/skills-content/canvas.js.map +1 -0
  533. package/dist/cli/skills-content/connection.d.ts +2 -0
  534. package/dist/cli/skills-content/connection.d.ts.map +1 -0
  535. package/dist/cli/skills-content/connection.js +53 -0
  536. package/dist/cli/skills-content/connection.js.map +1 -0
  537. package/dist/cli/skills-content/content-skill.d.ts +2 -0
  538. package/dist/cli/skills-content/content-skill.d.ts.map +1 -0
  539. package/dist/cli/skills-content/content-skill.js +110 -0
  540. package/dist/cli/skills-content/content-skill.js.map +1 -0
  541. package/dist/cli/skills-content/design-exploration-skill.d.ts +2 -0
  542. package/dist/cli/skills-content/design-exploration-skill.d.ts.map +1 -0
  543. package/dist/cli/skills-content/design-exploration-skill.js +119 -0
  544. package/dist/cli/skills-content/design-exploration-skill.js.map +1 -0
  545. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +2 -0
  546. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -0
  547. package/dist/cli/skills-content/design-visual-edit-skill.js +229 -0
  548. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -0
  549. package/dist/cli/skills-content/document-quality.d.ts +4 -0
  550. package/dist/cli/skills-content/document-quality.d.ts.map +1 -0
  551. package/dist/cli/skills-content/document-quality.js +195 -0
  552. package/dist/cli/skills-content/document-quality.js.map +1 -0
  553. package/dist/cli/skills-content/exemplar.d.ts +4 -0
  554. package/dist/cli/skills-content/exemplar.d.ts.map +1 -0
  555. package/dist/cli/skills-content/exemplar.js +68 -0
  556. package/dist/cli/skills-content/exemplar.js.map +1 -0
  557. package/dist/cli/skills-content/help.d.ts +2 -0
  558. package/dist/cli/skills-content/help.d.ts.map +1 -0
  559. package/dist/cli/skills-content/help.js +78 -0
  560. package/dist/cli/skills-content/help.js.map +1 -0
  561. package/dist/cli/skills-content/index.d.ts +23 -0
  562. package/dist/cli/skills-content/index.d.ts.map +1 -0
  563. package/dist/cli/skills-content/index.js +23 -0
  564. package/dist/cli/skills-content/index.js.map +1 -0
  565. package/dist/cli/skills-content/local-files.d.ts +2 -0
  566. package/dist/cli/skills-content/local-files.d.ts.map +1 -0
  567. package/dist/cli/skills-content/local-files.js +96 -0
  568. package/dist/cli/skills-content/local-files.js.map +1 -0
  569. package/dist/cli/skills-content/plan-setup-auth.d.ts +9 -0
  570. package/dist/cli/skills-content/plan-setup-auth.d.ts.map +1 -0
  571. package/dist/cli/skills-content/plan-setup-auth.js +81 -0
  572. package/dist/cli/skills-content/plan-setup-auth.js.map +1 -0
  573. package/dist/cli/skills-content/visual-plan-skill.d.ts +2 -0
  574. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -0
  575. package/dist/cli/skills-content/visual-plan-skill.js +471 -0
  576. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -0
  577. package/dist/cli/skills-content/visual-recap-skill.d.ts +2 -0
  578. package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -0
  579. package/dist/cli/skills-content/visual-recap-skill.js +548 -0
  580. package/dist/cli/skills-content/visual-recap-skill.js.map +1 -0
  581. package/dist/cli/skills-content/visualize-repo-skill.d.ts +2 -0
  582. package/dist/cli/skills-content/visualize-repo-skill.d.ts.map +1 -0
  583. package/dist/cli/skills-content/visualize-repo-skill.js +94 -0
  584. package/dist/cli/skills-content/visualize-repo-skill.js.map +1 -0
  585. package/dist/cli/skills-content/wireframe.d.ts +4 -0
  586. package/dist/cli/skills-content/wireframe.d.ts.map +1 -0
  587. package/dist/cli/skills-content/wireframe.js +347 -0
  588. package/dist/cli/skills-content/wireframe.js.map +1 -0
  589. package/dist/cli/skills.d.ts +2 -10
  590. package/dist/cli/skills.d.ts.map +1 -1
  591. package/dist/cli/skills.js +2 -2710
  592. package/dist/cli/skills.js.map +1 -1
  593. package/dist/client/AgentPanel.d.ts.map +1 -1
  594. package/dist/client/AgentPanel.js +6 -5
  595. package/dist/client/AgentPanel.js.map +1 -1
  596. package/dist/client/AssistantChat.d.ts +7 -0
  597. package/dist/client/AssistantChat.d.ts.map +1 -1
  598. package/dist/client/AssistantChat.js +62 -40
  599. package/dist/client/AssistantChat.js.map +1 -1
  600. package/dist/client/CommandMenu.d.ts.map +1 -1
  601. package/dist/client/CommandMenu.js +15 -3
  602. package/dist/client/CommandMenu.js.map +1 -1
  603. package/dist/client/FeedbackButton.js +2 -2
  604. package/dist/client/FeedbackButton.js.map +1 -1
  605. package/dist/client/analytics.d.ts.map +1 -1
  606. package/dist/client/analytics.js +26 -0
  607. package/dist/client/analytics.js.map +1 -1
  608. package/dist/client/app-providers.d.ts +13 -5
  609. package/dist/client/app-providers.d.ts.map +1 -1
  610. package/dist/client/app-providers.js +9 -6
  611. package/dist/client/app-providers.js.map +1 -1
  612. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  613. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  614. package/dist/client/blocks/library/wireframe-kit.js +9 -2
  615. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  616. package/dist/client/chat/tool-call-display.d.ts +4 -0
  617. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  618. package/dist/client/chat/tool-call-display.js +3 -3
  619. package/dist/client/chat/tool-call-display.js.map +1 -1
  620. package/dist/client/chat-model-groups.d.ts.map +1 -1
  621. package/dist/client/chat-model-groups.js +24 -0
  622. package/dist/client/chat-model-groups.js.map +1 -1
  623. package/dist/client/composer/PastedTextChip.js +1 -1
  624. package/dist/client/composer/PastedTextChip.js.map +1 -1
  625. package/dist/client/composer/RealtimeVoiceMode.d.ts +40 -2
  626. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
  627. package/dist/client/composer/RealtimeVoiceMode.js +186 -35
  628. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
  629. package/dist/client/composer/TiptapComposer.d.ts +4 -0
  630. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  631. package/dist/client/composer/TiptapComposer.js +48 -30
  632. package/dist/client/composer/TiptapComposer.js.map +1 -1
  633. package/dist/client/composer/VoiceButton.d.ts +2 -0
  634. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  635. package/dist/client/composer/VoiceButton.js +9 -3
  636. package/dist/client/composer/VoiceButton.js.map +1 -1
  637. package/dist/client/composer/index.d.ts +2 -2
  638. package/dist/client/composer/index.d.ts.map +1 -1
  639. package/dist/client/composer/index.js +1 -1
  640. package/dist/client/composer/index.js.map +1 -1
  641. package/dist/client/composer/useRealtimeVoiceMode.d.ts +104 -2
  642. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  643. package/dist/client/composer/useRealtimeVoiceMode.js +1015 -35
  644. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
  645. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  646. package/dist/client/context-xray/ContextXRayPanel.js +4 -1
  647. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  648. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  649. package/dist/client/extensions/ExtensionEditor.js +15 -5
  650. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  651. package/dist/client/extensions/ExtensionQueryErrorState.d.ts +8 -0
  652. package/dist/client/extensions/ExtensionQueryErrorState.d.ts.map +1 -0
  653. package/dist/client/extensions/ExtensionQueryErrorState.js +11 -0
  654. package/dist/client/extensions/ExtensionQueryErrorState.js.map +1 -0
  655. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  656. package/dist/client/extensions/ExtensionSlot.js +17 -7
  657. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  658. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  659. package/dist/client/extensions/ExtensionViewer.js +17 -7
  660. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  661. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  662. package/dist/client/extensions/ExtensionsListPage.js +5 -3
  663. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  664. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  665. package/dist/client/extensions/ExtensionsSidebarSection.js +21 -8
  666. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  667. package/dist/client/index.d.ts +1 -3
  668. package/dist/client/index.d.ts.map +1 -1
  669. package/dist/client/index.js +1 -6
  670. package/dist/client/index.js.map +1 -1
  671. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  672. package/dist/client/progress/RunsTray.js +17 -4
  673. package/dist/client/progress/RunsTray.js.map +1 -1
  674. package/dist/client/settings/SecretsSection.d.ts +2 -3
  675. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  676. package/dist/client/settings/SecretsSection.js +46 -22
  677. package/dist/client/settings/SecretsSection.js.map +1 -1
  678. package/dist/client/settings/SettingsPanel.d.ts +9 -0
  679. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  680. package/dist/client/settings/SettingsPanel.js +46 -12
  681. package/dist/client/settings/SettingsPanel.js.map +1 -1
  682. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  683. package/dist/client/settings/SettingsTabsPage.js +4 -0
  684. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  685. package/dist/client/settings/useBuilderStatus.d.ts +2 -0
  686. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  687. package/dist/client/settings/useBuilderStatus.js +4 -0
  688. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  689. package/dist/client/tool-cells/EditCell.d.ts.map +1 -1
  690. package/dist/client/tool-cells/EditCell.js +2 -1
  691. package/dist/client/tool-cells/EditCell.js.map +1 -1
  692. package/dist/client/tool-cells/FilesChangedSummary.d.ts.map +1 -1
  693. package/dist/client/tool-cells/FilesChangedSummary.js +2 -1
  694. package/dist/client/tool-cells/FilesChangedSummary.js.map +1 -1
  695. package/dist/client/tool-cells/WriteCell.d.ts.map +1 -1
  696. package/dist/client/tool-cells/WriteCell.js +2 -1
  697. package/dist/client/tool-cells/WriteCell.js.map +1 -1
  698. package/dist/client/use-action.d.ts +2 -0
  699. package/dist/client/use-action.d.ts.map +1 -1
  700. package/dist/client/use-action.js +10 -0
  701. package/dist/client/use-action.js.map +1 -1
  702. package/dist/client/use-agent-chat-home-handoff.d.ts +2 -0
  703. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  704. package/dist/client/use-agent-chat-home-handoff.js +7 -1
  705. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  706. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  707. package/dist/client/use-agent-engine-configured.js +17 -3
  708. package/dist/client/use-agent-engine-configured.js.map +1 -1
  709. package/dist/client/use-db-sync.d.ts +8 -2
  710. package/dist/client/use-db-sync.d.ts.map +1 -1
  711. package/dist/client/use-db-sync.js +57 -32
  712. package/dist/client/use-db-sync.js.map +1 -1
  713. package/dist/client/use-pausing-interval.d.ts.map +1 -1
  714. package/dist/client/use-pausing-interval.js +16 -4
  715. package/dist/client/use-pausing-interval.js.map +1 -1
  716. package/dist/client/visual-style-controls.js +1 -1
  717. package/dist/client/visual-style-controls.js.map +1 -1
  718. package/dist/collab/routes.d.ts +1 -1
  719. package/dist/deploy/build.d.ts.map +1 -1
  720. package/dist/deploy/build.js +36 -14
  721. package/dist/deploy/build.js.map +1 -1
  722. package/dist/integrations/google-docs-poller.d.ts +7 -0
  723. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  724. package/dist/integrations/google-docs-poller.js +13 -3
  725. package/dist/integrations/google-docs-poller.js.map +1 -1
  726. package/dist/integrations/plugin.d.ts.map +1 -1
  727. package/dist/integrations/plugin.js +10 -0
  728. package/dist/integrations/plugin.js.map +1 -1
  729. package/dist/integrations/scope-store.js +1 -1
  730. package/dist/integrations/scope-store.js.map +1 -1
  731. package/dist/integrations/usage-budget-store.js +1 -1
  732. package/dist/integrations/usage-budget-store.js.map +1 -1
  733. package/dist/integrations/webhook-handler.d.ts +11 -0
  734. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  735. package/dist/integrations/webhook-handler.js +16 -4
  736. package/dist/integrations/webhook-handler.js.map +1 -1
  737. package/dist/jobs/scheduler.d.ts +12 -0
  738. package/dist/jobs/scheduler.d.ts.map +1 -1
  739. package/dist/jobs/scheduler.js +13 -3
  740. package/dist/jobs/scheduler.js.map +1 -1
  741. package/dist/localization/default-messages.d.ts +47 -0
  742. package/dist/localization/default-messages.d.ts.map +1 -1
  743. package/dist/localization/default-messages.js +48 -1
  744. package/dist/localization/default-messages.js.map +1 -1
  745. package/dist/mcp/oauth-token.d.ts +1 -1
  746. package/dist/mcp/oauth-token.d.ts.map +1 -1
  747. package/dist/mcp/oauth-token.js +6 -1
  748. package/dist/mcp/oauth-token.js.map +1 -1
  749. package/dist/mcp-client/workspace-servers.js +4 -4
  750. package/dist/mcp-client/workspace-servers.js.map +1 -1
  751. package/dist/notifications/routes.d.ts +2 -2
  752. package/dist/observability/routes.d.ts +5 -5
  753. package/dist/observability/routes.d.ts.map +1 -1
  754. package/dist/observability/routes.js +32 -0
  755. package/dist/observability/routes.js.map +1 -1
  756. package/dist/observability/sentiment.d.ts +42 -0
  757. package/dist/observability/sentiment.d.ts.map +1 -0
  758. package/dist/observability/sentiment.js +196 -0
  759. package/dist/observability/sentiment.js.map +1 -0
  760. package/dist/observability/store.d.ts +5 -0
  761. package/dist/observability/store.d.ts.map +1 -1
  762. package/dist/observability/store.js +17 -0
  763. package/dist/observability/store.js.map +1 -1
  764. package/dist/observability/traces.d.ts +2 -0
  765. package/dist/observability/traces.d.ts.map +1 -1
  766. package/dist/observability/traces.js +42 -57
  767. package/dist/observability/traces.js.map +1 -1
  768. package/dist/observability/tracking-identity.d.ts +3 -0
  769. package/dist/observability/tracking-identity.d.ts.map +1 -0
  770. package/dist/observability/tracking-identity.js +51 -0
  771. package/dist/observability/tracking-identity.js.map +1 -0
  772. package/dist/observability/types.d.ts +10 -0
  773. package/dist/observability/types.d.ts.map +1 -1
  774. package/dist/observability/types.js +3 -0
  775. package/dist/observability/types.js.map +1 -1
  776. package/dist/progress/routes.d.ts +1 -1
  777. package/dist/resources/handlers.d.ts +1 -1
  778. package/dist/secrets/crypto.d.ts +7 -6
  779. package/dist/secrets/crypto.d.ts.map +1 -1
  780. package/dist/secrets/crypto.js +30 -11
  781. package/dist/secrets/crypto.js.map +1 -1
  782. package/dist/secrets/routes.d.ts +9 -9
  783. package/dist/secrets/storage.d.ts +6 -0
  784. package/dist/secrets/storage.d.ts.map +1 -1
  785. package/dist/secrets/storage.js +61 -3
  786. package/dist/secrets/storage.js.map +1 -1
  787. package/dist/server/action-change.d.ts +1 -0
  788. package/dist/server/action-change.d.ts.map +1 -1
  789. package/dist/server/action-change.js +4 -1
  790. package/dist/server/action-change.js.map +1 -1
  791. package/dist/server/action-routes.d.ts.map +1 -1
  792. package/dist/server/action-routes.js +5 -0
  793. package/dist/server/action-routes.js.map +1 -1
  794. package/dist/server/agent-chat/action-filters-a2a.d.ts +50 -0
  795. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -0
  796. package/dist/server/agent-chat/action-filters-a2a.js +127 -0
  797. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -0
  798. package/dist/server/agent-chat/browser-team-tools.d.ts +21 -0
  799. package/dist/server/agent-chat/browser-team-tools.d.ts.map +1 -0
  800. package/dist/server/agent-chat/browser-team-tools.js +417 -0
  801. package/dist/server/agent-chat/browser-team-tools.js.map +1 -0
  802. package/dist/server/agent-chat/context-tools.d.ts +33 -0
  803. package/dist/server/agent-chat/context-tools.d.ts.map +1 -0
  804. package/dist/server/agent-chat/context-tools.js +520 -0
  805. package/dist/server/agent-chat/context-tools.js.map +1 -0
  806. package/dist/server/agent-chat/framework-prompts.d.ts +65 -0
  807. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -0
  808. package/dist/server/agent-chat/framework-prompts.js +403 -0
  809. package/dist/server/agent-chat/framework-prompts.js.map +1 -0
  810. package/dist/server/agent-chat/lazy-fs.d.ts +2 -0
  811. package/dist/server/agent-chat/lazy-fs.d.ts.map +1 -0
  812. package/dist/server/agent-chat/lazy-fs.js +11 -0
  813. package/dist/server/agent-chat/lazy-fs.js.map +1 -0
  814. package/dist/server/agent-chat/mcp-glue.d.ts +9 -0
  815. package/dist/server/agent-chat/mcp-glue.d.ts.map +1 -0
  816. package/dist/server/agent-chat/mcp-glue.js +63 -0
  817. package/dist/server/agent-chat/mcp-glue.js.map +1 -0
  818. package/dist/server/agent-chat/plugin-options.d.ts +322 -0
  819. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -0
  820. package/dist/server/agent-chat/plugin-options.js +2 -0
  821. package/dist/server/agent-chat/plugin-options.js.map +1 -0
  822. package/dist/server/agent-chat/process-run-failure.d.ts +12 -0
  823. package/dist/server/agent-chat/process-run-failure.d.ts.map +1 -0
  824. package/dist/server/agent-chat/process-run-failure.js +24 -0
  825. package/dist/server/agent-chat/process-run-failure.js.map +1 -0
  826. package/dist/server/agent-chat/prompt-resources.d.ts +28 -0
  827. package/dist/server/agent-chat/prompt-resources.d.ts.map +1 -0
  828. package/dist/server/agent-chat/prompt-resources.js +514 -0
  829. package/dist/server/agent-chat/prompt-resources.js.map +1 -0
  830. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +5 -0
  831. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts.map +1 -0
  832. package/dist/server/agent-chat/recurring-jobs-runtime.js +53 -0
  833. package/dist/server/agent-chat/recurring-jobs-runtime.js.map +1 -0
  834. package/dist/server/agent-chat/request-surface.d.ts +8 -0
  835. package/dist/server/agent-chat/request-surface.d.ts.map +1 -0
  836. package/dist/server/agent-chat/request-surface.js +56 -0
  837. package/dist/server/agent-chat/request-surface.js.map +1 -0
  838. package/dist/server/agent-chat/run-code-tools.d.ts +17 -0
  839. package/dist/server/agent-chat/run-code-tools.d.ts.map +1 -0
  840. package/dist/server/agent-chat/run-code-tools.js +55 -0
  841. package/dist/server/agent-chat/run-code-tools.js.map +1 -0
  842. package/dist/server/agent-chat/script-entries.d.ts +47 -0
  843. package/dist/server/agent-chat/script-entries.d.ts.map +1 -0
  844. package/dist/server/agent-chat/script-entries.js +633 -0
  845. package/dist/server/agent-chat/script-entries.js.map +1 -0
  846. package/dist/server/agent-chat/shared-thread.d.ts +33 -0
  847. package/dist/server/agent-chat/shared-thread.d.ts.map +1 -0
  848. package/dist/server/agent-chat/shared-thread.js +242 -0
  849. package/dist/server/agent-chat/shared-thread.js.map +1 -0
  850. package/dist/server/agent-chat/skill-frontmatter.d.ts +7 -0
  851. package/dist/server/agent-chat/skill-frontmatter.d.ts.map +1 -0
  852. package/dist/server/agent-chat/skill-frontmatter.js +26 -0
  853. package/dist/server/agent-chat/skill-frontmatter.js.map +1 -0
  854. package/dist/server/agent-chat-plugin.d.ts +45 -486
  855. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  856. package/dist/server/agent-chat-plugin.js +173 -3005
  857. package/dist/server/agent-chat-plugin.js.map +1 -1
  858. package/dist/server/agent-teams.d.ts +10 -0
  859. package/dist/server/agent-teams.d.ts.map +1 -1
  860. package/dist/server/agent-teams.js +13 -3
  861. package/dist/server/agent-teams.js.map +1 -1
  862. package/dist/server/auth.d.ts.map +1 -1
  863. package/dist/server/auth.js +50 -52
  864. package/dist/server/auth.js.map +1 -1
  865. package/dist/server/credential-provider.d.ts.map +1 -1
  866. package/dist/server/credential-provider.js +22 -21
  867. package/dist/server/credential-provider.js.map +1 -1
  868. package/dist/server/edge.d.ts +1 -0
  869. package/dist/server/edge.d.ts.map +1 -1
  870. package/dist/server/edge.js +1 -0
  871. package/dist/server/edge.js.map +1 -1
  872. package/dist/server/onboarding-html.d.ts.map +1 -1
  873. package/dist/server/onboarding-html.js +1 -16
  874. package/dist/server/onboarding-html.js.map +1 -1
  875. package/dist/server/poll.d.ts.map +1 -1
  876. package/dist/server/poll.js +1 -0
  877. package/dist/server/poll.js.map +1 -1
  878. package/dist/server/realtime-voice.d.ts +10 -0
  879. package/dist/server/realtime-voice.d.ts.map +1 -1
  880. package/dist/server/realtime-voice.js +249 -15
  881. package/dist/server/realtime-voice.js.map +1 -1
  882. package/dist/server/request-origin.d.ts.map +1 -1
  883. package/dist/server/request-origin.js +6 -3
  884. package/dist/server/request-origin.js.map +1 -1
  885. package/dist/server/ssr-handler.d.ts.map +1 -1
  886. package/dist/server/ssr-handler.js +47 -2
  887. package/dist/server/ssr-handler.js.map +1 -1
  888. package/dist/sharing/access.d.ts +63 -3
  889. package/dist/sharing/access.d.ts.map +1 -1
  890. package/dist/sharing/access.js +53 -15
  891. package/dist/sharing/access.js.map +1 -1
  892. package/dist/sharing/registry.d.ts +7 -0
  893. package/dist/sharing/registry.d.ts.map +1 -1
  894. package/dist/sharing/registry.js.map +1 -1
  895. package/dist/styles/agent-native.css +17 -16
  896. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  897. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  898. package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
  899. package/dist/templates/default/app/i18n/de-DE.ts +6 -0
  900. package/dist/templates/default/app/i18n/en-US.ts +6 -0
  901. package/dist/templates/default/app/i18n/es-ES.ts +6 -0
  902. package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
  903. package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
  904. package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
  905. package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
  906. package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
  907. package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
  908. package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
  909. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  910. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  911. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  912. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  913. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  914. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  915. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  916. package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  917. package/dist/templates/workspace-core/src/server/index.ts +4 -2
  918. package/dist/testing.d.ts +16 -0
  919. package/dist/testing.d.ts.map +1 -0
  920. package/dist/testing.js +16 -0
  921. package/dist/testing.js.map +1 -0
  922. package/dist/triggers/dispatcher.d.ts +7 -0
  923. package/dist/triggers/dispatcher.d.ts.map +1 -1
  924. package/dist/triggers/dispatcher.js +13 -3
  925. package/dist/triggers/dispatcher.js.map +1 -1
  926. package/dist/vite/client.d.ts +16 -1
  927. package/dist/vite/client.d.ts.map +1 -1
  928. package/dist/vite/client.js +111 -3
  929. package/dist/vite/client.js.map +1 -1
  930. package/docs/content/authentication.mdx +3 -3
  931. package/docs/content/doctor.mdx +170 -0
  932. package/docs/content/external-agents.mdx +8 -7
  933. package/docs/content/locales/ar-SA/authentication.mdx +2 -2
  934. package/docs/content/locales/ar-SA/external-agents.mdx +8 -7
  935. package/docs/content/locales/ar-SA/mcp-protocol.mdx +1 -1
  936. package/docs/content/locales/ar-SA/security.mdx +2 -0
  937. package/docs/content/locales/de-DE/authentication.mdx +1 -1
  938. package/docs/content/locales/de-DE/external-agents.mdx +8 -7
  939. package/docs/content/locales/de-DE/mcp-protocol.mdx +1 -1
  940. package/docs/content/locales/de-DE/security.mdx +2 -0
  941. package/docs/content/locales/es-ES/authentication.mdx +2 -2
  942. package/docs/content/locales/es-ES/external-agents.mdx +8 -7
  943. package/docs/content/locales/es-ES/mcp-protocol.mdx +1 -1
  944. package/docs/content/locales/es-ES/security.mdx +2 -0
  945. package/docs/content/locales/fr-FR/authentication.mdx +1 -1
  946. package/docs/content/locales/fr-FR/external-agents.mdx +8 -7
  947. package/docs/content/locales/fr-FR/mcp-protocol.mdx +1 -1
  948. package/docs/content/locales/fr-FR/security.mdx +2 -0
  949. package/docs/content/locales/hi-IN/authentication.mdx +2 -2
  950. package/docs/content/locales/hi-IN/external-agents.mdx +8 -7
  951. package/docs/content/locales/hi-IN/mcp-protocol.mdx +1 -1
  952. package/docs/content/locales/hi-IN/security.mdx +2 -0
  953. package/docs/content/locales/ja-JP/authentication.mdx +2 -2
  954. package/docs/content/locales/ja-JP/external-agents.mdx +8 -7
  955. package/docs/content/locales/ja-JP/mcp-protocol.mdx +1 -1
  956. package/docs/content/locales/ja-JP/security.mdx +2 -0
  957. package/docs/content/locales/ko-KR/authentication.mdx +2 -2
  958. package/docs/content/locales/ko-KR/external-agents.mdx +8 -7
  959. package/docs/content/locales/ko-KR/mcp-protocol.mdx +1 -1
  960. package/docs/content/locales/ko-KR/security.mdx +2 -0
  961. package/docs/content/locales/pt-BR/authentication.mdx +2 -2
  962. package/docs/content/locales/pt-BR/external-agents.mdx +8 -7
  963. package/docs/content/locales/pt-BR/mcp-protocol.mdx +1 -1
  964. package/docs/content/locales/pt-BR/security.mdx +2 -0
  965. package/docs/content/locales/zh-CN/authentication.mdx +2 -2
  966. package/docs/content/locales/zh-CN/external-agents.mdx +8 -7
  967. package/docs/content/locales/zh-CN/mcp-protocol.mdx +1 -1
  968. package/docs/content/locales/zh-CN/security.mdx +2 -0
  969. package/docs/content/locales/zh-TW/authentication.mdx +2 -2
  970. package/docs/content/locales/zh-TW/external-agents.mdx +8 -7
  971. package/docs/content/locales/zh-TW/mcp-protocol.mdx +1 -1
  972. package/docs/content/locales/zh-TW/security.mdx +2 -0
  973. package/docs/content/mcp-protocol.mdx +1 -1
  974. package/docs/content/security.mdx +2 -0
  975. package/package.json +7 -3
  976. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  977. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  978. package/src/templates/default/app/i18n/ar-SA.ts +6 -0
  979. package/src/templates/default/app/i18n/de-DE.ts +6 -0
  980. package/src/templates/default/app/i18n/en-US.ts +6 -0
  981. package/src/templates/default/app/i18n/es-ES.ts +6 -0
  982. package/src/templates/default/app/i18n/fr-FR.ts +6 -0
  983. package/src/templates/default/app/i18n/hi-IN.ts +6 -0
  984. package/src/templates/default/app/i18n/ja-JP.ts +6 -0
  985. package/src/templates/default/app/i18n/ko-KR.ts +6 -0
  986. package/src/templates/default/app/i18n/pt-BR.ts +6 -0
  987. package/src/templates/default/app/i18n/zh-CN.ts +6 -0
  988. package/src/templates/default/app/i18n/zh-TW.ts +6 -0
  989. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  990. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  991. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  992. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  993. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  994. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  995. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  996. package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  997. package/src/templates/workspace-core/src/server/index.ts +4 -2
  998. package/corpus/core/src/client/ProductionAgentPanel.tsx +0 -9
  999. package/corpus/core/src/client/auth-redirect-url.ts +0 -23
  1000. package/corpus/core/src/client/useProductionAgent.ts +0 -253
  1001. package/corpus/core/src/shared/auth-redirect-url.ts +0 -1
  1002. package/corpus/templates/analytics/app/pages/Index.tsx +0 -16
  1003. package/corpus/templates/analytics/seeds/dashboards/agent-observability-llm.json +0 -173
  1004. package/dist/client/ProductionAgentPanel.d.ts +0 -6
  1005. package/dist/client/ProductionAgentPanel.d.ts.map +0 -1
  1006. package/dist/client/ProductionAgentPanel.js +0 -6
  1007. package/dist/client/ProductionAgentPanel.js.map +0 -1
  1008. package/dist/client/auth-redirect-url.d.ts +0 -2
  1009. package/dist/client/auth-redirect-url.d.ts.map +0 -1
  1010. package/dist/client/auth-redirect-url.js +0 -19
  1011. package/dist/client/auth-redirect-url.js.map +0 -1
  1012. package/dist/client/useProductionAgent.d.ts +0 -24
  1013. package/dist/client/useProductionAgent.d.ts.map +0 -1
  1014. package/dist/client/useProductionAgent.js +0 -179
  1015. package/dist/client/useProductionAgent.js.map +0 -1
  1016. package/dist/shared/auth-redirect-url.d.ts +0 -2
  1017. package/dist/shared/auth-redirect-url.d.ts.map +0 -1
  1018. package/dist/shared/auth-redirect-url.js +0 -2
  1019. package/dist/shared/auth-redirect-url.js.map +0 -1
@@ -11,9 +11,333 @@ import { createRealtimeVoiceAudioLevelStore, normalizeRealtimeVoiceRms, smoothRe
11
11
  import { realtimeVoiceTranscriptRegistry } from "./realtime-voice-transcript.js";
12
12
  import { RealtimeVoiceModeDock, } from "./RealtimeVoiceMode.js";
13
13
  const REALTIME_VOICE_STATE_KEY = "realtime-voice-session";
14
+ const REALTIME_VOICE_PREFERENCES_KEY = "realtime-voice-prefs";
14
15
  const REALTIME_VOICE_REQUEST_SOURCE = "realtime-voice";
15
16
  const REALTIME_VOICE_SESSION_PATH = "/_agent-native/realtime-voice/session";
16
17
  const REALTIME_VOICE_TOOL_PATH = "/_agent-native/realtime-voice/tool";
18
+ const REALTIME_VOICE_CAPABILITY_HEADER = "X-Agent-Native-Realtime-Capability";
19
+ const REALTIME_VOICE_CONNECTION_TIMEOUT_MS = 15_000;
20
+ const REALTIME_VOICE_MAX_TOOLS = 32;
21
+ const REALTIME_VOICE_MAX_TOOL_SCHEMA_BYTES = 32_000;
22
+ const REALTIME_VOICE_MAX_SESSION_BYTES = 64_000;
23
+ const REALTIME_VOICE_TOOL_UPDATE_TIMEOUT_MS = 5_000;
24
+ const REALTIME_VOICE_PRIORITY_TOOL_NAMES = [
25
+ "navigate",
26
+ "set-url-path",
27
+ "set-search-params",
28
+ "view-screen",
29
+ "tool-search",
30
+ ];
31
+ const REALTIME_VOICE_TOOL_NAME = /^[A-Za-z0-9_-]{1,64}$/;
32
+ const REALTIME_VOICE_MICROPHONE_STORAGE_KEY = "agent-native:realtime-voice-microphone";
33
+ export const REALTIME_VOICE_LANGUAGES = [
34
+ "auto",
35
+ "en",
36
+ "es",
37
+ "fr",
38
+ "de",
39
+ "it",
40
+ "pt",
41
+ "ja",
42
+ "ko",
43
+ "zh",
44
+ ];
45
+ export const REALTIME_VOICE_INTELLIGENCE_LEVELS = [
46
+ "instant",
47
+ "balanced",
48
+ "deep",
49
+ ];
50
+ export const REALTIME_VOICES = [
51
+ "marin",
52
+ "cedar",
53
+ "coral",
54
+ "sage",
55
+ "verse",
56
+ "alloy",
57
+ "ash",
58
+ "ballad",
59
+ "echo",
60
+ "shimmer",
61
+ ];
62
+ export const DEFAULT_REALTIME_VOICE_PREFERENCES = {
63
+ language: "auto",
64
+ intelligence: "instant",
65
+ voice: "marin",
66
+ };
67
+ export const REALTIME_VOICE_AUDIO_CONSTRAINTS = {
68
+ // Prefer the browser/OS-selected input instead of whichever physical device
69
+ // happens to be enumerated first. `ideal` keeps browsers without the
70
+ // synthetic `default` device from failing with OverconstrainedError.
71
+ deviceId: { ideal: "default" },
72
+ echoCancellation: true,
73
+ noiseSuppression: true,
74
+ autoGainControl: true,
75
+ };
76
+ export function createRealtimeVoiceAudioConstraints(deviceId = "default", exact = false) {
77
+ return {
78
+ ...REALTIME_VOICE_AUDIO_CONSTRAINTS,
79
+ deviceId: deviceId === "default"
80
+ ? { ideal: "default" }
81
+ : exact
82
+ ? { exact: deviceId }
83
+ : { ideal: deviceId },
84
+ };
85
+ }
86
+ export async function replaceRealtimeVoiceMicrophone(options) {
87
+ const replacementStream = await options.mediaDevices.getUserMedia({
88
+ audio: createRealtimeVoiceAudioConstraints(options.deviceId, true),
89
+ });
90
+ try {
91
+ const replacementTrack = replacementStream.getAudioTracks()[0];
92
+ const sender = options.peer
93
+ .getSenders()
94
+ .find((candidate) => candidate.track?.kind === "audio");
95
+ if (!replacementTrack || !sender) {
96
+ throw new Error("No active microphone track is available.");
97
+ }
98
+ await sender.replaceTrack(replacementTrack);
99
+ for (const track of options.currentStream?.getTracks() ?? []) {
100
+ track.onended = null;
101
+ track.stop();
102
+ }
103
+ return replacementStream;
104
+ }
105
+ catch (error) {
106
+ for (const track of replacementStream.getTracks())
107
+ track.stop();
108
+ throw error;
109
+ }
110
+ }
111
+ function readRealtimeVoiceMicrophoneId() {
112
+ if (typeof window === "undefined")
113
+ return "default";
114
+ try {
115
+ return (window.localStorage.getItem(REALTIME_VOICE_MICROPHONE_STORAGE_KEY) ||
116
+ "default");
117
+ }
118
+ catch {
119
+ return "default";
120
+ }
121
+ }
122
+ function writeRealtimeVoiceMicrophoneId(deviceId) {
123
+ try {
124
+ window.localStorage.setItem(REALTIME_VOICE_MICROPHONE_STORAGE_KEY, deviceId);
125
+ }
126
+ catch {
127
+ // A remembered local device is optional and must never block voice mode.
128
+ }
129
+ }
130
+ function isOneOf(values, value) {
131
+ return typeof value === "string" && values.includes(value);
132
+ }
133
+ export function normalizeRealtimeVoicePreferences(value) {
134
+ const record = value && typeof value === "object" && !Array.isArray(value)
135
+ ? value
136
+ : {};
137
+ return {
138
+ language: isOneOf(REALTIME_VOICE_LANGUAGES, record.language)
139
+ ? record.language
140
+ : DEFAULT_REALTIME_VOICE_PREFERENCES.language,
141
+ intelligence: isOneOf(REALTIME_VOICE_INTELLIGENCE_LEVELS, record.intelligence)
142
+ ? record.intelligence
143
+ : DEFAULT_REALTIME_VOICE_PREFERENCES.intelligence,
144
+ voice: isOneOf(REALTIME_VOICES, record.voice)
145
+ ? record.voice
146
+ : DEFAULT_REALTIME_VOICE_PREFERENCES.voice,
147
+ };
148
+ }
149
+ export function resolveRealtimeVoiceLanguage(language, browserLanguages = []) {
150
+ if (language !== "auto")
151
+ return language;
152
+ for (const locale of browserLanguages) {
153
+ const primary = locale.trim().split("-")[0]?.toLowerCase();
154
+ if (isOneOf(REALTIME_VOICE_LANGUAGES, primary) && primary !== "auto") {
155
+ return primary;
156
+ }
157
+ }
158
+ return "en";
159
+ }
160
+ export function realtimeVoiceReasoningEffort(intelligence) {
161
+ if (intelligence === "balanced")
162
+ return "low";
163
+ if (intelligence === "deep")
164
+ return "medium";
165
+ return "minimal";
166
+ }
167
+ export function createRealtimeVoicePreferenceUpdate(preferences, options = {}) {
168
+ return {
169
+ type: "session.update",
170
+ session: {
171
+ type: "realtime",
172
+ reasoning: {
173
+ effort: realtimeVoiceReasoningEffort(preferences.intelligence),
174
+ },
175
+ audio: {
176
+ input: {
177
+ transcription: {
178
+ model: "gpt-4o-mini-transcribe",
179
+ language: resolveRealtimeVoiceLanguage(preferences.language, options.browserLanguages),
180
+ },
181
+ },
182
+ ...(options.includeVoice
183
+ ? { output: { voice: preferences.voice } }
184
+ : {}),
185
+ },
186
+ },
187
+ };
188
+ }
189
+ /**
190
+ * Input transcription is produced by a separate ASR model and can finish after
191
+ * the assistant response. Reserve each message's position when OpenAI adds it
192
+ * to the conversation, then publish only the contiguous completed prefix.
193
+ */
194
+ export function createRealtimeVoiceTranscriptSequencer(publish) {
195
+ const order = [];
196
+ const items = new Map();
197
+ const settledItemIds = new Set();
198
+ const receivedTranscriptIds = new Set();
199
+ const reserve = (id, role) => {
200
+ if (settledItemIds.has(id))
201
+ return;
202
+ const existing = items.get(id);
203
+ if (existing) {
204
+ existing.role ??= role;
205
+ return;
206
+ }
207
+ order.push(id);
208
+ items.set(id, { status: "pending", role });
209
+ };
210
+ const drain = () => {
211
+ while (order.length > 0) {
212
+ const id = order[0];
213
+ const entry = items.get(id);
214
+ if (!entry || entry.status === "pending")
215
+ return;
216
+ order.shift();
217
+ items.delete(id);
218
+ settledItemIds.add(id);
219
+ if (entry.status === "completed" && entry.transcript) {
220
+ publish(entry.transcript);
221
+ }
222
+ }
223
+ };
224
+ const skip = (id) => {
225
+ if (typeof id !== "string" || !id)
226
+ return;
227
+ reserve(id);
228
+ const entry = items.get(id);
229
+ if (entry.status === "pending")
230
+ entry.status = "skipped";
231
+ };
232
+ return {
233
+ handle(event) {
234
+ if (event.type === "conversation.item.added" ||
235
+ event.type === "conversation.item.created") {
236
+ const item = event.item;
237
+ if (item && typeof item === "object") {
238
+ const record = item;
239
+ if (record.type === "message" &&
240
+ (record.role === "user" || record.role === "assistant") &&
241
+ typeof record.id === "string") {
242
+ reserve(record.id, record.role);
243
+ }
244
+ }
245
+ }
246
+ const transcript = extractCompletedRealtimeVoiceTranscript(event);
247
+ if (transcript) {
248
+ const transcriptId = transcript.providerId
249
+ ? `${transcript.role}:${transcript.providerId}`
250
+ : undefined;
251
+ if (transcriptId && receivedTranscriptIds.has(transcriptId))
252
+ return;
253
+ if (transcriptId)
254
+ receivedTranscriptIds.add(transcriptId);
255
+ const itemId = typeof event.item_id === "string" ? event.item_id : undefined;
256
+ if (!itemId) {
257
+ // Older providers may omit item_id. Match the first reserved slot for
258
+ // that role so one incomplete legacy event cannot strand the queue.
259
+ const reservedId = order.find((id) => {
260
+ const entry = items.get(id);
261
+ return (entry?.status === "pending" && entry.role === transcript.role);
262
+ });
263
+ if (reservedId) {
264
+ items.set(reservedId, {
265
+ status: "completed",
266
+ role: transcript.role,
267
+ transcript,
268
+ });
269
+ }
270
+ else {
271
+ publish(transcript);
272
+ }
273
+ }
274
+ else {
275
+ if (settledItemIds.has(itemId))
276
+ return;
277
+ reserve(itemId, transcript.role);
278
+ items.set(itemId, {
279
+ status: "completed",
280
+ role: transcript.role,
281
+ transcript,
282
+ });
283
+ }
284
+ }
285
+ else if (event.type === "conversation.item.input_audio_transcription.failed" ||
286
+ event.type === "conversation.item.deleted") {
287
+ skip(event.item_id);
288
+ }
289
+ else if (event.type === "response.done") {
290
+ const response = event.response;
291
+ const output = response && typeof response === "object"
292
+ ? response.output
293
+ : undefined;
294
+ if (Array.isArray(output)) {
295
+ for (const item of output) {
296
+ if (!item || typeof item !== "object")
297
+ continue;
298
+ const record = item;
299
+ if (record.type === "message")
300
+ skip(record.id);
301
+ }
302
+ }
303
+ }
304
+ drain();
305
+ },
306
+ reset() {
307
+ order.length = 0;
308
+ items.clear();
309
+ settledItemIds.clear();
310
+ receivedTranscriptIds.clear();
311
+ },
312
+ };
313
+ }
314
+ export function createRealtimeVoiceGreetingEvent() {
315
+ return {
316
+ type: "response.create",
317
+ response: {
318
+ output_modalities: ["audio"],
319
+ instructions: 'Say exactly: "How can I help you?" Do not add anything else.',
320
+ // Do not set max_output_tokens here. Realtime counts assistant audio at
321
+ // roughly one token per 50 ms, so a text-sized cap can cut speech off.
322
+ // The exact-response instruction already keeps this greeting bounded.
323
+ },
324
+ };
325
+ }
326
+ export function createRealtimeVoiceGreetingStarter(send) {
327
+ let started = false;
328
+ return {
329
+ start() {
330
+ if (started)
331
+ return false;
332
+ started = true;
333
+ send(createRealtimeVoiceGreetingEvent());
334
+ return true;
335
+ },
336
+ reset() {
337
+ started = false;
338
+ },
339
+ };
340
+ }
17
341
  /**
18
342
  * Voice mode owns the chat only temporarily. Restore the captured transcript
19
343
  * when it is still the user's active thread (or the chat has no active thread)
@@ -41,6 +365,30 @@ export function extractCompletedRealtimeVoiceTranscript(event) {
41
365
  function errorMessage(error) {
42
366
  return error instanceof Error ? error.message : String(error);
43
367
  }
368
+ export function isRealtimeVoiceAbortError(error) {
369
+ return Boolean(error &&
370
+ typeof error === "object" &&
371
+ error.name === "AbortError");
372
+ }
373
+ export function isRealtimeVoiceSetupRequiredError(error) {
374
+ return Boolean(error &&
375
+ typeof error === "object" &&
376
+ error.status === 409);
377
+ }
378
+ export function createRealtimeVoiceConnectionTimeout(onTimeout, timeoutMs = REALTIME_VOICE_CONNECTION_TIMEOUT_MS) {
379
+ const timeout = window.setTimeout(onTimeout, timeoutMs);
380
+ return () => window.clearTimeout(timeout);
381
+ }
382
+ export function createRealtimeVoiceConnectionGate(onTimeout, timeoutMs = REALTIME_VOICE_CONNECTION_TIMEOUT_MS) {
383
+ const cancel = createRealtimeVoiceConnectionTimeout(onTimeout, timeoutMs);
384
+ return {
385
+ // RTC connectivity alone is not enough: the session may never finish its
386
+ // Realtime handshake. Keep the deadline armed until session.created.
387
+ markTransportReady() { },
388
+ markSessionCreated: cancel,
389
+ cancel,
390
+ };
391
+ }
44
392
  async function readErrorResponse(response) {
45
393
  const raw = await response.text().catch(() => "");
46
394
  if (!raw)
@@ -53,7 +401,8 @@ async function readErrorResponse(response) {
53
401
  return raw.slice(0, 500);
54
402
  }
55
403
  }
56
- export async function createRealtimeVoiceSession(offerSdp, options = {}) {
404
+ export async function createRealtimeVoiceSessionWithCapability(offerSdp, options = {}) {
405
+ const preferences = options.preferences;
57
406
  const response = await fetch(agentNativePath(REALTIME_VOICE_SESSION_PATH), {
58
407
  method: "POST",
59
408
  credentials: "same-origin",
@@ -62,6 +411,13 @@ export async function createRealtimeVoiceSession(offerSdp, options = {}) {
62
411
  ...(options.browserTabId
63
412
  ? { "X-Agent-Native-Browser-Tab": options.browserTabId }
64
413
  : {}),
414
+ ...(preferences
415
+ ? {
416
+ "X-Agent-Native-Realtime-Language": resolveRealtimeVoiceLanguage(preferences.language, options.browserLanguages),
417
+ "X-Agent-Native-Realtime-Intelligence": preferences.intelligence,
418
+ "X-Agent-Native-Realtime-Voice": preferences.voice,
419
+ }
420
+ : {}),
65
421
  },
66
422
  body: offerSdp,
67
423
  signal: options.signal,
@@ -72,7 +428,17 @@ export async function createRealtimeVoiceSession(offerSdp, options = {}) {
72
428
  error.status = response.status;
73
429
  throw error;
74
430
  }
75
- return response.text();
431
+ const sdp = await response.text();
432
+ const capability = response.headers.get(REALTIME_VOICE_CAPABILITY_HEADER);
433
+ return {
434
+ sdp,
435
+ ...(capability ? { capability } : {}),
436
+ };
437
+ }
438
+ /** Backwards-compatible SDP-only session helper for existing client callers. */
439
+ export async function createRealtimeVoiceSession(offerSdp, options = {}) {
440
+ return (await createRealtimeVoiceSessionWithCapability(offerSdp, options))
441
+ .sdp;
76
442
  }
77
443
  export async function executeRealtimeVoiceTool(input) {
78
444
  const response = await fetch(agentNativePath(REALTIME_VOICE_TOOL_PATH), {
@@ -83,6 +449,9 @@ export async function executeRealtimeVoiceTool(input) {
83
449
  ...(input.browserTabId
84
450
  ? { "X-Agent-Native-Browser-Tab": input.browserTabId }
85
451
  : {}),
452
+ ...(input.capability
453
+ ? { [REALTIME_VOICE_CAPABILITY_HEADER]: input.capability }
454
+ : {}),
86
455
  },
87
456
  body: JSON.stringify({
88
457
  name: input.name,
@@ -98,6 +467,217 @@ export async function executeRealtimeVoiceTool(input) {
98
467
  }
99
468
  return (await response.json());
100
469
  }
470
+ function jsonByteLength(value) {
471
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
472
+ }
473
+ function normalizeRealtimeVoiceFunctionTool(value) {
474
+ if (!value || typeof value !== "object" || Array.isArray(value))
475
+ return null;
476
+ const record = value;
477
+ if (record.type !== "function" ||
478
+ typeof record.name !== "string" ||
479
+ !REALTIME_VOICE_TOOL_NAME.test(record.name)) {
480
+ return null;
481
+ }
482
+ if (record.description !== undefined &&
483
+ typeof record.description !== "string") {
484
+ return null;
485
+ }
486
+ if (record.parameters !== undefined &&
487
+ (!record.parameters ||
488
+ typeof record.parameters !== "object" ||
489
+ Array.isArray(record.parameters))) {
490
+ return null;
491
+ }
492
+ try {
493
+ if (jsonByteLength(record) > REALTIME_VOICE_MAX_TOOL_SCHEMA_BYTES) {
494
+ return null;
495
+ }
496
+ return JSON.parse(JSON.stringify(record));
497
+ }
498
+ catch {
499
+ return null;
500
+ }
501
+ }
502
+ export function extractRealtimeVoiceSessionTools(event) {
503
+ if (event.type !== "session.created" && event.type !== "session.updated") {
504
+ return null;
505
+ }
506
+ const session = event.session;
507
+ if (!session || typeof session !== "object")
508
+ return null;
509
+ const tools = session.tools;
510
+ if (!Array.isArray(tools))
511
+ return null;
512
+ return tools
513
+ .map(normalizeRealtimeVoiceFunctionTool)
514
+ .filter((tool) => Boolean(tool));
515
+ }
516
+ function createRealtimeVoiceToolManifestUpdate(tools, eventId) {
517
+ return {
518
+ type: "session.update",
519
+ ...(eventId ? { event_id: eventId } : {}),
520
+ session: {
521
+ type: "realtime",
522
+ tools,
523
+ tool_choice: "auto",
524
+ },
525
+ };
526
+ }
527
+ /**
528
+ * Merge search-discovered schemas into the live manifest. Pinned navigation
529
+ * and discovery tools stay available, then the newest discoveries take the
530
+ * remaining slots ahead of lower-priority tools from the original manifest.
531
+ */
532
+ export function mergeRealtimeVoiceToolManifest(currentTools, expandedTools) {
533
+ const current = new Map();
534
+ for (const value of currentTools) {
535
+ const tool = normalizeRealtimeVoiceFunctionTool(value);
536
+ if (tool)
537
+ current.set(tool.name, tool);
538
+ }
539
+ const expanded = new Map();
540
+ for (const value of expandedTools) {
541
+ const tool = normalizeRealtimeVoiceFunctionTool(value);
542
+ if (tool)
543
+ expanded.set(tool.name, tool);
544
+ }
545
+ const candidates = [];
546
+ const seen = new Set();
547
+ const add = (tool) => {
548
+ if (!tool || seen.has(tool.name))
549
+ return;
550
+ seen.add(tool.name);
551
+ candidates.push(tool);
552
+ };
553
+ for (const name of REALTIME_VOICE_PRIORITY_TOOL_NAMES) {
554
+ add(expanded.get(name) ?? current.get(name));
555
+ }
556
+ for (const tool of expanded.values())
557
+ add(tool);
558
+ for (const tool of current.values())
559
+ add(tool);
560
+ const packed = [];
561
+ for (const tool of candidates) {
562
+ if (packed.length >= REALTIME_VOICE_MAX_TOOLS)
563
+ break;
564
+ const candidate = [...packed, tool];
565
+ if (jsonByteLength(createRealtimeVoiceToolManifestUpdate(candidate, "realtime_tool_manifest_999999999")) <= REALTIME_VOICE_MAX_SESSION_BYTES) {
566
+ packed.push(tool);
567
+ }
568
+ }
569
+ return packed;
570
+ }
571
+ function createRealtimeVoiceToolResultEvent(result) {
572
+ const modelResult = {
573
+ callId: result.callId,
574
+ status: result.status,
575
+ output: result.output,
576
+ ...(result.approvalKey ? { approvalKey: result.approvalKey } : {}),
577
+ };
578
+ return {
579
+ type: "conversation.item.create",
580
+ item: {
581
+ type: "function_call_output",
582
+ call_id: result.callId,
583
+ output: JSON.stringify(modelResult),
584
+ },
585
+ };
586
+ }
587
+ /**
588
+ * Realtime treats `session.update.tools` as a full replacement. Serialize
589
+ * discovery updates and wait for a confirming `session.updated` manifest
590
+ * before returning the search result and allowing the next model response.
591
+ */
592
+ export function createRealtimeVoiceToolManifestCoordinator(send, timeoutMs = REALTIME_VOICE_TOOL_UPDATE_TIMEOUT_MS) {
593
+ let currentTools = [];
594
+ const queue = [];
595
+ let updateSequence = 0;
596
+ let active;
597
+ const finish = (failureMessage) => {
598
+ if (!active)
599
+ return;
600
+ const { result, timer } = active;
601
+ clearTimeout(timer);
602
+ active = undefined;
603
+ send(createRealtimeVoiceToolResultEvent(failureMessage
604
+ ? {
605
+ callId: result.callId,
606
+ status: "failed",
607
+ output: `${failureMessage} The discovered tools were not added to this voice session. Original tool result: ${result.output}`,
608
+ }
609
+ : result));
610
+ send({ type: "response.create" });
611
+ drain();
612
+ };
613
+ const drain = () => {
614
+ if (active)
615
+ return;
616
+ const result = queue.shift();
617
+ if (!result)
618
+ return;
619
+ const expanded = Array.isArray(result.expandedTools)
620
+ ? result.expandedTools
621
+ .map(normalizeRealtimeVoiceFunctionTool)
622
+ .filter((tool) => Boolean(tool))
623
+ : [];
624
+ if (result.status !== "completed" || expanded.length === 0) {
625
+ send(createRealtimeVoiceToolResultEvent(result));
626
+ send({ type: "response.create" });
627
+ drain();
628
+ return;
629
+ }
630
+ const merged = mergeRealtimeVoiceToolManifest(currentTools, expanded);
631
+ const mergedNames = new Set(merged.map((tool) => tool.name));
632
+ const expectedNames = expanded
633
+ .map((tool) => tool.name)
634
+ .filter((name) => mergedNames.has(name));
635
+ if (expectedNames.length === 0) {
636
+ send(createRealtimeVoiceToolResultEvent(result));
637
+ send({ type: "response.create" });
638
+ drain();
639
+ return;
640
+ }
641
+ const eventId = `realtime_tool_manifest_${++updateSequence}`;
642
+ active = {
643
+ result,
644
+ expectedNames,
645
+ eventId,
646
+ timer: setTimeout(() => finish("Timed out while installing the discovered tools."), timeoutMs),
647
+ };
648
+ send(createRealtimeVoiceToolManifestUpdate(merged, eventId));
649
+ };
650
+ return {
651
+ enqueue(result) {
652
+ queue.push(result);
653
+ drain();
654
+ },
655
+ setSessionTools(tools) {
656
+ currentTools = mergeRealtimeVoiceToolManifest([], tools);
657
+ if (!active)
658
+ return;
659
+ const names = new Set(currentTools.map((tool) => tool.name));
660
+ if (active.expectedNames.every((name) => names.has(name)))
661
+ finish();
662
+ },
663
+ handleError(eventId, message) {
664
+ if (!active || !eventId || active.eventId !== eventId)
665
+ return false;
666
+ finish(message || "The provider rejected the discovered tool update.");
667
+ return true;
668
+ },
669
+ reset() {
670
+ if (active)
671
+ clearTimeout(active.timer);
672
+ active = undefined;
673
+ queue.length = 0;
674
+ currentTools = [];
675
+ },
676
+ getTools() {
677
+ return currentTools;
678
+ },
679
+ };
680
+ }
101
681
  export function extractRealtimeVoiceFunctionCalls(event) {
102
682
  if (event.type === "response.function_call_arguments.done") {
103
683
  const name = typeof event.name === "string" ? event.name : "";
@@ -160,6 +740,10 @@ function openOpenAiKeySettings() {
160
740
  detail: { section: "secrets" },
161
741
  }));
162
742
  }
743
+ export function listenForRealtimeVoicePageHide(cleanup) {
744
+ window.addEventListener("pagehide", cleanup);
745
+ return () => window.removeEventListener("pagehide", cleanup);
746
+ }
163
747
  function voiceCopy(t) {
164
748
  return {
165
749
  entryButtonLabel: t("agentPanel.voiceMode.entryButtonLabel"),
@@ -175,6 +759,45 @@ function voiceCopy(t) {
175
759
  showChat: t("agentPanel.voiceMode.showChat"),
176
760
  hideChat: t("agentPanel.voiceMode.hideChat"),
177
761
  endVoiceMode: t("agentPanel.voiceMode.end"),
762
+ voiceSettings: t("agentPanel.voiceMode.voiceSettings"),
763
+ settings: {
764
+ language: t("agentPanel.voiceMode.settings.language"),
765
+ autoLanguage: t("agentPanel.voiceMode.settings.autoLanguage"),
766
+ languages: {
767
+ en: t("agentPanel.voiceMode.settings.languages.en"),
768
+ es: t("agentPanel.voiceMode.settings.languages.es"),
769
+ fr: t("agentPanel.voiceMode.settings.languages.fr"),
770
+ de: t("agentPanel.voiceMode.settings.languages.de"),
771
+ it: t("agentPanel.voiceMode.settings.languages.it"),
772
+ pt: t("agentPanel.voiceMode.settings.languages.pt"),
773
+ ja: t("agentPanel.voiceMode.settings.languages.ja"),
774
+ ko: t("agentPanel.voiceMode.settings.languages.ko"),
775
+ zh: t("agentPanel.voiceMode.settings.languages.zh"),
776
+ },
777
+ intelligence: t("agentPanel.voiceMode.settings.intelligence"),
778
+ intelligenceLevels: {
779
+ instant: t("agentPanel.voiceMode.settings.intelligenceLevels.instant"),
780
+ balanced: t("agentPanel.voiceMode.settings.intelligenceLevels.balanced"),
781
+ deep: t("agentPanel.voiceMode.settings.intelligenceLevels.deep"),
782
+ },
783
+ voiceStyle: t("agentPanel.voiceMode.settings.voiceStyle"),
784
+ microphone: t("agentPanel.voiceMode.settings.microphone"),
785
+ defaultMicrophone: t("agentPanel.voiceMode.settings.defaultMicrophone"),
786
+ microphoneSwitchFailed: t("agentPanel.voiceMode.settings.microphoneSwitchFailed"),
787
+ voiceChangePending: t("agentPanel.voiceMode.settings.voiceChangePending"),
788
+ voiceDescriptions: {
789
+ marin: t("agentPanel.voiceMode.settings.voiceDescriptions.marin"),
790
+ cedar: t("agentPanel.voiceMode.settings.voiceDescriptions.cedar"),
791
+ coral: t("agentPanel.voiceMode.settings.voiceDescriptions.coral"),
792
+ sage: t("agentPanel.voiceMode.settings.voiceDescriptions.sage"),
793
+ verse: t("agentPanel.voiceMode.settings.voiceDescriptions.verse"),
794
+ alloy: t("agentPanel.voiceMode.settings.voiceDescriptions.alloy"),
795
+ ash: t("agentPanel.voiceMode.settings.voiceDescriptions.ash"),
796
+ ballad: t("agentPanel.voiceMode.settings.voiceDescriptions.ballad"),
797
+ echo: t("agentPanel.voiceMode.settings.voiceDescriptions.echo"),
798
+ shimmer: t("agentPanel.voiceMode.settings.voiceDescriptions.shimmer"),
799
+ },
800
+ },
178
801
  status: {
179
802
  connecting: t("agentPanel.voiceMode.status.connecting"),
180
803
  listening: t("agentPanel.voiceMode.status.listening"),
@@ -188,6 +811,7 @@ function voiceCopy(t) {
188
811
  responseFailed: t("agentPanel.voiceMode.errors.responseFailed"),
189
812
  sessionFailed: t("agentPanel.voiceMode.errors.sessionFailed"),
190
813
  channelDisconnected: t("agentPanel.voiceMode.errors.channelDisconnected"),
814
+ connectionTimedOut: t("agentPanel.voiceMode.errors.connectionTimedOut"),
191
815
  connectionFailed: t("agentPanel.voiceMode.errors.connectionFailed"),
192
816
  offerFailed: t("agentPanel.voiceMode.errors.offerFailed"),
193
817
  },
@@ -201,8 +825,16 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
201
825
  const [state, setState] = useState("idle");
202
826
  const [error, setError] = useState(null);
203
827
  const [chatVisible, setChatVisible] = useState(false);
828
+ const [preferences, setPreferences] = useState(DEFAULT_REALTIME_VOICE_PREFERENCES);
829
+ const [voiceChangePending, setVoiceChangePending] = useState(false);
830
+ const [microphones, setMicrophones] = useState([]);
831
+ const [microphoneDeviceId, setMicrophoneDeviceId] = useState(readRealtimeVoiceMicrophoneId);
832
+ const [microphoneSwitching, setMicrophoneSwitching] = useState(false);
833
+ const [microphoneError, setMicrophoneError] = useState(null);
204
834
  const [audioLevels] = useState(createRealtimeVoiceAudioLevelStore);
205
835
  const stateRef = useRef(state);
836
+ const preferencesRef = useRef(preferences);
837
+ const hasOutputAudioRef = useRef(false);
206
838
  const peerRef = useRef(null);
207
839
  const channelRef = useRef(null);
208
840
  const streamRef = useRef(null);
@@ -217,16 +849,47 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
217
849
  const meterFrameRef = useRef(null);
218
850
  const lastMeterSampleRef = useRef(0);
219
851
  const abortRef = useRef(null);
852
+ const connectionGateRef = useRef(null);
220
853
  const handledCallsRef = useRef(new Set());
221
854
  const sessionIdRef = useRef(undefined);
855
+ const capabilityRef = useRef(undefined);
856
+ const transportGenerationRef = useRef(0);
222
857
  const startedAtRef = useRef(undefined);
223
858
  const lastUserTextRef = useRef("");
224
859
  const lastAssistantTextRef = useRef("");
225
860
  const transcriptThreadIdRef = useRef(undefined);
226
861
  const transcriptSequenceRef = useRef(0);
862
+ const preferencesHydratedRef = useRef(false);
863
+ const preferencesEditedRef = useRef(false);
864
+ const preferenceWriteChainRef = useRef(Promise.resolve());
865
+ const toolManifestCoordinator = useMemo(() => createRealtimeVoiceToolManifestCoordinator((event) => {
866
+ sendDataChannelEvent(channelRef.current, event);
867
+ }), []);
868
+ const switchMicrophoneRef = useRef(async () => undefined);
227
869
  useEffect(() => {
228
870
  stateRef.current = state;
229
871
  }, [state]);
872
+ useEffect(() => {
873
+ preferencesRef.current = preferences;
874
+ }, [preferences]);
875
+ const hydratePreferences = useCallback(async () => {
876
+ if (preferencesHydratedRef.current)
877
+ return;
878
+ try {
879
+ const stored = await readClientAppState(REALTIME_VOICE_PREFERENCES_KEY);
880
+ if (!preferencesEditedRef.current && stored != null) {
881
+ const next = normalizeRealtimeVoicePreferences(stored);
882
+ preferencesRef.current = next;
883
+ setPreferences(next);
884
+ }
885
+ }
886
+ catch {
887
+ // Preferences are optional; keep safe defaults when storage is unavailable.
888
+ }
889
+ finally {
890
+ preferencesHydratedRef.current = true;
891
+ }
892
+ }, []);
230
893
  const syncAppState = useCallback((nextState) => {
231
894
  const value = nextState === "idle"
232
895
  ? null
@@ -237,6 +900,7 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
237
900
  startedAt: startedAtRef.current,
238
901
  sessionId: sessionIdRef.current,
239
902
  browserTabId,
903
+ preferences: preferencesRef.current,
240
904
  lastUserText: lastUserTextRef.current || undefined,
241
905
  lastAssistantText: lastAssistantTextRef.current || undefined,
242
906
  };
@@ -249,6 +913,70 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
249
913
  setState(nextState);
250
914
  syncAppState(nextState);
251
915
  }, [syncAppState]);
916
+ const savePreferences = useCallback((next) => {
917
+ preferencesEditedRef.current = true;
918
+ preferencesHydratedRef.current = true;
919
+ preferencesRef.current = next;
920
+ setPreferences(next);
921
+ preferenceWriteChainRef.current = preferenceWriteChainRef.current
922
+ .catch(() => undefined)
923
+ .then(async () => {
924
+ await setClientAppState(REALTIME_VOICE_PREFERENCES_KEY, next, {
925
+ requestSource: REALTIME_VOICE_REQUEST_SOURCE,
926
+ });
927
+ })
928
+ .catch(() => undefined);
929
+ }, []);
930
+ const updateLivePreferences = useCallback((next, includeVoice = false) => {
931
+ sendDataChannelEvent(channelRef.current, createRealtimeVoicePreferenceUpdate(next, {
932
+ browserLanguages: typeof navigator === "undefined" ? [] : navigator.languages,
933
+ includeVoice,
934
+ }));
935
+ }, []);
936
+ const setLanguage = useCallback((language) => {
937
+ const next = { ...preferencesRef.current, language };
938
+ savePreferences(next);
939
+ updateLivePreferences(next);
940
+ }, [savePreferences, updateLivePreferences]);
941
+ const setIntelligence = useCallback((intelligence) => {
942
+ const next = { ...preferencesRef.current, intelligence };
943
+ savePreferences(next);
944
+ updateLivePreferences(next);
945
+ }, [savePreferences, updateLivePreferences]);
946
+ const setVoice = useCallback((voice) => {
947
+ const next = { ...preferencesRef.current, voice };
948
+ savePreferences(next);
949
+ if (hasOutputAudioRef.current) {
950
+ setVoiceChangePending(true);
951
+ updateLivePreferences(next);
952
+ return;
953
+ }
954
+ setVoiceChangePending(false);
955
+ updateLivePreferences(next, true);
956
+ }, [savePreferences, updateLivePreferences]);
957
+ const refreshMicrophones = useCallback(async () => {
958
+ const mediaDevices = navigator.mediaDevices;
959
+ if (!mediaDevices?.enumerateDevices)
960
+ return null;
961
+ try {
962
+ const devices = await mediaDevices.enumerateDevices();
963
+ const inputs = devices
964
+ .filter((device) => device.kind === "audioinput" &&
965
+ device.deviceId &&
966
+ device.deviceId !== "default" &&
967
+ device.deviceId !== "communications")
968
+ .map((device, index) => ({
969
+ deviceId: device.deviceId,
970
+ label: device.label || `Microphone ${index + 1}`,
971
+ }));
972
+ setMicrophones(inputs);
973
+ return inputs;
974
+ }
975
+ catch {
976
+ // Enumeration is progressive enhancement; system default remains usable.
977
+ return null;
978
+ }
979
+ }, []);
252
980
  const startMeterLoop = useCallback(() => {
253
981
  if (meterFrameRef.current !== null)
254
982
  return;
@@ -308,15 +1036,65 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
308
1036
  // Audio metering is visual-only; keep the realtime call healthy.
309
1037
  }
310
1038
  }, [startMeterLoop]);
1039
+ const setMicrophone = useCallback(async (deviceId, force = false) => {
1040
+ if ((!force && deviceId === microphoneDeviceId) || microphoneSwitching) {
1041
+ return;
1042
+ }
1043
+ const mediaDevices = navigator.mediaDevices;
1044
+ const peer = peerRef.current;
1045
+ if (!mediaDevices?.getUserMedia || !peer)
1046
+ return;
1047
+ setMicrophoneSwitching(true);
1048
+ setMicrophoneError(null);
1049
+ try {
1050
+ const replacementStream = await replaceRealtimeVoiceMicrophone({
1051
+ mediaDevices,
1052
+ peer,
1053
+ currentStream: streamRef.current,
1054
+ deviceId,
1055
+ });
1056
+ const replacementTrack = replacementStream.getAudioTracks()[0];
1057
+ streamRef.current = replacementStream;
1058
+ if (replacementTrack) {
1059
+ replacementTrack.onended = () => {
1060
+ void switchMicrophoneRef.current("default", true);
1061
+ };
1062
+ }
1063
+ attachAudioMeter(streamRef.current, "input");
1064
+ writeRealtimeVoiceMicrophoneId(deviceId);
1065
+ setMicrophoneDeviceId(deviceId);
1066
+ await refreshMicrophones();
1067
+ }
1068
+ catch {
1069
+ setMicrophoneError(copy?.settings.microphoneSwitchFailed ??
1070
+ "Could not switch microphones. Your current microphone is still active.");
1071
+ }
1072
+ finally {
1073
+ setMicrophoneSwitching(false);
1074
+ }
1075
+ }, [
1076
+ attachAudioMeter,
1077
+ copy,
1078
+ microphoneDeviceId,
1079
+ microphoneSwitching,
1080
+ refreshMicrophones,
1081
+ ]);
1082
+ switchMicrophoneRef.current = setMicrophone;
311
1083
  const cleanupTransport = useCallback(() => {
1084
+ connectionGateRef.current?.cancel();
1085
+ connectionGateRef.current = null;
1086
+ transportGenerationRef.current += 1;
1087
+ capabilityRef.current = undefined;
312
1088
  abortRef.current?.abort();
313
1089
  abortRef.current = null;
314
1090
  channelRef.current?.close();
315
1091
  channelRef.current = null;
316
1092
  peerRef.current?.close();
317
1093
  peerRef.current = null;
318
- for (const track of streamRef.current?.getTracks() ?? [])
1094
+ for (const track of streamRef.current?.getTracks() ?? []) {
1095
+ track.onended = null;
319
1096
  track.stop();
1097
+ }
320
1098
  streamRef.current = null;
321
1099
  if (audioRef.current) {
322
1100
  audioRef.current.pause();
@@ -342,7 +1120,8 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
342
1120
  void audioContext.close().catch(() => undefined);
343
1121
  audioLevels.reset();
344
1122
  handledCallsRef.current.clear();
345
- }, [audioLevels]);
1123
+ toolManifestCoordinator.reset();
1124
+ }, [audioLevels, toolManifestCoordinator]);
346
1125
  const fail = useCallback((message, options) => {
347
1126
  cleanupTransport();
348
1127
  setError(message);
@@ -354,6 +1133,8 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
354
1133
  if (handledCallsRef.current.has(call.callId))
355
1134
  return;
356
1135
  handledCallsRef.current.add(call.callId);
1136
+ const transportGeneration = transportGenerationRef.current;
1137
+ const transportChannel = channelRef.current;
357
1138
  transition("working");
358
1139
  let result;
359
1140
  try {
@@ -364,6 +1145,7 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
364
1145
  callId: call.callId,
365
1146
  sessionId: sessionIdRef.current,
366
1147
  browserTabId,
1148
+ capability: capabilityRef.current,
367
1149
  signal: abortRef.current?.signal,
368
1150
  });
369
1151
  }
@@ -374,20 +1156,15 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
374
1156
  output: errorMessage(toolError),
375
1157
  };
376
1158
  }
377
- sendDataChannelEvent(channelRef.current, {
378
- type: "conversation.item.create",
379
- item: {
380
- type: "function_call_output",
381
- call_id: call.callId,
382
- output: JSON.stringify(result),
383
- },
384
- });
385
- sendDataChannelEvent(channelRef.current, { type: "response.create" });
386
- }, [browserTabId, transition]);
387
- const persistCompletedTranscript = useCallback((event) => {
388
- const transcript = extractCompletedRealtimeVoiceTranscript(event);
1159
+ if (transportGeneration !== transportGenerationRef.current ||
1160
+ channelRef.current !== transportChannel) {
1161
+ return;
1162
+ }
1163
+ toolManifestCoordinator.enqueue(result);
1164
+ }, [browserTabId, toolManifestCoordinator, transition]);
1165
+ const publishCompletedTranscript = useCallback((transcript) => {
389
1166
  const threadId = transcriptThreadIdRef.current;
390
- if (!transcript || !threadId)
1167
+ if (!threadId)
391
1168
  return;
392
1169
  const sessionIdentity = sessionIdRef.current ?? startedAtRef.current ?? "pending";
393
1170
  const providerIdentity = transcript.providerId ?? `sequence-${++transcriptSequenceRef.current}`;
@@ -399,15 +1176,27 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
399
1176
  createdAt: new Date().toISOString(),
400
1177
  });
401
1178
  }, []);
1179
+ const transcriptSequencer = useMemo(() => createRealtimeVoiceTranscriptSequencer(publishCompletedTranscript), [publishCompletedTranscript]);
1180
+ const greetingStarter = useMemo(() => createRealtimeVoiceGreetingStarter((event) => {
1181
+ sendDataChannelEvent(channelRef.current, event);
1182
+ }), []);
402
1183
  const handleServerEvent = useCallback((event) => {
1184
+ transcriptSequencer.handle(event);
1185
+ const sessionTools = extractRealtimeVoiceSessionTools(event);
1186
+ if (sessionTools)
1187
+ toolManifestCoordinator.setSessionTools(sessionTools);
403
1188
  if (event.type === "session.created") {
1189
+ connectionGateRef.current?.markSessionCreated();
1190
+ connectionGateRef.current = null;
404
1191
  const session = event.session;
405
1192
  if (session && typeof session === "object") {
406
1193
  const id = session.id;
407
1194
  if (typeof id === "string")
408
1195
  sessionIdRef.current = id;
409
1196
  }
410
- transition("listening");
1197
+ updateLivePreferences(preferencesRef.current, true);
1198
+ greetingStarter.start();
1199
+ transition("working");
411
1200
  }
412
1201
  else if (event.type === "input_audio_buffer.speech_started") {
413
1202
  transition("listening");
@@ -416,10 +1205,14 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
416
1205
  transition("working");
417
1206
  }
418
1207
  else if (event.type === "response.created") {
1208
+ // From this point onward the response is committed to audio output, so
1209
+ // changing voices risks violating Realtime's per-session voice lock.
1210
+ hasOutputAudioRef.current = true;
419
1211
  lastAssistantTextRef.current = "";
420
1212
  transition("working");
421
1213
  }
422
1214
  else if (event.type === "response.output_audio_transcript.delta") {
1215
+ hasOutputAudioRef.current = true;
423
1216
  if (typeof event.delta === "string") {
424
1217
  lastAssistantTextRef.current += event.delta;
425
1218
  }
@@ -429,14 +1222,12 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
429
1222
  if (typeof event.transcript === "string") {
430
1223
  lastAssistantTextRef.current = event.transcript;
431
1224
  }
432
- persistCompletedTranscript(event);
433
1225
  syncAppState("speaking");
434
1226
  }
435
1227
  else if (event.type === "conversation.item.input_audio_transcription.completed") {
436
1228
  if (typeof event.transcript === "string") {
437
1229
  lastUserTextRef.current = event.transcript;
438
1230
  }
439
- persistCompletedTranscript(event);
440
1231
  syncAppState("working");
441
1232
  }
442
1233
  else if (event.type === "response.done") {
@@ -457,6 +1248,12 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
457
1248
  : typeof detail === "string"
458
1249
  ? detail
459
1250
  : "";
1251
+ const expansionEventId = detail && typeof detail === "object"
1252
+ ? (detail.event_id ?? event.event_id)
1253
+ : event.event_id;
1254
+ if (toolManifestCoordinator.handleError(typeof expansionEventId === "string" ? expansionEventId : undefined, message)) {
1255
+ return;
1256
+ }
460
1257
  fail(message ||
461
1258
  copy?.errors.sessionFailed ||
462
1259
  "The realtime voice session encountered an error.");
@@ -471,10 +1268,13 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
471
1268
  }, [
472
1269
  copy,
473
1270
  fail,
1271
+ greetingStarter,
474
1272
  handleFunctionCall,
475
- persistCompletedTranscript,
476
1273
  syncAppState,
1274
+ transcriptSequencer,
477
1275
  transition,
1276
+ toolManifestCoordinator,
1277
+ updateLivePreferences,
478
1278
  ]);
479
1279
  const start = useCallback(async () => {
480
1280
  if (stateRef.current !== "idle")
@@ -490,24 +1290,56 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
490
1290
  lastUserTextRef.current = "";
491
1291
  lastAssistantTextRef.current = "";
492
1292
  sessionIdRef.current = undefined;
1293
+ hasOutputAudioRef.current = false;
1294
+ greetingStarter.reset();
1295
+ setVoiceChangePending(false);
493
1296
  transcriptThreadIdRef.current =
494
1297
  realtimeVoiceTranscriptRegistry.activeThreadId();
495
1298
  transcriptSequenceRef.current = 0;
1299
+ transcriptSequencer.reset();
496
1300
  transition("connecting");
497
1301
  setChatVisible(false);
498
1302
  window.dispatchEvent(new Event("agent-panel:close"));
1303
+ await hydratePreferences();
1304
+ if (stateRef.current !== "connecting")
1305
+ return;
499
1306
  const abortController = new AbortController();
500
1307
  abortRef.current = abortController;
1308
+ const isCurrentAttempt = () => abortRef.current === abortController && !abortController.signal.aborted;
1309
+ const connectionGate = createRealtimeVoiceConnectionGate(() => {
1310
+ if (!isCurrentAttempt())
1311
+ return;
1312
+ fail(copy?.errors.connectionTimedOut ??
1313
+ "The realtime voice connection timed out.");
1314
+ });
1315
+ connectionGateRef.current = connectionGate;
501
1316
  try {
502
1317
  const stream = await navigator.mediaDevices.getUserMedia({
503
- audio: {
504
- echoCancellation: true,
505
- noiseSuppression: true,
506
- autoGainControl: true,
507
- },
1318
+ audio: createRealtimeVoiceAudioConstraints(readRealtimeVoiceMicrophoneId()),
508
1319
  });
1320
+ if (!isCurrentAttempt()) {
1321
+ for (const track of stream.getTracks())
1322
+ track.stop();
1323
+ return;
1324
+ }
509
1325
  streamRef.current = stream;
1326
+ for (const track of stream.getAudioTracks()) {
1327
+ track.onended = () => {
1328
+ void switchMicrophoneRef.current("default", true);
1329
+ };
1330
+ }
510
1331
  attachAudioMeter(stream, "input");
1332
+ void refreshMicrophones().then((inputs) => {
1333
+ const selected = readRealtimeVoiceMicrophoneId();
1334
+ if (inputs &&
1335
+ selected !== "default" &&
1336
+ !inputs.some((device) => device.deviceId === selected)) {
1337
+ // The persisted device was only an ideal preference, so getUserMedia
1338
+ // already selected a usable fallback for this new session.
1339
+ writeRealtimeVoiceMicrophoneId("default");
1340
+ setMicrophoneDeviceId("default");
1341
+ }
1342
+ });
511
1343
  const peer = new RTCPeerConnection();
512
1344
  peerRef.current = peer;
513
1345
  for (const track of stream.getAudioTracks())
@@ -525,8 +1357,10 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
525
1357
  };
526
1358
  const channel = peer.createDataChannel("oai-events");
527
1359
  channelRef.current = channel;
528
- channel.onopen = () => transition("listening");
1360
+ channel.onopen = connectionGate.markTransportReady;
529
1361
  channel.onmessage = (messageEvent) => {
1362
+ if (!isCurrentAttempt())
1363
+ return;
530
1364
  try {
531
1365
  handleServerEvent(JSON.parse(String(messageEvent.data)));
532
1366
  }
@@ -534,38 +1368,83 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
534
1368
  // Ignore malformed provider events without ending a healthy call.
535
1369
  }
536
1370
  };
537
- channel.onerror = () => fail(copy?.errors.channelDisconnected ??
538
- "The realtime voice control channel disconnected.");
1371
+ channel.onerror = () => {
1372
+ if (!isCurrentAttempt())
1373
+ return;
1374
+ fail(copy?.errors.channelDisconnected ??
1375
+ "The realtime voice control channel disconnected.");
1376
+ };
539
1377
  peer.onconnectionstatechange = () => {
540
- if (peer.connectionState === "connected")
541
- transition("listening");
1378
+ if (!isCurrentAttempt())
1379
+ return;
1380
+ if (peer.connectionState === "connected") {
1381
+ connectionGate.markTransportReady();
1382
+ }
542
1383
  if (peer.connectionState === "failed") {
543
1384
  fail(copy?.errors.connectionFailed ??
544
1385
  "The realtime voice connection failed.");
545
1386
  }
546
1387
  };
547
1388
  const offer = await peer.createOffer();
1389
+ if (!isCurrentAttempt())
1390
+ return;
548
1391
  await peer.setLocalDescription(offer);
1392
+ if (!isCurrentAttempt())
1393
+ return;
549
1394
  if (!offer.sdp) {
550
1395
  throw new Error(copy?.errors.offerFailed ??
551
1396
  "The browser did not create an audio offer.");
552
1397
  }
553
- const answerSdp = await createRealtimeVoiceSession(offer.sdp, {
1398
+ const answer = await createRealtimeVoiceSessionWithCapability(offer.sdp, {
554
1399
  browserTabId,
555
1400
  signal: abortController.signal,
1401
+ preferences: preferencesRef.current,
1402
+ browserLanguages: navigator.languages,
556
1403
  });
557
- await peer.setRemoteDescription({ type: "answer", sdp: answerSdp });
1404
+ if (!isCurrentAttempt())
1405
+ return;
1406
+ capabilityRef.current = answer.capability;
1407
+ await peer.setRemoteDescription({ type: "answer", sdp: answer.sdp });
558
1408
  }
559
1409
  catch (startError) {
1410
+ // Ending a connection aborts the SDP request by design. A superseded
1411
+ // attempt must never resurrect the dock or surface that cancellation as
1412
+ // an error after cleanup.
1413
+ if (isRealtimeVoiceAbortError(startError) ||
1414
+ abortController.signal.aborted ||
1415
+ abortRef.current !== abortController) {
1416
+ return;
1417
+ }
1418
+ if (isRealtimeVoiceSetupRequiredError(startError)) {
1419
+ // Credentials can disappear after the entry-point status check. Treat
1420
+ // the authoritative setup response as a gate, not as an active voice
1421
+ // session failure: clean up the mic/RTC attempt, reopen chat, and
1422
+ // refresh both the chat and voice provider setup surfaces.
1423
+ cleanupTransport();
1424
+ setError(null);
1425
+ startedAtRef.current = undefined;
1426
+ sessionIdRef.current = undefined;
1427
+ transcriptThreadIdRef.current = undefined;
1428
+ transition("idle");
1429
+ setChatVisible(true);
1430
+ window.dispatchEvent(new Event("agent-panel:open"));
1431
+ window.dispatchEvent(new Event("agent-engine:configured-changed"));
1432
+ return;
1433
+ }
560
1434
  const status = startError?.status;
561
1435
  fail(errorMessage(startError), { openKeySettings: status === 400 });
562
1436
  }
563
1437
  }, [
564
1438
  attachAudioMeter,
565
1439
  browserTabId,
1440
+ cleanupTransport,
566
1441
  copy,
567
1442
  fail,
1443
+ greetingStarter,
568
1444
  handleServerEvent,
1445
+ hydratePreferences,
1446
+ refreshMicrophones,
1447
+ transcriptSequencer,
569
1448
  transition,
570
1449
  ]);
571
1450
  const end = useCallback(() => {
@@ -598,6 +1477,23 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
598
1477
  setChatVisible((current) => !current);
599
1478
  window.dispatchEvent(new Event("agent-panel:toggle"));
600
1479
  }, []);
1480
+ useEffect(() => {
1481
+ const mediaDevices = navigator.mediaDevices;
1482
+ if (!mediaDevices?.addEventListener)
1483
+ return;
1484
+ const handleDeviceChange = () => {
1485
+ const selected = readRealtimeVoiceMicrophoneId();
1486
+ void refreshMicrophones().then((inputs) => {
1487
+ if (inputs &&
1488
+ selected !== "default" &&
1489
+ !inputs.some((device) => device.deviceId === selected)) {
1490
+ void setMicrophone("default");
1491
+ }
1492
+ });
1493
+ };
1494
+ mediaDevices.addEventListener("devicechange", handleDeviceChange);
1495
+ return () => mediaDevices.removeEventListener("devicechange", handleDeviceChange);
1496
+ }, [refreshMicrophones, setMicrophone]);
601
1497
  useEffect(() => {
602
1498
  const onSidebarState = (event) => {
603
1499
  const detail = event
@@ -609,13 +1505,29 @@ function useRealtimeVoiceModeController(browserTabId, copy) {
609
1505
  window.addEventListener(SIDEBAR_STATE_CHANGE_EVENT, onSidebarState);
610
1506
  return () => window.removeEventListener(SIDEBAR_STATE_CHANGE_EVENT, onSidebarState);
611
1507
  }, []);
612
- useEffect(() => cleanupTransport, [cleanupTransport]);
1508
+ useEffect(() => {
1509
+ const stopListening = listenForRealtimeVoicePageHide(cleanupTransport);
1510
+ return () => {
1511
+ stopListening();
1512
+ cleanupTransport();
1513
+ };
1514
+ }, [cleanupTransport]);
613
1515
  return {
614
1516
  state,
615
1517
  active: state !== "idle",
616
1518
  errorMessage: error,
617
1519
  chatVisible,
618
1520
  audioLevels,
1521
+ preferences,
1522
+ microphones,
1523
+ microphoneDeviceId,
1524
+ microphoneSwitching,
1525
+ microphoneError,
1526
+ voiceChangePending,
1527
+ setLanguage,
1528
+ setIntelligence,
1529
+ setVoice,
1530
+ setMicrophone,
619
1531
  start,
620
1532
  end,
621
1533
  toggleChat,
@@ -626,8 +1538,76 @@ export function RealtimeVoiceModeProvider({ children, browserTabId, }) {
626
1538
  const resolvedBrowserTabId = useMemo(() => browserTabId ?? getBrowserTabId(), [browserTabId]);
627
1539
  const copy = useRealtimeVoiceModeCopy();
628
1540
  const voice = useRealtimeVoiceModeController(resolvedBrowserTabId, copy);
1541
+ const inlineSettings = useMemo(() => ({
1542
+ dialogLabel: copy.voiceSettings,
1543
+ ...(voice.voiceChangePending
1544
+ ? { appliesNextConversationNote: copy.settings.voiceChangePending }
1545
+ : {}),
1546
+ ...(voice.microphoneError
1547
+ ? { microphoneError: voice.microphoneError }
1548
+ : {}),
1549
+ microphone: {
1550
+ label: copy.settings.microphone,
1551
+ value: voice.microphoneDeviceId,
1552
+ disabled: voice.microphoneSwitching,
1553
+ options: [
1554
+ {
1555
+ value: "default",
1556
+ label: copy.settings.defaultMicrophone,
1557
+ },
1558
+ ...voice.microphones.map((microphone) => ({
1559
+ value: microphone.deviceId,
1560
+ label: microphone.label,
1561
+ })),
1562
+ ],
1563
+ onValueChange: (value) => {
1564
+ void voice.setMicrophone(value);
1565
+ },
1566
+ },
1567
+ language: {
1568
+ label: copy.settings.language,
1569
+ value: voice.preferences.language,
1570
+ options: REALTIME_VOICE_LANGUAGES.map((language) => ({
1571
+ value: language,
1572
+ label: language === "auto"
1573
+ ? copy.settings.autoLanguage
1574
+ : copy.settings.languages[language],
1575
+ })),
1576
+ onValueChange: (value) => {
1577
+ if (isOneOf(REALTIME_VOICE_LANGUAGES, value)) {
1578
+ voice.setLanguage(value);
1579
+ }
1580
+ },
1581
+ },
1582
+ intelligence: {
1583
+ label: copy.settings.intelligence,
1584
+ value: voice.preferences.intelligence,
1585
+ options: REALTIME_VOICE_INTELLIGENCE_LEVELS.map((intelligence) => ({
1586
+ value: intelligence,
1587
+ label: copy.settings.intelligenceLevels[intelligence],
1588
+ })),
1589
+ onValueChange: (value) => {
1590
+ if (isOneOf(REALTIME_VOICE_INTELLIGENCE_LEVELS, value)) {
1591
+ voice.setIntelligence(value);
1592
+ }
1593
+ },
1594
+ },
1595
+ voiceStyle: {
1596
+ label: copy.settings.voiceStyle,
1597
+ value: voice.preferences.voice,
1598
+ options: REALTIME_VOICES.map((voiceName) => ({
1599
+ value: voiceName,
1600
+ label: `${voiceName[0].toUpperCase()}${voiceName.slice(1)}`,
1601
+ description: copy.settings.voiceDescriptions[voiceName],
1602
+ })),
1603
+ onValueChange: (value) => {
1604
+ if (isOneOf(REALTIME_VOICES, value))
1605
+ voice.setVoice(value);
1606
+ },
1607
+ },
1608
+ }), [copy, voice]);
629
1609
  return (_jsxs(RealtimeVoiceModeContext.Provider, { value: voice, children: [children, voice.active && typeof document !== "undefined"
630
- ? createPortal(_jsx(RealtimeVoiceModeDock, { state: voice.state === "idle" ? "ending" : voice.state, copy: copy, chatVisible: voice.chatVisible, audioLevels: voice.audioLevels, onToggleChat: voice.toggleChat, onEndVoiceMode: voice.end, errorMessage: voice.errorMessage }), document.body)
1610
+ ? createPortal(_jsx(RealtimeVoiceModeDock, { state: voice.state === "idle" ? "ending" : voice.state, copy: copy, chatVisible: voice.chatVisible, audioLevels: voice.audioLevels, onToggleChat: voice.toggleChat, onEndVoiceMode: voice.end, settings: inlineSettings, errorMessage: voice.errorMessage }), document.body)
631
1611
  : null] }));
632
1612
  }
633
1613
  /**