@opengeni/react 3.1.0 → 3.1.2

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 (863) hide show
  1. package/README.md +769 -22
  2. package/dist/accounts.js +89 -11
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/approvals.d.ts +2 -1
  5. package/dist/artifacts-document.js +5 -3
  6. package/dist/artifacts-presentation.js +5 -3
  7. package/dist/artifacts-spreadsheet.d.ts +1 -1
  8. package/dist/artifacts-spreadsheet.js +5 -3
  9. package/dist/artifacts.d.ts +5 -1
  10. package/dist/artifacts.js +536 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-ZWR6MWJ7.js +19 -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-BO2IWXVK.js +14 -0
  16. package/dist/chunk-2DDJ6YH6.js +41 -0
  17. package/dist/chunk-2DDJ6YH6.js.map +1 -0
  18. package/dist/chunk-2HVLQ26H.js +183 -0
  19. package/dist/chunk-2HVLQ26H.js.map +1 -0
  20. package/dist/{chunk-RGALCTWO.js → chunk-2I6R3GCZ.js} +4285 -3980
  21. package/dist/chunk-2I6R3GCZ.js.map +1 -0
  22. package/dist/{chunk-D3UIAJKY.js → chunk-2SFFYIH3.js} +1179 -166
  23. package/dist/chunk-2SFFYIH3.js.map +1 -0
  24. package/dist/chunk-3PVDYTTB.js +24 -0
  25. package/dist/chunk-3PVDYTTB.js.map +1 -0
  26. package/dist/chunk-3UZCWK46.js +298 -0
  27. package/dist/chunk-3UZCWK46.js.map +1 -0
  28. package/dist/chunk-47CKUXTW.js +293 -0
  29. package/dist/chunk-47CKUXTW.js.map +1 -0
  30. package/dist/chunk-4QYP6QUI.js +109 -0
  31. package/dist/chunk-4QYP6QUI.js.map +1 -0
  32. package/dist/chunk-5EY26VZ7.js +1053 -0
  33. package/dist/chunk-5EY26VZ7.js.map +1 -0
  34. package/dist/chunk-5I4VRWBB.js +56 -0
  35. package/dist/chunk-5I4VRWBB.js.map +1 -0
  36. package/dist/chunk-5WOR7UCL.js +191 -0
  37. package/dist/chunk-5WOR7UCL.js.map +1 -0
  38. package/dist/chunk-5YJLGOM5.js +51 -0
  39. package/dist/chunk-5YJLGOM5.js.map +1 -0
  40. package/dist/chunk-6JFN3OWG.js +386 -0
  41. package/dist/chunk-6JFN3OWG.js.map +1 -0
  42. package/dist/chunk-7QJT5O4S.js +35 -0
  43. package/dist/chunk-7QJT5O4S.js.map +1 -0
  44. package/dist/chunk-A55KV72M.js +402 -0
  45. package/dist/chunk-A55KV72M.js.map +1 -0
  46. package/dist/chunk-ADWCLI4G.js +2028 -0
  47. package/dist/chunk-ADWCLI4G.js.map +1 -0
  48. package/dist/chunk-B27E3V37.js +29 -0
  49. package/dist/chunk-B27E3V37.js.map +1 -0
  50. package/dist/chunk-B7TC2A33.js +83 -0
  51. package/dist/chunk-B7TC2A33.js.map +1 -0
  52. package/dist/chunk-BLL56F7R.js +385 -0
  53. package/dist/chunk-BLL56F7R.js.map +1 -0
  54. package/dist/chunk-BOFEQC6K.js +162 -0
  55. package/dist/chunk-BOFEQC6K.js.map +1 -0
  56. package/dist/chunk-CM7LVUKC.js +35 -0
  57. package/dist/chunk-CM7LVUKC.js.map +1 -0
  58. package/dist/chunk-CORUP6JB.js +122 -0
  59. package/dist/chunk-CORUP6JB.js.map +1 -0
  60. package/dist/chunk-CSX5FFKZ.js +35 -0
  61. package/dist/chunk-CSX5FFKZ.js.map +1 -0
  62. package/dist/chunk-EGVHJKGJ.js +3125 -0
  63. package/dist/chunk-EGVHJKGJ.js.map +1 -0
  64. package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
  65. package/dist/chunk-G76LSA76.js.map +1 -0
  66. package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
  67. package/dist/chunk-GQMRL52F.js.map +1 -0
  68. package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
  69. package/dist/chunk-GUUXOISA.js.map +1 -0
  70. package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
  71. package/dist/chunk-I7X2P4FU.js.map +1 -0
  72. package/dist/chunk-IGFZFLI2.js +1390 -0
  73. package/dist/chunk-IGFZFLI2.js.map +1 -0
  74. package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
  75. package/dist/chunk-IMSUVYQB.js.map +1 -0
  76. package/dist/chunk-IOYHDEP3.js +38 -0
  77. package/dist/chunk-IOYHDEP3.js.map +1 -0
  78. package/dist/chunk-IZV5FTJC.js +55 -0
  79. package/dist/chunk-IZV5FTJC.js.map +1 -0
  80. package/dist/chunk-KF33GTWN.js +343 -0
  81. package/dist/chunk-KF33GTWN.js.map +1 -0
  82. package/dist/chunk-KSGQ5ODA.js +457 -0
  83. package/dist/chunk-KSGQ5ODA.js.map +1 -0
  84. package/dist/{chunk-OAM4WAAM.js → chunk-KZC6QRNR.js} +1513 -697
  85. package/dist/chunk-KZC6QRNR.js.map +1 -0
  86. package/dist/chunk-LJUMYUBO.js +218 -0
  87. package/dist/chunk-LJUMYUBO.js.map +1 -0
  88. package/dist/chunk-LSW2OJVV.js +380 -0
  89. package/dist/chunk-LSW2OJVV.js.map +1 -0
  90. package/dist/chunk-M357MHH3.js +2 -0
  91. package/dist/chunk-M357MHH3.js.map +1 -0
  92. package/dist/chunk-MK2TQO4Y.js +24 -0
  93. package/dist/chunk-MK2TQO4Y.js.map +1 -0
  94. package/dist/chunk-N7S72EXK.js +25 -0
  95. package/dist/chunk-N7S72EXK.js.map +1 -0
  96. package/dist/{chunk-XXWH2JLC.js → chunk-NKMYZFHA.js} +616 -621
  97. package/dist/chunk-NKMYZFHA.js.map +1 -0
  98. package/dist/chunk-NX4ADH73.js +14 -0
  99. package/dist/chunk-NX4ADH73.js.map +1 -0
  100. package/dist/chunk-O7F6UJO4.js +71 -0
  101. package/dist/chunk-O7F6UJO4.js.map +1 -0
  102. package/dist/chunk-OVB5WIG5.js +14064 -0
  103. package/dist/chunk-OVB5WIG5.js.map +1 -0
  104. package/dist/chunk-OYQQJL3J.js +16 -0
  105. package/dist/chunk-OYQQJL3J.js.map +1 -0
  106. package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
  107. package/dist/chunk-P4BNUO57.js.map +1 -0
  108. package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
  109. package/dist/chunk-PEHTX3V7.js.map +1 -0
  110. package/dist/chunk-PMV53IMM.js +26 -0
  111. package/dist/chunk-PMV53IMM.js.map +1 -0
  112. package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
  113. package/dist/chunk-PYEOPA4M.js.map +1 -0
  114. package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
  115. package/dist/chunk-QHUE7E4N.js.map +1 -0
  116. package/dist/chunk-QV3DJVRZ.js +11 -0
  117. package/dist/chunk-QV3DJVRZ.js.map +1 -0
  118. package/dist/chunk-R5SBNG7S.js +810 -0
  119. package/dist/chunk-R5SBNG7S.js.map +1 -0
  120. package/dist/chunk-RI42H5IU.js +326 -0
  121. package/dist/chunk-RI42H5IU.js.map +1 -0
  122. package/dist/chunk-S2QH6EZ5.js +211 -0
  123. package/dist/chunk-S2QH6EZ5.js.map +1 -0
  124. package/dist/chunk-SHLZMAJN.js +304 -0
  125. package/dist/chunk-SHLZMAJN.js.map +1 -0
  126. package/dist/chunk-TGXK4BAZ.js +293 -0
  127. package/dist/chunk-TGXK4BAZ.js.map +1 -0
  128. package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
  129. package/dist/chunk-TNEZNMSN.js.map +1 -0
  130. package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
  131. package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
  132. package/dist/chunk-UNJPZGNK.js +63 -0
  133. package/dist/chunk-UNJPZGNK.js.map +1 -0
  134. package/dist/{chunk-MZ2G2XBA.js → chunk-V5ZUJT2T.js} +205 -45
  135. package/dist/chunk-V5ZUJT2T.js.map +1 -0
  136. package/dist/chunk-VIUEOHXY.js +394 -0
  137. package/dist/chunk-VIUEOHXY.js.map +1 -0
  138. package/dist/chunk-WIUKB3LD.js +1911 -0
  139. package/dist/chunk-WIUKB3LD.js.map +1 -0
  140. package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
  141. package/dist/chunk-WNN7NO2N.js.map +1 -0
  142. package/dist/{chunk-YJFGAFBD.js → chunk-X5UVUIMF.js} +1892 -1223
  143. package/dist/chunk-X5UVUIMF.js.map +1 -0
  144. package/dist/chunk-XDA5QJE7.js +402 -0
  145. package/dist/chunk-XDA5QJE7.js.map +1 -0
  146. package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
  147. package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
  148. package/dist/chunk-XHF7OYAN.js +1150 -0
  149. package/dist/chunk-XHF7OYAN.js.map +1 -0
  150. package/dist/chunk-YSRBFJMQ.js +43 -0
  151. package/dist/chunk-YSRBFJMQ.js.map +1 -0
  152. package/dist/chunk-ZOZAPAUO.js +174 -0
  153. package/dist/chunk-ZOZAPAUO.js.map +1 -0
  154. package/dist/chunk-ZQV5W7YC.js +809 -0
  155. package/dist/chunk-ZQV5W7YC.js.map +1 -0
  156. package/dist/chunk-ZUWF4NF7.js +13 -0
  157. package/dist/chunk-ZUWF4NF7.js.map +1 -0
  158. package/dist/client.d.ts +16 -7
  159. package/dist/clipboard.js +3 -1
  160. package/dist/commands/types.d.ts +2 -0
  161. package/dist/components/anthropic-mark.d.ts +3 -0
  162. package/dist/components/approval-surface.d.ts +19 -6
  163. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  164. package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
  165. package/dist/components/artifacts/artifact-surface.d.ts +4 -2
  166. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  167. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  168. package/dist/components/artifacts/document-editor.d.ts +4 -2
  169. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  170. package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
  171. package/dist/components/artifacts/editable-document.d.ts +1 -1
  172. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  173. package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
  174. package/dist/components/artifacts/index.d.ts +9 -2
  175. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  176. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  177. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  178. package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
  179. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  180. package/dist/components/artifacts/site-view.d.ts +26 -0
  181. package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
  182. package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
  183. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  184. package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
  185. package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
  186. package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
  187. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  188. package/dist/components/browser-select-control.d.ts +16 -0
  189. package/dist/components/browser-viewer.d.ts +11 -2
  190. package/dist/components/chat-composer.d.ts +21 -3
  191. package/dist/components/child-session-link.d.ts +9 -0
  192. package/dist/components/claude-mark.d.ts +3 -0
  193. package/dist/components/code-editor.d.ts +1 -4
  194. package/dist/components/composer-transcription-control.d.ts +7 -0
  195. package/dist/components/composer.d.ts +34 -67
  196. package/dist/components/computer-viewer.d.ts +1 -1
  197. package/dist/components/copy-button.d.ts +3 -1
  198. package/dist/components/desktop-viewer.d.ts +1 -1
  199. package/dist/components/fleet-tile.d.ts +2 -2
  200. package/dist/components/grok-mark.d.ts +26 -0
  201. package/dist/components/human-input-form.d.ts +28 -32
  202. package/dist/components/human-input-surface.d.ts +7 -2
  203. package/dist/components/linkified-text.d.ts +18 -0
  204. package/dist/components/machine-input-display.d.ts +22 -1
  205. package/dist/components/machines/agent-status-icon.d.ts +6 -0
  206. package/dist/components/machines/machine-detail.d.ts +7 -1
  207. package/dist/components/machines/machine-status.d.ts +48 -0
  208. package/dist/components/markdown-table-layout.d.ts +18 -0
  209. package/dist/components/markdown.d.ts +37 -4
  210. package/dist/components/message-timeline.d.ts +86 -7
  211. package/dist/components/model-mark.d.ts +29 -0
  212. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  213. package/dist/components/model-policy-picker.d.ts +41 -25
  214. package/dist/components/new-conversation.d.ts +32 -0
  215. package/dist/components/open-geni-chat.d.ts +73 -0
  216. package/dist/components/open-geni-links.d.ts +68 -0
  217. package/dist/components/openrouter-mark.d.ts +6 -0
  218. package/dist/components/opper-mark.d.ts +7 -0
  219. package/dist/components/preview-loading.d.ts +2 -0
  220. package/dist/components/provider-recovery-notice.d.ts +16 -0
  221. package/dist/components/queue-item-content.d.ts +9 -0
  222. package/dist/components/rehype-secret-refs.d.ts +23 -0
  223. package/dist/components/remark-soft-line-breaks.d.ts +38 -0
  224. package/dist/components/sandbox-files.d.ts +3 -1
  225. package/dist/components/sandbox-workspace.d.ts +18 -0
  226. package/dist/components/secret-question-field.d.ts +31 -0
  227. package/dist/components/secret-ref-chip.d.ts +35 -0
  228. package/dist/components/session-capability-frame.d.ts +37 -0
  229. package/dist/components/session-chrome.d.ts +57 -8
  230. package/dist/components/session-commands-panel.d.ts +6 -0
  231. package/dist/components/session-commands.d.ts +6 -0
  232. package/dist/components/session-connection-request.d.ts +8 -0
  233. package/dist/components/session-conversation.d.ts +157 -0
  234. package/dist/components/session-list.d.ts +39 -0
  235. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  236. package/dist/components/session-proxy-scope.d.ts +35 -0
  237. package/dist/components/session-status.d.ts +4 -1
  238. package/dist/components/session-usage-limit-notice.d.ts +39 -0
  239. package/dist/components/timeline-anchor.d.ts +24 -0
  240. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  241. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  242. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  243. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  244. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  245. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  246. package/dist/components/timeline-annotations.d.ts +13 -3
  247. package/dist/components/timeline-reading-progress.d.ts +11 -0
  248. package/dist/components/timeline-search.d.ts +34 -0
  249. package/dist/components/timeline-settlement.d.ts +16 -0
  250. package/dist/components/tip-follow.d.ts +16 -0
  251. package/dist/components/tool-action-review.d.ts +47 -0
  252. package/dist/components/tool-review-history.d.ts +25 -0
  253. package/dist/components/usage-limit-notice.d.ts +49 -0
  254. package/dist/components/usage-member-list.d.ts +91 -0
  255. package/dist/components/usage-meter.d.ts +73 -0
  256. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  257. package/dist/components/user-message-body.d.ts +10 -1
  258. package/dist/composer-messages.d.ts +74 -0
  259. package/dist/composer-messages.js +9 -0
  260. package/dist/composer-messages.js.map +1 -0
  261. package/dist/composer-voice-events.d.ts +8 -0
  262. package/dist/composer.d.ts +5 -4
  263. package/dist/composer.js +26 -13
  264. package/dist/computer-viewer-GMLDXPON.js +20 -0
  265. package/dist/computer-viewer-GMLDXPON.js.map +1 -0
  266. package/dist/connect-account-identity.d.ts +8 -0
  267. package/dist/connect-accounts.d.ts +15 -0
  268. package/dist/connect-chooser.d.ts +18 -0
  269. package/dist/connect-panel.d.ts +18 -0
  270. package/dist/connect-setup.d.ts +18 -0
  271. package/dist/connect.d.ts +21 -0
  272. package/dist/connect.js +2149 -0
  273. package/dist/connect.js.map +1 -0
  274. package/dist/connection-catalog.d.ts +38 -0
  275. package/dist/connection-discovery.d.ts +12 -0
  276. package/dist/connection-installed.d.ts +17 -0
  277. package/dist/connection-logo.d.ts +9 -0
  278. package/dist/connection-service-logo.d.ts +8 -0
  279. package/dist/connection-service-presentation.d.ts +13 -0
  280. package/dist/connection-skeleton.d.ts +5 -0
  281. package/dist/connection-type-picker.d.ts +6 -0
  282. package/dist/conversation-timeline.d.ts +5 -0
  283. package/dist/desktop.d.ts +7 -0
  284. package/dist/desktop.js +27 -0
  285. package/dist/desktop.js.map +1 -0
  286. package/dist/device-authorization.d.ts +23 -0
  287. package/dist/diffs.d.ts +8 -0
  288. package/dist/diffs.js +15 -0
  289. package/dist/diffs.js.map +1 -0
  290. package/dist/discovery-cache.d.ts +5 -0
  291. package/dist/editor.d.ts +7 -0
  292. package/dist/editor.js +22 -0
  293. package/dist/editor.js.map +1 -0
  294. package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
  295. package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
  296. package/dist/embedded-voice-RPHPYVBT.js +18 -0
  297. package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
  298. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
  299. package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
  300. package/dist/hooks/latest-question.d.ts +25 -0
  301. package/dist/hooks/shared-machines-list.d.ts +4 -0
  302. package/dist/hooks/shared-query.d.ts +113 -0
  303. package/dist/hooks/use-attached-browsers.d.ts +1 -1
  304. package/dist/hooks/use-auth-runs.d.ts +1 -4
  305. package/dist/hooks/use-available-models.d.ts +1 -1
  306. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  307. package/dist/hooks/use-browser-session.d.ts +12 -1
  308. package/dist/hooks/use-client-config-flags.d.ts +49 -0
  309. package/dist/hooks/use-codex-accounts.d.ts +59 -10
  310. package/dist/hooks/use-composer.d.ts +24 -2
  311. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  312. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  313. package/dist/hooks/use-computer-session.d.ts +4 -0
  314. package/dist/hooks/use-connect.d.ts +23 -0
  315. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  316. package/dist/hooks/use-file-attachments.d.ts +12 -0
  317. package/dist/hooks/use-goal.d.ts +2 -1
  318. package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
  319. package/dist/hooks/use-new-conversation.d.ts +56 -0
  320. package/dist/hooks/use-new-session-draft.d.ts +74 -0
  321. package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
  322. package/dist/hooks/use-sandbox-files.d.ts +4 -1
  323. package/dist/hooks/use-session-conversation.d.ts +49 -0
  324. package/dist/hooks/use-session-events.d.ts +28 -7
  325. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  326. package/dist/hooks/use-session-model-account.d.ts +48 -0
  327. package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
  328. package/dist/hooks/use-terminal-stream.d.ts +11 -5
  329. package/dist/hooks/use-usage.d.ts +40 -0
  330. package/dist/hooks/use-vaults.d.ts +53 -0
  331. package/dist/hooks/use-voice-input.d.ts +8 -1
  332. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  333. package/dist/hooks/use-workspace-sessions.d.ts +22 -5
  334. package/dist/human-input-model.d.ts +122 -0
  335. package/dist/identity-link-accounts.d.ts +11 -0
  336. package/dist/identity-link-consent.d.ts +18 -0
  337. package/dist/index.d.ts +82 -20
  338. package/dist/index.js +2350 -6605
  339. package/dist/index.js.map +1 -1
  340. package/dist/interaction.d.ts +1 -1
  341. package/dist/interaction.js +14 -24
  342. package/dist/interaction.js.map +1 -1
  343. package/dist/latest-question-R77KWSUP.js +118 -0
  344. package/dist/latest-question-R77KWSUP.js.map +1 -0
  345. package/dist/lib/clipboard.d.ts +7 -0
  346. package/dist/lib/error-message.d.ts +7 -0
  347. package/dist/lib/format.d.ts +58 -4
  348. package/dist/lib/host-theme.d.ts +77 -0
  349. package/dist/lib/interaction-errors.d.ts +3 -0
  350. package/dist/lib/menu-styles.d.ts +22 -0
  351. package/dist/lib/notify-observer.d.ts +2 -0
  352. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  353. package/dist/lib/provider-recovery.d.ts +55 -0
  354. package/dist/lib/scrollbars.d.ts +11 -0
  355. package/dist/lib/terminal-input-readiness.d.ts +11 -0
  356. package/dist/lib/transient-retry.d.ts +25 -0
  357. package/dist/lib/workbench-peers.d.ts +36 -0
  358. package/dist/lib/xterm-theme.d.ts +7 -5
  359. package/dist/machines.js +9 -5
  360. package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
  361. package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
  362. package/dist/mcp-connection-status.d.ts +14 -0
  363. package/dist/model-mark-paths.d.ts +34 -0
  364. package/dist/model-mark-paths.js +16 -0
  365. package/dist/model-mark-paths.js.map +1 -0
  366. package/dist/model-picker-model.d.ts +111 -0
  367. package/dist/model-picker-model.js +25 -0
  368. package/dist/model-picker-model.js.map +1 -0
  369. package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
  370. package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
  371. package/dist/model-policy.d.ts +30 -3
  372. package/dist/model-policy.js +14 -1
  373. package/dist/native-previews.d.ts +28 -0
  374. package/dist/native-previews.js +82 -0
  375. package/dist/native-previews.js.map +1 -0
  376. package/dist/new-session-draft.d.ts +7 -0
  377. package/dist/new-session-draft.js +639 -0
  378. package/dist/new-session-draft.js.map +1 -0
  379. package/dist/notification-text.d.ts +27 -0
  380. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
  381. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
  382. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
  383. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
  384. package/dist/older-history.d.ts +3 -2
  385. package/dist/organization-model.d.ts +32 -0
  386. package/dist/organization-model.js +65 -0
  387. package/dist/organization-model.js.map +1 -0
  388. package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
  389. package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
  390. package/dist/plugin-details.d.ts +14 -0
  391. package/dist/plugin-discovery.d.ts +25 -0
  392. package/dist/preview-loading-paint.d.ts +20 -0
  393. package/dist/provider.d.ts +25 -2
  394. package/dist/queue-presentation-model.d.ts +72 -0
  395. package/dist/queue-presentation-model.js +38 -0
  396. package/dist/queue-presentation-model.js.map +1 -0
  397. package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
  398. package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
  399. package/dist/realtime/embedded-new-voice.d.ts +1 -0
  400. package/dist/realtime/embedded-voice.d.ts +1 -0
  401. package/dist/realtime/realtime-control.d.ts +4 -65
  402. package/dist/realtime/session-realtime.d.ts +78 -0
  403. package/dist/realtime.js +25 -1294
  404. package/dist/realtime.js.map +1 -1
  405. package/dist/sandbox-files-O27IPOZW.js +21 -0
  406. package/dist/sandbox-files-O27IPOZW.js.map +1 -0
  407. package/dist/sandbox-label-model.d.ts +30 -0
  408. package/dist/sandbox-label-model.js +20 -0
  409. package/dist/sandbox-label-model.js.map +1 -0
  410. package/dist/scrollbars.d.ts +1 -0
  411. package/dist/scrollbars.js +10 -0
  412. package/dist/scrollbars.js.map +1 -0
  413. package/dist/secret-reference-label.d.ts +14 -0
  414. package/dist/secrets-ui.d.ts +57 -0
  415. package/dist/session-agents-model.d.ts +10 -0
  416. package/dist/session-agents-model.js +25 -0
  417. package/dist/session-agents-model.js.map +1 -0
  418. package/dist/session-attention-model.d.ts +8 -0
  419. package/dist/session-attention-model.js +47 -0
  420. package/dist/session-attention-model.js.map +1 -0
  421. package/dist/session-auth-recommendation.d.ts +5 -0
  422. package/dist/session-capability-policy.d.ts +31 -0
  423. package/dist/session-feedback-model.d.ts +20 -0
  424. package/dist/session-feedback-model.js +56 -0
  425. package/dist/session-feedback-model.js.map +1 -0
  426. package/dist/session-list-model.d.ts +138 -0
  427. package/dist/session-list-model.js +274 -0
  428. package/dist/session-list-model.js.map +1 -0
  429. package/dist/session-realtime-7DJOIHQW.js +21 -0
  430. package/dist/session-realtime-7DJOIHQW.js.map +1 -0
  431. package/dist/session-realtime.d.ts +7 -0
  432. package/dist/session-realtime.js +19 -0
  433. package/dist/session-realtime.js.map +1 -0
  434. package/dist/session-status-model.d.ts +36 -0
  435. package/dist/session-ui.d.ts +39 -1
  436. package/dist/session-ui.js +126 -12
  437. package/dist/session-ui.js.map +1 -1
  438. package/dist/session.d.ts +8 -2
  439. package/dist/session.js +35 -20
  440. package/dist/site-snapshot.d.ts +14 -0
  441. package/dist/sites-ui.d.ts +24 -0
  442. package/dist/sites.d.ts +3 -0
  443. package/dist/sites.js +14 -0
  444. package/dist/sites.js.map +1 -0
  445. package/dist/skill-discovery.d.ts +47 -0
  446. package/dist/terminal.d.ts +8 -0
  447. package/dist/terminal.js +32 -0
  448. package/dist/terminal.js.map +1 -0
  449. package/dist/testing/session-scenarios.d.ts +10 -0
  450. package/dist/testing/session-scenarios.js +367 -0
  451. package/dist/testing/session-scenarios.js.map +1 -0
  452. package/dist/timeline/activity-rail.d.ts +11 -2
  453. package/dist/timeline/agent-identity.d.ts +30 -0
  454. package/dist/timeline/agent-row.d.ts +31 -0
  455. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  456. package/dist/timeline/compaction-copy.d.ts +46 -0
  457. package/dist/timeline/entrance.d.ts +13 -1
  458. package/dist/timeline/focus-sequence.d.ts +9 -0
  459. package/dist/timeline/genie-copy.d.ts +3 -0
  460. package/dist/timeline/genie-loading.d.ts +47 -0
  461. package/dist/timeline/index.d.ts +10 -5
  462. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  463. package/dist/timeline/message-sender.d.ts +19 -0
  464. package/dist/timeline/notice-presentation.d.ts +13 -0
  465. package/dist/timeline/parsers.d.ts +11 -0
  466. package/dist/timeline/patch-apply-command.d.ts +18 -0
  467. package/dist/timeline/platform-activity-presentation.d.ts +21 -0
  468. package/dist/timeline/platform-activity-row.d.ts +1 -2
  469. package/dist/timeline/presented-image.d.ts +11 -0
  470. package/dist/timeline/projection.d.ts +31 -2
  471. package/dist/timeline/provider-logo.d.ts +15 -0
  472. package/dist/timeline/question-nav-model.d.ts +23 -0
  473. package/dist/timeline/registry.d.ts +12 -1
  474. package/dist/timeline/retained-image.d.ts +18 -0
  475. package/dist/timeline/retained-loaders.d.ts +27 -0
  476. package/dist/timeline/rolling-activity.d.ts +11 -0
  477. package/dist/timeline/screenshot-lightbox.d.ts +23 -1
  478. package/dist/timeline/session-usage-limit-row.d.ts +11 -0
  479. package/dist/timeline/shared.d.ts +4 -1
  480. package/dist/timeline/startup-dispatch-details.d.ts +5 -0
  481. package/dist/timeline/startup-preference.d.ts +3 -0
  482. package/dist/timeline/startup-timings.d.ts +4 -0
  483. package/dist/timeline/tool-display-name.d.ts +5 -2
  484. package/dist/timeline/tool-presentation.d.ts +172 -0
  485. package/dist/timeline/turn-summary-model.d.ts +95 -0
  486. package/dist/timeline/turn-summary.d.ts +20 -54
  487. package/dist/timeline/types.d.ts +179 -7
  488. package/dist/timeline/work-presentation.d.ts +60 -0
  489. package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
  490. package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
  491. package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
  492. package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
  493. package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
  494. package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
  495. package/dist/timeline-model.d.ts +29 -0
  496. package/dist/timeline-model.js +254 -0
  497. package/dist/timeline-model.js.map +1 -0
  498. package/dist/usage/allowance-copy.d.ts +25 -0
  499. package/dist/usage/session-usage-limit.d.ts +88 -0
  500. package/dist/usage/summary.d.ts +35 -0
  501. package/dist/usage.d.ts +17 -0
  502. package/dist/usage.js +1187 -0
  503. package/dist/usage.js.map +1 -0
  504. package/dist/voice-recording-owner.d.ts +7 -0
  505. package/package.json +107 -7
  506. package/src/accounts.tsx +116 -14
  507. package/src/approvals.ts +8 -1
  508. package/src/artifacts-spreadsheet.ts +1 -0
  509. package/src/artifacts.ts +44 -0
  510. package/src/assets/README.md +8 -0
  511. package/src/assets/gmail.ico +0 -0
  512. package/src/assets/outlook.ico +0 -0
  513. package/src/capability-catalog-row.tsx +94 -0
  514. package/src/capability-logo-fallback.ts +22 -0
  515. package/src/client.ts +20 -31
  516. package/src/commands/registry.ts +18 -15
  517. package/src/commands/types.ts +2 -0
  518. package/src/components/anthropic-mark.tsx +10 -0
  519. package/src/components/approval-surface.tsx +401 -138
  520. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  521. package/src/components/artifacts/artifact-sandbox.tsx +189 -0
  522. package/src/components/artifacts/artifact-surface.tsx +40 -20
  523. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  524. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  525. package/src/components/artifacts/document-editor.tsx +141 -16
  526. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  527. package/src/components/artifacts/editable-artifact-view.tsx +197 -0
  528. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  529. package/src/components/artifacts/editable-document.tsx +37 -36
  530. package/src/components/artifacts/editable-presentation.tsx +36 -18
  531. package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
  532. package/src/components/artifacts/index.ts +45 -0
  533. package/src/components/artifacts/inline-html-document.ts +24 -0
  534. package/src/components/artifacts/latest-task-runner.ts +49 -0
  535. package/src/components/artifacts/presentation-editor.tsx +323 -67
  536. package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
  537. package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
  538. package/src/components/artifacts/site-view.tsx +121 -0
  539. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  540. package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
  541. package/src/components/artifacts/spreadsheet-download.tsx +109 -0
  542. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  543. package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
  544. package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
  545. package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
  546. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  547. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  548. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  549. package/src/components/browser-select-control.tsx +312 -0
  550. package/src/components/browser-viewer.tsx +778 -318
  551. package/src/components/chat-composer.tsx +47 -5
  552. package/src/components/child-session-link.tsx +36 -0
  553. package/src/components/claude-mark.tsx +11 -0
  554. package/src/components/code-editor.tsx +13 -16
  555. package/src/components/composer-transcription-control.tsx +128 -30
  556. package/src/components/composer.tsx +404 -195
  557. package/src/components/computer-viewer.tsx +880 -253
  558. package/src/components/copy-button.tsx +13 -5
  559. package/src/components/desktop-viewer.tsx +1 -1
  560. package/src/components/enrollment-consent.tsx +1 -1
  561. package/src/components/enrollment-device-flow.tsx +1 -1
  562. package/src/components/file-browser.tsx +10 -14
  563. package/src/components/fleet-tile.tsx +9 -18
  564. package/src/components/generated-video-player.tsx +4 -2
  565. package/src/components/grok-mark.tsx +34 -0
  566. package/src/components/human-input-form.tsx +590 -283
  567. package/src/components/human-input-surface.tsx +11 -0
  568. package/src/components/interaction-intervention-banner.tsx +2 -2
  569. package/src/components/linkified-text.tsx +79 -0
  570. package/src/components/machine-card.tsx +35 -78
  571. package/src/components/machine-dock-bar.tsx +1 -1
  572. package/src/components/machine-input-display.ts +197 -3
  573. package/src/components/machines/agent-status-icon.tsx +31 -0
  574. package/src/components/machines/machine-detail.tsx +200 -31
  575. package/src/components/machines/machine-operation-policy.tsx +1 -1
  576. package/src/components/machines/machine-status.ts +241 -0
  577. package/src/components/machines-dashboard.tsx +2 -17
  578. package/src/components/markdown-table-layout.ts +143 -0
  579. package/src/components/markdown.tsx +466 -129
  580. package/src/components/message-timeline.tsx +2567 -728
  581. package/src/components/model-mark.tsx +102 -0
  582. package/src/components/model-picker.tsx +15 -4
  583. package/src/components/model-policy-picker-menu.tsx +371 -0
  584. package/src/components/model-policy-picker.tsx +256 -412
  585. package/src/components/new-conversation.tsx +221 -0
  586. package/src/components/open-geni-chat.tsx +309 -0
  587. package/src/components/open-geni-links.tsx +179 -0
  588. package/src/components/openrouter-mark.tsx +13 -0
  589. package/src/components/opper-mark.tsx +18 -0
  590. package/src/components/pierre-diff.tsx +41 -16
  591. package/src/components/pierre-file.tsx +35 -10
  592. package/src/components/preview-loading.tsx +109 -0
  593. package/src/components/provider-recovery-notice.tsx +49 -0
  594. package/src/components/queue-item-content.ts +14 -0
  595. package/src/components/queue-surface-implementation.tsx +51 -356
  596. package/src/components/queue-surface-state.tsx +3 -1
  597. package/src/components/rehype-secret-refs.ts +98 -0
  598. package/src/components/remark-soft-line-breaks.ts +166 -0
  599. package/src/components/sandbox-files.tsx +91 -15
  600. package/src/components/sandbox-terminal.tsx +84 -13
  601. package/src/components/sandbox-workspace.tsx +147 -51
  602. package/src/components/secret-question-field.tsx +324 -0
  603. package/src/components/secret-ref-chip.tsx +185 -0
  604. package/src/components/session-capability-frame.tsx +197 -0
  605. package/src/components/session-chrome.tsx +842 -251
  606. package/src/components/session-commands-panel.tsx +126 -0
  607. package/src/components/session-commands.tsx +18 -0
  608. package/src/components/session-connection-request.tsx +97 -0
  609. package/src/components/session-conversation.tsx +876 -0
  610. package/src/components/session-list.tsx +257 -0
  611. package/src/components/session-mcp-capability-card.tsx +680 -0
  612. package/src/components/session-proxy-scope.tsx +153 -0
  613. package/src/components/session-status.tsx +26 -17
  614. package/src/components/session-usage-limit-notice.tsx +174 -0
  615. package/src/components/timeline-anchor.tsx +119 -0
  616. package/src/components/timeline-annotation-chrome.tsx +196 -0
  617. package/src/components/timeline-annotation-layout.ts +268 -0
  618. package/src/components/timeline-annotation-markers.tsx +185 -0
  619. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  620. package/src/components/timeline-annotation-selection.tsx +106 -54
  621. package/src/components/timeline-annotation-shared.ts +245 -0
  622. package/src/components/timeline-annotations-dialog.tsx +185 -128
  623. package/src/components/timeline-annotations.tsx +189 -45
  624. package/src/components/timeline-reading-progress.ts +80 -0
  625. package/src/components/timeline-search.tsx +168 -0
  626. package/src/components/timeline-settlement.ts +60 -0
  627. package/src/components/tip-follow.ts +52 -0
  628. package/src/components/tool-action-review.tsx +650 -0
  629. package/src/components/tool-review-history.tsx +88 -0
  630. package/src/components/tooltip.tsx +38 -5
  631. package/src/components/usage-limit-notice.tsx +179 -0
  632. package/src/components/usage-member-list.tsx +792 -0
  633. package/src/components/usage-meter.tsx +382 -0
  634. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  635. package/src/components/user-message-body.tsx +27 -2
  636. package/src/components/workspace-dock.tsx +18 -1
  637. package/src/composer-messages.ts +150 -0
  638. package/src/composer-voice-events.ts +12 -0
  639. package/src/composer.ts +6 -1
  640. package/src/connect-account-identity.tsx +34 -0
  641. package/src/connect-accounts.tsx +233 -0
  642. package/src/connect-chooser.tsx +336 -0
  643. package/src/connect-panel.tsx +99 -0
  644. package/src/connect-setup.tsx +355 -0
  645. package/src/connect.ts +60 -0
  646. package/src/connection-assets.d.ts +4 -0
  647. package/src/connection-catalog.tsx +162 -0
  648. package/src/connection-discovery.tsx +238 -0
  649. package/src/connection-installed.tsx +51 -0
  650. package/src/connection-logo.tsx +37 -0
  651. package/src/connection-service-logo.tsx +55 -0
  652. package/src/connection-service-presentation.ts +46 -0
  653. package/src/connection-skeleton.tsx +16 -0
  654. package/src/connection-type-picker.tsx +36 -0
  655. package/src/conversation-timeline.ts +92 -0
  656. package/src/desktop.ts +24 -0
  657. package/src/device-authorization.tsx +98 -0
  658. package/src/diffs.ts +16 -0
  659. package/src/discovery-cache.ts +42 -0
  660. package/src/editor.ts +13 -0
  661. package/src/hooks/internal.ts +3 -2
  662. package/src/hooks/latest-question.ts +164 -0
  663. package/src/hooks/shared-machines-list.ts +34 -1
  664. package/src/hooks/shared-query.ts +721 -0
  665. package/src/hooks/use-attached-browsers.ts +1 -1
  666. package/src/hooks/use-auth-runs.ts +0 -27
  667. package/src/hooks/use-available-models.ts +21 -15
  668. package/src/hooks/use-browser-frame-stream.ts +19 -2
  669. package/src/hooks/use-browser-session.ts +680 -205
  670. package/src/hooks/use-browser-sessions.ts +32 -1
  671. package/src/hooks/use-client-config-flags.ts +118 -0
  672. package/src/hooks/use-codex-accounts.ts +247 -47
  673. package/src/hooks/use-composer.ts +276 -47
  674. package/src/hooks/use-computer-frame-stream.ts +25 -7
  675. package/src/hooks/use-computer-input-posture.ts +94 -0
  676. package/src/hooks/use-computer-session.ts +409 -95
  677. package/src/hooks/use-connect.ts +23 -0
  678. package/src/hooks/use-desktop-stream.ts +19 -28
  679. package/src/hooks/use-file-attachments.ts +80 -4
  680. package/src/hooks/use-goal.ts +107 -13
  681. package/src/hooks/use-last-started-turn-policy.ts +46 -14
  682. package/src/hooks/use-machines.ts +4 -0
  683. package/src/hooks/use-new-conversation.ts +374 -0
  684. package/src/hooks/use-new-session-draft.ts +813 -0
  685. package/src/hooks/use-realtime-voice-models.ts +46 -0
  686. package/src/hooks/use-sandbox-files.ts +68 -20
  687. package/src/hooks/use-session-background-commands.ts +22 -11
  688. package/src/hooks/use-session-capabilities.ts +3 -2
  689. package/src/hooks/use-session-conversation.ts +150 -0
  690. package/src/hooks/use-session-events.ts +703 -382
  691. package/src/hooks/use-session-lineage.ts +20 -16
  692. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  693. package/src/hooks/use-session-model-account.ts +174 -0
  694. package/src/hooks/use-session.ts +53 -21
  695. package/src/hooks/use-slash-commands.ts +6 -11
  696. package/src/hooks/use-supergrok-accounts.ts +22 -8
  697. package/src/hooks/use-terminal-stream.ts +153 -27
  698. package/src/hooks/use-transcription.ts +6 -0
  699. package/src/hooks/use-turn-queue.ts +2 -1
  700. package/src/hooks/use-usage.ts +100 -0
  701. package/src/hooks/use-vaults.ts +153 -0
  702. package/src/hooks/use-video-artifact-playback.ts +1 -1
  703. package/src/hooks/use-voice-input.ts +127 -19
  704. package/src/hooks/use-workspace-capture.ts +3 -2
  705. package/src/hooks/use-workspace-edit.ts +23 -5
  706. package/src/hooks/use-workspace-sessions.ts +97 -32
  707. package/src/human-input-model.ts +359 -0
  708. package/src/identity-link-accounts.tsx +148 -0
  709. package/src/identity-link-consent.tsx +192 -0
  710. package/src/index.ts +262 -16
  711. package/src/interaction.ts +1 -0
  712. package/src/lib/clipboard.ts +29 -0
  713. package/src/lib/error-message.ts +37 -0
  714. package/src/lib/format.ts +213 -16
  715. package/src/lib/host-theme.ts +529 -0
  716. package/src/lib/interaction-errors.ts +15 -0
  717. package/src/lib/menu-styles.ts +44 -0
  718. package/src/lib/notify-observer.ts +15 -0
  719. package/src/lib/pierre-diffs-loader.ts +53 -0
  720. package/src/lib/provider-recovery.ts +243 -0
  721. package/src/lib/scrollbars.ts +30 -0
  722. package/src/lib/terminal-input-readiness.ts +51 -0
  723. package/src/lib/transient-retry.ts +99 -0
  724. package/src/lib/workbench-peers.ts +62 -0
  725. package/src/lib/xterm-theme.ts +23 -21
  726. package/src/mcp-connection-status.ts +35 -0
  727. package/src/model-mark-paths.ts +53 -0
  728. package/src/model-picker-model.ts +330 -0
  729. package/src/model-policy.ts +299 -74
  730. package/src/native-previews.ts +100 -0
  731. package/src/new-session-draft.ts +22 -0
  732. package/src/notification-text.ts +81 -0
  733. package/src/older-history.ts +22 -4
  734. package/src/organization-model.ts +118 -0
  735. package/src/plugin-details.tsx +185 -0
  736. package/src/plugin-discovery.tsx +196 -0
  737. package/src/preview-loading-paint.ts +68 -0
  738. package/src/provider.tsx +74 -15
  739. package/src/queue-presentation-model.ts +464 -0
  740. package/src/realtime/dropdown-menu.tsx +19 -12
  741. package/src/realtime/embedded-new-voice.tsx +1 -0
  742. package/src/realtime/embedded-voice.tsx +3 -0
  743. package/src/realtime/realtime-control.tsx +138 -501
  744. package/src/realtime/session-realtime.ts +566 -0
  745. package/src/sandbox-label-model.ts +53 -0
  746. package/src/scrollbars.ts +3 -0
  747. package/src/secret-reference-label.ts +43 -0
  748. package/src/secrets-ui.tsx +59 -0
  749. package/src/session-agents-model.ts +33 -0
  750. package/src/session-attention-model.ts +62 -0
  751. package/src/session-auth-recommendation.ts +48 -0
  752. package/src/session-capability-policy.ts +196 -0
  753. package/src/session-context.ts +3 -4
  754. package/src/session-feedback-model.ts +95 -0
  755. package/src/session-list-model.ts +434 -0
  756. package/src/session-realtime.ts +18 -0
  757. package/src/session-status-model.ts +99 -0
  758. package/src/session-ui.ts +98 -1
  759. package/src/session.ts +17 -1
  760. package/src/site-snapshot.ts +74 -0
  761. package/src/sites-ui.tsx +348 -0
  762. package/src/sites.ts +3 -0
  763. package/src/skill-discovery.tsx +208 -0
  764. package/src/terminal.ts +26 -0
  765. package/src/testing/session-scenarios.ts +404 -0
  766. package/src/timeline/activity-rail.tsx +242 -101
  767. package/src/timeline/agent-identity.tsx +84 -0
  768. package/src/timeline/agent-row.tsx +231 -0
  769. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  770. package/src/timeline/compaction-copy.ts +115 -0
  771. package/src/timeline/entrance.tsx +28 -3
  772. package/src/timeline/fleet-decision-projection.ts +2 -1
  773. package/src/timeline/fleet-decision-row.tsx +1 -0
  774. package/src/timeline/focus-sequence.ts +44 -0
  775. package/src/timeline/genie-copy.ts +19 -0
  776. package/src/timeline/genie-loading.tsx +143 -0
  777. package/src/timeline/index.ts +30 -2
  778. package/src/timeline/knowledge-receipt.tsx +100 -0
  779. package/src/timeline/message-sender.tsx +71 -0
  780. package/src/timeline/notice-presentation.ts +48 -0
  781. package/src/timeline/parsers.ts +42 -2
  782. package/src/timeline/patch-apply-command.tsx +135 -0
  783. package/src/timeline/platform-activity-presentation.ts +166 -0
  784. package/src/timeline/platform-activity-row.tsx +15 -90
  785. package/src/timeline/presented-image.ts +63 -0
  786. package/src/timeline/projection.ts +1746 -76
  787. package/src/timeline/provider-logo.tsx +53 -0
  788. package/src/timeline/question-nav-model.ts +28 -0
  789. package/src/timeline/registry.ts +26 -4
  790. package/src/timeline/retained-image.ts +97 -0
  791. package/src/timeline/retained-loaders.ts +91 -0
  792. package/src/timeline/rolling-activity.tsx +80 -0
  793. package/src/timeline/screenshot-lightbox.tsx +228 -5
  794. package/src/timeline/session-usage-limit-row.tsx +42 -0
  795. package/src/timeline/shared.tsx +42 -15
  796. package/src/timeline/startup-dispatch-details.tsx +36 -0
  797. package/src/timeline/startup-preference.ts +33 -0
  798. package/src/timeline/startup-timings.tsx +145 -0
  799. package/src/timeline/tool-display-name.ts +19 -7
  800. package/src/timeline/tool-presentation.ts +1316 -0
  801. package/src/timeline/tool-renderers.tsx +835 -1138
  802. package/src/timeline/turn-summary-model.ts +343 -0
  803. package/src/timeline/turn-summary.tsx +272 -365
  804. package/src/timeline/types.ts +189 -6
  805. package/src/timeline/work-presentation.ts +189 -0
  806. package/src/timeline-model.ts +143 -0
  807. package/src/usage/allowance-copy.ts +64 -0
  808. package/src/usage/session-usage-limit.ts +266 -0
  809. package/src/usage/summary.ts +93 -0
  810. package/src/usage.ts +70 -0
  811. package/src/voice-recording-owner.ts +22 -0
  812. package/styles/compiled.css +2319 -748
  813. package/styles/connect.css +290 -0
  814. package/styles/connect.d.ts +1 -0
  815. package/styles/effective-tokens.css +1 -0
  816. package/styles/index.css +309 -9
  817. package/styles/responsive.css +99 -7
  818. package/styles/session-capability.css +44 -0
  819. package/styles/tokens.css +134 -66
  820. package/dist/browser-viewer-AEFHUYZK.js +0 -14
  821. package/dist/chunk-4MDLEHXL.js.map +0 -1
  822. package/dist/chunk-5YK2ZDIG.js.map +0 -1
  823. package/dist/chunk-D3UIAJKY.js.map +0 -1
  824. package/dist/chunk-ELIYWBZR.js.map +0 -1
  825. package/dist/chunk-H5YGYNXS.js.map +0 -1
  826. package/dist/chunk-HQVCKCLG.js +0 -9458
  827. package/dist/chunk-HQVCKCLG.js.map +0 -1
  828. package/dist/chunk-HUIKIDM5.js.map +0 -1
  829. package/dist/chunk-ICA6R6TW.js.map +0 -1
  830. package/dist/chunk-JVYQRRC4.js.map +0 -1
  831. package/dist/chunk-KCGXPP5V.js.map +0 -1
  832. package/dist/chunk-KZ73RL76.js.map +0 -1
  833. package/dist/chunk-LAKLF4PA.js +0 -141
  834. package/dist/chunk-LAKLF4PA.js.map +0 -1
  835. package/dist/chunk-MZ2G2XBA.js.map +0 -1
  836. package/dist/chunk-NEXLLTP4.js.map +0 -1
  837. package/dist/chunk-OAM4WAAM.js.map +0 -1
  838. package/dist/chunk-PEI6RANI.js.map +0 -1
  839. package/dist/chunk-RGALCTWO.js.map +0 -1
  840. package/dist/chunk-W6NFJXSA.js +0 -454
  841. package/dist/chunk-W6NFJXSA.js.map +0 -1
  842. package/dist/chunk-WSK7G5LE.js +0 -170
  843. package/dist/chunk-WSK7G5LE.js.map +0 -1
  844. package/dist/chunk-X4A66EWZ.js +0 -223
  845. package/dist/chunk-X4A66EWZ.js.map +0 -1
  846. package/dist/chunk-XXWH2JLC.js.map +0 -1
  847. package/dist/chunk-YFKJ7VZH.js +0 -268
  848. package/dist/chunk-YFKJ7VZH.js.map +0 -1
  849. package/dist/chunk-YJFGAFBD.js.map +0 -1
  850. package/dist/computer-viewer-FWEZISW4.js +0 -16
  851. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  852. package/dist/hooks/use-environments.d.ts +0 -41
  853. package/dist/hooks/use-packs.d.ts +0 -32
  854. package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
  855. package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
  856. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  857. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  858. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  859. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  860. package/src/hooks/use-environments.ts +0 -182
  861. package/src/hooks/use-packs.ts +0 -157
  862. /package/dist/{browser-viewer-AEFHUYZK.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
  863. /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-BO2IWXVK.js.map} +0 -0
@@ -19,10 +19,28 @@ import {
19
19
  import { isNonRetryableInteractionError } from "../lib/interaction-errors";
20
20
  import { usePageLiveActivity } from "./internal";
21
21
 
22
+ /** Immutable input fence; queued actions never need the encoded screenshot. */
23
+ export type BrowserFrameInputFence = Pick<
24
+ BrowserFrame,
25
+ | "browserSessionId"
26
+ | "controllerGeneration"
27
+ | "targetId"
28
+ | "targetGeneration"
29
+ | "documentGeneration"
30
+ | "frameId"
31
+ >;
32
+
33
+ export type BrowserInputFailure = Pick<BrowserActionReceipt, "operationId" | "error"> & {
34
+ state: Exclude<BrowserActionReceipt["state"], "completed">;
35
+ };
36
+
22
37
  export type UseBrowserSessionOptions = EmbeddedBrowserInteractionClientOverride & {
23
38
  browserSessionId: string | null;
24
39
  enabled?: boolean | undefined;
25
40
  pollIntervalMs?: number | undefined;
41
+ /** Keep session/tab inventory current without repeatedly fetching the full
42
+ * accessibility tree while a live frame is available or the viewer is hidden. */
43
+ semanticObservationEnabled?: boolean | undefined;
26
44
  };
27
45
 
28
46
  export type UseBrowserSessionResult = {
@@ -33,7 +51,13 @@ export type UseBrowserSessionResult = {
33
51
  loading: boolean;
34
52
  mutating: boolean;
35
53
  error: Error | null;
54
+ inputFailure: BrowserInputFailure | null;
36
55
  refresh: () => Promise<void>;
56
+ observeForInput: () => Promise<BrowserObservation>;
57
+ actFromObservation: (
58
+ action: BrowserAction,
59
+ observation: BrowserObservation,
60
+ ) => Promise<BrowserActionReceipt>;
37
61
  selectTarget: (targetId: string) => Promise<BrowserTarget>;
38
62
  openTarget: (url?: string) => Promise<BrowserTarget>;
39
63
  closeTarget: (targetId: string) => Promise<void>;
@@ -45,8 +69,9 @@ export type UseBrowserSessionResult = {
45
69
  * the controller fence instead of targeting a newer page. */
46
70
  actFromFrame: (
47
71
  action: BrowserAction | BrowserActionBatch,
48
- frame: BrowserFrame,
72
+ frame: BrowserFrameInputFence,
49
73
  operationId?: string,
74
+ observationMode?: "none" | "input",
50
75
  ) => Promise<BrowserActionReceipt>;
51
76
  readClipboard: () => Promise<BrowserClipboard>;
52
77
  diagnostics: (options?: BrowserDiagnosticsOptions) => Promise<BrowserDiagnosticBatch>;
@@ -58,9 +83,27 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
58
83
  const { client, workspaceId } = useEmbeddedBrowserInteraction(options);
59
84
  const browserSessionId = options.browserSessionId;
60
85
  const enabled = (options.enabled ?? true) && browserSessionId !== null;
86
+ const sourceRef = useRef({ client, workspaceId, browserSessionId, enabled });
87
+ if (
88
+ sourceRef.current.client !== client ||
89
+ sourceRef.current.workspaceId !== workspaceId ||
90
+ sourceRef.current.browserSessionId !== browserSessionId ||
91
+ sourceRef.current.enabled !== enabled
92
+ ) {
93
+ sourceRef.current = { client, workspaceId, browserSessionId, enabled };
94
+ }
95
+ const source = sourceRef.current;
96
+ const semanticObservationEnabled = options.semanticObservationEnabled ?? true;
97
+ const semanticObservationEnabledRef = useRef(semanticObservationEnabled);
98
+ semanticObservationEnabledRef.current = semanticObservationEnabled;
99
+ const previousSemanticObservationRef = useRef({
100
+ browserSessionId,
101
+ enabled: semanticObservationEnabled,
102
+ });
61
103
  const pageLive = usePageLiveActivity();
62
104
  const pollIntervalMs = Math.max(750, options.pollIntervalMs ?? 2_000);
63
105
  const [state, setState] = useState<{
106
+ source: typeof source;
64
107
  browserSessionId: string | null;
65
108
  session: BrowserSession | null;
66
109
  targets: BrowserTarget[];
@@ -69,16 +112,30 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
69
112
  loading: boolean;
70
113
  mutating: boolean;
71
114
  error: Error | null;
72
- }>(() => emptyState(browserSessionId, enabled));
115
+ inputFailure: BrowserInputFailure | null;
116
+ actionResultOrder: number;
117
+ }>(() => ({ ...emptyState(browserSessionId, enabled), source }));
73
118
  const visible =
74
- state.browserSessionId === browserSessionId ? state : emptyState(browserSessionId, enabled);
119
+ state.source === source && state.browserSessionId === browserSessionId
120
+ ? state
121
+ : { ...emptyState(browserSessionId, enabled), source };
75
122
  const refreshBlocked = isNonRetryableInteractionError(visible.error);
123
+ const inputFailureRef = useRef(visible.inputFailure);
124
+ inputFailureRef.current = visible.inputFailure;
76
125
  const selectedTargetIdRef = useRef<string | null>(visible.selectedTargetId);
77
126
  selectedTargetIdRef.current = visible.selectedTargetId;
127
+ const selectionRevisionRef = useRef(0);
128
+ const actionResultOrderRef = useRef({ next: 0, settled: 0 });
129
+ const selectedTargetRef = useRef<BrowserTarget | null>(
130
+ visible.targets.find((target) => target.id === visible.selectedTargetId) ?? null,
131
+ );
132
+ selectedTargetRef.current =
133
+ visible.targets.find((target) => target.id === visible.selectedTargetId) ?? null;
78
134
  const observationRef = useRef<{
79
135
  browserSessionId: string | null;
80
136
  observation: BrowserObservation | null;
81
137
  }>({ browserSessionId, observation: visible.observation });
138
+ const lastObservationAtRef = useRef(0);
82
139
  if (observationRef.current.browserSessionId !== browserSessionId) {
83
140
  observationRef.current = {
84
141
  browserSessionId,
@@ -93,12 +150,20 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
93
150
  });
94
151
  const mutationRef = useRef<{
95
152
  browserSessionId: string | null;
153
+ source: typeof source;
96
154
  count: number;
155
+ needsInventoryReconcile: boolean;
97
156
  }>({
98
157
  browserSessionId,
158
+ source,
99
159
  count: 0,
160
+ needsInventoryReconcile: false,
100
161
  });
101
162
  const mountedRef = useRef(true);
163
+ const isCurrentSource = useCallback(
164
+ () => mountedRef.current && sourceRef.current === source,
165
+ [source],
166
+ );
102
167
 
103
168
  const invalidateRefresh = useCallback(() => {
104
169
  const id = requestRef.current.id + 1;
@@ -106,113 +171,244 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
106
171
  requestRef.current = { id, controller: null };
107
172
  }, []);
108
173
 
109
- const refresh = useCallback(async (): Promise<void> => {
110
- if (!enabled || !browserSessionId) return;
111
- const id = requestRef.current.id + 1;
112
- requestRef.current.controller?.abort();
113
- const controller = new AbortController();
114
- requestRef.current = { id, controller };
115
- try {
116
- const [session, targetResponse] = await Promise.all([
117
- client.getBrowserSession(workspaceId, browserSessionId, {
118
- signal: controller.signal,
119
- }),
120
- client.listBrowserTargets(workspaceId, browserSessionId, {
121
- signal: controller.signal,
122
- }),
123
- ]);
124
- if (!mountedRef.current || requestRef.current.id !== id) return;
125
- const selected = chooseTarget(targetResponse.targets, selectedTargetIdRef.current);
126
- selectedTargetIdRef.current = selected?.id ?? null;
127
- observationRef.current = { browserSessionId, observation: null };
128
- setState((current) =>
129
- current.browserSessionId === browserSessionId
130
- ? {
131
- ...current,
132
- session,
133
- targets: targetResponse.targets,
134
- selectedTargetId: selected?.id ?? null,
135
- observation: null,
136
- loading: false,
137
- error: null,
138
- }
139
- : current,
140
- );
141
- if (!selected) return;
174
+ const refreshInventory = useCallback(
175
+ async (checkInput = false, observeSelectedTarget = true) => {
176
+ if (!enabled || !browserSessionId || !isCurrentSource()) return;
177
+ const checkedInputFailure = inputFailureRef.current;
178
+ const id = requestRef.current.id + 1;
179
+ requestRef.current.controller?.abort();
180
+ const controller = new AbortController();
181
+ requestRef.current = { id, controller };
142
182
  try {
143
- const observation = await client.observeBrowserTarget(
144
- workspaceId,
183
+ const [session, targetResponse] = await Promise.all([
184
+ client.getBrowserSession(workspaceId, browserSessionId, {
185
+ signal: controller.signal,
186
+ }),
187
+ client.listBrowserTargets(workspaceId, browserSessionId, {
188
+ signal: controller.signal,
189
+ }),
190
+ ]);
191
+ if (!isCurrentSource() || requestRef.current.id !== id) return;
192
+ const selected = chooseTarget(targetResponse.targets, selectedTargetIdRef.current);
193
+ selectedTargetIdRef.current = selected?.id ?? null;
194
+ selectedTargetRef.current = selected;
195
+ const previousObservation =
196
+ observationRef.current.browserSessionId === browserSessionId
197
+ ? observationRef.current.observation
198
+ : null;
199
+ const retainedObservation =
200
+ selected && previousObservation && sameObservationTarget(previousObservation, selected)
201
+ ? previousObservation
202
+ : null;
203
+ observationRef.current = {
145
204
  browserSessionId,
146
- selected.id,
147
- { signal: controller.signal },
148
- );
149
- if (!mountedRef.current || requestRef.current.id !== id) return;
150
- observationRef.current = { browserSessionId, observation };
205
+ observation: retainedObservation,
206
+ };
151
207
  setState((current) =>
152
- current.browserSessionId === browserSessionId &&
153
- current.selectedTargetId === observation.target.id
154
- ? { ...current, observation }
208
+ isCurrentSource() &&
209
+ current.source === source &&
210
+ current.browserSessionId === browserSessionId
211
+ ? {
212
+ ...current,
213
+ session,
214
+ targets: targetResponse.targets,
215
+ selectedTargetId: selected?.id ?? null,
216
+ observation: retainedObservation,
217
+ loading: false,
218
+ error: null,
219
+ // Media and background polling cannot confirm an input outcome.
220
+ // Only an explicit fresh check clears the notice it began with.
221
+ inputFailure:
222
+ checkInput &&
223
+ session.id === browserSessionId &&
224
+ targetResponse.browserSessionId === browserSessionId &&
225
+ current.inputFailure === checkedInputFailure
226
+ ? null
227
+ : current.inputFailure,
228
+ }
155
229
  : current,
156
230
  );
231
+ if (!selected || !observeSelectedTarget || !semanticObservationEnabledRef.current) return;
232
+ try {
233
+ const observation = await client.observeBrowserTarget(
234
+ workspaceId,
235
+ browserSessionId,
236
+ selected.id,
237
+ { signal: controller.signal },
238
+ );
239
+ if (!isCurrentSource() || requestRef.current.id !== id) return;
240
+ const currentSelected = selectedTargetRef.current;
241
+ if (
242
+ observationRef.current.browserSessionId !== browserSessionId ||
243
+ currentSelected?.id !== selected.id ||
244
+ observation.browserSessionId !== browserSessionId ||
245
+ observation.target.id !== selected.id ||
246
+ observation.target.controllerGeneration !== currentSelected.controllerGeneration ||
247
+ observation.target.targetGeneration !== currentSelected.targetGeneration
248
+ )
249
+ return;
250
+ // Navigation may complete between the inventory and its selected-page
251
+ // observation. Keep both the selected target and input fence coherent.
252
+ selectedTargetRef.current = observation.target;
253
+ observationRef.current = { browserSessionId, observation };
254
+ lastObservationAtRef.current = Date.now();
255
+ setState((current) =>
256
+ isCurrentSource() &&
257
+ current.source === source &&
258
+ current.browserSessionId === browserSessionId &&
259
+ current.selectedTargetId === observation.target.id
260
+ ? {
261
+ ...current,
262
+ observation,
263
+ targets: replaceTarget(current.targets, observation.target),
264
+ }
265
+ : current,
266
+ );
267
+ } catch (cause) {
268
+ if (controller.signal.aborted || !isCurrentSource() || requestRef.current.id !== id)
269
+ return;
270
+ // Target inventory and the media plane remain authoritative for the
271
+ // human-facing browser. A failed semantic snapshot must not blank or
272
+ // disable an otherwise live visual browser.
273
+ void cause;
274
+ }
157
275
  } catch (cause) {
158
- if (controller.signal.aborted || !mountedRef.current || requestRef.current.id !== id)
159
- return;
160
- // Target inventory and the media plane remain authoritative for the
161
- // human-facing browser. A failed semantic snapshot must not blank or
162
- // disable an otherwise live visual browser.
163
- void cause;
276
+ if (controller.signal.aborted || !isCurrentSource() || requestRef.current.id !== id) return;
277
+ setState((current) =>
278
+ isCurrentSource() &&
279
+ current.source === source &&
280
+ current.browserSessionId === browserSessionId
281
+ ? {
282
+ ...current,
283
+ loading: false,
284
+ error: cause instanceof Error ? cause : new Error(String(cause)),
285
+ }
286
+ : current,
287
+ );
288
+ } finally {
289
+ if (requestRef.current.id === id) {
290
+ requestRef.current = { id, controller: null };
291
+ }
164
292
  }
165
- } catch (cause) {
166
- if (controller.signal.aborted || !mountedRef.current || requestRef.current.id !== id) return;
293
+ },
294
+ [browserSessionId, client, enabled, isCurrentSource, source, workspaceId],
295
+ );
296
+
297
+ const refresh = useCallback(async () => await refreshInventory(true), [refreshInventory]);
298
+
299
+ const refreshSemantic = useCallback(async (): Promise<void> => {
300
+ if (!enabled || !browserSessionId || !isCurrentSource()) return;
301
+ const target = selectedTargetRef.current;
302
+ if (!target) return;
303
+ const id = requestRef.current.id + 1;
304
+ requestRef.current.controller?.abort();
305
+ const controller = new AbortController();
306
+ requestRef.current = { id, controller };
307
+ try {
308
+ const observation = await client.observeBrowserTarget(
309
+ workspaceId,
310
+ browserSessionId,
311
+ target.id,
312
+ { signal: controller.signal },
313
+ );
314
+ if (!isCurrentSource() || requestRef.current.id !== id) return;
315
+ if (!sameObservationTarget(observation, selectedTargetRef.current)) return;
316
+ observationRef.current = { browserSessionId, observation };
317
+ lastObservationAtRef.current = Date.now();
167
318
  setState((current) =>
168
- current.browserSessionId === browserSessionId
169
- ? {
170
- ...current,
171
- loading: false,
172
- error: cause instanceof Error ? cause : new Error(String(cause)),
173
- }
319
+ isCurrentSource() &&
320
+ current.source === source &&
321
+ current.browserSessionId === browserSessionId &&
322
+ current.selectedTargetId === target.id
323
+ ? { ...current, observation }
174
324
  : current,
175
325
  );
326
+ } catch {
327
+ // A failed semantic fallback cannot disable an otherwise live browser.
176
328
  } finally {
177
- if (requestRef.current.id === id) {
178
- requestRef.current = { id, controller: null };
179
- }
329
+ if (requestRef.current.id === id) requestRef.current = { id, controller: null };
180
330
  }
181
- }, [browserSessionId, client, enabled, workspaceId]);
331
+ }, [browserSessionId, client, enabled, isCurrentSource, source, workspaceId]);
182
332
 
183
333
  useEffect(() => {
184
334
  mountedRef.current = true;
185
335
  if (!enabled) {
186
336
  invalidateRefresh();
187
- setState(emptyState(browserSessionId, false));
337
+ setState({ ...emptyState(browserSessionId, false), source });
188
338
  return;
189
339
  }
190
340
  setState((current) =>
341
+ isCurrentSource() &&
342
+ current.source === source &&
191
343
  current.browserSessionId === browserSessionId
192
344
  ? { ...current, loading: true }
193
- : emptyState(browserSessionId, true),
345
+ : { ...emptyState(browserSessionId, true), source },
194
346
  );
195
- void refresh();
347
+ void refreshInventory();
196
348
  return () => {
197
349
  mountedRef.current = false;
198
350
  invalidateRefresh();
199
351
  };
200
- }, [browserSessionId, enabled, invalidateRefresh, refresh]);
352
+ }, [browserSessionId, enabled, invalidateRefresh, isCurrentSource, refreshInventory, source]);
353
+
354
+ useEffect(() => {
355
+ const previous = previousSemanticObservationRef.current;
356
+ previousSemanticObservationRef.current = {
357
+ browserSessionId,
358
+ enabled: semanticObservationEnabled,
359
+ };
360
+ if (
361
+ enabled &&
362
+ semanticObservationEnabled &&
363
+ previous.browserSessionId === browserSessionId &&
364
+ !previous.enabled
365
+ ) {
366
+ // The media stream disappeared or the user returned to the Browser tab.
367
+ // A just-returned action/tab observation is already a fresh fallback.
368
+ // Otherwise drop the old tree/fence until a new read settles.
369
+ const currentObservation = observationRef.current.observation;
370
+ if (
371
+ currentObservation &&
372
+ sameObservationTarget(currentObservation, selectedTargetRef.current) &&
373
+ Date.now() - lastObservationAtRef.current < pollIntervalMs
374
+ ) {
375
+ return;
376
+ }
377
+ observationRef.current = { browserSessionId, observation: null };
378
+ setState((current) =>
379
+ isCurrentSource() &&
380
+ current.source === source &&
381
+ current.browserSessionId === browserSessionId
382
+ ? { ...current, observation: null }
383
+ : current,
384
+ );
385
+ void refreshSemantic();
386
+ }
387
+ }, [
388
+ browserSessionId,
389
+ enabled,
390
+ isCurrentSource,
391
+ pollIntervalMs,
392
+ refreshSemantic,
393
+ semanticObservationEnabled,
394
+ source,
395
+ ]);
201
396
 
202
397
  useEffect(() => {
203
398
  if (!enabled || !pageLive || visible.mutating || refreshBlocked) return;
204
399
  const timer = setInterval(() => {
205
- if (!requestRef.current.controller) void refresh();
400
+ if (!requestRef.current.controller) void refreshInventory();
206
401
  }, pollIntervalMs);
207
402
  return () => clearInterval(timer);
208
- }, [enabled, pageLive, pollIntervalMs, refresh, refreshBlocked, visible.mutating]);
403
+ }, [enabled, pageLive, pollIntervalMs, refreshInventory, refreshBlocked, visible.mutating]);
209
404
 
210
405
  useEffect(() => {
211
406
  if (!enabled || !browserSessionId || !pageLive || refreshBlocked) return;
212
407
  let disposed = false;
213
408
  const heartbeat = () => {
409
+ if (!isCurrentSource()) return;
214
410
  void client.heartbeatBrowserSession(workspaceId, browserSessionId).catch(() => {
215
- if (!disposed) void refresh();
411
+ if (!disposed) void refreshInventory();
216
412
  });
217
413
  };
218
414
  const timer = setInterval(heartbeat, 30_000);
@@ -220,173 +416,306 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
220
416
  disposed = true;
221
417
  clearInterval(timer);
222
418
  };
223
- }, [browserSessionId, client, enabled, pageLive, refresh, refreshBlocked, workspaceId]);
419
+ }, [
420
+ browserSessionId,
421
+ client,
422
+ enabled,
423
+ isCurrentSource,
424
+ pageLive,
425
+ refreshInventory,
426
+ refreshBlocked,
427
+ workspaceId,
428
+ ]);
224
429
 
225
430
  const runMutation = useCallback(
226
- async <T>(scopeBrowserSessionId: string, operation: () => Promise<T>): Promise<T> => {
431
+ async <T>(
432
+ scopeBrowserSessionId: string,
433
+ operation: (selectionRevision: number, readRequestId: number) => Promise<T>,
434
+ selectionRead = false,
435
+ changesInventory = false,
436
+ ): Promise<T> => {
437
+ if (!enabled || !isCurrentSource()) {
438
+ throw new Error("The browser source is no longer selected.");
439
+ }
440
+ const selectionRevision = ++selectionRevisionRef.current;
227
441
  invalidateRefresh();
228
- if (mutationRef.current.browserSessionId !== scopeBrowserSessionId) {
442
+ const readRequestId = requestRef.current.id;
443
+ if (
444
+ mutationRef.current.browserSessionId !== scopeBrowserSessionId ||
445
+ mutationRef.current.source !== source
446
+ ) {
229
447
  mutationRef.current = {
230
448
  browserSessionId: scopeBrowserSessionId,
449
+ source,
231
450
  count: 0,
451
+ needsInventoryReconcile: false,
232
452
  };
233
453
  }
234
454
  mutationRef.current.count += 1;
235
455
  setState((current) =>
456
+ isCurrentSource() &&
457
+ current.source === source &&
236
458
  current.browserSessionId === scopeBrowserSessionId
237
459
  ? { ...current, mutating: true, error: null }
238
460
  : current,
239
461
  );
240
462
  try {
241
- return await operation();
463
+ return await operation(selectionRevision, readRequestId);
242
464
  } catch (cause) {
243
465
  const error = cause instanceof Error ? cause : new Error(String(cause));
244
- setState((current) =>
245
- current.browserSessionId === scopeBrowserSessionId ? { ...current, error } : current,
246
- );
466
+ // Selection observations share refresh ordering; physical mutations
467
+ // keep their existing outcome admission.
468
+ if (!selectionRead || requestRef.current.id === readRequestId) {
469
+ setState((current) =>
470
+ isCurrentSource() &&
471
+ selectionRevisionRef.current === selectionRevision &&
472
+ current.source === source &&
473
+ current.browserSessionId === scopeBrowserSessionId
474
+ ? { ...current, error }
475
+ : current,
476
+ );
477
+ }
247
478
  throw error;
248
479
  } finally {
249
- if (mutationRef.current.browserSessionId === scopeBrowserSessionId) {
480
+ if (
481
+ mutationRef.current.browserSessionId === scopeBrowserSessionId &&
482
+ mutationRef.current.source === source
483
+ ) {
484
+ if (
485
+ changesInventory &&
486
+ (selectionRevisionRef.current !== selectionRevision ||
487
+ requestRef.current.id !== readRequestId)
488
+ ) {
489
+ mutationRef.current.needsInventoryReconcile = true;
490
+ }
250
491
  mutationRef.current.count = Math.max(0, mutationRef.current.count - 1);
251
492
  const mutating = mutationRef.current.count > 0;
252
493
  setState((current) =>
253
- current.browserSessionId === scopeBrowserSessionId ? { ...current, mutating } : current,
494
+ isCurrentSource() &&
495
+ current.source === source &&
496
+ current.browserSessionId === scopeBrowserSessionId
497
+ ? { ...current, mutating }
498
+ : current,
254
499
  );
500
+ if (!mutating && mutationRef.current.needsInventoryReconcile && isCurrentSource()) {
501
+ mutationRef.current.needsInventoryReconcile = false;
502
+ // A superseded tab mutation still changed the real inventory. Wait
503
+ // for all selections to settle, then reconcile without replacing
504
+ // the latest selected-page observation or cancelling its read.
505
+ void refreshInventory(false, false);
506
+ }
255
507
  }
256
508
  }
257
509
  },
258
- [invalidateRefresh],
510
+ [enabled, invalidateRefresh, isCurrentSource, refreshInventory, source],
259
511
  );
260
512
 
261
513
  const selectTarget = useCallback(
262
514
  async (targetId: string): Promise<BrowserTarget> => {
263
515
  if (!browserSessionId) throw new Error("No BrowserSession is selected.");
264
- return await runMutation(browserSessionId, async () => {
265
- let targets = visible.targets;
266
- let target: BrowserTarget;
267
- let observation: BrowserObservation;
268
- try {
269
- observation = await client.selectBrowserTarget(workspaceId, browserSessionId, targetId);
270
- target = observation.target;
271
- } catch (cause) {
272
- if (!isMissingBrowserTarget(cause)) throw cause;
273
- // A physical/attached tab may disappear between inventory and click.
274
- // Reconcile once from the authoritative controller inventory and move
275
- // to its live selected/first page instead of leaving a dead tab ID in
276
- // React state. Session-level 404s are deliberately not swallowed.
277
- const response = await client.listBrowserTargets(workspaceId, browserSessionId);
278
- targets = response.targets;
279
- const fallback = chooseTarget(targets, null);
280
- if (!fallback) {
281
- selectedTargetIdRef.current = null;
282
- observationRef.current = { browserSessionId, observation: null };
283
- setState((current) =>
284
- current.browserSessionId === browserSessionId
285
- ? {
286
- ...current,
287
- targets,
288
- selectedTargetId: null,
289
- observation: null,
290
- }
291
- : current,
516
+ return await runMutation(
517
+ browserSessionId,
518
+ async (selectionRevision, readRequestId) => {
519
+ const isCurrentSelection = () =>
520
+ isCurrentSource() && selectionRevisionRef.current === selectionRevision;
521
+ // Once admitted, a queued observation survives immediate input.
522
+ const isCurrentSelectionRead = () =>
523
+ isCurrentSelection() && requestRef.current.id === readRequestId;
524
+ let targets = visible.targets;
525
+ let target: BrowserTarget;
526
+ let observation: BrowserObservation;
527
+ try {
528
+ observation = await client.selectBrowserTarget(workspaceId, browserSessionId, targetId);
529
+ target = observation.target;
530
+ } catch (cause) {
531
+ if (!isCurrentSelectionRead() || !isMissingBrowserTarget(cause)) throw cause;
532
+ // A physical/attached tab may disappear between inventory and click.
533
+ // Reconcile once from the authoritative controller inventory and move
534
+ // to its live selected/first page instead of leaving a dead tab ID in
535
+ // React state. Session-level 404s are deliberately not swallowed.
536
+ const response = await client.listBrowserTargets(workspaceId, browserSessionId);
537
+ if (!isCurrentSelectionRead()) throw cause;
538
+ targets = response.targets;
539
+ const fallback = chooseTarget(targets, null);
540
+ if (!fallback) {
541
+ selectedTargetIdRef.current = null;
542
+ selectedTargetRef.current = null;
543
+ observationRef.current = { browserSessionId, observation: null };
544
+ setState((current) =>
545
+ isCurrentSelection() &&
546
+ current.source === source &&
547
+ current.browserSessionId === browserSessionId
548
+ ? {
549
+ ...current,
550
+ targets,
551
+ selectedTargetId: null,
552
+ observation: null,
553
+ }
554
+ : current,
555
+ );
556
+ throw cause;
557
+ }
558
+ observation = await client.selectBrowserTarget(
559
+ workspaceId,
560
+ browserSessionId,
561
+ fallback.id,
292
562
  );
293
- throw cause;
563
+ target = observation.target;
294
564
  }
295
- observation = await client.selectBrowserTarget(
296
- workspaceId,
297
- browserSessionId,
298
- fallback.id,
565
+ if (!isCurrentSelectionRead()) return target;
566
+ selectedTargetIdRef.current = target.id;
567
+ selectedTargetRef.current = target;
568
+ observationRef.current = { browserSessionId, observation };
569
+ lastObservationAtRef.current = Date.now();
570
+ setState((current) =>
571
+ isCurrentSelection() &&
572
+ current.source === source &&
573
+ current.browserSessionId === browserSessionId
574
+ ? {
575
+ ...current,
576
+ targets: replaceTarget(targets, target).map((candidate) => ({
577
+ ...candidate,
578
+ selected: candidate.id === target.id,
579
+ })),
580
+ selectedTargetId: target.id,
581
+ observation,
582
+ }
583
+ : current,
299
584
  );
300
- target = observation.target;
301
- }
302
- selectedTargetIdRef.current = target.id;
303
- observationRef.current = { browserSessionId, observation };
304
- setState((current) =>
305
- current.browserSessionId === browserSessionId
306
- ? {
307
- ...current,
308
- targets: targets.map((candidate) => ({
309
- ...candidate,
310
- selected: candidate.id === target.id,
311
- })),
312
- selectedTargetId: target.id,
313
- observation,
314
- }
315
- : current,
316
- );
317
- return target;
318
- });
585
+ return target;
586
+ },
587
+ true,
588
+ );
319
589
  },
320
- [browserSessionId, client, runMutation, visible.targets, workspaceId],
590
+ [browserSessionId, client, isCurrentSource, runMutation, source, visible.targets, workspaceId],
321
591
  );
322
592
 
323
593
  const openTarget = useCallback(
324
594
  async (url?: string): Promise<BrowserTarget> => {
325
595
  if (!browserSessionId) throw new Error("No BrowserSession is selected.");
326
- return await runMutation(browserSessionId, async () => {
327
- const observation = await client.openBrowserTarget(
328
- workspaceId,
329
- browserSessionId,
330
- url === undefined ? {} : { url },
331
- );
332
- const target = observation.target;
333
- selectedTargetIdRef.current = target.id;
334
- observationRef.current = { browserSessionId, observation };
335
- setState((current) =>
336
- current.browserSessionId === browserSessionId
337
- ? {
338
- ...current,
339
- targets: [
340
- ...current.targets.map((candidate) => ({
341
- ...candidate,
342
- selected: false,
343
- })),
344
- target,
345
- ],
346
- selectedTargetId: target.id,
347
- observation,
348
- }
349
- : current,
350
- );
351
- return target;
352
- });
596
+ return await runMutation(
597
+ browserSessionId,
598
+ async (selectionRevision, readRequestId) => {
599
+ const isCurrentSelection = () =>
600
+ isCurrentSource() && selectionRevisionRef.current === selectionRevision;
601
+ const isCurrentSelectionRead = () =>
602
+ isCurrentSelection() && requestRef.current.id === readRequestId;
603
+ const observation = await client.openBrowserTarget(
604
+ workspaceId,
605
+ browserSessionId,
606
+ url === undefined ? {} : { url },
607
+ );
608
+ const target = observation.target;
609
+ if (!isCurrentSource()) return target;
610
+ if (!isCurrentSelectionRead()) return target;
611
+ selectedTargetIdRef.current = target.id;
612
+ selectedTargetRef.current = target;
613
+ observationRef.current = { browserSessionId, observation };
614
+ lastObservationAtRef.current = Date.now();
615
+ setState((current) =>
616
+ isCurrentSelection() &&
617
+ current.source === source &&
618
+ current.browserSessionId === browserSessionId
619
+ ? {
620
+ ...current,
621
+ targets: [
622
+ ...current.targets.map((candidate) => ({
623
+ ...candidate,
624
+ selected: false,
625
+ })),
626
+ target,
627
+ ],
628
+ selectedTargetId: target.id,
629
+ observation,
630
+ }
631
+ : current,
632
+ );
633
+ return target;
634
+ },
635
+ false,
636
+ true,
637
+ );
353
638
  },
354
- [browserSessionId, client, runMutation, workspaceId],
639
+ [browserSessionId, client, isCurrentSource, runMutation, source, workspaceId],
355
640
  );
356
641
 
357
642
  const closeTarget = useCallback(
358
643
  async (targetId: string): Promise<void> => {
359
644
  if (!browserSessionId) throw new Error("No BrowserSession is selected.");
360
- await runMutation(browserSessionId, async () => {
361
- const response = await client.closeBrowserTarget(workspaceId, browserSessionId, targetId);
362
- const selected = chooseTarget(response.targets, null);
363
- const observation = selected
364
- ? await client.observeBrowserTarget(workspaceId, browserSessionId, selected.id)
365
- : null;
366
- selectedTargetIdRef.current = selected?.id ?? null;
367
- observationRef.current = { browserSessionId, observation };
368
- setState((current) =>
369
- current.browserSessionId === browserSessionId
370
- ? {
371
- ...current,
372
- targets: response.targets,
373
- selectedTargetId: selected?.id ?? null,
374
- observation,
375
- }
376
- : current,
377
- );
378
- });
645
+ await runMutation(
646
+ browserSessionId,
647
+ async (selectionRevision, readRequestId) => {
648
+ const isCurrentSelection = () =>
649
+ isCurrentSource() && selectionRevisionRef.current === selectionRevision;
650
+ const isCurrentSelectionRead = () =>
651
+ isCurrentSelection() && requestRef.current.id === readRequestId;
652
+ const response = await client.closeBrowserTarget(workspaceId, browserSessionId, targetId);
653
+ if (!isCurrentSource()) return;
654
+ if (!isCurrentSelectionRead()) return;
655
+ const selected = chooseTarget(response.targets, selectedTargetIdRef.current);
656
+ const observed = selected
657
+ ? await client.observeBrowserTarget(workspaceId, browserSessionId, selected.id)
658
+ : null;
659
+ if (!isCurrentSource()) return;
660
+ if (!isCurrentSelectionRead()) return;
661
+ const observation =
662
+ observed &&
663
+ selected &&
664
+ observed.browserSessionId === browserSessionId &&
665
+ observed.target.id === selected.id &&
666
+ observed.target.controllerGeneration === selected.controllerGeneration &&
667
+ observed.target.targetGeneration === selected.targetGeneration
668
+ ? observed
669
+ : null;
670
+ const currentTarget = observation?.target ?? selected;
671
+ selectedTargetIdRef.current = currentTarget?.id ?? null;
672
+ selectedTargetRef.current = currentTarget;
673
+ observationRef.current = { browserSessionId, observation };
674
+ if (observation) lastObservationAtRef.current = Date.now();
675
+ setState((current) =>
676
+ isCurrentSelection() &&
677
+ current.source === source &&
678
+ current.browserSessionId === browserSessionId
679
+ ? {
680
+ ...current,
681
+ targets: currentTarget
682
+ ? replaceTarget(response.targets, currentTarget)
683
+ : response.targets,
684
+ selectedTargetId: currentTarget?.id ?? null,
685
+ observation,
686
+ }
687
+ : current,
688
+ );
689
+ },
690
+ false,
691
+ true,
692
+ );
379
693
  },
380
- [browserSessionId, client, runMutation, workspaceId],
694
+ [browserSessionId, client, isCurrentSource, runMutation, source, workspaceId],
381
695
  );
382
696
 
383
697
  const dispatchAction = useCallback(
384
698
  async (
385
699
  action: BrowserAction | BrowserActionBatch,
386
700
  operationId: string,
387
- frame: BrowserFrame | null,
701
+ frame:
702
+ | (Pick<
703
+ BrowserFrame,
704
+ "browserSessionId" | "controllerGeneration" | "targetId" | "targetGeneration"
705
+ > & {
706
+ frameId: string | null;
707
+ documentGeneration: string | null;
708
+ })
709
+ | null,
710
+ observationMode: "none" | "input" = "none",
388
711
  ): Promise<BrowserActionReceipt> => {
389
712
  if (!browserSessionId) throw new Error("No BrowserSession is selected.");
713
+ if (!enabled || !isCurrentSource()) {
714
+ throw new Error("The browser source is no longer selected.");
715
+ }
716
+ if (!selectedTargetRef.current) {
717
+ throw new Error("The browser page is not ready for input.");
718
+ }
390
719
  if (frame && frame.browserSessionId !== browserSessionId) {
391
720
  throw new Error("The displayed browser frame belongs to another BrowserSession.");
392
721
  }
@@ -401,7 +730,7 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
401
730
  expectedDocumentGeneration: frame.documentGeneration,
402
731
  expectedFrameId: frame.frameId,
403
732
  }
404
- : currentObservation
733
+ : currentObservation && sameObservationTarget(currentObservation, selectedTargetRef.current)
405
734
  ? {
406
735
  targetId: currentObservation.target.id,
407
736
  expectedTargetGeneration: currentObservation.target.targetGeneration,
@@ -412,38 +741,123 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
412
741
  if (!fence) {
413
742
  throw new Error("The browser page is not ready for input.");
414
743
  }
744
+ const expectedControllerGeneration =
745
+ frame?.controllerGeneration ?? currentObservation!.target.controllerGeneration;
746
+ const selectionRevision = selectionRevisionRef.current;
747
+ const resultOrder = ++actionResultOrderRef.current.next;
748
+ let resultDocumentGeneration = fence.expectedDocumentGeneration;
749
+ const isCurrentResultView = () => {
750
+ const selected = selectedTargetRef.current;
751
+ return (
752
+ isCurrentSource() &&
753
+ selectionRevisionRef.current === selectionRevision &&
754
+ selected?.browserSessionId === browserSessionId &&
755
+ selected.id === fence.targetId &&
756
+ selected.controllerGeneration === expectedControllerGeneration &&
757
+ selected.targetGeneration === fence.expectedTargetGeneration &&
758
+ (selected.documentGeneration === fence.expectedDocumentGeneration ||
759
+ selected.documentGeneration === resultDocumentGeneration)
760
+ );
761
+ };
762
+ const canProjectResult = () =>
763
+ isCurrentResultView() && resultOrder >= actionResultOrderRef.current.settled;
764
+ const settleResult = () => {
765
+ if (!canProjectResult()) return false;
766
+ actionResultOrderRef.current.settled = resultOrder;
767
+ invalidateRefresh();
768
+ return true;
769
+ };
415
770
  try {
416
771
  const receipt = await client.actInBrowser(workspaceId, browserSessionId, {
417
772
  operationId,
418
773
  ...fence,
419
- observationMode: "none",
774
+ observationMode,
420
775
  action,
421
776
  });
422
- if (receipt.observation) {
777
+ resultDocumentGeneration =
778
+ receipt.observation?.target.documentGeneration ?? fence.expectedDocumentGeneration;
779
+ const settled =
780
+ receipt.state === "completed" ||
781
+ receipt.state === "failed" ||
782
+ receipt.state === "outcome_unknown";
783
+ // Keep the operation result available to its caller, but an older
784
+ // delivery cannot replace a newer settled view or input failure.
785
+ if (!canProjectResult() || (settled && !settleResult())) return receipt;
786
+ const receivedObservation = receipt.observation;
787
+ const selectedTarget = selectedTargetRef.current;
788
+ let projectedObservation: BrowserObservation | null = null;
789
+ if (
790
+ settled &&
791
+ receivedObservation &&
792
+ canProjectResult() &&
793
+ receipt.browserSessionId === browserSessionId &&
794
+ receipt.controllerGeneration === expectedControllerGeneration &&
795
+ receipt.targetId === fence.targetId &&
796
+ observationRef.current.browserSessionId === browserSessionId &&
797
+ receivedObservation.browserSessionId === browserSessionId &&
798
+ selectedTarget?.browserSessionId === browserSessionId &&
799
+ selectedTarget.id === fence.targetId &&
800
+ receivedObservation.target.id === fence.targetId &&
801
+ selectedTarget.controllerGeneration === expectedControllerGeneration &&
802
+ receivedObservation.target.controllerGeneration === expectedControllerGeneration &&
803
+ selectedTarget.targetGeneration === fence.expectedTargetGeneration &&
804
+ receivedObservation.target.targetGeneration === fence.expectedTargetGeneration &&
805
+ (selectedTarget.documentGeneration === fence.expectedDocumentGeneration ||
806
+ selectedTarget.documentGeneration === receivedObservation.target.documentGeneration)
807
+ ) {
808
+ // A receipt updates its own selected page only. Its operation outcome
809
+ // remains available even when the human has moved to another page.
810
+ projectedObservation = receivedObservation;
423
811
  observationRef.current = {
424
812
  browserSessionId,
425
- observation: receipt.observation,
813
+ observation: receivedObservation,
426
814
  };
427
- setState((current) =>
428
- current.browserSessionId === browserSessionId
429
- ? {
430
- ...current,
431
- observation: receipt.observation,
432
- targets: replaceTarget(current.targets, receipt.observation!.target),
433
- }
434
- : current,
435
- );
815
+ selectedTargetRef.current = receivedObservation.target;
816
+ lastObservationAtRef.current = Date.now();
436
817
  }
818
+ setState((current) =>
819
+ isCurrentResultView() &&
820
+ current.source === source &&
821
+ current.browserSessionId === browserSessionId &&
822
+ current.actionResultOrder <= resultOrder
823
+ ? {
824
+ ...current,
825
+ actionResultOrder: settled ? resultOrder : current.actionResultOrder,
826
+ error: receipt.state === "completed" ? null : current.error,
827
+ inputFailure:
828
+ receipt.state === "completed"
829
+ ? current.inputFailure
830
+ : {
831
+ operationId: receipt.operationId,
832
+ state: receipt.state,
833
+ error: receipt.error,
834
+ },
835
+ ...(projectedObservation
836
+ ? {
837
+ observation: projectedObservation,
838
+ targets: replaceTarget(current.targets, projectedObservation.target),
839
+ }
840
+ : {}),
841
+ }
842
+ : current,
843
+ );
437
844
  return receipt;
438
845
  } catch (cause) {
439
846
  const error = cause instanceof Error ? cause : new Error(String(cause));
440
- setState((current) =>
441
- current.browserSessionId === browserSessionId ? { ...current, error } : current,
442
- );
847
+ if (settleResult()) {
848
+ setState((current) =>
849
+ isCurrentResultView() &&
850
+ current.source === source &&
851
+ current.browserSessionId === browserSessionId &&
852
+ current.actionResultOrder <= resultOrder
853
+ ? { ...current, error, actionResultOrder: resultOrder }
854
+ : current,
855
+ );
856
+ }
443
857
  throw error;
444
858
  }
445
859
  },
446
- [browserSessionId, client, workspaceId],
860
+ [browserSessionId, client, enabled, invalidateRefresh, isCurrentSource, source, workspaceId],
447
861
  );
448
862
 
449
863
  const act = useCallback(
@@ -457,14 +871,53 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
457
871
  const actFromFrame = useCallback(
458
872
  async (
459
873
  action: BrowserAction | BrowserActionBatch,
460
- frame: BrowserFrame,
874
+ frame: BrowserFrameInputFence,
461
875
  operationId: string = crypto.randomUUID(),
462
- ): Promise<BrowserActionReceipt> => await dispatchAction(action, operationId, frame),
876
+ observationMode: "none" | "input" = "none",
877
+ ): Promise<BrowserActionReceipt> =>
878
+ await dispatchAction(action, operationId, frame, observationMode),
879
+ [dispatchAction],
880
+ );
881
+
882
+ const observeForInput = useCallback(async (): Promise<BrowserObservation> => {
883
+ const target = selectedTargetRef.current;
884
+ if (!enabled || !isCurrentSource()) {
885
+ throw new Error("The browser source is no longer selected.");
886
+ }
887
+ if (!browserSessionId || !target) throw new Error("No browser tab is selected.");
888
+ const observation = await client.observeBrowserTarget(workspaceId, browserSessionId, target.id);
889
+ if (
890
+ !isCurrentSource() ||
891
+ observation.browserSessionId !== browserSessionId ||
892
+ !sameObservationTarget(observation, selectedTargetRef.current)
893
+ ) {
894
+ throw new Error("The browser page changed. Open the options again.");
895
+ }
896
+ return observation;
897
+ }, [browserSessionId, client, enabled, isCurrentSource, workspaceId]);
898
+
899
+ const actFromObservation = useCallback(
900
+ async (action: BrowserAction, observation: BrowserObservation) => {
901
+ if (!sameObservationTarget(observation, selectedTargetRef.current)) {
902
+ throw new Error("The browser page changed. Open the options again.");
903
+ }
904
+ return await dispatchAction(action, crypto.randomUUID(), {
905
+ browserSessionId: observation.browserSessionId,
906
+ controllerGeneration: observation.target.controllerGeneration,
907
+ targetId: observation.target.id,
908
+ targetGeneration: observation.target.targetGeneration,
909
+ documentGeneration: observation.target.documentGeneration,
910
+ frameId: observation.frameId,
911
+ });
912
+ },
463
913
  [dispatchAction],
464
914
  );
465
915
 
466
916
  const diagnostics = useCallback(
467
917
  async (diagnosticOptions: BrowserDiagnosticsOptions = {}): Promise<BrowserDiagnosticBatch> => {
918
+ if (!enabled || !isCurrentSource()) {
919
+ throw new Error("The browser source is no longer selected.");
920
+ }
468
921
  const targetId = selectedTargetIdRef.current;
469
922
  if (!browserSessionId || !targetId) {
470
923
  throw new Error("No browser tab is selected.");
@@ -476,17 +929,20 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
476
929
  diagnosticOptions,
477
930
  );
478
931
  },
479
- [browserSessionId, client, workspaceId],
932
+ [browserSessionId, client, enabled, isCurrentSource, workspaceId],
480
933
  );
481
934
 
482
935
  const readClipboard = useCallback(async (): Promise<BrowserClipboard> => {
936
+ if (!enabled || !isCurrentSource()) {
937
+ throw new Error("The browser source is no longer selected.");
938
+ }
483
939
  if (!browserSessionId) throw new Error("No BrowserSession is selected.");
484
940
  const clipboard = await client.readBrowserClipboard(workspaceId, browserSessionId);
485
- if (clipboard.browserSessionId !== browserSessionId) {
941
+ if (!isCurrentSource() || clipboard.browserSessionId !== browserSessionId) {
486
942
  throw new Error("Browser clipboard belongs to another BrowserSession.");
487
943
  }
488
944
  return clipboard;
489
- }, [browserSessionId, client, workspaceId]);
945
+ }, [browserSessionId, client, enabled, isCurrentSource, workspaceId]);
490
946
 
491
947
  return {
492
948
  session: visible.session,
@@ -497,7 +953,10 @@ export function useBrowserSession(options: UseBrowserSessionOptions): UseBrowser
497
953
  loading: visible.loading,
498
954
  mutating: visible.mutating,
499
955
  error: visible.error,
956
+ inputFailure: visible.inputFailure,
500
957
  refresh,
958
+ observeForInput,
959
+ actFromObservation,
501
960
  selectTarget,
502
961
  openTarget,
503
962
  closeTarget,
@@ -518,6 +977,8 @@ function emptyState(browserSessionId: string | null, loading: boolean) {
518
977
  loading,
519
978
  mutating: false,
520
979
  error: null as Error | null,
980
+ inputFailure: null as BrowserInputFailure | null,
981
+ actionResultOrder: 0,
521
982
  };
522
983
  }
523
984
 
@@ -540,6 +1001,20 @@ function replaceTarget(targets: readonly BrowserTarget[], target: BrowserTarget)
540
1001
  return next.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
541
1002
  }
542
1003
 
1004
+ function sameObservationTarget(
1005
+ observation: BrowserObservation,
1006
+ target: BrowserTarget | null,
1007
+ ): boolean {
1008
+ return (
1009
+ target !== null &&
1010
+ observation.browserSessionId === target.browserSessionId &&
1011
+ observation.target.id === target.id &&
1012
+ observation.target.controllerGeneration === target.controllerGeneration &&
1013
+ observation.target.targetGeneration === target.targetGeneration &&
1014
+ observation.target.documentGeneration === target.documentGeneration
1015
+ );
1016
+ }
1017
+
543
1018
  function isMissingBrowserTarget(error: unknown): boolean {
544
1019
  return error instanceof OpenGeniApiError && error.code === "target_not_found";
545
1020
  }