@opengeni/react 0.57.0 → 1.0.2-canary.37191796234001

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 (629) hide show
  1. package/README.md +654 -22
  2. package/dist/accounts.d.ts +64 -0
  3. package/dist/accounts.js +822 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/approvals.d.ts +2 -1
  6. package/dist/artifacts-document.js +3 -2
  7. package/dist/artifacts-presentation.js +3 -2
  8. package/dist/artifacts-spreadsheet.js +2 -2
  9. package/dist/artifacts.d.ts +4 -1
  10. package/dist/artifacts.js +518 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-GTR5XQ7X.js +16 -0
  13. package/dist/capability-catalog-row.d.ts +20 -0
  14. package/dist/capability-logo-fallback.d.ts +3 -0
  15. package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
  16. package/dist/chat-interactive-block-UGBTNB3L.js.map +1 -0
  17. package/dist/{chunk-5UQPNLIO.js → chunk-23J2ZNXT.js} +4117 -3896
  18. package/dist/chunk-23J2ZNXT.js.map +1 -0
  19. package/dist/chunk-447JLCBU.js +209 -0
  20. package/dist/chunk-447JLCBU.js.map +1 -0
  21. package/dist/chunk-4RVYOY4O.js +379 -0
  22. package/dist/chunk-4RVYOY4O.js.map +1 -0
  23. package/dist/chunk-5CVXZA3Y.js +292 -0
  24. package/dist/chunk-5CVXZA3Y.js.map +1 -0
  25. package/dist/chunk-5J4FOW6Q.js +108 -0
  26. package/dist/chunk-5J4FOW6Q.js.map +1 -0
  27. package/dist/chunk-A2PI6UMY.js +41 -0
  28. package/dist/chunk-A2PI6UMY.js.map +1 -0
  29. package/dist/{chunk-7WCLAEFV.js → chunk-A4UJB2MM.js} +37 -27
  30. package/dist/chunk-A4UJB2MM.js.map +1 -0
  31. package/dist/chunk-B3V6TG77.js +41 -0
  32. package/dist/chunk-B3V6TG77.js.map +1 -0
  33. package/dist/chunk-BRM6FVZA.js +302 -0
  34. package/dist/chunk-BRM6FVZA.js.map +1 -0
  35. package/dist/chunk-C5X5AJXK.js +182 -0
  36. package/dist/chunk-C5X5AJXK.js.map +1 -0
  37. package/dist/chunk-CR7U7HAR.js +453 -0
  38. package/dist/chunk-CR7U7HAR.js.map +1 -0
  39. package/dist/{chunk-R3AZOAB5.js → chunk-DYWBUX5Q.js} +29 -123
  40. package/dist/chunk-DYWBUX5Q.js.map +1 -0
  41. package/dist/chunk-E3G7SAYZ.js +3124 -0
  42. package/dist/chunk-E3G7SAYZ.js.map +1 -0
  43. package/dist/chunk-ELCE5SXV.js +359 -0
  44. package/dist/chunk-ELCE5SXV.js.map +1 -0
  45. package/dist/chunk-ERGYJIBB.js +21 -0
  46. package/dist/chunk-ERGYJIBB.js.map +1 -0
  47. package/dist/chunk-FFA2OVOV.js +319 -0
  48. package/dist/chunk-FFA2OVOV.js.map +1 -0
  49. package/dist/chunk-FZCP527Y.js +116 -0
  50. package/dist/chunk-FZCP527Y.js.map +1 -0
  51. package/dist/chunk-GIMRELBW.js +14 -0
  52. package/dist/chunk-GIMRELBW.js.map +1 -0
  53. package/dist/{chunk-6KLX2RH5.js → chunk-H2NJQORO.js} +1069 -79
  54. package/dist/chunk-H2NJQORO.js.map +1 -0
  55. package/dist/chunk-I7IWRQLN.js +1608 -0
  56. package/dist/chunk-I7IWRQLN.js.map +1 -0
  57. package/dist/{chunk-HA46CYQK.js → chunk-IQUCRAT7.js} +792 -537
  58. package/dist/chunk-IQUCRAT7.js.map +1 -0
  59. package/dist/chunk-IWIDV7SB.js +1 -0
  60. package/dist/chunk-IWIDV7SB.js.map +1 -0
  61. package/dist/chunk-J2QWVSQY.js +312 -0
  62. package/dist/chunk-J2QWVSQY.js.map +1 -0
  63. package/dist/chunk-JFNEV4LU.js +2733 -0
  64. package/dist/chunk-JFNEV4LU.js.map +1 -0
  65. package/dist/chunk-JT4JW7BC.js +54 -0
  66. package/dist/chunk-JT4JW7BC.js.map +1 -0
  67. package/dist/chunk-K3HQAKQX.js +24 -0
  68. package/dist/chunk-K3HQAKQX.js.map +1 -0
  69. package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
  70. package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
  71. package/dist/chunk-NZUI76EM.js +371 -0
  72. package/dist/chunk-NZUI76EM.js.map +1 -0
  73. package/dist/{chunk-PEI6RANI.js → chunk-PNY3JKBJ.js} +309 -74
  74. package/dist/chunk-PNY3JKBJ.js.map +1 -0
  75. package/dist/{chunk-IGC6A2ZI.js → chunk-Q5QBEZIQ.js} +777 -246
  76. package/dist/chunk-Q5QBEZIQ.js.map +1 -0
  77. package/dist/chunk-RHREZ7BO.js +11 -0
  78. package/dist/chunk-RHREZ7BO.js.map +1 -0
  79. package/dist/chunk-SCOTPE2I.js +589 -0
  80. package/dist/chunk-SCOTPE2I.js.map +1 -0
  81. package/dist/{chunk-B6WPZSTT.js → chunk-SJZDKVW2.js} +1331 -1163
  82. package/dist/chunk-SJZDKVW2.js.map +1 -0
  83. package/dist/chunk-TMJRG4YC.js +12803 -0
  84. package/dist/chunk-TMJRG4YC.js.map +1 -0
  85. package/dist/chunk-TMYGL6X5.js +742 -0
  86. package/dist/chunk-TMYGL6X5.js.map +1 -0
  87. package/dist/chunk-UGLEYEMP.js +33 -0
  88. package/dist/chunk-UGLEYEMP.js.map +1 -0
  89. package/dist/chunk-UK4TINKT.js +27 -0
  90. package/dist/chunk-UK4TINKT.js.map +1 -0
  91. package/dist/chunk-UTRTG6LH.js +220 -0
  92. package/dist/chunk-UTRTG6LH.js.map +1 -0
  93. package/dist/chunk-WEHMPOXK.js +39 -0
  94. package/dist/chunk-WEHMPOXK.js.map +1 -0
  95. package/dist/chunk-WRHIZYZF.js +988 -0
  96. package/dist/chunk-WRHIZYZF.js.map +1 -0
  97. package/dist/{chunk-HUIKIDM5.js → chunk-WUISZ3WU.js} +223 -115
  98. package/dist/chunk-WUISZ3WU.js.map +1 -0
  99. package/dist/chunk-XCHWDJ22.js +107 -0
  100. package/dist/chunk-XCHWDJ22.js.map +1 -0
  101. package/dist/chunk-XOAMRDDK.js +481 -0
  102. package/dist/chunk-XOAMRDDK.js.map +1 -0
  103. package/dist/chunk-XUW2UWQM.js +299 -0
  104. package/dist/chunk-XUW2UWQM.js.map +1 -0
  105. package/dist/{chunk-KCGXPP5V.js → chunk-Y2PRMYLC.js} +11 -6
  106. package/dist/chunk-Y2PRMYLC.js.map +1 -0
  107. package/dist/chunk-YBXQDQFX.js +1772 -0
  108. package/dist/chunk-YBXQDQFX.js.map +1 -0
  109. package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
  110. package/dist/chunk-YQEAA6LT.js.map +1 -0
  111. package/dist/chunk-YV4L3ILF.js +9 -0
  112. package/dist/chunk-YV4L3ILF.js.map +1 -0
  113. package/dist/{chunk-LLOLUHVG.js → chunk-YWFG7ZX7.js} +1358 -2746
  114. package/dist/chunk-YWFG7ZX7.js.map +1 -0
  115. package/dist/chunk-ZYRGEKWS.js +216 -0
  116. package/dist/chunk-ZYRGEKWS.js.map +1 -0
  117. package/dist/client.d.ts +7 -4
  118. package/dist/clipboard.js +1 -0
  119. package/dist/commands/types.d.ts +2 -0
  120. package/dist/components/anthropic-mark.d.ts +3 -0
  121. package/dist/components/approval-surface.d.ts +15 -0
  122. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  123. package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
  124. package/dist/components/artifacts/artifact-surface.d.ts +3 -1
  125. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  126. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  127. package/dist/components/artifacts/document-editor.d.ts +4 -2
  128. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  129. package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
  130. package/dist/components/artifacts/editable-document.d.ts +1 -1
  131. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  132. package/dist/components/artifacts/editable-spreadsheet.d.ts +2 -1
  133. package/dist/components/artifacts/index.d.ts +8 -1
  134. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  135. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  136. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  137. package/dist/components/artifacts/published-html-artifact-frame.d.ts +48 -3
  138. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  139. package/dist/components/artifacts/site-view.d.ts +23 -0
  140. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  141. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  142. package/dist/components/browser-select-control.d.ts +16 -0
  143. package/dist/components/browser-viewer.d.ts +10 -1
  144. package/dist/components/chat-composer.d.ts +21 -3
  145. package/dist/components/child-session-link.d.ts +5 -0
  146. package/dist/components/claude-mark.d.ts +3 -0
  147. package/dist/components/code-editor.d.ts +1 -4
  148. package/dist/components/composer.d.ts +45 -4
  149. package/dist/components/computer-viewer.d.ts +4 -1
  150. package/dist/components/copy-button.d.ts +3 -1
  151. package/dist/components/desktop-viewer.d.ts +1 -1
  152. package/dist/components/enrollment-consent.d.ts +6 -3
  153. package/dist/components/file-browser.d.ts +10 -1
  154. package/dist/components/fleet-tile.d.ts +2 -2
  155. package/dist/components/grok-mark.d.ts +26 -0
  156. package/dist/components/human-input-form.d.ts +21 -2
  157. package/dist/components/human-input-surface.d.ts +6 -3
  158. package/dist/components/machine-card.d.ts +4 -1
  159. package/dist/components/machines/machine-detail.d.ts +4 -1
  160. package/dist/components/machines/machine-operation-policy.d.ts +11 -0
  161. package/dist/components/machines-dashboard.d.ts +3 -1
  162. package/dist/components/markdown-table-layout.d.ts +12 -0
  163. package/dist/components/markdown.d.ts +47 -3
  164. package/dist/components/message-timeline.d.ts +72 -9
  165. package/dist/components/model-mark.d.ts +29 -0
  166. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  167. package/dist/components/model-policy-picker.d.ts +62 -13
  168. package/dist/components/open-geni-chat.d.ts +55 -0
  169. package/dist/components/open-geni-links.d.ts +68 -0
  170. package/dist/components/openrouter-mark.d.ts +6 -0
  171. package/dist/components/pierre-file.d.ts +1 -1
  172. package/dist/components/preview-loading.d.ts +2 -0
  173. package/dist/components/queue-item-content.d.ts +9 -0
  174. package/dist/components/sandbox-files.d.ts +13 -2
  175. package/dist/components/sandbox-workspace.d.ts +43 -3
  176. package/dist/components/session-capability-frame.d.ts +35 -0
  177. package/dist/components/session-chrome.d.ts +66 -8
  178. package/dist/components/session-commands-panel.d.ts +6 -0
  179. package/dist/components/session-commands.d.ts +6 -0
  180. package/dist/components/session-connection-request.d.ts +8 -0
  181. package/dist/components/session-conversation.d.ts +86 -0
  182. package/dist/components/session-list.d.ts +36 -0
  183. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  184. package/dist/components/timeline-anchor.d.ts +24 -0
  185. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  186. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  187. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  188. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  189. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  190. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  191. package/dist/components/timeline-annotations.d.ts +13 -3
  192. package/dist/components/timeline-reading-progress.d.ts +11 -0
  193. package/dist/components/timeline-search.d.ts +34 -0
  194. package/dist/components/timeline-settlement.d.ts +16 -0
  195. package/dist/components/tip-follow.d.ts +16 -0
  196. package/dist/components/usage-limit-notice.d.ts +49 -0
  197. package/dist/components/usage-member-list.d.ts +91 -0
  198. package/dist/components/usage-meter.d.ts +73 -0
  199. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  200. package/dist/components/user-message-body.d.ts +10 -1
  201. package/dist/components/workspace-dock.d.ts +6 -2
  202. package/dist/composer.d.ts +5 -4
  203. package/dist/composer.js +15 -9
  204. package/dist/computer-viewer-ENHVAZ2Q.js +19 -0
  205. package/dist/computer-viewer-ENHVAZ2Q.js.map +1 -0
  206. package/dist/connect-account-identity.d.ts +8 -0
  207. package/dist/connect-accounts.d.ts +15 -0
  208. package/dist/connect-chooser.d.ts +18 -0
  209. package/dist/connect-panel.d.ts +18 -0
  210. package/dist/connect-setup.d.ts +16 -0
  211. package/dist/connect.d.ts +21 -0
  212. package/dist/connect.js +2129 -0
  213. package/dist/connect.js.map +1 -0
  214. package/dist/connection-catalog.d.ts +38 -0
  215. package/dist/connection-discovery.d.ts +12 -0
  216. package/dist/connection-installed.d.ts +17 -0
  217. package/dist/connection-logo.d.ts +9 -0
  218. package/dist/connection-service-logo.d.ts +8 -0
  219. package/dist/connection-service-presentation.d.ts +13 -0
  220. package/dist/connection-skeleton.d.ts +5 -0
  221. package/dist/connection-type-picker.d.ts +6 -0
  222. package/dist/conversation-timeline.d.ts +5 -0
  223. package/dist/desktop.d.ts +7 -0
  224. package/dist/desktop.js +26 -0
  225. package/dist/desktop.js.map +1 -0
  226. package/dist/device-authorization.d.ts +23 -0
  227. package/dist/diffs.d.ts +8 -0
  228. package/dist/diffs.js +14 -0
  229. package/dist/diffs.js.map +1 -0
  230. package/dist/discovery-cache.d.ts +5 -0
  231. package/dist/editor.d.ts +7 -0
  232. package/dist/editor.js +21 -0
  233. package/dist/editor.js.map +1 -0
  234. package/dist/embedded-session-client.d.ts +23 -0
  235. package/dist/file-node-visibility.d.ts +15 -0
  236. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-YZ3ZKWMM.js} +2 -1
  237. package/dist/fleet-decision-row-YZ3ZKWMM.js.map +1 -0
  238. package/dist/hooks/channel-cache.d.ts +23 -0
  239. package/dist/hooks/latest-question.d.ts +25 -0
  240. package/dist/hooks/shared-machines-list.d.ts +14 -0
  241. package/dist/hooks/use-attached-browsers.d.ts +2 -1
  242. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  243. package/dist/hooks/use-browser-session.d.ts +12 -1
  244. package/dist/hooks/use-channels.d.ts +1 -0
  245. package/dist/hooks/use-codex-accounts.d.ts +25 -7
  246. package/dist/hooks/use-composer.d.ts +45 -9
  247. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  248. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  249. package/dist/hooks/use-computer-session.d.ts +2 -0
  250. package/dist/hooks/use-connect.d.ts +22 -0
  251. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  252. package/dist/hooks/use-file-attachments.d.ts +21 -2
  253. package/dist/hooks/use-machine-chip.d.ts +3 -3
  254. package/dist/hooks/use-machines.d.ts +19 -1
  255. package/dist/hooks/use-sandbox-files.d.ts +5 -1
  256. package/dist/hooks/use-session-background-commands.d.ts +14 -0
  257. package/dist/hooks/use-session-events.d.ts +30 -8
  258. package/dist/hooks/use-session-lineage.d.ts +4 -0
  259. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  260. package/dist/hooks/use-session.d.ts +6 -0
  261. package/dist/hooks/use-turn-queue.d.ts +12 -0
  262. package/dist/hooks/use-usage.d.ts +40 -0
  263. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  264. package/dist/hooks/use-workspace-sessions.d.ts +27 -5
  265. package/dist/human-input.d.ts +3 -1
  266. package/dist/identity-link-accounts.d.ts +11 -0
  267. package/dist/identity-link-consent.d.ts +18 -0
  268. package/dist/index.d.ts +60 -17
  269. package/dist/index.js +2237 -6200
  270. package/dist/index.js.map +1 -1
  271. package/dist/interaction.d.ts +1 -1
  272. package/dist/interaction.js +35 -184
  273. package/dist/interaction.js.map +1 -1
  274. package/dist/latest-question-755OW5DS.js +117 -0
  275. package/dist/latest-question-755OW5DS.js.map +1 -0
  276. package/dist/lib/error-message.d.ts +7 -0
  277. package/dist/lib/format.d.ts +36 -2
  278. package/dist/lib/host-theme.d.ts +70 -0
  279. package/dist/lib/interaction-errors.d.ts +6 -0
  280. package/dist/lib/menu-styles.d.ts +22 -0
  281. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  282. package/dist/lib/workbench-peers.d.ts +36 -0
  283. package/dist/lib/xterm-theme.d.ts +7 -5
  284. package/dist/machines.d.ts +4 -2
  285. package/dist/machines.js +14 -4
  286. package/dist/markdown-table-layout-QXSLK4BY.js +106 -0
  287. package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
  288. package/dist/mcp-connection-status.d.ts +14 -0
  289. package/dist/model-policy-picker-menu-PWRI7R2X.js +14 -0
  290. package/dist/model-policy-picker-menu-PWRI7R2X.js.map +1 -0
  291. package/dist/model-policy.d.ts +19 -3
  292. package/dist/model-policy.js +9 -1
  293. package/dist/older-history.d.ts +30 -0
  294. package/dist/platform-activity-row-627BFZ46.js +182 -0
  295. package/dist/platform-activity-row-627BFZ46.js.map +1 -0
  296. package/dist/plugin-details.d.ts +14 -0
  297. package/dist/plugin-discovery.d.ts +25 -0
  298. package/dist/provider.d.ts +13 -1
  299. package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-ZHFI5JBP.js} +131 -44
  300. package/dist/queue-surface-implementation-ZHFI5JBP.js.map +1 -0
  301. package/dist/realtime/realtime-control.d.ts +10 -3
  302. package/dist/realtime.js +229 -83
  303. package/dist/realtime.js.map +1 -1
  304. package/dist/sandbox-files-BBC47SLD.js +20 -0
  305. package/dist/sandbox-files-BBC47SLD.js.map +1 -0
  306. package/dist/session-auth-recommendation.d.ts +5 -0
  307. package/dist/session-capability-policy.d.ts +12 -0
  308. package/dist/session-ui.d.ts +30 -2
  309. package/dist/session-ui.js +85 -7
  310. package/dist/session-ui.js.map +1 -1
  311. package/dist/session.d.ts +8 -2
  312. package/dist/session.js +30 -19
  313. package/dist/sites-ui.d.ts +34 -0
  314. package/dist/sites.d.ts +3 -0
  315. package/dist/sites.js +11 -0
  316. package/dist/sites.js.map +1 -0
  317. package/dist/skill-discovery.d.ts +47 -0
  318. package/dist/terminal.d.ts +8 -0
  319. package/dist/terminal.js +31 -0
  320. package/dist/terminal.js.map +1 -0
  321. package/dist/timeline/activity-rail.d.ts +11 -2
  322. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  323. package/dist/timeline/compaction-copy.d.ts +10 -0
  324. package/dist/timeline/entrance.d.ts +13 -1
  325. package/dist/timeline/genie-loading.d.ts +34 -0
  326. package/dist/timeline/index.d.ts +6 -2
  327. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  328. package/dist/timeline/platform-activity-row.d.ts +14 -0
  329. package/dist/timeline/presented-image.d.ts +6 -0
  330. package/dist/timeline/projection.d.ts +31 -2
  331. package/dist/timeline/registry.d.ts +2 -0
  332. package/dist/timeline/retained-image.d.ts +18 -0
  333. package/dist/timeline/rolling-activity.d.ts +11 -0
  334. package/dist/timeline/screenshot-lightbox.d.ts +16 -1
  335. package/dist/timeline/shared.d.ts +8 -3
  336. package/dist/timeline/startup-preference.d.ts +3 -0
  337. package/dist/timeline/startup-timings.d.ts +4 -0
  338. package/dist/timeline/tool-display-name.d.ts +2 -1
  339. package/dist/timeline/turn-summary.d.ts +32 -3
  340. package/dist/timeline/types.d.ts +141 -7
  341. package/dist/timeline-annotation-markers-GNDHTGBD.js +165 -0
  342. package/dist/timeline-annotation-markers-GNDHTGBD.js.map +1 -0
  343. package/dist/timeline-annotation-selection-DMLMM2TX.js +241 -0
  344. package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
  345. package/dist/timeline-annotations-dialog-ELRDBHTS.js +273 -0
  346. package/dist/timeline-annotations-dialog-ELRDBHTS.js.map +1 -0
  347. package/dist/types/machines.d.ts +2 -2
  348. package/dist/usage/allowance-copy.d.ts +25 -0
  349. package/dist/usage/summary.d.ts +35 -0
  350. package/dist/usage.d.ts +13 -0
  351. package/dist/usage.js +1074 -0
  352. package/dist/usage.js.map +1 -0
  353. package/package.json +44 -4
  354. package/src/accounts.tsx +1072 -0
  355. package/src/approvals.ts +8 -1
  356. package/src/artifacts.ts +42 -0
  357. package/src/assets/README.md +8 -0
  358. package/src/assets/gmail.ico +0 -0
  359. package/src/assets/outlook.ico +0 -0
  360. package/src/capability-catalog-row.tsx +94 -0
  361. package/src/capability-logo-fallback.ts +22 -0
  362. package/src/client.ts +22 -13
  363. package/src/commands/registry.ts +18 -15
  364. package/src/commands/types.ts +2 -0
  365. package/src/components/anthropic-mark.tsx +10 -0
  366. package/src/components/approval-surface.tsx +171 -37
  367. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  368. package/src/components/artifacts/artifact-sandbox.tsx +185 -0
  369. package/src/components/artifacts/artifact-surface.tsx +39 -19
  370. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  371. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  372. package/src/components/artifacts/document-editor.tsx +141 -16
  373. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  374. package/src/components/artifacts/editable-artifact-view.tsx +187 -0
  375. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  376. package/src/components/artifacts/editable-document.tsx +37 -36
  377. package/src/components/artifacts/editable-presentation.tsx +36 -18
  378. package/src/components/artifacts/editable-spreadsheet.tsx +5 -2
  379. package/src/components/artifacts/index.ts +44 -0
  380. package/src/components/artifacts/inline-html-document.ts +24 -0
  381. package/src/components/artifacts/latest-task-runner.ts +49 -0
  382. package/src/components/artifacts/presentation-editor.tsx +323 -67
  383. package/src/components/artifacts/published-html-artifact-frame.tsx +338 -5
  384. package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
  385. package/src/components/artifacts/site-view.tsx +116 -0
  386. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  387. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  388. package/src/components/artifacts/spreadsheet-grid.tsx +12 -13
  389. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  390. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  391. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  392. package/src/components/browser-select-control.tsx +312 -0
  393. package/src/components/browser-viewer.tsx +1054 -314
  394. package/src/components/chat-composer.tsx +131 -85
  395. package/src/components/child-session-link.tsx +27 -0
  396. package/src/components/claude-mark.tsx +10 -0
  397. package/src/components/code-editor.tsx +13 -16
  398. package/src/components/composer-transcription-control.tsx +7 -5
  399. package/src/components/composer.tsx +376 -49
  400. package/src/components/computer-viewer.tsx +1041 -329
  401. package/src/components/copy-button.tsx +13 -5
  402. package/src/components/desktop-viewer.tsx +1 -1
  403. package/src/components/enrollment-consent.tsx +65 -7
  404. package/src/components/enrollment-device-flow.tsx +1 -1
  405. package/src/components/file-browser.tsx +158 -34
  406. package/src/components/fleet-tile.tsx +8 -16
  407. package/src/components/generated-video-player.tsx +4 -2
  408. package/src/components/grok-mark.tsx +33 -0
  409. package/src/components/human-input-form.tsx +455 -114
  410. package/src/components/human-input-surface.tsx +18 -7
  411. package/src/components/interaction-intervention-banner.tsx +2 -2
  412. package/src/components/machine-card.tsx +119 -4
  413. package/src/components/machine-dock-bar.tsx +1 -1
  414. package/src/components/machine-input-display.ts +23 -2
  415. package/src/components/machines/machine-detail.tsx +52 -2
  416. package/src/components/machines/machine-operation-policy.tsx +179 -0
  417. package/src/components/machines-dashboard.tsx +8 -17
  418. package/src/components/markdown-table-layout.ts +132 -0
  419. package/src/components/markdown.tsx +473 -44
  420. package/src/components/message-timeline.tsx +2498 -663
  421. package/src/components/model-mark.tsx +90 -0
  422. package/src/components/model-picker.tsx +15 -4
  423. package/src/components/model-policy-picker-menu.tsx +424 -0
  424. package/src/components/model-policy-picker.tsx +337 -381
  425. package/src/components/open-geni-chat.tsx +319 -0
  426. package/src/components/open-geni-links.tsx +179 -0
  427. package/src/components/openrouter-mark.tsx +13 -0
  428. package/src/components/pierre-diff.tsx +41 -16
  429. package/src/components/pierre-file.tsx +36 -11
  430. package/src/components/preview-loading.tsx +154 -0
  431. package/src/components/queue-item-content.ts +14 -0
  432. package/src/components/queue-surface-implementation.tsx +132 -42
  433. package/src/components/queue-surface-state.tsx +3 -1
  434. package/src/components/sandbox-files.tsx +267 -35
  435. package/src/components/sandbox-terminal.tsx +48 -11
  436. package/src/components/sandbox-workspace.tsx +337 -135
  437. package/src/components/session-capability-frame.tsx +192 -0
  438. package/src/components/session-chrome.tsx +1027 -328
  439. package/src/components/session-commands-panel.tsx +126 -0
  440. package/src/components/session-commands.tsx +18 -0
  441. package/src/components/session-connection-request.tsx +97 -0
  442. package/src/components/session-conversation.tsx +512 -0
  443. package/src/components/session-list.tsx +250 -0
  444. package/src/components/session-mcp-capability-card.tsx +680 -0
  445. package/src/components/session-status.tsx +1 -1
  446. package/src/components/timeline-anchor.tsx +119 -0
  447. package/src/components/timeline-annotation-chrome.tsx +196 -0
  448. package/src/components/timeline-annotation-layout.ts +268 -0
  449. package/src/components/timeline-annotation-markers.tsx +185 -0
  450. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  451. package/src/components/timeline-annotation-selection.tsx +106 -54
  452. package/src/components/timeline-annotation-shared.ts +245 -0
  453. package/src/components/timeline-annotations-dialog.tsx +185 -128
  454. package/src/components/timeline-annotations.tsx +189 -45
  455. package/src/components/timeline-reading-progress.ts +80 -0
  456. package/src/components/timeline-search.tsx +168 -0
  457. package/src/components/timeline-settlement.ts +60 -0
  458. package/src/components/tip-follow.ts +70 -7
  459. package/src/components/tooltip.tsx +38 -5
  460. package/src/components/usage-limit-notice.tsx +179 -0
  461. package/src/components/usage-member-list.tsx +792 -0
  462. package/src/components/usage-meter.tsx +382 -0
  463. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  464. package/src/components/user-message-body.tsx +194 -49
  465. package/src/components/workspace-dock.tsx +141 -175
  466. package/src/composer.ts +6 -1
  467. package/src/connect-account-identity.tsx +34 -0
  468. package/src/connect-accounts.tsx +233 -0
  469. package/src/connect-chooser.tsx +336 -0
  470. package/src/connect-panel.tsx +99 -0
  471. package/src/connect-setup.tsx +307 -0
  472. package/src/connect.ts +60 -0
  473. package/src/connection-assets.d.ts +4 -0
  474. package/src/connection-catalog.tsx +162 -0
  475. package/src/connection-discovery.tsx +235 -0
  476. package/src/connection-installed.tsx +51 -0
  477. package/src/connection-logo.tsx +37 -0
  478. package/src/connection-service-logo.tsx +55 -0
  479. package/src/connection-service-presentation.ts +46 -0
  480. package/src/connection-skeleton.tsx +16 -0
  481. package/src/connection-type-picker.tsx +36 -0
  482. package/src/conversation-timeline.ts +92 -0
  483. package/src/desktop.ts +24 -0
  484. package/src/device-authorization.tsx +98 -0
  485. package/src/diffs.ts +16 -0
  486. package/src/discovery-cache.ts +42 -0
  487. package/src/editor.ts +13 -0
  488. package/src/embedded-session-client.ts +104 -0
  489. package/src/file-node-visibility.ts +66 -0
  490. package/src/hooks/channel-cache.ts +104 -0
  491. package/src/hooks/internal.ts +3 -2
  492. package/src/hooks/latest-question.ts +164 -0
  493. package/src/hooks/shared-machines-list.ts +239 -0
  494. package/src/hooks/use-attached-browsers.ts +5 -1
  495. package/src/hooks/use-available-models.ts +20 -14
  496. package/src/hooks/use-browser-frame-stream.ts +25 -3
  497. package/src/hooks/use-browser-session.ts +271 -71
  498. package/src/hooks/use-browser-sessions.ts +7 -1
  499. package/src/hooks/use-channels.ts +32 -10
  500. package/src/hooks/use-codex-accounts.ts +78 -21
  501. package/src/hooks/use-composer.ts +1034 -320
  502. package/src/hooks/use-computer-frame-stream.ts +39 -16
  503. package/src/hooks/use-computer-input-posture.ts +94 -0
  504. package/src/hooks/use-computer-session.ts +110 -32
  505. package/src/hooks/use-computer-sessions.ts +8 -1
  506. package/src/hooks/use-connect.ts +23 -0
  507. package/src/hooks/use-desktop-stream.ts +19 -28
  508. package/src/hooks/use-file-attachments.ts +118 -10
  509. package/src/hooks/use-goal.ts +36 -9
  510. package/src/hooks/use-human-input.ts +31 -4
  511. package/src/hooks/use-last-started-turn-policy.ts +15 -13
  512. package/src/hooks/use-machine-chip.ts +23 -6
  513. package/src/hooks/use-machines.ts +104 -6
  514. package/src/hooks/use-sandbox-files.ts +253 -150
  515. package/src/hooks/use-sandbox-git.ts +58 -29
  516. package/src/hooks/use-session-background-commands.ts +67 -0
  517. package/src/hooks/use-session-capabilities.ts +21 -2
  518. package/src/hooks/use-session-events.ts +759 -433
  519. package/src/hooks/use-session-lineage.ts +28 -6
  520. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  521. package/src/hooks/use-session.ts +75 -16
  522. package/src/hooks/use-slash-commands.ts +6 -11
  523. package/src/hooks/use-turn-queue.ts +113 -13
  524. package/src/hooks/use-usage.ts +100 -0
  525. package/src/hooks/use-voice-input.ts +12 -1
  526. package/src/hooks/use-workspace-capture.ts +3 -2
  527. package/src/hooks/use-workspace-edit.ts +23 -5
  528. package/src/hooks/use-workspace-sessions.ts +99 -11
  529. package/src/human-input.ts +12 -1
  530. package/src/identity-link-accounts.tsx +148 -0
  531. package/src/identity-link-consent.tsx +192 -0
  532. package/src/index.ts +157 -12
  533. package/src/interaction.ts +1 -0
  534. package/src/lib/error-message.ts +37 -0
  535. package/src/lib/format.ts +150 -14
  536. package/src/lib/host-theme.ts +511 -0
  537. package/src/lib/interaction-errors.ts +33 -0
  538. package/src/lib/menu-styles.ts +44 -0
  539. package/src/lib/pierre-diffs-loader.ts +53 -0
  540. package/src/lib/workbench-peers.ts +62 -0
  541. package/src/lib/xterm-theme.ts +23 -21
  542. package/src/machines.ts +9 -1
  543. package/src/mcp-connection-status.ts +35 -0
  544. package/src/model-policy.ts +223 -69
  545. package/src/older-history.ts +87 -0
  546. package/src/plugin-details.tsx +185 -0
  547. package/src/plugin-discovery.tsx +196 -0
  548. package/src/provider.tsx +55 -14
  549. package/src/realtime/dropdown-menu.tsx +19 -12
  550. package/src/realtime/realtime-control.tsx +274 -60
  551. package/src/session-auth-recommendation.ts +48 -0
  552. package/src/session-capability-policy.ts +83 -0
  553. package/src/session-context.ts +1 -0
  554. package/src/session-ui.ts +66 -2
  555. package/src/session.ts +18 -1
  556. package/src/sites-ui.tsx +402 -0
  557. package/src/sites.ts +3 -0
  558. package/src/skill-discovery.tsx +208 -0
  559. package/src/terminal.ts +26 -0
  560. package/src/timeline/activity-rail.tsx +171 -80
  561. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  562. package/src/timeline/compaction-copy.ts +42 -0
  563. package/src/timeline/entrance.tsx +28 -3
  564. package/src/timeline/fleet-decision-projection.ts +2 -1
  565. package/src/timeline/fleet-decision-row.tsx +1 -0
  566. package/src/timeline/genie-loading.tsx +136 -0
  567. package/src/timeline/index.ts +11 -0
  568. package/src/timeline/knowledge-receipt.tsx +100 -0
  569. package/src/timeline/parsers.ts +2 -2
  570. package/src/timeline/platform-activity-row.tsx +216 -0
  571. package/src/timeline/presented-image.ts +49 -0
  572. package/src/timeline/projection.ts +1600 -84
  573. package/src/timeline/registry.ts +15 -3
  574. package/src/timeline/retained-image.ts +97 -0
  575. package/src/timeline/rolling-activity.tsx +92 -0
  576. package/src/timeline/screenshot-lightbox.tsx +115 -17
  577. package/src/timeline/shared.tsx +47 -15
  578. package/src/timeline/startup-preference.ts +33 -0
  579. package/src/timeline/startup-timings.tsx +145 -0
  580. package/src/timeline/tool-display-name.ts +8 -6
  581. package/src/timeline/tool-renderers.tsx +497 -128
  582. package/src/timeline/turn-summary.tsx +208 -44
  583. package/src/timeline/types.ts +186 -7
  584. package/src/types/machines.ts +10 -0
  585. package/src/usage/allowance-copy.ts +64 -0
  586. package/src/usage/summary.ts +93 -0
  587. package/src/usage.ts +50 -0
  588. package/styles/compiled.css +2098 -757
  589. package/styles/connect.css +284 -0
  590. package/styles/connect.d.ts +1 -0
  591. package/styles/effective-tokens.css +1 -0
  592. package/styles/index.css +201 -9
  593. package/styles/responsive.css +27 -1
  594. package/styles/session-capability.css +44 -0
  595. package/styles/tokens.css +135 -65
  596. package/dist/chunk-5UQPNLIO.js.map +0 -1
  597. package/dist/chunk-6KLX2RH5.js.map +0 -1
  598. package/dist/chunk-7WCLAEFV.js.map +0 -1
  599. package/dist/chunk-B6WPZSTT.js.map +0 -1
  600. package/dist/chunk-FK6VG4LL.js +0 -90
  601. package/dist/chunk-FK6VG4LL.js.map +0 -1
  602. package/dist/chunk-HA46CYQK.js.map +0 -1
  603. package/dist/chunk-HUIKIDM5.js.map +0 -1
  604. package/dist/chunk-IGC6A2ZI.js.map +0 -1
  605. package/dist/chunk-KCGXPP5V.js.map +0 -1
  606. package/dist/chunk-KZ73RL76.js.map +0 -1
  607. package/dist/chunk-LAKLF4PA.js +0 -141
  608. package/dist/chunk-LAKLF4PA.js.map +0 -1
  609. package/dist/chunk-LLOLUHVG.js.map +0 -1
  610. package/dist/chunk-MKPIAGVL.js +0 -465
  611. package/dist/chunk-MKPIAGVL.js.map +0 -1
  612. package/dist/chunk-PEI6RANI.js.map +0 -1
  613. package/dist/chunk-R3AZOAB5.js.map +0 -1
  614. package/dist/chunk-WSK7G5LE.js +0 -170
  615. package/dist/chunk-WSK7G5LE.js.map +0 -1
  616. package/dist/chunk-XBZWOM2K.js +0 -218
  617. package/dist/chunk-XBZWOM2K.js.map +0 -1
  618. package/dist/chunk-Y7OEDUJ5.js +0 -8810
  619. package/dist/chunk-Y7OEDUJ5.js.map +0 -1
  620. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  621. package/dist/hooks/use-packs.d.ts +0 -32
  622. package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
  623. package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
  624. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  625. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  626. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  627. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  628. package/src/hooks/use-packs.ts +0 -157
  629. /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GTR5XQ7X.js.map} +0 -0
@@ -4,6 +4,15 @@ import { ChevronRightIcon } from "lucide-react";
4
4
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
5
5
  import { createContext, useContext, type ComponentProps, type Ref } from "react";
6
6
  import { cn } from "../lib/cn";
7
+ import {
8
+ MENU_CHEVRON_CLASS,
9
+ MENU_ITEM_CLASS,
10
+ MENU_SEPARATOR_CLASS,
11
+ MENU_SURFACE_CLASS,
12
+ } from "../lib/menu-styles";
13
+
14
+ const MENU_MOTION_CLASS =
15
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95";
7
16
  import { usePortalTokenSource, usePortalTokenStyle } from "../lib/use-portal-token-style";
8
17
 
9
18
  type DropdownMenuSourceContextValue = {
@@ -58,7 +67,9 @@ function DropdownMenuContent({
58
67
  data-slot="dropdown-menu-content"
59
68
  sideOffset={sideOffset}
60
69
  className={cn(
61
- "og-root z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
70
+ "og-root z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto",
71
+ MENU_SURFACE_CLASS,
72
+ MENU_MOTION_CLASS,
62
73
  className,
63
74
  )}
64
75
  style={{ ...portalStyle, ...style }}
@@ -82,10 +93,7 @@ function DropdownMenuItem({
82
93
  data-slot="dropdown-menu-item"
83
94
  data-inset={inset}
84
95
  data-variant={variant}
85
- className={cn(
86
- "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
87
- className,
88
- )}
96
+ className={cn(MENU_ITEM_CLASS, "data-[inset]:pl-9", className)}
89
97
  {...props}
90
98
  />
91
99
  );
@@ -98,7 +106,7 @@ function DropdownMenuSeparator({
98
106
  return (
99
107
  <DropdownMenuPrimitive.Separator
100
108
  data-slot="dropdown-menu-separator"
101
- className={cn("-mx-1 my-1 h-px bg-border", className)}
109
+ className={cn(MENU_SEPARATOR_CLASS, className)}
102
110
  {...props}
103
111
  />
104
112
  );
@@ -118,14 +126,11 @@ function DropdownMenuSubTrigger({
118
126
  <DropdownMenuPrimitive.SubTrigger
119
127
  data-slot="dropdown-menu-sub-trigger"
120
128
  data-inset={inset}
121
- className={cn(
122
- "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
123
- className,
124
- )}
129
+ className={cn(MENU_ITEM_CLASS, "data-[inset]:pl-9", className)}
125
130
  {...props}
126
131
  >
127
132
  {children}
128
- <ChevronRightIcon className="ml-auto size-4" />
133
+ <ChevronRightIcon aria-hidden="true" className={cn(MENU_CHEVRON_CLASS, "ml-auto")} />
129
134
  </DropdownMenuPrimitive.SubTrigger>
130
135
  );
131
136
  }
@@ -141,7 +146,9 @@ function DropdownMenuSubContent({
141
146
  <DropdownMenuPrimitive.SubContent
142
147
  data-slot="dropdown-menu-sub-content"
143
148
  className={cn(
144
- "og-root z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
149
+ "og-root z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden",
150
+ MENU_SURFACE_CLASS,
151
+ MENU_MOTION_CLASS,
145
152
  className,
146
153
  )}
147
154
  style={{ ...portalStyle, ...style }}
@@ -6,6 +6,7 @@ import {
6
6
  type SessionRealtimeController,
7
7
  type SessionRealtimeControllerSnapshot,
8
8
  type CreateSessionRealtimeControllerOptions,
9
+ type SessionRealtimeLifecycleProjection,
9
10
  type SessionRealtimeModel,
10
11
  type WorkspaceRealtimeModelCatalogItem,
11
12
  } from "@opengeni/sdk/realtime";
@@ -53,6 +54,7 @@ import {
53
54
  DropdownMenuSubTrigger,
54
55
  DropdownMenuTrigger,
55
56
  } from "./dropdown-menu";
57
+ import { MENU_CHECK_CLASS } from "../lib/menu-styles";
56
58
 
57
59
  export type RealtimeModelOption = {
58
60
  id: SessionRealtimeModel;
@@ -98,9 +100,155 @@ const REALTIME_PROVIDER_META: Record<
98
100
  "Your Gateway": { billingClass: "byok", hint: "Billed to your AI Gateway" },
99
101
  };
100
102
  const REALTIME_MODEL_STORAGE_PREFIX = "opengeni:realtime-model";
103
+ const REALTIME_MODEL_CATALOG_CACHE_TTL_MS = 60_000;
104
+ const REALTIME_MODEL_CATALOG_CACHE_MAX_WORKSPACES = 64;
101
105
 
102
106
  type RealtimeControllerClient = EmbeddedRealtimeSessionClientLike & SessionRealtimeClientLike;
103
107
 
108
+ type RealtimeModelCatalogCacheEntry =
109
+ | {
110
+ state: "loading";
111
+ promise: Promise<RealtimeModelOption[]>;
112
+ controller: AbortController;
113
+ consumers: number;
114
+ }
115
+ | { state: "ready"; models: RealtimeModelOption[]; expiresAt: number };
116
+
117
+ // Scope advisory availability to the exact client object and workspace. The
118
+ // server still authorizes every realtime operation; changing principals should
119
+ // replace the client just as it does for the rest of the SDK state.
120
+ const realtimeModelCatalogCache = new WeakMap<
121
+ RealtimeControllerClient,
122
+ Map<string, RealtimeModelCatalogCacheEntry>
123
+ >();
124
+
125
+ function realtimeModelFallback(codexConnected: boolean): RealtimeModelOption[] {
126
+ return [
127
+ {
128
+ ...CODEX_LIVE_MODEL,
129
+ available: codexConnected,
130
+ unavailableReason: codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,
131
+ },
132
+ ];
133
+ }
134
+
135
+ function realtimeModelCatalogCacheFor(
136
+ client: RealtimeControllerClient,
137
+ ): Map<string, RealtimeModelCatalogCacheEntry> {
138
+ const existing = realtimeModelCatalogCache.get(client);
139
+ if (existing) return existing;
140
+ const created = new Map<string, RealtimeModelCatalogCacheEntry>();
141
+ realtimeModelCatalogCache.set(client, created);
142
+ return created;
143
+ }
144
+
145
+ function readCachedRealtimeModelCatalog(
146
+ client: RealtimeControllerClient,
147
+ workspaceId: string,
148
+ now = Date.now(),
149
+ ): RealtimeModelOption[] | null {
150
+ const cache = realtimeModelCatalogCache.get(client);
151
+ const entry = cache?.get(workspaceId);
152
+ if (!entry || entry.state === "loading") return null;
153
+ if (entry.expiresAt > now) return entry.models;
154
+ cache?.delete(workspaceId);
155
+ return null;
156
+ }
157
+
158
+ function pruneRealtimeModelCatalogCache(
159
+ cache: Map<string, RealtimeModelCatalogCacheEntry>,
160
+ now: number,
161
+ ): void {
162
+ for (const [workspaceId, entry] of cache) {
163
+ if (entry.state === "ready" && entry.expiresAt <= now) cache.delete(workspaceId);
164
+ }
165
+ while (cache.size >= REALTIME_MODEL_CATALOG_CACHE_MAX_WORKSPACES) {
166
+ const oldestWorkspaceId = cache.keys().next().value;
167
+ if (oldestWorkspaceId === undefined) return;
168
+ cache.delete(oldestWorkspaceId);
169
+ }
170
+ }
171
+
172
+ function loadRealtimeModelCatalog(
173
+ client: RealtimeControllerClient,
174
+ workspaceId: string,
175
+ signal?: AbortSignal,
176
+ ): Promise<RealtimeModelOption[]> | null {
177
+ const load = client.getWorkspaceRealtimeModelCatalog;
178
+ if (!load) return null;
179
+ if (signal?.aborted) {
180
+ return Promise.reject(signal.reason ?? new DOMException("Request aborted", "AbortError"));
181
+ }
182
+ const now = Date.now();
183
+ const cache = realtimeModelCatalogCacheFor(client);
184
+ const entry = cache.get(workspaceId);
185
+ if (entry?.state === "loading" && !entry.controller.signal.aborted) {
186
+ return consumeRealtimeModelCatalog(entry, signal);
187
+ }
188
+ if (entry?.state === "ready" && entry.expiresAt > now) return Promise.resolve(entry.models);
189
+ if (entry) cache.delete(workspaceId);
190
+ pruneRealtimeModelCatalogCache(cache, now);
191
+
192
+ const controller = new AbortController();
193
+ const promise = load
194
+ .call(client, workspaceId, { signal: controller.signal })
195
+ .then((response) => response.models.map(toRealtimeModelOption))
196
+ .then((models) => {
197
+ const current = cache.get(workspaceId);
198
+ if (current?.state === "loading" && current.promise === promise) {
199
+ cache.delete(workspaceId);
200
+ cache.set(workspaceId, {
201
+ state: "ready",
202
+ models,
203
+ expiresAt: Date.now() + REALTIME_MODEL_CATALOG_CACHE_TTL_MS,
204
+ });
205
+ }
206
+ return models;
207
+ })
208
+ .catch((error: unknown) => {
209
+ const current = cache.get(workspaceId);
210
+ if (current?.state === "loading" && current.promise === promise) cache.delete(workspaceId);
211
+ throw error;
212
+ });
213
+ const loading: RealtimeModelCatalogCacheEntry & { state: "loading" } = {
214
+ state: "loading",
215
+ promise,
216
+ controller,
217
+ consumers: 0,
218
+ };
219
+ cache.set(workspaceId, loading);
220
+ return consumeRealtimeModelCatalog(loading, signal);
221
+ }
222
+
223
+ function consumeRealtimeModelCatalog(
224
+ entry: RealtimeModelCatalogCacheEntry & { state: "loading" },
225
+ signal?: AbortSignal,
226
+ ): Promise<RealtimeModelOption[]> {
227
+ entry.consumers += 1;
228
+ return new Promise((resolve, reject) => {
229
+ let released = false;
230
+ const release = (abandoned: boolean) => {
231
+ if (released) return;
232
+ released = true;
233
+ entry.consumers = Math.max(0, entry.consumers - 1);
234
+ if (abandoned && entry.consumers === 0) {
235
+ entry.controller.abort(
236
+ signal?.reason ?? new DOMException("Request abandoned", "AbortError"),
237
+ );
238
+ }
239
+ };
240
+ const onAbort = () => {
241
+ release(true);
242
+ reject(signal?.reason ?? new DOMException("Request aborted", "AbortError"));
243
+ };
244
+ signal?.addEventListener("abort", onAbort, { once: true });
245
+ void entry.promise.then(resolve, reject).finally(() => {
246
+ signal?.removeEventListener("abort", onAbort);
247
+ release(false);
248
+ });
249
+ });
250
+ }
251
+
104
252
  export type SessionRealtimeControllerFactory = (
105
253
  options: CreateSessionRealtimeControllerOptions,
106
254
  ) => SessionRealtimeController;
@@ -138,6 +286,8 @@ export function useSessionRealtime(options: {
138
286
  model?: SessionRealtimeModel | undefined;
139
287
  modelAvailable?: boolean | undefined;
140
288
  modelUnavailableReason?: string | null | undefined;
289
+ /** Model-visible application context captured with each durable realtime message. */
290
+ getModelContext?: (() => string | undefined) | undefined;
141
291
  /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */
142
292
  controllerFactory?: SessionRealtimeControllerFactory | undefined;
143
293
  }) {
@@ -149,6 +299,8 @@ export function useSessionRealtime(options: {
149
299
  const audioRef = useRef<HTMLAudioElement>(null);
150
300
  const controllerRef = useRef<SessionRealtimeController | null>(null);
151
301
  const controllerModelRef = useRef<SessionRealtimeModel | null>(null);
302
+ const modelContextProviderRef = useRef(options.getModelContext);
303
+ modelContextProviderRef.current = options.getModelContext;
152
304
  const [snapshot, setSnapshot] = useState<SessionRealtimeControllerSnapshot>(() => ({
153
305
  status: hasStoredSessionRealtimeOwnerProof({
154
306
  workspaceId,
@@ -177,7 +329,7 @@ export function useSessionRealtime(options: {
177
329
  const eventsReadyRef = useRef(options.eventsReady);
178
330
  lifecycleRef.current = lifecycle;
179
331
  eventsReadyRef.current = options.eventsReady;
180
- const lifecycleActive = lifecycle?.state === "active";
332
+ const lifecycleActive = sessionRealtimeLifecycleIsActive(lifecycle);
181
333
 
182
334
  useEffect(() => {
183
335
  let disposed = false;
@@ -193,6 +345,7 @@ export function useSessionRealtime(options: {
193
345
  sessionId: options.sessionId,
194
346
  ...(audioRef.current ? { remoteAudio: audioRef.current } : {}),
195
347
  model,
348
+ getModelContext: () => modelContextProviderRef.current?.(),
196
349
  });
197
350
  controllerRef.current = controller;
198
351
  controllerModelRef.current = model;
@@ -297,6 +450,14 @@ export function useSessionRealtime(options: {
297
450
  };
298
451
  }
299
452
 
453
+ function sessionRealtimeLifecycleIsActive(
454
+ lifecycle: SessionRealtimeLifecycleProjection | null,
455
+ ): boolean {
456
+ if (lifecycle?.state !== "active") return false;
457
+ const leaseExpiresAt = Date.parse(lifecycle.leaseExpiresAt);
458
+ return !Number.isFinite(leaseExpiresAt) || leaseExpiresAt > Date.now();
459
+ }
460
+
300
461
  export function SessionRealtimeControl(props: {
301
462
  client?: RealtimeControllerClient | undefined;
302
463
  workspaceId?: string | undefined;
@@ -306,6 +467,8 @@ export function SessionRealtimeControl(props: {
306
467
  events: SessionEvent[];
307
468
  eventsReady: boolean;
308
469
  codexConnected: boolean;
470
+ /** Model-visible application context captured with each durable realtime message. */
471
+ getModelContext?: (() => string | undefined) | undefined;
309
472
  realtimeAutostartModel?: SessionRealtimeModel | undefined;
310
473
  onRealtimeAutostartConsumed?: (() => void) | undefined;
311
474
  /** Host hides dictate (and can choreograph layout) while realtime voice is live. */
@@ -317,15 +480,18 @@ export function SessionRealtimeControl(props: {
317
480
  * `none` never attaches a model menu to the bar button.
318
481
  */
319
482
  modelMenu?: "split" | "split-desktop" | "none" | undefined;
483
+ /** Explicitly expose low-level controller diagnostics; disabled by default. */
484
+ showDiagnostics?: boolean | undefined;
320
485
  /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */
321
486
  controllerFactory?: SessionRealtimeControllerFactory | undefined;
322
487
  }) {
323
488
  const lifecycle = useMemo(() => projectSessionRealtimeLifecycle(props.events), [props.events]);
489
+ const lifecycleActive = sessionRealtimeLifecycleIsActive(lifecycle);
324
490
  const selection = useRealtimeModelSelection({
325
491
  client: props.client,
326
492
  workspaceId: props.workspaceId,
327
493
  codexConnected: props.codexConnected,
328
- activeModel: lifecycle?.state === "active" ? lifecycle.model : null,
494
+ activeModel: lifecycleActive && lifecycle?.state === "active" ? lifecycle.model : null,
329
495
  });
330
496
  const selectedModel = selection.selectedModel;
331
497
  const realtime = useSessionRealtime({
@@ -349,7 +515,7 @@ export function SessionRealtimeControl(props: {
349
515
 
350
516
  useEffect(() => {
351
517
  const pending = autostartModelRef.current;
352
- if (!pending || autostartStartedRef.current || lifecycle?.state === "active") return;
518
+ if (!pending || autostartStartedRef.current || lifecycleActive) return;
353
519
  const available = models.some((model) => model.id === pending && model.available);
354
520
  if (!available) return;
355
521
  if (selectedRealtimeModel.id !== pending) {
@@ -368,7 +534,7 @@ export function SessionRealtimeControl(props: {
368
534
  });
369
535
  }, [
370
536
  canStart,
371
- lifecycle?.state,
537
+ lifecycleActive,
372
538
  models,
373
539
  props.sessionId,
374
540
  props.workspaceId,
@@ -386,6 +552,7 @@ export function SessionRealtimeControl(props: {
386
552
  modelAvailable={selectedModel.available}
387
553
  menuSide="top"
388
554
  modelMenu={props.modelMenu ?? "split"}
555
+ showDiagnostics={props.showDiagnostics}
389
556
  audioRef={realtime.audioRef}
390
557
  selectedModel={selectedModel}
391
558
  models={selection.models}
@@ -411,35 +578,58 @@ export function useRealtimeModelSelection(options: {
411
578
  workspaceId: options.workspaceId,
412
579
  });
413
580
  const activeModel = options.activeModel;
414
- const [catalog, setCatalog] = useState<RealtimeModelOption[]>(() => [
415
- {
416
- ...CODEX_LIVE_MODEL,
417
- available: options.codexConnected,
418
- unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,
419
- },
420
- ]);
421
- const [selectedModelId, setSelectedModelId] = useState<SessionRealtimeModel>(
422
- () => readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id,
581
+ const initialCachedCatalog = readCachedRealtimeModelCatalog(client, workspaceId);
582
+ const [catalog, setCatalog] = useState<RealtimeModelOption[]>(
583
+ () => initialCachedCatalog ?? realtimeModelFallback(options.codexConnected),
423
584
  );
585
+ const catalogScopeRef = useRef({
586
+ client,
587
+ workspaceId,
588
+ source: initialCachedCatalog ? ("cache" as const) : ("fallback" as const),
589
+ });
590
+ const [selectedModelId, setSelectedModelId] = useState<SessionRealtimeModel>(() => {
591
+ const preferred = readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id;
592
+ if (!initialCachedCatalog) return preferred;
593
+ if (initialCachedCatalog.some((model) => model.id === preferred && model.available)) {
594
+ return preferred;
595
+ }
596
+ return initialCachedCatalog.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;
597
+ });
424
598
 
425
599
  useEffect(() => {
426
600
  let disposed = false;
427
- const load = client.getWorkspaceRealtimeModelCatalog;
428
- if (!load) return;
429
- void load
430
- .call(client, workspaceId)
431
- .then((response) => {
601
+ const requestAbort = new AbortController();
602
+ const applyCatalog = (models: RealtimeModelOption[]) => {
603
+ catalogScopeRef.current = { client, workspaceId, source: "cache" };
604
+ setCatalog(models);
605
+ setSelectedModelId((current) => {
606
+ if (models.some((model) => model.id === current && model.available)) return current;
607
+ return models.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;
608
+ });
609
+ };
610
+ const cached = readCachedRealtimeModelCatalog(client, workspaceId);
611
+ if (cached) {
612
+ const scope = catalogScopeRef.current;
613
+ if (
614
+ scope.client !== client ||
615
+ scope.workspaceId !== workspaceId ||
616
+ scope.source !== "cache"
617
+ ) {
618
+ applyCatalog(cached);
619
+ }
620
+ return;
621
+ }
622
+ const loading = loadRealtimeModelCatalog(client, workspaceId, requestAbort.signal);
623
+ if (!loading) return;
624
+ void loading
625
+ .then((models) => {
432
626
  if (disposed) return;
433
- const models = response.models.map(toRealtimeModelOption);
434
- setCatalog(models);
435
- setSelectedModelId((current) => {
436
- if (models.some((model) => model.id === current && model.available)) return current;
437
- return models.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;
438
- });
627
+ applyCatalog(models);
439
628
  })
440
629
  .catch(() => undefined);
441
630
  return () => {
442
631
  disposed = true;
632
+ requestAbort.abort();
443
633
  };
444
634
  }, [client, workspaceId]);
445
635
 
@@ -482,7 +672,7 @@ const IDLE_REALTIME_SNAPSHOT: SessionRealtimeControllerSnapshot = {
482
672
  error: null,
483
673
  };
484
674
 
485
- export function NewSessionRealtimeControl(props: {
675
+ type NewSessionRealtimeControlProps = {
486
676
  client?: RealtimeControllerClient | undefined;
487
677
  workspaceId?: string | undefined;
488
678
  codexConnected: boolean;
@@ -500,20 +690,43 @@ export function NewSessionRealtimeControl(props: {
500
690
  * `none` never attaches a model menu to the bar button.
501
691
  */
502
692
  modelMenu?: "split" | "split-desktop" | "none" | undefined;
503
- }) {
504
- const internalSelection = useRealtimeModelSelection({
693
+ };
694
+
695
+ type NewSessionRealtimeSelection = {
696
+ models: readonly RealtimeModelOption[];
697
+ selectedModel: RealtimeModelOption;
698
+ selectModel: (modelId: string) => void;
699
+ };
700
+
701
+ export function NewSessionRealtimeControl(props: NewSessionRealtimeControlProps) {
702
+ if (props.models && props.selectedModel && props.onSelectModel) {
703
+ return (
704
+ <NewSessionRealtimeControlView
705
+ {...props}
706
+ selection={{
707
+ models: props.models,
708
+ selectedModel: props.selectedModel,
709
+ selectModel: props.onSelectModel,
710
+ }}
711
+ />
712
+ );
713
+ }
714
+ return <NewSessionRealtimeControlWithInternalSelection {...props} />;
715
+ }
716
+
717
+ function NewSessionRealtimeControlWithInternalSelection(props: NewSessionRealtimeControlProps) {
718
+ const selection = useRealtimeModelSelection({
505
719
  client: props.client,
506
720
  workspaceId: props.workspaceId,
507
721
  codexConnected: props.codexConnected,
508
722
  });
509
- const selection =
510
- props.models && props.selectedModel && props.onSelectModel
511
- ? {
512
- models: props.models,
513
- selectedModel: props.selectedModel,
514
- selectModel: props.onSelectModel,
515
- }
516
- : internalSelection;
723
+ return <NewSessionRealtimeControlView {...props} selection={selection} />;
724
+ }
725
+
726
+ function NewSessionRealtimeControlView(
727
+ props: NewSessionRealtimeControlProps & { selection: NewSessionRealtimeSelection },
728
+ ) {
729
+ const selection = props.selection;
517
730
  const audioRef = useRef<HTMLAudioElement>(null);
518
731
  const [starting, setStarting] = useState(false);
519
732
  const [error, setError] = useState<string | null>(null);
@@ -582,7 +795,7 @@ export function RealtimeVoiceControl(props: {
582
795
  * `none` = start button only.
583
796
  */
584
797
  modelMenu?: "split" | "split-desktop" | "none" | undefined;
585
- showDiagnostics?: boolean;
798
+ showDiagnostics?: boolean | undefined;
586
799
  /** Extra classes on the in-bar mute cluster (e.g. `max-sm:hidden` when mutes live in “+”). */
587
800
  muteControlsClassName?: string | undefined;
588
801
  audioRef: RefObject<HTMLAudioElement | null>;
@@ -636,7 +849,7 @@ export function RealtimeVoiceControl(props: {
636
849
  : modeOwned
637
850
  ? props.onStop
638
851
  : props.onStart;
639
- const diagnosticsVisible = props.showDiagnostics ?? import.meta.env.DEV;
852
+ const diagnosticsVisible = props.showDiagnostics ?? false;
640
853
  const modelMenu = props.modelMenu ?? "split";
641
854
  const showAttachedModelMenu = modelMenu === "split" || modelMenu === "split-desktop";
642
855
  const desktopOnlyModelMenu = modelMenu === "split-desktop";
@@ -793,7 +1006,7 @@ export function RealtimeVoiceControl(props: {
793
1006
  align="end"
794
1007
  sideOffset={8}
795
1008
  collisionPadding={12}
796
- className="og-realtime-menu flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden rounded-xl border-border bg-surface p-1.5 shadow-xl"
1009
+ className="og-realtime-menu flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden"
797
1010
  onCloseAutoFocus={(event) => event.preventDefault()}
798
1011
  >
799
1012
  <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
@@ -816,9 +1029,15 @@ export function RealtimeVoiceControl(props: {
816
1029
  />
817
1030
  </div>
818
1031
 
819
- {status.phase !== "idle" ? (
1032
+ {status.phase !== "idle" &&
1033
+ // Say it once: the selected model's row already carries its reason.
1034
+ !(
1035
+ status.phase === "unavailable" &&
1036
+ pickerProvider === selectedModel.provider &&
1037
+ selectedModel.unavailableReason === status.detail
1038
+ ) ? (
820
1039
  <>
821
- <DropdownMenuSeparator className="mx-1 bg-og-border" />
1040
+ <DropdownMenuSeparator />
822
1041
  <div className="px-2.5 py-2" role="status" aria-live="polite">
823
1042
  <div className="flex items-center gap-2 text-og-sm font-medium text-og-fg">
824
1043
  <RealtimeStatusDot
@@ -834,7 +1053,6 @@ export function RealtimeVoiceControl(props: {
834
1053
 
835
1054
  {audioBlocked ? (
836
1055
  <DropdownMenuItem
837
- className="rounded-og-md"
838
1056
  onSelect={() => void props.onRetryAudibleOutput().catch(() => undefined)}
839
1057
  >
840
1058
  <Volume2Icon />
@@ -842,10 +1060,7 @@ export function RealtimeVoiceControl(props: {
842
1060
  </DropdownMenuItem>
843
1061
  ) : null}
844
1062
  {retryConnection ? (
845
- <DropdownMenuItem
846
- className="rounded-og-md"
847
- onSelect={() => void props.onRetry().catch(() => undefined)}
848
- >
1063
+ <DropdownMenuItem onSelect={() => void props.onRetry().catch(() => undefined)}>
849
1064
  <RotateCcwIcon />
850
1065
  Retry connection
851
1066
  </DropdownMenuItem>
@@ -853,7 +1068,6 @@ export function RealtimeVoiceControl(props: {
853
1068
  {modeOwned && props.snapshot.status !== "lost_owner" ? (
854
1069
  <DropdownMenuItem
855
1070
  variant="destructive"
856
- className="rounded-og-md"
857
1071
  disabled={props.snapshot.status === "stopping"}
858
1072
  onSelect={() => void props.onStop().catch(() => undefined)}
859
1073
  >
@@ -893,16 +1107,14 @@ export function RealtimeVoiceModelPanel(props: {
893
1107
 
894
1108
  return (
895
1109
  <div className="flex min-h-0 flex-1 flex-col" data-testid="realtime-voice-model-panel">
896
- <div className="flex shrink-0 items-start gap-1 px-2 pt-1 pb-1.5">
1110
+ <div className="flex min-h-10 shrink-0 items-center gap-2 border-b border-og-border px-2 pb-2">
897
1111
  {props.leading}
898
- <div className="min-w-0">
899
- <div className="text-og-menu font-medium text-og-fg">Voice model</div>
900
- <p className="mt-0.5 text-og-control text-og-fg-subtle">
901
- Used when you start a voice conversation.
902
- </p>
903
- </div>
1112
+ <div className="min-w-0 flex-1 text-og-menu font-medium text-og-fg">Voice model</div>
904
1113
  </div>
905
- <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-1.5 pb-1.5">
1114
+ <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-2">
1115
+ <p className="mb-3 text-og-control text-og-fg-muted">
1116
+ Used when you start a voice conversation.
1117
+ </p>
906
1118
  <RealtimeModelPickerMenu
907
1119
  models={props.models}
908
1120
  selectedModel={props.selectedModel}
@@ -1016,7 +1228,9 @@ export function RealtimeModelPickerMenu(props: {
1016
1228
  title={model.unavailableReason ?? model.description}
1017
1229
  active={selected}
1018
1230
  showChevron={false}
1019
- trailing={selected ? <CheckIcon className="size-3.5" aria-hidden /> : undefined}
1231
+ trailing={
1232
+ selected ? <CheckIcon className={MENU_CHECK_CLASS} aria-hidden /> : undefined
1233
+ }
1020
1234
  testId={`realtime-model-choice-${model.id}`}
1021
1235
  onClick={() => props.onSelect(model.id)}
1022
1236
  />
@@ -1079,12 +1293,12 @@ function RealtimeDiagnosticsMenu({ snapshot }: { snapshot: SessionRealtimeContro
1079
1293
 
1080
1294
  return (
1081
1295
  <>
1082
- <DropdownMenuSeparator className="mx-1 bg-og-border" />
1296
+ <DropdownMenuSeparator />
1083
1297
  <DropdownMenuSub>
1084
- <DropdownMenuSubTrigger className="rounded-og-md text-og-fg-muted">
1298
+ <DropdownMenuSubTrigger className="text-og-fg-muted">
1085
1299
  Realtime diagnostics
1086
1300
  </DropdownMenuSubTrigger>
1087
- <DropdownMenuSubContent className="max-h-80 w-72 overflow-y-auto rounded-og-lg border-og-border bg-og-surface-1 p-1.5 text-og-fg shadow-og-lg">
1301
+ <DropdownMenuSubContent className="max-h-80 w-72 overflow-y-auto">
1088
1302
  {rows.map(([label, value]) => (
1089
1303
  <DropdownMenuItem
1090
1304
  key={label}
@@ -1316,7 +1530,7 @@ function RealtimeStatusDot(props: { phase: RealtimeVisualPhase; reduceMotion: bo
1316
1530
 
1317
1531
  function voiceButtonTone(phase: RealtimeVisualPhase): string {
1318
1532
  if (phase === "listening" || phase === "speaking") {
1319
- return "border border-og-accent/45 bg-og-accent text-og-accent-fg shadow-og-sm hover:bg-og-accent-strong";
1533
+ return "border border-og-primary-border bg-og-primary text-og-primary-fg hover:bg-og-primary-hover";
1320
1534
  }
1321
1535
  if (phase === "blocked" || phase === "error") {
1322
1536
  return "border border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15";
@@ -1330,7 +1544,7 @@ function voiceButtonTone(phase: RealtimeVisualPhase): string {
1330
1544
 
1331
1545
  function voiceChevronTone(phase: RealtimeVisualPhase): string {
1332
1546
  if (phase === "listening" || phase === "speaking") {
1333
- return "border border-l-0 border-og-accent/45 bg-og-accent text-og-accent-fg hover:bg-og-accent-strong";
1547
+ return "border border-l-0 border-og-primary-border bg-og-primary text-og-primary-fg hover:bg-og-primary-hover";
1334
1548
  }
1335
1549
  if (phase === "blocked" || phase === "error") {
1336
1550
  return "border border-l-0 border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15";
@@ -0,0 +1,48 @@
1
+ import type { AuthNeededItem } from "./timeline/types";
2
+ import type { CapabilityCatalogItem } from "@opengeni/sdk";
3
+
4
+ /** Recovery events identify runtime servers/connections, while recommendation
5
+ * events already carry a catalog id. Never guess among same-domain accounts. */
6
+ export function sessionAuthRecommendation(
7
+ item: AuthNeededItem,
8
+ catalog: CapabilityCatalogItem[],
9
+ ): AuthNeededItem | undefined {
10
+ if (
11
+ item.authoritySource === "host" ||
12
+ item.reason === "unsupported_auth" ||
13
+ item.reason === "resource_scope_unavailable"
14
+ )
15
+ return undefined;
16
+ if (item.capability) return item;
17
+ const recoveryServerId = item.canonicalServerId ?? item.serverId;
18
+ const matches = catalog.filter(
19
+ (candidate) =>
20
+ (recoveryServerId !== null &&
21
+ candidate.runtime.mcpServerId === recoveryServerId &&
22
+ recoveryServerId !== "opengeni") ||
23
+ (item.connectionId !== null && candidate.connectionRef?.connectionId === item.connectionId),
24
+ );
25
+ if (matches.length !== 1) return undefined;
26
+ const entry = matches[0]!;
27
+ const personalAccess = item.reason === "personal_authority_unavailable";
28
+ if (
29
+ personalAccess &&
30
+ ((item.connectionSubjectScope ?? entry.connectionRef?.subjectScope) !== "subject" ||
31
+ entry.connectionRef?.authoritySource === "host")
32
+ )
33
+ return undefined;
34
+ return {
35
+ ...item,
36
+ capability: {
37
+ id: entry.id,
38
+ name: entry.name,
39
+ kind: entry.kind,
40
+ source: entry.source,
41
+ action: "connect",
42
+ rationale: personalAccess
43
+ ? "Review permission to use your personal account in this conversation."
44
+ : "Reconnect this integration to use its tools in this conversation.",
45
+ requiredVariables: [],
46
+ },
47
+ };
48
+ }