@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.4

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 (275) hide show
  1. package/README.md +4 -7
  2. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  3. package/dist/lib/components/collection/collection-view.component.js +1 -0
  4. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  5. package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
  6. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
  7. package/dist/lib/components/composer/ai-composer.component.js +35 -4
  8. package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
  9. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +588 -51
  10. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  11. package/dist/lib/components/conversation/conversation-chat-area.component.js +2654 -665
  12. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  13. package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
  14. package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
  15. package/dist/lib/components/conversation/forks-popover.component.js +164 -0
  16. package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
  17. package/dist/lib/components/export/export-modal.component.d.ts +7 -2
  18. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  19. package/dist/lib/components/export/export-modal.component.js +16 -3
  20. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  21. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  22. package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
  23. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  24. package/dist/lib/components/message/message-input.component.d.ts +96 -11
  25. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  26. package/dist/lib/components/message/message-input.component.js +244 -103
  27. package/dist/lib/components/message/message-input.component.js.map +1 -1
  28. package/dist/lib/components/message/message-item.component.d.ts +171 -4
  29. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  30. package/dist/lib/components/message/message-item.component.js +899 -298
  31. package/dist/lib/components/message/message-item.component.js.map +1 -1
  32. package/dist/lib/components/message/message-list.component.d.ts +82 -21
  33. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  34. package/dist/lib/components/message/message-list.component.js +299 -52
  35. package/dist/lib/components/message/message-list.component.js.map +1 -1
  36. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
  37. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
  38. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
  39. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
  40. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
  41. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
  42. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
  43. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
  44. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
  45. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
  46. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
  47. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
  48. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
  49. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
  50. package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
  51. package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
  52. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
  53. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
  54. package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
  55. package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
  56. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
  57. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
  58. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
  59. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
  60. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
  61. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  62. package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
  63. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  64. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
  65. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  66. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
  67. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  68. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
  69. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
  70. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
  71. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
  72. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
  73. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
  74. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
  75. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
  76. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
  77. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
  78. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
  79. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
  80. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
  81. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
  82. package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
  83. package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
  84. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
  85. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
  86. package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
  87. package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
  88. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
  89. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
  90. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
  91. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
  92. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
  93. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
  94. package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
  95. package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
  96. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
  97. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
  98. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
  99. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
  100. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
  101. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
  102. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
  103. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
  104. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
  105. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
  106. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
  107. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
  108. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
  109. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
  110. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
  111. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
  112. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
  113. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
  114. package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
  115. package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
  116. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
  117. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
  118. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
  119. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
  120. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
  121. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
  122. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
  123. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
  124. package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
  125. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  126. package/dist/lib/components/realtime/media/media-channel.js +28 -1
  127. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  128. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
  129. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  130. package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
  131. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  132. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
  133. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
  134. package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
  135. package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
  136. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
  137. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
  138. package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
  139. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
  140. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
  141. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
  142. package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
  143. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
  144. package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
  145. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  146. package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
  147. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  148. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
  149. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
  150. package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
  151. package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
  152. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
  153. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  154. package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
  155. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  156. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
  157. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
  158. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
  159. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
  160. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
  161. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
  162. package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
  163. package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
  164. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
  165. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  166. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
  167. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  168. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
  169. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  170. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
  171. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  172. package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
  173. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  174. package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
  175. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  176. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
  177. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  178. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
  179. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  180. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
  181. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
  182. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
  183. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
  184. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
  185. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  186. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
  187. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  188. package/dist/lib/components/search/search-panel.component.d.ts +2 -0
  189. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  190. package/dist/lib/components/search/search-panel.component.js +25 -12
  191. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  192. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
  193. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  194. package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
  195. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  196. package/dist/lib/conversations.module.d.ts +30 -29
  197. package/dist/lib/conversations.module.d.ts.map +1 -1
  198. package/dist/lib/conversations.module.js +27 -5
  199. package/dist/lib/conversations.module.js.map +1 -1
  200. package/dist/lib/events/chat-events.d.ts +25 -0
  201. package/dist/lib/events/chat-events.d.ts.map +1 -1
  202. package/dist/lib/events/chat-events.js +36 -0
  203. package/dist/lib/events/chat-events.js.map +1 -1
  204. package/dist/lib/models/agent-turn.model.d.ts +5 -0
  205. package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
  206. package/dist/lib/models/agent-turn.model.js.map +1 -1
  207. package/dist/lib/services/agent-state.service.d.ts +34 -8
  208. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  209. package/dist/lib/services/agent-state.service.js +82 -29
  210. package/dist/lib/services/agent-state.service.js.map +1 -1
  211. package/dist/lib/services/artifact-state.service.d.ts +0 -9
  212. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  213. package/dist/lib/services/artifact-state.service.js +1 -32
  214. package/dist/lib/services/artifact-state.service.js.map +1 -1
  215. package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
  216. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
  217. package/dist/lib/services/browser-realtime-media-host.js +19 -0
  218. package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
  219. package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
  220. package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
  221. package/dist/lib/services/browser-recording-unload-guard.js +43 -0
  222. package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
  223. package/dist/lib/services/conversation-agent.service.d.ts +35 -11
  224. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  225. package/dist/lib/services/conversation-agent.service.js +65 -20
  226. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  227. package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
  228. package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
  229. package/dist/lib/services/conversation-detail-window.store.js +50 -9
  230. package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
  231. package/dist/lib/services/conversation-naming.d.ts +72 -22
  232. package/dist/lib/services/conversation-naming.d.ts.map +1 -1
  233. package/dist/lib/services/conversation-naming.js +84 -10
  234. package/dist/lib/services/conversation-naming.js.map +1 -1
  235. package/dist/lib/services/data-cache.service.d.ts +13 -5
  236. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  237. package/dist/lib/services/data-cache.service.js +39 -19
  238. package/dist/lib/services/data-cache.service.js.map +1 -1
  239. package/dist/lib/services/export.service.d.ts +26 -9
  240. package/dist/lib/services/export.service.d.ts.map +1 -1
  241. package/dist/lib/services/export.service.js +61 -18
  242. package/dist/lib/services/export.service.js.map +1 -1
  243. package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
  244. package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
  245. package/dist/lib/services/realtime-audio-recorder.js +71 -11
  246. package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
  247. package/dist/lib/services/realtime-pairing.d.ts +10 -5
  248. package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
  249. package/dist/lib/services/realtime-pairing.js +15 -6
  250. package/dist/lib/services/realtime-pairing.js.map +1 -1
  251. package/dist/lib/services/realtime-session.service.d.ts +3 -2
  252. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  253. package/dist/lib/services/realtime-session.service.js +7 -2
  254. package/dist/lib/services/realtime-session.service.js.map +1 -1
  255. package/dist/lib/services/search.service.d.ts +7 -2
  256. package/dist/lib/services/search.service.d.ts.map +1 -1
  257. package/dist/lib/services/search.service.js +13 -4
  258. package/dist/lib/services/search.service.js.map +1 -1
  259. package/dist/lib/utils/conversation-branching.d.ts +4 -0
  260. package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
  261. package/dist/lib/utils/conversation-branching.js +5 -0
  262. package/dist/lib/utils/conversation-branching.js.map +1 -0
  263. package/dist/lib/utils/conversation-forks.d.ts +315 -0
  264. package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
  265. package/dist/lib/utils/conversation-forks.js +456 -0
  266. package/dist/lib/utils/conversation-forks.js.map +1 -0
  267. package/dist/public-api.d.ts +23 -1
  268. package/dist/public-api.d.ts.map +1 -1
  269. package/dist/public-api.js +30 -1
  270. package/dist/public-api.js.map +1 -1
  271. package/package.json +37 -33
  272. package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
  273. package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
  274. package/dist/lib/components/thread/thread-panel.component.js +0 -440
  275. package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
@@ -8,7 +8,8 @@ var RemoteBrowserChannel_1;
8
8
  import { RegisterClass } from '@memberjunction/global';
9
9
  import { CHANNEL_INBOUND_VIDEO_TRACK } from '@memberjunction/ai';
10
10
  import { ChannelInboundVideoBridge } from '@memberjunction/ai-realtime-client';
11
- import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
11
+ import { REALTIME_CHANNEL_CONTRACT_VERSION } from '@memberjunction/ai-core-plus';
12
+ import { BaseRealtimeChannelClient, BuildToolBackedVerbs } from '@memberjunction/realtime-runtime';
12
13
  import { RemoteBrowserSurfaceComponent } from './remote-browser-surface.component';
13
14
  import { MapToolToAction, REMOTE_BROWSER_TOOL_DEFINITIONS, REMOTE_BROWSER_TOOL_NAMES, REMOTE_BROWSER_TOOL_PREFIX, RemoteBrowserToolArgError, } from './remote-browser-tools';
14
15
  import { MediaSourceAudioSink, RemoteBrowserAudioPlayer } from './remote-browser-audio-player';
@@ -284,6 +285,39 @@ let RemoteBrowserChannel = class RemoteBrowserChannel extends BaseRealtimeChanne
284
285
  GetSurfaceComponent() {
285
286
  return RemoteBrowserSurfaceComponent;
286
287
  }
288
+ /**
289
+ * The remote browser's self-description: a real, server-hosted web browser the user can watch, with
290
+ * every `browser_*` tool as a verb (so a tool a subclass adds shows up here too). The model is shown
291
+ * its pixels (page frames), so the exposure ceiling is `pixels`.
292
+ */
293
+ GetDescriptor() {
294
+ return {
295
+ Key: this.ChannelName,
296
+ Version: REALTIME_CHANNEL_CONTRACT_VERSION,
297
+ DisplayName: this.TabTitle,
298
+ OwningPackage: '@memberjunction/ng-conversations',
299
+ Instructions: 'A live web browser you can drive while the user watches: open pages, click, type, scroll and ' +
300
+ 'read what is on screen. Narrate what you are doing; do not announce each tiny step.',
301
+ Nouns: [
302
+ {
303
+ Name: 'page',
304
+ Description: 'The page the browser is currently showing (its URL and title).',
305
+ Schema: { type: 'object' }
306
+ }
307
+ ],
308
+ // Reading the page is what exposure limits: its text is the page's state, and what the vision model makes of the
309
+ // screenshot (or where it finds an element) is derived from its pixels. A goal's result reports what the browser found.
310
+ Verbs: BuildToolBackedVerbs(this.GetToolDefinitions(), this.ToolNamePrefix, 'agent', {
311
+ [REMOTE_BROWSER_TOOL_NAMES.GetPageText]: 'state',
312
+ [REMOTE_BROWSER_TOOL_NAMES.DescribePage]: 'pixels',
313
+ [REMOTE_BROWSER_TOOL_NAMES.LocateElement]: 'pixels',
314
+ [REMOTE_BROWSER_TOOL_NAMES.AchieveGoal]: 'state',
315
+ }),
316
+ DisplayPolicy: 'open-on-start',
317
+ DefaultAvailability: 'all-sessions',
318
+ MaxExposure: 'pixels'
319
+ };
320
+ }
287
321
  /** First-run intro shown the first time the user opens the Browser tab (once per user). */
288
322
  GetOnboardingDetails() {
289
323
  return {
@@ -345,6 +379,12 @@ let RemoteBrowserChannel = class RemoteBrowserChannel extends BaseRealtimeChanne
345
379
  void this.startScreencast(instance);
346
380
  void this.startAudioStream(instance);
347
381
  }
382
+ /** Pauses the surface's snapshot poll while it is out of sight; the screencast and the audio keep running. */
383
+ OnSurfaceVisibilityChange(visible) {
384
+ if (this.surface) {
385
+ this.surface.Visible = visible;
386
+ }
387
+ }
348
388
  UnbindSurface() {
349
389
  this.humanInputSub?.unsubscribe();
350
390
  this.humanInputSub = null;
@@ -421,7 +461,7 @@ let RemoteBrowserChannel = class RemoteBrowserChannel extends BaseRealtimeChanne
421
461
  /**
422
462
  * Forwards one PUSHED screencast frame to the bound surface's canvas. Called by the session service
423
463
  * when a `RemoteBrowserScreencastFrame` arrives on the push-status stream for THIS session. No-op when
424
- * the channel isn't streaming or has no bound surface (e.g. the tab pane is collapsed).
464
+ * the channel isn't streaming or has no bound surface (e.g. its tab has not been shown yet).
425
465
  *
426
466
  * Under streaming the surface's snapshot poll is stopped, so this is the ONLY thing that sees the
427
467
  * page while frames are being pushed — which is why the frame now carries the URL (#3496). Without
@@ -1 +1 @@
1
- {"version":3,"file":"remote-browser-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/remote-browser/remote-browser-channel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Type } from '@angular/core';\nimport type { Subscription } from 'rxjs';\nimport { RegisterClass } from '@memberjunction/global';\nimport { CHANNEL_INBOUND_VIDEO_TRACK, JSONValue, RealtimeToolDefinition, RealtimeTrack, RealtimeTrackDescriptor } from '@memberjunction/ai';\nimport { ChannelInboundVideoBridge, IChannelFrameProvider } from '@memberjunction/ai-realtime-client';\nimport { BaseRealtimeChannelClient, ChannelOnboardingDetails } from '@memberjunction/realtime-runtime';\nimport { RemoteBrowserHumanInputEvent, RemoteBrowserSnapshotView, RemoteBrowserSurfaceComponent } from './remote-browser-surface.component';\nimport {\n MapToolToAction,\n REMOTE_BROWSER_TOOL_DEFINITIONS,\n REMOTE_BROWSER_TOOL_NAMES,\n REMOTE_BROWSER_TOOL_PREFIX,\n RemoteBrowserAction,\n RemoteBrowserToolArgError,\n} from './remote-browser-tools';\nimport { MediaSourceAudioSink, RemoteBrowserAudioChunkInput, RemoteBrowserAudioPlayer } from './remote-browser-audio-player';\n\n/**\n * GraphQL mutation that drives the SERVER-hosted browser. The channel awaits it for every\n * `browser_*` tool call and feeds the result back to the model.\n */\nconst EXECUTE_REMOTE_BROWSER_ACTION_MUTATION = `\n mutation ExecuteRemoteBrowserAction(\n $agentSessionID: String!, $kind: String!, $url: String, $selector: String,\n $x: Float, $y: Float, $text: String, $key: String,\n $deltaX: Float, $deltaY: Float, $ms: Float\n ) {\n ExecuteRemoteBrowserAction(\n agentSessionID: $agentSessionID, kind: $kind, url: $url, selector: $selector,\n x: $x, y: $y, text: $text, key: $key,\n deltaX: $deltaX, deltaY: $deltaY, ms: $ms\n ) {\n Success\n CurrentUrl\n Detail\n }\n }\n`;\n\n/** The narrow projection of the `ExecuteRemoteBrowserAction` mutation payload the channel reads. */\ninterface ExecuteRemoteBrowserActionResult {\n ExecuteRemoteBrowserAction: {\n Success: boolean;\n CurrentUrl: string | null;\n Detail: string | null;\n } | null;\n}\n\n/**\n * GOAL mutation — hands a high-level goal to the server's autonomous browser agent (computer-use loop or\n * backend native AI) instead of relaying a granular action. The server plans + executes; we await the\n * terminal outcome. (Live per-step narration is a server-bridged concern; over this client-direct mutation\n * we get the final result.)\n */\nconst EXECUTE_REMOTE_BROWSER_GOAL_MUTATION = `\n mutation ExecuteRemoteBrowserGoal($agentSessionID: String!, $goal: String!, $startUrl: String) {\n ExecuteRemoteBrowserGoal(agentSessionID: $agentSessionID, goal: $goal, startUrl: $startUrl) {\n Success\n GoalRunID\n Strategy\n CurrentUrl\n Status\n StepCount\n Detail\n }\n }\n`;\n\n/**\n * POLL query for the async goal run. `ExecuteRemoteBrowserGoal` STARTS the (potentially multi-minute)\n * goal loop and returns a `GoalRunID` with `Status: 'Running'`; the channel polls this until the run\n * reports a terminal status — so no single request is held open for the whole loop (which would die at\n * a browser/proxy/janitor transport timeout and lose the result).\n */\nconst GET_REMOTE_BROWSER_GOAL_RESULT_QUERY = `\n query GetRemoteBrowserGoalResult($agentSessionID: String!, $goalRunID: String!) {\n GetRemoteBrowserGoalResult(agentSessionID: $agentSessionID, goalRunID: $goalRunID) {\n Success\n GoalRunID\n Strategy\n CurrentUrl\n Status\n StepCount\n Detail\n }\n }\n`;\n\n/** The narrow projection of a goal-result payload (shared by the start mutation + the poll query). */\ninterface RemoteBrowserGoalPayload {\n Success: boolean;\n GoalRunID: string | null;\n Strategy: string | null;\n CurrentUrl: string | null;\n Status: string | null;\n StepCount: number | null;\n Detail: string | null;\n}\n\n/** The narrow projection of the `ExecuteRemoteBrowserGoal` (start) mutation payload the channel reads. */\ninterface ExecuteRemoteBrowserGoalResult {\n ExecuteRemoteBrowserGoal: RemoteBrowserGoalPayload | null;\n}\n\n/** The narrow projection of the `GetRemoteBrowserGoalResult` (poll) query payload the channel reads. */\ninterface GetRemoteBrowserGoalResultPayload {\n GetRemoteBrowserGoalResult: RemoteBrowserGoalPayload | null;\n}\n\n/**\n * GraphQL mutation that asks the server to start PUSHING live CDP screencast frames for the session.\n * Returns `Streaming: true` when the backend supports `ScreenStreaming` and the stream started; the\n * channel then drives the surface's canvas. `Streaming: false` (capability absent / start failed) leaves\n * the surface on its 700ms snapshot poll fallback.\n */\nconst START_SCREENCAST_MUTATION = `\n mutation StartRemoteBrowserScreencast($agentSessionID: String!) {\n StartRemoteBrowserScreencast(agentSessionID: $agentSessionID) {\n Streaming\n }\n }\n`;\n\n/** GraphQL mutation that stops the server-pushed screencast (best-effort teardown). */\nconst STOP_SCREENCAST_MUTATION = `\n mutation StopRemoteBrowserScreencast($agentSessionID: String!) {\n StopRemoteBrowserScreencast(agentSessionID: $agentSessionID)\n }\n`;\n\n/**\n * GraphQL mutation that asks the server to start PUSHING live tab-audio chunks for the session — so a\n * co-agent demoing a video/audio site is HEARD. Returns `Streaming: true` when the backend can capture\n * audio (v1 gates by backend implementation) and the stream started; `Streaming: false` means no audio\n * (capability absent / start failed) and the client simply plays nothing.\n */\nconst START_AUDIO_STREAM_MUTATION = `\n mutation StartRemoteBrowserAudioStream($agentSessionID: String!) {\n StartRemoteBrowserAudioStream(agentSessionID: $agentSessionID) {\n Streaming\n }\n }\n`;\n\n/** GraphQL mutation that stops the server-pushed tab-audio stream (best-effort teardown). */\nconst STOP_AUDIO_STREAM_MUTATION = `\n mutation StopRemoteBrowserAudioStream($agentSessionID: String!) {\n StopRemoteBrowserAudioStream(agentSessionID: $agentSessionID)\n }\n`;\n\n/** The narrow projection of the `StartRemoteBrowserAudioStream` mutation payload the channel reads. */\ninterface StartRemoteBrowserAudioStreamResult {\n StartRemoteBrowserAudioStream: {\n Streaming: boolean;\n } | null;\n}\n\n/**\n * HUMAN-TAKEOVER mutation — relays ONE pointer/keyboard input the user performed on the live canvas into the\n * server-hosted browser (Collaborative control). Best-effort: the server returns `false` when the backend\n * lacks `HumanTakeover` or no live browser exists; the channel doesn't act on the boolean.\n */\nconst RELAY_HUMAN_INPUT_MUTATION = `\n mutation RelayRemoteBrowserHumanInput(\n $agentSessionID: String!, $kind: String!, $x: Float, $y: Float, $button: String, $key: String,\n $text: String, $deltaX: Float, $deltaY: Float, $modifiers: String\n ) {\n RelayRemoteBrowserHumanInput(\n agentSessionID: $agentSessionID, kind: $kind, x: $x, y: $y, button: $button, key: $key,\n text: $text, deltaX: $deltaX, deltaY: $deltaY, modifiers: $modifiers\n )\n }\n`;\n\n/**\n * COPY-OUT query — reads the remote page's current text selection so the surface can write it to the LOCAL\n * clipboard on a `copy` / Cmd+C (the mirror of the `'text'` paste-in path). Returns `''` when nothing is\n * selected, no live browser exists, or the backend lacks `HumanTakeover`.\n */\nconst GET_SELECTION_QUERY = `\n query GetRemoteBrowserSelection($agentSessionID: String!) {\n GetRemoteBrowserSelection(agentSessionID: $agentSessionID) {\n Text\n }\n }\n`;\n\n/** The narrow projection of the `GetRemoteBrowserSelection` query payload the channel reads. */\ninterface GetRemoteBrowserSelectionResult {\n GetRemoteBrowserSelection: {\n Text: string;\n } | null;\n}\n\n/** The narrow projection of the `StartRemoteBrowserScreencast` mutation payload the channel reads. */\ninterface StartRemoteBrowserScreencastResult {\n StartRemoteBrowserScreencast: {\n Streaming: boolean;\n } | null;\n}\n\n/** GraphQL query the surface fetcher runs — the live screenshot + URL of the server browser. */\nconst REMOTE_BROWSER_SNAPSHOT_QUERY = `\n query RemoteBrowserSnapshot($agentSessionID: String!) {\n RemoteBrowserSnapshot(agentSessionID: $agentSessionID) {\n ScreenshotBase64\n CurrentUrl\n }\n }\n`;\n\n/** The narrow projection of the `RemoteBrowserSnapshot` query payload the channel reads. */\ninterface RemoteBrowserSnapshotResult {\n RemoteBrowserSnapshot: RemoteBrowserSnapshotView | null;\n}\n\n/**\n * VISION-QUERY mutation (separate from {@link EXECUTE_REMOTE_BROWSER_ACTION_MUTATION} — this OBSERVES the page,\n * it does not drive it). The server captures the live screenshot and runs a fast vision model over it, so the\n * non-omnimodal voice agent can \"see\" the page: a text description and/or localized elements with pixel\n * centroids. Backs both `browser_DescribePage` (no target) and `browser_LocateElement` (a target description).\n */\nconst INTERPRET_PAGE_MUTATION = `\n mutation InterpretRemoteBrowserPage($agentSessionID: String!, $query: String) {\n InterpretRemoteBrowserPage(agentSessionID: $agentSessionID, query: $query) {\n Description\n Elements {\n Label\n X\n Y\n Confidence\n }\n Detail\n }\n }\n`;\n\n/** One element localized by the visual interpreter — label + pixel centroid + confidence. */\ninterface RemoteBrowserInterpretedElement {\n Label: string;\n X: number;\n Y: number;\n Confidence: number;\n}\n\n/** The narrow projection of the `InterpretRemoteBrowserPage` mutation payload the channel reads. */\ninterface InterpretRemoteBrowserPageResult {\n InterpretRemoteBrowserPage: {\n Description: string | null;\n Elements: RemoteBrowserInterpretedElement[];\n Detail: string | null;\n } | null;\n}\n\n/** The result payload (serialized to JSON) the channel returns to the model per tool call. */\ninterface RemoteBrowserToolResult {\n success: boolean;\n /** The page URL after the action, when the server reported one. */\n currentUrl?: string;\n /** Human-readable detail (e.g. extracted page text for `browser_GetPageText`, or an error). */\n detail?: string;\n /** Error description when `success` is false. */\n error?: string;\n}\n\n/**\n * The REMOTE BROWSER as a pluggable interactive channel — a {@link BaseRealtimeChannelClient}\n * resolved from the `MJ: AI Agent Channels` registry row whose `ClientPluginClass` is\n * `'RealtimeRemoteBrowserChannel'`. One instance per session (ClassFactory-created at session\n * start).\n *\n * Topology (CLIENT-DIRECT, like the whiteboard — the browser just happens to live on the\n * server):\n * - **Action**: the `browser_*` client-executed tool set ({@link REMOTE_BROWSER_TOOL_DEFINITIONS}).\n * {@link ApplyAgentTool} maps a tool call → a normalized {@link RemoteBrowserAction}\n * ({@link MapToolToAction}) and awaits the `ExecuteRemoteBrowserAction` GraphQL mutation\n * (via {@link RealtimeChannelContext.ExecuteServerAction}) to drive the server browser,\n * returning a concise JSON result for the model. Never throws — argument and transport\n * failures map to a `{ success: false, error }` payload.\n * - **Perception**: after a successful action, a `[browser]` context note carries the new\n * page URL so the agent perceives where the page went; the surface independently polls a\n * live screenshot.\n * - **Surface**: {@link RemoteBrowserSurfaceComponent}, created dynamically in the channel\n * tab; the plugin hands it the session's provider + id in {@link BindSurface} so it can\n * poll `RemoteBrowserSnapshot`. HUMAN TAKEOVER is enabled by default (Collaborative): the\n * user can click/type into the live canvas and those events relay to the server browser via\n * {@link RELAY_HUMAN_INPUT_MUTATION} (server-gated on the backend's `HumanTakeover` capability).\n *\n * The channel keeps NO client-side state of record — the browser's state lives entirely on\n * the server — so {@link SerializeState} / {@link RestoreState} use the base no-op behavior.\n */\n@RegisterClass(BaseRealtimeChannelClient, 'RealtimeRemoteBrowserChannel')\nexport class RemoteBrowserChannel extends BaseRealtimeChannelClient<RemoteBrowserSurfaceComponent> implements IChannelFrameProvider {\n /** The live bound surface, when the channel tab's pane is instantiated. */\n private surface: RemoteBrowserSurfaceComponent | null = null;\n\n /** Shared video bridge streaming browser frames to the model when the model supports inbound video. */\n private videoBridge: ChannelInboundVideoBridge | null = null;\n\n /**\n * Sourced tracks: Remote Browser can source inbound video to the model when the model supports it.\n */\n public override GetSourcedTracks(): readonly RealtimeTrackDescriptor[] {\n return [CHANNEL_INBOUND_VIDEO_TRACK];\n }\n\n /**\n * Produces the latest browser screenshot as a base64-encoded frame for the video bridge.\n * Under active screencast streaming, returns null to avoid redundant server snapshot round-trips\n * and duplicate frame sourcing into the video bridge.\n */\n public async GetLatestFrame(): Promise<string | null> {\n this.ensureVideoBridge();\n if (this.streaming) {\n return null;\n }\n const snapshot = await this.fetchSnapshot();\n return snapshot?.ScreenshotBase64 ?? null;\n }\n\n /** Subscription to the bound surface's `HumanInput` output, torn down on unbind/dispose. */\n private humanInputSub: Subscription | null = null;\n\n /**\n * Whether the server confirmed it is PUSHING screencast frames for this session (`ScreenStreaming`\n * supported). When `true` the surface renders pushed frames on its canvas and skips its poll, and\n * {@link OnScreencastFrame} forwards each pushed frame to it. When `false` the surface keeps polling.\n */\n private streaming = false;\n\n /**\n * Whether the server confirmed it is PUSHING tab-audio chunks for this session (the backend can capture\n * audio). When `true` {@link OnAudioChunk} feeds each pushed chunk to {@link audioPlayer}; when `false`\n * no audio plays.\n */\n private audioStreaming = false;\n\n /**\n * The last URL the agent was TOLD about, so an unchanged page is not re-announced (#3496). `null`\n * until the first sighting, which is deliberately announced as a plain \"current page\" rather than\n * as somebody else navigating — the first page of a session was nobody's takeover.\n */\n private lastNotedUrl: string | null = null;\n\n /**\n * How many browser operations the AGENT itself has in flight right now (#3496).\n *\n * Attribution cannot be read off the feed a change arrives on. A pushed frame or a perception poll\n * only says the page moved; it is `> 0` here that says the agent is the one moving it. Two cases\n * make that necessary rather than tidy:\n *\n * - **an action's frames outrun its reply.** Under streaming, frames of the new page are pushed\n * while `ExecuteRemoteBrowserAction` is still in flight, so the observation reliably lands BEFORE\n * the mutation returns the URL — the agent's own navigation announced back to it as a takeover.\n * - **a goal drives for minutes.** `browser_AchieveGoal` runs an autonomous loop server-side and\n * every page it opens is observed with nothing yet returned, so the whole run would narrate\n * itself as somebody else.\n *\n * A counter, not a flag: goals and actions overlap, and the last one to finish must not clear a\n * window another still owns.\n */\n private agentDrivingDepth = 0;\n\n /** The client-side audio player fed pushed chunks while {@link audioStreaming}; `null` until started. */\n private audioPlayer: RemoteBrowserAudioPlayer | null = null;\n\n /** Subscription to the bound surface's `AudioMutedChange` output (the speaker toggle), torn down on unbind. */\n private audioMutedSub: Subscription | null = null;\n\n /**\n * Poll cadence + deadline for {@link pollGoalResult} (the async `browser_AchieveGoal` result poll).\n * Protected so tests can shrink them; production polls every 2.5s for up to 5 minutes (a goal loop\n * past 5 min keeps running server-side, the model just gets a \"still running\" note).\n */\n protected GoalPollIntervalMs = 2500;\n protected GoalPollTimeoutMs = 5 * 60 * 1000;\n\n public get ChannelName(): string {\n return 'Remote Browser';\n }\n\n public get ToolNamePrefix(): string {\n return REMOTE_BROWSER_TOOL_PREFIX;\n }\n\n public get TabTitle(): string {\n return 'Browser';\n }\n\n public get TabIcon(): string {\n return 'fa-solid fa-globe';\n }\n\n public GetToolDefinitions(): RealtimeToolDefinition[] {\n return REMOTE_BROWSER_TOOL_DEFINITIONS;\n }\n\n public override GetSurfaceComponent(): Type<RemoteBrowserSurfaceComponent> {\n return RemoteBrowserSurfaceComponent;\n }\n\n /** First-run intro shown the first time the user opens the Browser tab (once per user). */\n public override GetOnboardingDetails(): ChannelOnboardingDetails {\n return {\n Heading: 'Remote Browser',\n Description:\n 'The agent drives a live web browser on the server and you can watch it work right here. ' +\n 'You can also grab the wheel: click and type directly on the live page and the agent picks ' +\n 'up right where you left off.',\n Tips: [\n 'Ask the agent to look something up, open a site or fill in a form — it controls the page.',\n 'Click on the live view to take over, then click and type to drive it yourself — the \"You\\'re driving\" badge shows when takeover is active.',\n 'The current page URL is shown so you always know where the agent has navigated.',\n ],\n IconClass: 'fa-solid fa-globe',\n };\n }\n\n /** Starts the video bridge streaming browser frames to the model when inbound video is supported. */\n protected override OnInitialize(): void {\n this.ensureVideoBridge();\n }\n\n public override OnSessionStarted(): void {\n this.ensureVideoBridge();\n }\n\n private ensureVideoBridge(): ChannelInboundVideoBridge | null {\n if (!this.videoBridge && this.Context) {\n this.videoBridge = new ChannelInboundVideoBridge(() => this.Context?.Client, this);\n }\n if (this.videoBridge && !this.videoBridge.IsActive && this.Context?.Client?.IsTrackEstablished('video', 'inbound')) {\n this.videoBridge.Start?.();\n }\n return this.videoBridge;\n }\n\n /**\n * Wires the dynamically-created surface: hands it a snapshot fetcher closing over the\n * channel context (session id + provider live there), so the surface stays transport-\n * agnostic. Set BEFORE the surface's first change detection (the pane binds synchronously),\n * so its `ngOnInit` poll has the fetcher.\n *\n * Also asks the server to start a live screencast. When the backend supports `ScreenStreaming` the\n * server starts PUSHING frames and reports `Streaming: true`; we flip the surface to canvas mode (its\n * poll is then skipped) and {@link OnScreencastFrame} paints each pushed frame. When the backend lacks\n * the capability (`Streaming: false`) the surface keeps the snapshot poll already running — graceful\n * fallback, no further action.\n *\n * HUMAN TAKEOVER is enabled BY DEFAULT (Collaborative): the surface is flipped `Interactive = true` and\n * its `HumanInput` output subscribed, forwarding each pointer/keyboard event to the server via\n * {@link RELAY_HUMAN_INPUT_MUTATION}. Takeover only takes effect on the canvas (screencast) path; the\n * `<img>` poll fallback stays view-only. The server gates the actual routing on the backend's\n * `HumanTakeover` capability, so this is safe to enable unconditionally.\n */\n public BindSurface(instance: RemoteBrowserSurfaceComponent): void {\n this.surface = instance;\n instance.Fetch = () => this.fetchSnapshot();\n // Copy-out: the surface reads the remote selection through this on a local `copy` and writes it locally.\n instance.FetchSelection = () => this.fetchSelection();\n instance.Interactive = true;\n this.ensureVideoBridge();\n this.humanInputSub = instance.HumanInput.subscribe((input) => this.relayHumanInput(input));\n this.audioMutedSub = instance.AudioMutedChange.subscribe((muted) => this.audioPlayer?.SetMuted(muted));\n void this.startScreencast(instance);\n void this.startAudioStream(instance);\n }\n\n public override UnbindSurface(): void {\n this.humanInputSub?.unsubscribe();\n this.humanInputSub = null;\n this.audioMutedSub?.unsubscribe();\n this.audioMutedSub = null;\n void this.stopScreencast();\n void this.stopAudioStream();\n this.surface = null;\n }\n\n public override Dispose(): void {\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n this.videoBridge?.Stop();\n this.videoBridge = null;\n this.humanInputSub?.unsubscribe();\n this.humanInputSub = null;\n this.audioMutedSub?.unsubscribe();\n this.audioMutedSub = null;\n void this.stopScreencast();\n void this.stopAudioStream();\n super.Dispose();\n }\n\n /** Timestamp of the last screencast frame pushed to the video bridge (paces pushes to negotiated cadence). */\n private lastScreencastPushTime = 0;\n\n /** Base64 content of the last frame pushed to the video bridge (for change-driven deduplication). */\n private lastPushedScreencastFrame: string | null = null;\n\n /** URL associated with the last frame pushed to the video bridge. */\n private lastPushedUrl: string | null = null;\n\n /** Minimum allowable screencast push cadence (250ms = 4 fps debounce limit during active bursts). */\n private static readonly SCREENCAST_MIN_CADENCE_MS = 250;\n\n /** Default screencast push cadence when not otherwise negotiated (1000ms = 1 fps ceiling for Gemini Live). */\n private static readonly SCREENCAST_DEFAULT_CADENCE_MS = 1000;\n\n /** Maximum interval (ms) between visual frame pushes on a static page (heartbeat to maintain track liveness). */\n private static readonly SCREENCAST_HEARTBEAT_MS = 15_000;\n\n /** Trailing timer to deliver the settled resting frame after a burst of rapid user activity. */\n private screencastTrailingTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Pending frame buffered during an active cooldown interval, waiting to settle. */\n private pendingScreencastFrame: { dataBase64: string; currentUrl?: string | null } | null = null;\n\n /** Cancels any active trailing-edge settle timer and clears the handle. */\n private clearScreencastTrailingTimer(): void {\n if (this.screencastTrailingTimer != null) {\n clearTimeout(this.screencastTrailingTimer);\n this.screencastTrailingTimer = null;\n }\n }\n\n /**\n * Pushes a frame to the video bridge, recording timestamp, frame content, and URL.\n */\n private pushScreencastFrame(dataBase64: string, currentUrl?: string | null): void {\n this.lastScreencastPushTime = Date.now();\n this.lastPushedScreencastFrame = dataBase64;\n this.lastPushedUrl = currentUrl ?? null;\n this.ensureVideoBridge()?.PushFrame(dataBase64);\n }\n\n /**\n * Resolves the effective push cadence in milliseconds based on the negotiated inbound video track.\n * Defaults to 1000ms (1 fps ceiling for Gemini Live), but clamps down to a minimum of 250ms (4 fps)\n * if the negotiated track specifies a higher `Rate`.\n */\n private getNegotiatedVideoCadenceMs(): number {\n const client = this.Context?.Client;\n if (!client) {\n return RemoteBrowserChannel.SCREENCAST_DEFAULT_CADENCE_MS;\n }\n const tracks: readonly RealtimeTrack[] = client.EstablishedTracks;\n const videoTrack = tracks.find(\n (t: RealtimeTrack) =>\n t.Descriptor.Modality === 'video' &&\n t.Descriptor.Direction === 'inbound'\n );\n const rate = videoTrack?.Descriptor.Rate;\n if (typeof rate === 'number' && rate > 0) {\n return Math.max(\n RemoteBrowserChannel.SCREENCAST_MIN_CADENCE_MS,\n Math.floor(1000 / rate)\n );\n }\n return RemoteBrowserChannel.SCREENCAST_DEFAULT_CADENCE_MS;\n }\n\n /**\n * Forwards one PUSHED screencast frame to the bound surface's canvas. Called by the session service\n * when a `RemoteBrowserScreencastFrame` arrives on the push-status stream for THIS session. No-op when\n * the channel isn't streaming or has no bound surface (e.g. the tab pane is collapsed).\n *\n * Under streaming the surface's snapshot poll is stopped, so this is the ONLY thing that sees the\n * page while frames are being pushed — which is why the frame now carries the URL (#3496). Without\n * it, a user navigating during a screencast changed the picture and nothing else: the agent kept\n * describing the page it last opened, and the pixels proving otherwise were right there on screen.\n *\n * Pushes to the video bridge are CHANGE-DRIVEN with a TRAILING-EDGE SETTLE DEBOUNCE:\n * 1. The human user surface renders immediately at full 60fps responsiveness.\n * 2. When the page is static (same image and URL), pushes are deduplicated to avoid burning\n * ~15k tokens/min of identical visual context.\n * 3. A frame is pushed immediately on the leading edge when visual content or URL changes after\n * the negotiated cadence (default 1000ms, clamped to >= 250ms).\n * 4. During rapid bursts (scrolling, typing, clicking) within the cooldown window, subsequent frames\n * are buffered; when the cooldown expires, a trailing timer delivers the settled resting frame\n * so the model never misses the final user state.\n * 5. A 15-second heartbeat ensures visual track liveness even during extended idle periods.\n *\n * @param dataBase64 The frame image as raw base64 JPEG (no `data:` prefix).\n * @param currentUrl The browser's URL when the frame was captured; absent from older servers.\n */\n public OnScreencastFrame(dataBase64: string, currentUrl?: string | null): void {\n if (!this.streaming) {\n return;\n }\n\n this.surface?.RenderFrame(dataBase64);\n\n const now = Date.now();\n const cadenceMs = this.getNegotiatedVideoCadenceMs();\n const elapsed = now - this.lastScreencastPushTime;\n\n if (elapsed >= cadenceMs) {\n // Cooldown has expired: leading edge push.\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n\n const frameChanged = dataBase64 !== this.lastPushedScreencastFrame;\n const urlChanged = currentUrl != null && currentUrl !== this.lastPushedUrl;\n const heartbeatElapsed = elapsed >= RemoteBrowserChannel.SCREENCAST_HEARTBEAT_MS;\n\n if (frameChanged || urlChanged || heartbeatElapsed) {\n this.pushScreencastFrame(dataBase64, currentUrl);\n }\n } else {\n // Within cooldown window: buffer latest frame and schedule trailing settle timer.\n this.pendingScreencastFrame = { dataBase64, currentUrl };\n if (!this.screencastTrailingTimer) {\n const delay = Math.max(0, cadenceMs - elapsed);\n this.screencastTrailingTimer = setTimeout(() => {\n this.screencastTrailingTimer = null;\n if (!this.streaming || !this.pendingScreencastFrame) {\n return;\n }\n const { dataBase64: pendingData, currentUrl: pendingUrl } = this.pendingScreencastFrame;\n this.pendingScreencastFrame = null;\n\n const frameChanged = pendingData !== this.lastPushedScreencastFrame;\n const urlChanged = pendingUrl != null && pendingUrl !== this.lastPushedUrl;\n const heartbeat = (Date.now() - this.lastScreencastPushTime) >= RemoteBrowserChannel.SCREENCAST_HEARTBEAT_MS;\n\n if (frameChanged || urlChanged || heartbeat) {\n this.pushScreencastFrame(pendingData, pendingUrl);\n }\n }, delay);\n }\n }\n\n // #3496: URL perception note runs AFTER the push so the visual image lands before/with the note.\n this.notePageChange(currentUrl, 'observed');\n }\n\n /**\n * Feeds one PUSHED tab-audio chunk to the client-side audio player. Called by the session service when a\n * `RemoteBrowserAudioChunk` arrives on the push-status stream for THIS session. No-op when the channel\n * isn't audio-streaming or the player has been torn down.\n *\n * @param chunk The pushed audio chunk (base64 webm-opus + codec/seq metadata).\n */\n public OnAudioChunk(chunk: RemoteBrowserAudioChunkInput): void {\n if (this.audioStreaming) {\n this.audioPlayer?.Enqueue(chunk);\n }\n }\n\n /**\n * Asks the server to start the live screencast and, on success, flips the surface to canvas mode so it\n * stops polling and starts painting pushed frames. Best-effort: a `null`/`Streaming: false` result\n * (capability absent or transport failure) leaves the surface on its poll fallback.\n */\n private async startScreencast(instance: RemoteBrowserSurfaceComponent): Promise<void> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n const data = await this.Context?.ExecuteServerAction<StartRemoteBrowserScreencastResult>(START_SCREENCAST_MUTATION, { agentSessionID: sessionId });\n if (data?.StartRemoteBrowserScreencast?.Streaming === true) {\n this.streaming = true;\n instance.Streaming = true;\n }\n }\n\n /**\n * Asks the server to start the live tab-audio stream and, on success, spins up the client-side\n * {@link RemoteBrowserAudioPlayer} (speaker ON by default — the call is the activating user gesture) so\n * pushed chunks play. Best-effort: a `null`/`Streaming: false` result (no audio capability or transport\n * failure) leaves the channel silent with no player.\n *\n * @param instance The bound surface, flipped to show the speaker toggle when audio starts.\n */\n private async startAudioStream(instance: RemoteBrowserSurfaceComponent): Promise<void> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n const data = await this.Context?.ExecuteServerAction<StartRemoteBrowserAudioStreamResult>(START_AUDIO_STREAM_MUTATION, { agentSessionID: sessionId });\n if (data?.StartRemoteBrowserAudioStream?.Streaming === true) {\n this.audioStreaming = true;\n this.audioPlayer = new RemoteBrowserAudioPlayer(new MediaSourceAudioSink());\n // Speaker defaults ON; reflect that on the surface so the toggle renders un-muted.\n instance.AudioAvailable = true;\n instance.AudioMuted = false;\n }\n }\n\n /** Asks the server to stop the tab-audio stream (best-effort), disposes the player, and clears state. */\n private async stopAudioStream(): Promise<void> {\n const wasStreaming = this.audioStreaming;\n this.audioStreaming = false;\n this.audioPlayer?.Dispose();\n this.audioPlayer = null;\n const sessionId = this.Context?.AgentSessionID;\n if (!wasStreaming || !sessionId) {\n return;\n }\n await this.Context?.ExecuteServerAction(STOP_AUDIO_STREAM_MUTATION, { agentSessionID: sessionId });\n }\n\n /**\n * Relays ONE human-takeover input from the surface to the server's {@link RELAY_HUMAN_INPUT_MUTATION}.\n * Best-effort and fire-and-forget: never throws, and the boolean result is ignored (the server already\n * gates routing on the backend's `HumanTakeover` capability). No-op when no live session id exists.\n *\n * @param input The flattened pointer/keyboard input the user performed on the live canvas.\n */\n private relayHumanInput(input: RemoteBrowserHumanInputEvent): void {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n void this.Context?.ExecuteServerAction(RELAY_HUMAN_INPUT_MUTATION, {\n agentSessionID: sessionId,\n kind: input.kind,\n x: input.x ?? null,\n y: input.y ?? null,\n button: input.button ?? null,\n key: input.key ?? null,\n // Paste-in: the `'text'` kind carries the local clipboard text the server inserts into the page.\n text: input.text ?? null,\n deltaX: input.deltaX ?? null,\n deltaY: input.deltaY ?? null,\n // Server expects a comma-separated modifier list (e.g. \"Shift,Control\"); null when none held.\n modifiers: input.modifiers && input.modifiers.length > 0 ? input.modifiers.join(',') : null,\n });\n }\n\n /**\n * Reads the remote page's current selection for COPY-OUT — backs the surface's `FetchSelection`. Awaits\n * the `GetRemoteBrowserSelection` query and returns its text. Best-effort by contract\n * ({@link RemoteBrowserSelectionFetcher}): returns `''` when no session is live or the query fails, so a\n * best-effort copy never throws.\n */\n private async fetchSelection(): Promise<string> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return '';\n }\n const data = await this.Context?.ExecuteServerAction<GetRemoteBrowserSelectionResult>(GET_SELECTION_QUERY, { agentSessionID: sessionId });\n return data?.GetRemoteBrowserSelection?.Text ?? '';\n }\n\n /** Asks the server to stop the screencast (best-effort) and clears the streaming flag. */\n private async stopScreencast(): Promise<void> {\n const wasStreaming = this.streaming;\n this.streaming = false;\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n this.lastPushedScreencastFrame = null;\n this.lastPushedUrl = null;\n this.lastScreencastPushTime = 0;\n const sessionId = this.Context?.AgentSessionID;\n if (!wasStreaming || !sessionId) {\n return;\n }\n await this.Context?.ExecuteServerAction(STOP_SCREENCAST_MUTATION, { agentSessionID: sessionId });\n }\n\n /**\n * Fetches one live snapshot of the server browser for the surface — the PERCEPTION poll.\n * Best-effort by contract ({@link RemoteBrowserSnapshotFetcher}): returns `null` when no\n * session is live or the query fails (the surface keeps its last good frame).\n *\n * Also the channel's chance to NOTICE a page change it did not cause (#3496): the poll already\n * carries the URL, and until now only the surface read it.\n */\n private async fetchSnapshot(): Promise<RemoteBrowserSnapshotView | null> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return null;\n }\n const data = await this.Context?.ExecuteServerAction<RemoteBrowserSnapshotResult>(REMOTE_BROWSER_SNAPSHOT_QUERY, { agentSessionID: sessionId });\n const snapshot = data?.RemoteBrowserSnapshot ?? null;\n this.notePageChange(snapshot?.CurrentUrl ?? null, 'observed');\n return snapshot;\n }\n\n /**\n * The ONE place the agent is told where the page is (#3496).\n *\n * Before this, the `[browser] current page:` note was pushed from exactly two call sites, both\n * immediately after a server action the MODEL itself initiated. That placement — not any caching —\n * was the bug: **a surface change the agent did not cause was invisible to it.** A user taking over\n * and navigating produced no note, so the agent went on confidently describing the previous page,\n * and only corrected when told to look again. Human takeover is on by default for `Collaborative`\n * providers, so the default configuration was the broken one.\n *\n * Routing every observation through here makes the rule \"the agent hears about the page whenever it\n * MOVES, whoever moved it\" — a property of this method rather than of where callers happen to be.\n *\n * `cause` is what the agent could never work out for itself. An `'agent'` change is one this\n * channel just performed; anything spotted by the perception poll or a pushed frame is\n * `'observed'` — someone else is driving, and saying so is the difference between the agent\n * knowing the page moved and knowing it is no longer the one moving it.\n *\n * Silent when the URL has not changed, which is not an optimisation but a requirement: the\n * perception poll runs every ~700ms and an unconditional note would bury the conversation in\n * hundreds of identical lines.\n */\n private notePageChange(url: string | null | undefined, cause: 'agent' | 'observed'): void {\n const next = (url ?? '').trim();\n if (next.length === 0) {\n return;\n }\n // The live-view bar is refreshed even when the URL is unchanged: it is idempotent, and in\n // streaming mode it is the only thing keeping the bar off \"No page loaded yet\".\n this.surface?.SetCurrentUrl(next);\n if (next === this.lastNotedUrl) {\n return;\n }\n const firstSighting = this.lastNotedUrl === null;\n this.lastNotedUrl = next;\n // A change seen WHILE the agent is driving is the agent's own, whichever feed spotted it first.\n const byAgent = cause === 'agent' || this.agentDrivingDepth > 0;\n this.Context?.SendContextNote(\n byAgent || firstSighting\n ? `[browser] current page: ${next}`\n : `[browser] the page changed to: ${next} — you did not navigate here, so someone else is driving. `\n + `Describe THIS page, not the one you last opened.`,\n );\n }\n\n /**\n * Runs one agent-initiated browser operation with {@link agentDrivingDepth} raised, so any page\n * change observed while it runs is attributed to the agent rather than to a phantom third party.\n *\n * `finally` and not a trailing decrement: the window must close on a thrown transport error too,\n * or one failed tool call would leave the channel permanently unable to report a real takeover.\n */\n private async whileAgentDrives<T>(work: () => Promise<T>): Promise<T> {\n this.agentDrivingDepth++;\n try {\n return await work();\n } finally {\n this.agentDrivingDepth--;\n }\n }\n\n /**\n * Executes ONE `browser_*` tool call: maps it to a server action and awaits the\n * `ExecuteRemoteBrowserAction` mutation, then returns a concise JSON result the model reads.\n * On success it also feeds the new page URL to the agent as a `[browser]` context note. Never\n * throws — bad arguments, no live session, and server failures all become a failed-result\n * payload so the model can narrate the problem.\n */\n public async ApplyAgentTool(toolName: string, argsJson: string): Promise<string> {\n // VISION-QUERY branch: the two interpreter tools OBSERVE the page (run a vision model over a screenshot)\n // rather than drive it, so they route to the separate interpret mutation, not MapToolToAction.\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.DescribePage) {\n return this.interpretPage(undefined);\n }\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.AchieveGoal) {\n return this.achieveGoal(argsJson);\n }\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.LocateElement) {\n const description = this.asArgString(this.parseArgs(argsJson)['description']);\n if (!description) {\n return this.fail('browser_LocateElement requires a \"description\" of the element to find.');\n }\n return this.interpretPage(description);\n }\n\n let action: RemoteBrowserAction;\n try {\n action = MapToolToAction(toolName, this.parseArgs(argsJson));\n } catch (error) {\n const message = error instanceof RemoteBrowserToolArgError ? error.message : 'Invalid Remote Browser tool arguments.';\n return this.fail(message);\n }\n\n // Briefly WAIT for the session id rather than failing instantly: the model can fire a tool the\n // first beat it connects, before mintSession binds the id (the \"session id missing\" race).\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n // Diagnostic: distinguishes \"channel never Initialized (no Context)\" from \"session id never\n // resolved within the wait window\" — the two distinct causes of a null id at tool-execution time.\n console.warn('[RemoteBrowser] browser tool invoked but AgentSessionID is null', {\n tool: toolName,\n hasContext: !!this.Context,\n agentSessionID: this.Context?.AgentSessionID ?? null,\n });\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n\n return this.whileAgentDrives(async () => {\n const data = await this.Context?.ExecuteServerAction<ExecuteRemoteBrowserActionResult>(\n EXECUTE_REMOTE_BROWSER_ACTION_MUTATION,\n this.buildVariables(sessionId, action),\n );\n const result = data?.ExecuteRemoteBrowserAction ?? null;\n if (!result) {\n return this.fail('The browser action could not be executed (no response from the server).');\n }\n if (!result.Success) {\n return this.fail(result.Detail ?? 'The browser action failed.');\n }\n\n // PERCEPTION: tell the agent where the page is now (background — no spoken reply), and refresh\n // the live-view bar, which in streaming mode has no poll feeding it.\n this.notePageChange(result.CurrentUrl, 'agent');\n return this.ok(result.CurrentUrl, result.Detail);\n });\n }\n\n /** Builds the flat mutation variables from a normalized action (omitted fields ride as null). */\n private buildVariables(sessionId: string, action: RemoteBrowserAction): Record<string, JSONValue> {\n return {\n agentSessionID: sessionId,\n kind: action.Kind,\n url: action.Url ?? null,\n selector: action.Selector ?? null,\n x: action.X ?? null,\n y: action.Y ?? null,\n text: action.Text ?? null,\n key: action.Key ?? null,\n deltaX: action.DeltaX ?? null,\n deltaY: action.DeltaY ?? null,\n ms: action.Ms ?? null,\n };\n }\n\n /**\n * GOAL path for the `browser_AchieveGoal` tool: hands a high-level goal to the server's autonomous\n * browser agent (computer-use loop / native AI) via {@link EXECUTE_REMOTE_BROWSER_GOAL_MUTATION} and\n * returns a concise result for the model. Never throws — failures map to a `{ success: false }` string.\n *\n * @param argsJson The raw tool-call arguments (`{ goal, startUrl? }`).\n * @returns The model-readable result string.\n */\n private async achieveGoal(argsJson: string): Promise<string> {\n // Wait briefly for the session id (mint/reconnect race) before giving up — see ResolveAgentSessionId.\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n const args = this.parseArgs(argsJson);\n const goal = this.asArgString(args['goal']);\n if (!goal) {\n return this.fail('browser_AchieveGoal requires a \"goal\" describing what to accomplish.');\n }\n const startUrl = this.asArgString(args['startUrl']) ?? null;\n\n // START the goal (returns immediately with a GoalRunID) then POLL — a goal loop can run for\n // minutes, far longer than any single request survives, so we never hold one open for the loop.\n // The whole span is agent-driven: every page the loop opens is observed with nothing returned\n // yet, so without the window the agent would narrate its own goal as somebody else's takeover.\n return this.whileAgentDrives(async () => {\n const startData = await this.Context?.ExecuteServerAction<ExecuteRemoteBrowserGoalResult>(EXECUTE_REMOTE_BROWSER_GOAL_MUTATION, {\n agentSessionID: sessionId,\n goal,\n startUrl,\n });\n const started = startData?.ExecuteRemoteBrowserGoal ?? null;\n if (!started) {\n return this.fail('The browser goal could not be started (no response from the server).');\n }\n // Defensive: if the server ever returns a terminal status synchronously, use it directly.\n const result = started.Status === 'Running' && started.GoalRunID\n ? await this.pollGoalResult(sessionId, started.GoalRunID)\n : started;\n if (!result) {\n return this.fail('The browser goal is taking longer than expected and could not be confirmed. It may still be running.');\n }\n this.notePageChange(result.CurrentUrl, 'agent');\n if (!result.Success) {\n return this.fail(result.Detail ?? `The goal could not be completed (${result.Status ?? 'unknown'}).`);\n }\n return this.ok(result.CurrentUrl, result.Detail ?? `Goal completed (${result.Status ?? 'Completed'}, ${result.StepCount ?? 0} steps).`);\n });\n }\n\n /**\n * Polls {@link GET_REMOTE_BROWSER_GOAL_RESULT_QUERY} for a started goal run until it reports a\n * terminal status (anything other than `Running`), then returns that terminal payload. Each poll is\n * a short request, so no transport boundary times out while a long goal loop runs server-side.\n *\n * Returns `null` if the goal is still `Running` after {@link GoalPollTimeoutMs} (the loop keeps\n * running server-side; the caller maps this to a \"still running\" message), the session went away, or\n * the run id is no longer known (`Unknown` — expired/superseded).\n */\n private async pollGoalResult(sessionId: string, goalRunID: string): Promise<RemoteBrowserGoalPayload | null> {\n const interval = Math.max(1, this.GoalPollIntervalMs);\n for (let waited = 0; waited < this.GoalPollTimeoutMs; waited += interval) {\n await new Promise<void>((resolve) => setTimeout(resolve, interval));\n // The session ended mid-goal — stop polling (the live browser is gone).\n if (!this.Context?.AgentSessionID) {\n return null;\n }\n const data = await this.Context.ExecuteServerAction<GetRemoteBrowserGoalResultPayload>(GET_REMOTE_BROWSER_GOAL_RESULT_QUERY, {\n agentSessionID: sessionId,\n goalRunID,\n });\n const payload = data?.GetRemoteBrowserGoalResult ?? null;\n // A transient null (one failed poll) shouldn't abort — keep polling until the deadline.\n if (payload && payload.Status !== 'Running') {\n return payload;\n }\n }\n return null;\n }\n\n /**\n * Runs the VISION-QUERY path for the `browser_DescribePage` / `browser_LocateElement` tools: awaits the\n * `InterpretRemoteBrowserPage` mutation (server captures a screenshot + runs a fast vision model) and returns\n * a concise JSON string the model reads. For a describe (no `query`) it returns `{ description }`; for a locate\n * it returns `{ found, element, all }` so the agent can `browser_Click` the centroid. Never throws — a null\n * session, no response, or a server detail-only result all map to a result string the model can narrate.\n *\n * @param query The visual target to locate, or `undefined` for a plain page description.\n * @returns A JSON string describing the interpretation for the model.\n */\n private async interpretPage(query: string | undefined): Promise<string> {\n // Wait briefly for the session id (mint/reconnect race) before giving up — see ResolveAgentSessionId.\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n console.warn('[RemoteBrowser] interpret tool invoked but AgentSessionID is null', {\n hasContext: !!this.Context,\n agentSessionID: this.Context?.AgentSessionID ?? null,\n });\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n\n const data = await this.Context?.ExecuteServerAction<InterpretRemoteBrowserPageResult>(INTERPRET_PAGE_MUTATION, {\n agentSessionID: sessionId,\n query: query ?? null,\n });\n const result = data?.InterpretRemoteBrowserPage ?? null;\n if (!result) {\n return this.fail('The page could not be interpreted (no response from the server).');\n }\n\n if (query === undefined) {\n // DescribePage — hand back the description (or the server's detail note when nothing was interpreted).\n return JSON.stringify({ description: result.Description ?? result.Detail ?? null });\n }\n\n // LocateElement — surface whether anything matched, the best match, and all candidates.\n const elements = result.Elements ?? [];\n const best = elements[0];\n return JSON.stringify({\n found: elements.length > 0,\n element: best ? { label: best.Label, x: best.X, y: best.Y } : null,\n all: elements,\n ...(result.Detail ? { detail: result.Detail } : {}),\n });\n }\n\n /** Coerces a parsed tool-arg to a non-empty string, or `undefined` when absent / wrong-typed. */\n private asArgString(value: JSONValue | undefined): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n }\n\n /** Parses the tool-args JSON into a plain object; returns `{}` for empty/malformed input. */\n private parseArgs(argsJson: string): Record<string, JSONValue> {\n const trimmed = argsJson?.trim();\n if (!trimmed) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(trimmed);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as Record<string, JSONValue>) : {};\n } catch {\n return {};\n }\n }\n\n /** Builds a successful tool-result JSON string for the model. */\n private ok(currentUrl: string | null, detail: string | null): string {\n const result: RemoteBrowserToolResult = { success: true };\n if (currentUrl) {\n result.currentUrl = currentUrl;\n }\n if (detail) {\n result.detail = detail;\n }\n return JSON.stringify(result);\n }\n\n /** Builds a failed tool-result JSON string for the model. */\n private fail(error: string): string {\n const result: RemoteBrowserToolResult = { success: false, error };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Tree-shaking prevention: the Remote Browser channel is resolved dynamically through the\n * ClassFactory (by the registry row's `ClientPluginClass` key), so this static call is what\n * keeps its `@RegisterClass` side effect from being eliminated by the bundler. Called from\n * `conversations.module.ts` alongside {@link LoadRealtimeWhiteboardChannel}.\n */\nexport function LoadRealtimeRemoteBrowserChannel(): void {\n // intentional no-op — the import side effect performs the registration\n}\n"]}
1
+ {"version":3,"file":"remote-browser-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/remote-browser/remote-browser-channel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Type } from '@angular/core';\nimport type { Subscription } from 'rxjs';\nimport { RegisterClass } from '@memberjunction/global';\nimport { CHANNEL_INBOUND_VIDEO_TRACK, JSONValue, RealtimeToolDefinition, RealtimeTrack, RealtimeTrackDescriptor } from '@memberjunction/ai';\nimport { ChannelInboundVideoBridge, IChannelFrameProvider } from '@memberjunction/ai-realtime-client';\nimport { REALTIME_CHANNEL_CONTRACT_VERSION, type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';\nimport { BaseRealtimeChannelClient, BuildToolBackedVerbs, ChannelOnboardingDetails } from '@memberjunction/realtime-runtime';\nimport { RemoteBrowserHumanInputEvent, RemoteBrowserSnapshotView, RemoteBrowserSurfaceComponent } from './remote-browser-surface.component';\nimport {\n MapToolToAction,\n REMOTE_BROWSER_TOOL_DEFINITIONS,\n REMOTE_BROWSER_TOOL_NAMES,\n REMOTE_BROWSER_TOOL_PREFIX,\n RemoteBrowserAction,\n RemoteBrowserToolArgError,\n} from './remote-browser-tools';\nimport { MediaSourceAudioSink, RemoteBrowserAudioChunkInput, RemoteBrowserAudioPlayer } from './remote-browser-audio-player';\n\n/**\n * GraphQL mutation that drives the SERVER-hosted browser. The channel awaits it for every\n * `browser_*` tool call and feeds the result back to the model.\n */\nconst EXECUTE_REMOTE_BROWSER_ACTION_MUTATION = `\n mutation ExecuteRemoteBrowserAction(\n $agentSessionID: String!, $kind: String!, $url: String, $selector: String,\n $x: Float, $y: Float, $text: String, $key: String,\n $deltaX: Float, $deltaY: Float, $ms: Float\n ) {\n ExecuteRemoteBrowserAction(\n agentSessionID: $agentSessionID, kind: $kind, url: $url, selector: $selector,\n x: $x, y: $y, text: $text, key: $key,\n deltaX: $deltaX, deltaY: $deltaY, ms: $ms\n ) {\n Success\n CurrentUrl\n Detail\n }\n }\n`;\n\n/** The narrow projection of the `ExecuteRemoteBrowserAction` mutation payload the channel reads. */\ninterface ExecuteRemoteBrowserActionResult {\n ExecuteRemoteBrowserAction: {\n Success: boolean;\n CurrentUrl: string | null;\n Detail: string | null;\n } | null;\n}\n\n/**\n * GOAL mutation — hands a high-level goal to the server's autonomous browser agent (computer-use loop or\n * backend native AI) instead of relaying a granular action. The server plans + executes; we await the\n * terminal outcome. (Live per-step narration is a server-bridged concern; over this client-direct mutation\n * we get the final result.)\n */\nconst EXECUTE_REMOTE_BROWSER_GOAL_MUTATION = `\n mutation ExecuteRemoteBrowserGoal($agentSessionID: String!, $goal: String!, $startUrl: String) {\n ExecuteRemoteBrowserGoal(agentSessionID: $agentSessionID, goal: $goal, startUrl: $startUrl) {\n Success\n GoalRunID\n Strategy\n CurrentUrl\n Status\n StepCount\n Detail\n }\n }\n`;\n\n/**\n * POLL query for the async goal run. `ExecuteRemoteBrowserGoal` STARTS the (potentially multi-minute)\n * goal loop and returns a `GoalRunID` with `Status: 'Running'`; the channel polls this until the run\n * reports a terminal status — so no single request is held open for the whole loop (which would die at\n * a browser/proxy/janitor transport timeout and lose the result).\n */\nconst GET_REMOTE_BROWSER_GOAL_RESULT_QUERY = `\n query GetRemoteBrowserGoalResult($agentSessionID: String!, $goalRunID: String!) {\n GetRemoteBrowserGoalResult(agentSessionID: $agentSessionID, goalRunID: $goalRunID) {\n Success\n GoalRunID\n Strategy\n CurrentUrl\n Status\n StepCount\n Detail\n }\n }\n`;\n\n/** The narrow projection of a goal-result payload (shared by the start mutation + the poll query). */\ninterface RemoteBrowserGoalPayload {\n Success: boolean;\n GoalRunID: string | null;\n Strategy: string | null;\n CurrentUrl: string | null;\n Status: string | null;\n StepCount: number | null;\n Detail: string | null;\n}\n\n/** The narrow projection of the `ExecuteRemoteBrowserGoal` (start) mutation payload the channel reads. */\ninterface ExecuteRemoteBrowserGoalResult {\n ExecuteRemoteBrowserGoal: RemoteBrowserGoalPayload | null;\n}\n\n/** The narrow projection of the `GetRemoteBrowserGoalResult` (poll) query payload the channel reads. */\ninterface GetRemoteBrowserGoalResultPayload {\n GetRemoteBrowserGoalResult: RemoteBrowserGoalPayload | null;\n}\n\n/**\n * GraphQL mutation that asks the server to start PUSHING live CDP screencast frames for the session.\n * Returns `Streaming: true` when the backend supports `ScreenStreaming` and the stream started; the\n * channel then drives the surface's canvas. `Streaming: false` (capability absent / start failed) leaves\n * the surface on its 700ms snapshot poll fallback.\n */\nconst START_SCREENCAST_MUTATION = `\n mutation StartRemoteBrowserScreencast($agentSessionID: String!) {\n StartRemoteBrowserScreencast(agentSessionID: $agentSessionID) {\n Streaming\n }\n }\n`;\n\n/** GraphQL mutation that stops the server-pushed screencast (best-effort teardown). */\nconst STOP_SCREENCAST_MUTATION = `\n mutation StopRemoteBrowserScreencast($agentSessionID: String!) {\n StopRemoteBrowserScreencast(agentSessionID: $agentSessionID)\n }\n`;\n\n/**\n * GraphQL mutation that asks the server to start PUSHING live tab-audio chunks for the session — so a\n * co-agent demoing a video/audio site is HEARD. Returns `Streaming: true` when the backend can capture\n * audio (v1 gates by backend implementation) and the stream started; `Streaming: false` means no audio\n * (capability absent / start failed) and the client simply plays nothing.\n */\nconst START_AUDIO_STREAM_MUTATION = `\n mutation StartRemoteBrowserAudioStream($agentSessionID: String!) {\n StartRemoteBrowserAudioStream(agentSessionID: $agentSessionID) {\n Streaming\n }\n }\n`;\n\n/** GraphQL mutation that stops the server-pushed tab-audio stream (best-effort teardown). */\nconst STOP_AUDIO_STREAM_MUTATION = `\n mutation StopRemoteBrowserAudioStream($agentSessionID: String!) {\n StopRemoteBrowserAudioStream(agentSessionID: $agentSessionID)\n }\n`;\n\n/** The narrow projection of the `StartRemoteBrowserAudioStream` mutation payload the channel reads. */\ninterface StartRemoteBrowserAudioStreamResult {\n StartRemoteBrowserAudioStream: {\n Streaming: boolean;\n } | null;\n}\n\n/**\n * HUMAN-TAKEOVER mutation — relays ONE pointer/keyboard input the user performed on the live canvas into the\n * server-hosted browser (Collaborative control). Best-effort: the server returns `false` when the backend\n * lacks `HumanTakeover` or no live browser exists; the channel doesn't act on the boolean.\n */\nconst RELAY_HUMAN_INPUT_MUTATION = `\n mutation RelayRemoteBrowserHumanInput(\n $agentSessionID: String!, $kind: String!, $x: Float, $y: Float, $button: String, $key: String,\n $text: String, $deltaX: Float, $deltaY: Float, $modifiers: String\n ) {\n RelayRemoteBrowserHumanInput(\n agentSessionID: $agentSessionID, kind: $kind, x: $x, y: $y, button: $button, key: $key,\n text: $text, deltaX: $deltaX, deltaY: $deltaY, modifiers: $modifiers\n )\n }\n`;\n\n/**\n * COPY-OUT query — reads the remote page's current text selection so the surface can write it to the LOCAL\n * clipboard on a `copy` / Cmd+C (the mirror of the `'text'` paste-in path). Returns `''` when nothing is\n * selected, no live browser exists, or the backend lacks `HumanTakeover`.\n */\nconst GET_SELECTION_QUERY = `\n query GetRemoteBrowserSelection($agentSessionID: String!) {\n GetRemoteBrowserSelection(agentSessionID: $agentSessionID) {\n Text\n }\n }\n`;\n\n/** The narrow projection of the `GetRemoteBrowserSelection` query payload the channel reads. */\ninterface GetRemoteBrowserSelectionResult {\n GetRemoteBrowserSelection: {\n Text: string;\n } | null;\n}\n\n/** The narrow projection of the `StartRemoteBrowserScreencast` mutation payload the channel reads. */\ninterface StartRemoteBrowserScreencastResult {\n StartRemoteBrowserScreencast: {\n Streaming: boolean;\n } | null;\n}\n\n/** GraphQL query the surface fetcher runs — the live screenshot + URL of the server browser. */\nconst REMOTE_BROWSER_SNAPSHOT_QUERY = `\n query RemoteBrowserSnapshot($agentSessionID: String!) {\n RemoteBrowserSnapshot(agentSessionID: $agentSessionID) {\n ScreenshotBase64\n CurrentUrl\n }\n }\n`;\n\n/** The narrow projection of the `RemoteBrowserSnapshot` query payload the channel reads. */\ninterface RemoteBrowserSnapshotResult {\n RemoteBrowserSnapshot: RemoteBrowserSnapshotView | null;\n}\n\n/**\n * VISION-QUERY mutation (separate from {@link EXECUTE_REMOTE_BROWSER_ACTION_MUTATION} — this OBSERVES the page,\n * it does not drive it). The server captures the live screenshot and runs a fast vision model over it, so the\n * non-omnimodal voice agent can \"see\" the page: a text description and/or localized elements with pixel\n * centroids. Backs both `browser_DescribePage` (no target) and `browser_LocateElement` (a target description).\n */\nconst INTERPRET_PAGE_MUTATION = `\n mutation InterpretRemoteBrowserPage($agentSessionID: String!, $query: String) {\n InterpretRemoteBrowserPage(agentSessionID: $agentSessionID, query: $query) {\n Description\n Elements {\n Label\n X\n Y\n Confidence\n }\n Detail\n }\n }\n`;\n\n/** One element localized by the visual interpreter — label + pixel centroid + confidence. */\ninterface RemoteBrowserInterpretedElement {\n Label: string;\n X: number;\n Y: number;\n Confidence: number;\n}\n\n/** The narrow projection of the `InterpretRemoteBrowserPage` mutation payload the channel reads. */\ninterface InterpretRemoteBrowserPageResult {\n InterpretRemoteBrowserPage: {\n Description: string | null;\n Elements: RemoteBrowserInterpretedElement[];\n Detail: string | null;\n } | null;\n}\n\n/** The result payload (serialized to JSON) the channel returns to the model per tool call. */\ninterface RemoteBrowserToolResult {\n success: boolean;\n /** The page URL after the action, when the server reported one. */\n currentUrl?: string;\n /** Human-readable detail (e.g. extracted page text for `browser_GetPageText`, or an error). */\n detail?: string;\n /** Error description when `success` is false. */\n error?: string;\n}\n\n/**\n * The REMOTE BROWSER as a pluggable interactive channel — a {@link BaseRealtimeChannelClient}\n * resolved from the `MJ: AI Agent Channels` registry row whose `ClientPluginClass` is\n * `'RealtimeRemoteBrowserChannel'`. One instance per session (ClassFactory-created at session\n * start).\n *\n * Topology (CLIENT-DIRECT, like the whiteboard — the browser just happens to live on the\n * server):\n * - **Action**: the `browser_*` client-executed tool set ({@link REMOTE_BROWSER_TOOL_DEFINITIONS}).\n * {@link ApplyAgentTool} maps a tool call → a normalized {@link RemoteBrowserAction}\n * ({@link MapToolToAction}) and awaits the `ExecuteRemoteBrowserAction` GraphQL mutation\n * (via {@link RealtimeChannelContext.ExecuteServerAction}) to drive the server browser,\n * returning a concise JSON result for the model. Never throws — argument and transport\n * failures map to a `{ success: false, error }` payload.\n * - **Perception**: after a successful action, a `[browser]` context note carries the new\n * page URL so the agent perceives where the page went; the surface independently polls a\n * live screenshot.\n * - **Surface**: {@link RemoteBrowserSurfaceComponent}, created dynamically in the channel\n * tab; the plugin hands it the session's provider + id in {@link BindSurface} so it can\n * poll `RemoteBrowserSnapshot`. HUMAN TAKEOVER is enabled by default (Collaborative): the\n * user can click/type into the live canvas and those events relay to the server browser via\n * {@link RELAY_HUMAN_INPUT_MUTATION} (server-gated on the backend's `HumanTakeover` capability).\n *\n * The channel keeps NO client-side state of record — the browser's state lives entirely on\n * the server — so {@link SerializeState} / {@link RestoreState} use the base no-op behavior.\n */\n@RegisterClass(BaseRealtimeChannelClient, 'RealtimeRemoteBrowserChannel')\nexport class RemoteBrowserChannel extends BaseRealtimeChannelClient<RemoteBrowserSurfaceComponent> implements IChannelFrameProvider {\n /** The live bound surface, when the channel tab's pane is instantiated. */\n private surface: RemoteBrowserSurfaceComponent | null = null;\n\n /** Shared video bridge streaming browser frames to the model when the model supports inbound video. */\n private videoBridge: ChannelInboundVideoBridge | null = null;\n\n /**\n * Sourced tracks: Remote Browser can source inbound video to the model when the model supports it.\n */\n public override GetSourcedTracks(): readonly RealtimeTrackDescriptor[] {\n return [CHANNEL_INBOUND_VIDEO_TRACK];\n }\n\n /**\n * Produces the latest browser screenshot as a base64-encoded frame for the video bridge.\n * Under active screencast streaming, returns null to avoid redundant server snapshot round-trips\n * and duplicate frame sourcing into the video bridge.\n */\n public async GetLatestFrame(): Promise<string | null> {\n this.ensureVideoBridge();\n if (this.streaming) {\n return null;\n }\n const snapshot = await this.fetchSnapshot();\n return snapshot?.ScreenshotBase64 ?? null;\n }\n\n /** Subscription to the bound surface's `HumanInput` output, torn down on unbind/dispose. */\n private humanInputSub: Subscription | null = null;\n\n /**\n * Whether the server confirmed it is PUSHING screencast frames for this session (`ScreenStreaming`\n * supported). When `true` the surface renders pushed frames on its canvas and skips its poll, and\n * {@link OnScreencastFrame} forwards each pushed frame to it. When `false` the surface keeps polling.\n */\n private streaming = false;\n\n /**\n * Whether the server confirmed it is PUSHING tab-audio chunks for this session (the backend can capture\n * audio). When `true` {@link OnAudioChunk} feeds each pushed chunk to {@link audioPlayer}; when `false`\n * no audio plays.\n */\n private audioStreaming = false;\n\n /**\n * The last URL the agent was TOLD about, so an unchanged page is not re-announced (#3496). `null`\n * until the first sighting, which is deliberately announced as a plain \"current page\" rather than\n * as somebody else navigating — the first page of a session was nobody's takeover.\n */\n private lastNotedUrl: string | null = null;\n\n /**\n * How many browser operations the AGENT itself has in flight right now (#3496).\n *\n * Attribution cannot be read off the feed a change arrives on. A pushed frame or a perception poll\n * only says the page moved; it is `> 0` here that says the agent is the one moving it. Two cases\n * make that necessary rather than tidy:\n *\n * - **an action's frames outrun its reply.** Under streaming, frames of the new page are pushed\n * while `ExecuteRemoteBrowserAction` is still in flight, so the observation reliably lands BEFORE\n * the mutation returns the URL — the agent's own navigation announced back to it as a takeover.\n * - **a goal drives for minutes.** `browser_AchieveGoal` runs an autonomous loop server-side and\n * every page it opens is observed with nothing yet returned, so the whole run would narrate\n * itself as somebody else.\n *\n * A counter, not a flag: goals and actions overlap, and the last one to finish must not clear a\n * window another still owns.\n */\n private agentDrivingDepth = 0;\n\n /** The client-side audio player fed pushed chunks while {@link audioStreaming}; `null` until started. */\n private audioPlayer: RemoteBrowserAudioPlayer | null = null;\n\n /** Subscription to the bound surface's `AudioMutedChange` output (the speaker toggle), torn down on unbind. */\n private audioMutedSub: Subscription | null = null;\n\n /**\n * Poll cadence + deadline for {@link pollGoalResult} (the async `browser_AchieveGoal` result poll).\n * Protected so tests can shrink them; production polls every 2.5s for up to 5 minutes (a goal loop\n * past 5 min keeps running server-side, the model just gets a \"still running\" note).\n */\n protected GoalPollIntervalMs = 2500;\n protected GoalPollTimeoutMs = 5 * 60 * 1000;\n\n public get ChannelName(): string {\n return 'Remote Browser';\n }\n\n public get ToolNamePrefix(): string {\n return REMOTE_BROWSER_TOOL_PREFIX;\n }\n\n public get TabTitle(): string {\n return 'Browser';\n }\n\n public get TabIcon(): string {\n return 'fa-solid fa-globe';\n }\n\n public GetToolDefinitions(): RealtimeToolDefinition[] {\n return REMOTE_BROWSER_TOOL_DEFINITIONS;\n }\n\n public override GetSurfaceComponent(): Type<RemoteBrowserSurfaceComponent> {\n return RemoteBrowserSurfaceComponent;\n }\n\n /**\n * The remote browser's self-description: a real, server-hosted web browser the user can watch, with\n * every `browser_*` tool as a verb (so a tool a subclass adds shows up here too). The model is shown\n * its pixels (page frames), so the exposure ceiling is `pixels`.\n */\n public override GetDescriptor(): RealtimeChannelDescriptor {\n return {\n Key: this.ChannelName,\n Version: REALTIME_CHANNEL_CONTRACT_VERSION,\n DisplayName: this.TabTitle,\n OwningPackage: '@memberjunction/ng-conversations',\n Instructions:\n 'A live web browser you can drive while the user watches: open pages, click, type, scroll and ' +\n 'read what is on screen. Narrate what you are doing; do not announce each tiny step.',\n Nouns: [\n {\n Name: 'page',\n Description: 'The page the browser is currently showing (its URL and title).',\n Schema: { type: 'object' }\n }\n ],\n // Reading the page is what exposure limits: its text is the page's state, and what the vision model makes of the\n // screenshot (or where it finds an element) is derived from its pixels. A goal's result reports what the browser found.\n Verbs: BuildToolBackedVerbs(this.GetToolDefinitions(), this.ToolNamePrefix, 'agent', {\n [REMOTE_BROWSER_TOOL_NAMES.GetPageText]: 'state',\n [REMOTE_BROWSER_TOOL_NAMES.DescribePage]: 'pixels',\n [REMOTE_BROWSER_TOOL_NAMES.LocateElement]: 'pixels',\n [REMOTE_BROWSER_TOOL_NAMES.AchieveGoal]: 'state',\n }),\n DisplayPolicy: 'open-on-start',\n DefaultAvailability: 'all-sessions',\n MaxExposure: 'pixels'\n };\n }\n\n /** First-run intro shown the first time the user opens the Browser tab (once per user). */\n public override GetOnboardingDetails(): ChannelOnboardingDetails {\n return {\n Heading: 'Remote Browser',\n Description:\n 'The agent drives a live web browser on the server and you can watch it work right here. ' +\n 'You can also grab the wheel: click and type directly on the live page and the agent picks ' +\n 'up right where you left off.',\n Tips: [\n 'Ask the agent to look something up, open a site or fill in a form — it controls the page.',\n 'Click on the live view to take over, then click and type to drive it yourself — the \"You\\'re driving\" badge shows when takeover is active.',\n 'The current page URL is shown so you always know where the agent has navigated.',\n ],\n IconClass: 'fa-solid fa-globe',\n };\n }\n\n /** Starts the video bridge streaming browser frames to the model when inbound video is supported. */\n protected override OnInitialize(): void {\n this.ensureVideoBridge();\n }\n\n public override OnSessionStarted(): void {\n this.ensureVideoBridge();\n }\n\n private ensureVideoBridge(): ChannelInboundVideoBridge | null {\n if (!this.videoBridge && this.Context) {\n this.videoBridge = new ChannelInboundVideoBridge(() => this.Context?.Client, this);\n }\n if (this.videoBridge && !this.videoBridge.IsActive && this.Context?.Client?.IsTrackEstablished('video', 'inbound')) {\n this.videoBridge.Start?.();\n }\n return this.videoBridge;\n }\n\n /**\n * Wires the dynamically-created surface: hands it a snapshot fetcher closing over the\n * channel context (session id + provider live there), so the surface stays transport-\n * agnostic. Set BEFORE the surface's first change detection (the pane binds synchronously),\n * so its `ngOnInit` poll has the fetcher.\n *\n * Also asks the server to start a live screencast. When the backend supports `ScreenStreaming` the\n * server starts PUSHING frames and reports `Streaming: true`; we flip the surface to canvas mode (its\n * poll is then skipped) and {@link OnScreencastFrame} paints each pushed frame. When the backend lacks\n * the capability (`Streaming: false`) the surface keeps the snapshot poll already running — graceful\n * fallback, no further action.\n *\n * HUMAN TAKEOVER is enabled BY DEFAULT (Collaborative): the surface is flipped `Interactive = true` and\n * its `HumanInput` output subscribed, forwarding each pointer/keyboard event to the server via\n * {@link RELAY_HUMAN_INPUT_MUTATION}. Takeover only takes effect on the canvas (screencast) path; the\n * `<img>` poll fallback stays view-only. The server gates the actual routing on the backend's\n * `HumanTakeover` capability, so this is safe to enable unconditionally.\n */\n public BindSurface(instance: RemoteBrowserSurfaceComponent): void {\n this.surface = instance;\n instance.Fetch = () => this.fetchSnapshot();\n // Copy-out: the surface reads the remote selection through this on a local `copy` and writes it locally.\n instance.FetchSelection = () => this.fetchSelection();\n instance.Interactive = true;\n this.ensureVideoBridge();\n this.humanInputSub = instance.HumanInput.subscribe((input) => this.relayHumanInput(input));\n this.audioMutedSub = instance.AudioMutedChange.subscribe((muted) => this.audioPlayer?.SetMuted(muted));\n void this.startScreencast(instance);\n void this.startAudioStream(instance);\n }\n\n /** Pauses the surface's snapshot poll while it is out of sight; the screencast and the audio keep running. */\n public override OnSurfaceVisibilityChange(visible: boolean): void {\n if (this.surface) {\n this.surface.Visible = visible;\n }\n }\n\n public override UnbindSurface(): void {\n this.humanInputSub?.unsubscribe();\n this.humanInputSub = null;\n this.audioMutedSub?.unsubscribe();\n this.audioMutedSub = null;\n void this.stopScreencast();\n void this.stopAudioStream();\n this.surface = null;\n }\n\n public override Dispose(): void {\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n this.videoBridge?.Stop();\n this.videoBridge = null;\n this.humanInputSub?.unsubscribe();\n this.humanInputSub = null;\n this.audioMutedSub?.unsubscribe();\n this.audioMutedSub = null;\n void this.stopScreencast();\n void this.stopAudioStream();\n super.Dispose();\n }\n\n /** Timestamp of the last screencast frame pushed to the video bridge (paces pushes to negotiated cadence). */\n private lastScreencastPushTime = 0;\n\n /** Base64 content of the last frame pushed to the video bridge (for change-driven deduplication). */\n private lastPushedScreencastFrame: string | null = null;\n\n /** URL associated with the last frame pushed to the video bridge. */\n private lastPushedUrl: string | null = null;\n\n /** Minimum allowable screencast push cadence (250ms = 4 fps debounce limit during active bursts). */\n private static readonly SCREENCAST_MIN_CADENCE_MS = 250;\n\n /** Default screencast push cadence when not otherwise negotiated (1000ms = 1 fps ceiling for Gemini Live). */\n private static readonly SCREENCAST_DEFAULT_CADENCE_MS = 1000;\n\n /** Maximum interval (ms) between visual frame pushes on a static page (heartbeat to maintain track liveness). */\n private static readonly SCREENCAST_HEARTBEAT_MS = 15_000;\n\n /** Trailing timer to deliver the settled resting frame after a burst of rapid user activity. */\n private screencastTrailingTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Pending frame buffered during an active cooldown interval, waiting to settle. */\n private pendingScreencastFrame: { dataBase64: string; currentUrl?: string | null } | null = null;\n\n /** Cancels any active trailing-edge settle timer and clears the handle. */\n private clearScreencastTrailingTimer(): void {\n if (this.screencastTrailingTimer != null) {\n clearTimeout(this.screencastTrailingTimer);\n this.screencastTrailingTimer = null;\n }\n }\n\n /**\n * Pushes a frame to the video bridge, recording timestamp, frame content, and URL.\n */\n private pushScreencastFrame(dataBase64: string, currentUrl?: string | null): void {\n this.lastScreencastPushTime = Date.now();\n this.lastPushedScreencastFrame = dataBase64;\n this.lastPushedUrl = currentUrl ?? null;\n this.ensureVideoBridge()?.PushFrame(dataBase64);\n }\n\n /**\n * Resolves the effective push cadence in milliseconds based on the negotiated inbound video track.\n * Defaults to 1000ms (1 fps ceiling for Gemini Live), but clamps down to a minimum of 250ms (4 fps)\n * if the negotiated track specifies a higher `Rate`.\n */\n private getNegotiatedVideoCadenceMs(): number {\n const client = this.Context?.Client;\n if (!client) {\n return RemoteBrowserChannel.SCREENCAST_DEFAULT_CADENCE_MS;\n }\n const tracks: readonly RealtimeTrack[] = client.EstablishedTracks;\n const videoTrack = tracks.find(\n (t: RealtimeTrack) =>\n t.Descriptor.Modality === 'video' &&\n t.Descriptor.Direction === 'inbound'\n );\n const rate = videoTrack?.Descriptor.Rate;\n if (typeof rate === 'number' && rate > 0) {\n return Math.max(\n RemoteBrowserChannel.SCREENCAST_MIN_CADENCE_MS,\n Math.floor(1000 / rate)\n );\n }\n return RemoteBrowserChannel.SCREENCAST_DEFAULT_CADENCE_MS;\n }\n\n /**\n * Forwards one PUSHED screencast frame to the bound surface's canvas. Called by the session service\n * when a `RemoteBrowserScreencastFrame` arrives on the push-status stream for THIS session. No-op when\n * the channel isn't streaming or has no bound surface (e.g. its tab has not been shown yet).\n *\n * Under streaming the surface's snapshot poll is stopped, so this is the ONLY thing that sees the\n * page while frames are being pushed — which is why the frame now carries the URL (#3496). Without\n * it, a user navigating during a screencast changed the picture and nothing else: the agent kept\n * describing the page it last opened, and the pixels proving otherwise were right there on screen.\n *\n * Pushes to the video bridge are CHANGE-DRIVEN with a TRAILING-EDGE SETTLE DEBOUNCE:\n * 1. The human user surface renders immediately at full 60fps responsiveness.\n * 2. When the page is static (same image and URL), pushes are deduplicated to avoid burning\n * ~15k tokens/min of identical visual context.\n * 3. A frame is pushed immediately on the leading edge when visual content or URL changes after\n * the negotiated cadence (default 1000ms, clamped to >= 250ms).\n * 4. During rapid bursts (scrolling, typing, clicking) within the cooldown window, subsequent frames\n * are buffered; when the cooldown expires, a trailing timer delivers the settled resting frame\n * so the model never misses the final user state.\n * 5. A 15-second heartbeat ensures visual track liveness even during extended idle periods.\n *\n * @param dataBase64 The frame image as raw base64 JPEG (no `data:` prefix).\n * @param currentUrl The browser's URL when the frame was captured; absent from older servers.\n */\n public OnScreencastFrame(dataBase64: string, currentUrl?: string | null): void {\n if (!this.streaming) {\n return;\n }\n\n this.surface?.RenderFrame(dataBase64);\n\n const now = Date.now();\n const cadenceMs = this.getNegotiatedVideoCadenceMs();\n const elapsed = now - this.lastScreencastPushTime;\n\n if (elapsed >= cadenceMs) {\n // Cooldown has expired: leading edge push.\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n\n const frameChanged = dataBase64 !== this.lastPushedScreencastFrame;\n const urlChanged = currentUrl != null && currentUrl !== this.lastPushedUrl;\n const heartbeatElapsed = elapsed >= RemoteBrowserChannel.SCREENCAST_HEARTBEAT_MS;\n\n if (frameChanged || urlChanged || heartbeatElapsed) {\n this.pushScreencastFrame(dataBase64, currentUrl);\n }\n } else {\n // Within cooldown window: buffer latest frame and schedule trailing settle timer.\n this.pendingScreencastFrame = { dataBase64, currentUrl };\n if (!this.screencastTrailingTimer) {\n const delay = Math.max(0, cadenceMs - elapsed);\n this.screencastTrailingTimer = setTimeout(() => {\n this.screencastTrailingTimer = null;\n if (!this.streaming || !this.pendingScreencastFrame) {\n return;\n }\n const { dataBase64: pendingData, currentUrl: pendingUrl } = this.pendingScreencastFrame;\n this.pendingScreencastFrame = null;\n\n const frameChanged = pendingData !== this.lastPushedScreencastFrame;\n const urlChanged = pendingUrl != null && pendingUrl !== this.lastPushedUrl;\n const heartbeat = (Date.now() - this.lastScreencastPushTime) >= RemoteBrowserChannel.SCREENCAST_HEARTBEAT_MS;\n\n if (frameChanged || urlChanged || heartbeat) {\n this.pushScreencastFrame(pendingData, pendingUrl);\n }\n }, delay);\n }\n }\n\n // #3496: URL perception note runs AFTER the push so the visual image lands before/with the note.\n this.notePageChange(currentUrl, 'observed');\n }\n\n /**\n * Feeds one PUSHED tab-audio chunk to the client-side audio player. Called by the session service when a\n * `RemoteBrowserAudioChunk` arrives on the push-status stream for THIS session. No-op when the channel\n * isn't audio-streaming or the player has been torn down.\n *\n * @param chunk The pushed audio chunk (base64 webm-opus + codec/seq metadata).\n */\n public OnAudioChunk(chunk: RemoteBrowserAudioChunkInput): void {\n if (this.audioStreaming) {\n this.audioPlayer?.Enqueue(chunk);\n }\n }\n\n /**\n * Asks the server to start the live screencast and, on success, flips the surface to canvas mode so it\n * stops polling and starts painting pushed frames. Best-effort: a `null`/`Streaming: false` result\n * (capability absent or transport failure) leaves the surface on its poll fallback.\n */\n private async startScreencast(instance: RemoteBrowserSurfaceComponent): Promise<void> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n const data = await this.Context?.ExecuteServerAction<StartRemoteBrowserScreencastResult>(START_SCREENCAST_MUTATION, { agentSessionID: sessionId });\n if (data?.StartRemoteBrowserScreencast?.Streaming === true) {\n this.streaming = true;\n instance.Streaming = true;\n }\n }\n\n /**\n * Asks the server to start the live tab-audio stream and, on success, spins up the client-side\n * {@link RemoteBrowserAudioPlayer} (speaker ON by default — the call is the activating user gesture) so\n * pushed chunks play. Best-effort: a `null`/`Streaming: false` result (no audio capability or transport\n * failure) leaves the channel silent with no player.\n *\n * @param instance The bound surface, flipped to show the speaker toggle when audio starts.\n */\n private async startAudioStream(instance: RemoteBrowserSurfaceComponent): Promise<void> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n const data = await this.Context?.ExecuteServerAction<StartRemoteBrowserAudioStreamResult>(START_AUDIO_STREAM_MUTATION, { agentSessionID: sessionId });\n if (data?.StartRemoteBrowserAudioStream?.Streaming === true) {\n this.audioStreaming = true;\n this.audioPlayer = new RemoteBrowserAudioPlayer(new MediaSourceAudioSink());\n // Speaker defaults ON; reflect that on the surface so the toggle renders un-muted.\n instance.AudioAvailable = true;\n instance.AudioMuted = false;\n }\n }\n\n /** Asks the server to stop the tab-audio stream (best-effort), disposes the player, and clears state. */\n private async stopAudioStream(): Promise<void> {\n const wasStreaming = this.audioStreaming;\n this.audioStreaming = false;\n this.audioPlayer?.Dispose();\n this.audioPlayer = null;\n const sessionId = this.Context?.AgentSessionID;\n if (!wasStreaming || !sessionId) {\n return;\n }\n await this.Context?.ExecuteServerAction(STOP_AUDIO_STREAM_MUTATION, { agentSessionID: sessionId });\n }\n\n /**\n * Relays ONE human-takeover input from the surface to the server's {@link RELAY_HUMAN_INPUT_MUTATION}.\n * Best-effort and fire-and-forget: never throws, and the boolean result is ignored (the server already\n * gates routing on the backend's `HumanTakeover` capability). No-op when no live session id exists.\n *\n * @param input The flattened pointer/keyboard input the user performed on the live canvas.\n */\n private relayHumanInput(input: RemoteBrowserHumanInputEvent): void {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return;\n }\n void this.Context?.ExecuteServerAction(RELAY_HUMAN_INPUT_MUTATION, {\n agentSessionID: sessionId,\n kind: input.kind,\n x: input.x ?? null,\n y: input.y ?? null,\n button: input.button ?? null,\n key: input.key ?? null,\n // Paste-in: the `'text'` kind carries the local clipboard text the server inserts into the page.\n text: input.text ?? null,\n deltaX: input.deltaX ?? null,\n deltaY: input.deltaY ?? null,\n // Server expects a comma-separated modifier list (e.g. \"Shift,Control\"); null when none held.\n modifiers: input.modifiers && input.modifiers.length > 0 ? input.modifiers.join(',') : null,\n });\n }\n\n /**\n * Reads the remote page's current selection for COPY-OUT — backs the surface's `FetchSelection`. Awaits\n * the `GetRemoteBrowserSelection` query and returns its text. Best-effort by contract\n * ({@link RemoteBrowserSelectionFetcher}): returns `''` when no session is live or the query fails, so a\n * best-effort copy never throws.\n */\n private async fetchSelection(): Promise<string> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return '';\n }\n const data = await this.Context?.ExecuteServerAction<GetRemoteBrowserSelectionResult>(GET_SELECTION_QUERY, { agentSessionID: sessionId });\n return data?.GetRemoteBrowserSelection?.Text ?? '';\n }\n\n /** Asks the server to stop the screencast (best-effort) and clears the streaming flag. */\n private async stopScreencast(): Promise<void> {\n const wasStreaming = this.streaming;\n this.streaming = false;\n this.clearScreencastTrailingTimer();\n this.pendingScreencastFrame = null;\n this.lastPushedScreencastFrame = null;\n this.lastPushedUrl = null;\n this.lastScreencastPushTime = 0;\n const sessionId = this.Context?.AgentSessionID;\n if (!wasStreaming || !sessionId) {\n return;\n }\n await this.Context?.ExecuteServerAction(STOP_SCREENCAST_MUTATION, { agentSessionID: sessionId });\n }\n\n /**\n * Fetches one live snapshot of the server browser for the surface — the PERCEPTION poll.\n * Best-effort by contract ({@link RemoteBrowserSnapshotFetcher}): returns `null` when no\n * session is live or the query fails (the surface keeps its last good frame).\n *\n * Also the channel's chance to NOTICE a page change it did not cause (#3496): the poll already\n * carries the URL, and until now only the surface read it.\n */\n private async fetchSnapshot(): Promise<RemoteBrowserSnapshotView | null> {\n const sessionId = this.Context?.AgentSessionID;\n if (!sessionId) {\n return null;\n }\n const data = await this.Context?.ExecuteServerAction<RemoteBrowserSnapshotResult>(REMOTE_BROWSER_SNAPSHOT_QUERY, { agentSessionID: sessionId });\n const snapshot = data?.RemoteBrowserSnapshot ?? null;\n this.notePageChange(snapshot?.CurrentUrl ?? null, 'observed');\n return snapshot;\n }\n\n /**\n * The ONE place the agent is told where the page is (#3496).\n *\n * Before this, the `[browser] current page:` note was pushed from exactly two call sites, both\n * immediately after a server action the MODEL itself initiated. That placement — not any caching —\n * was the bug: **a surface change the agent did not cause was invisible to it.** A user taking over\n * and navigating produced no note, so the agent went on confidently describing the previous page,\n * and only corrected when told to look again. Human takeover is on by default for `Collaborative`\n * providers, so the default configuration was the broken one.\n *\n * Routing every observation through here makes the rule \"the agent hears about the page whenever it\n * MOVES, whoever moved it\" — a property of this method rather than of where callers happen to be.\n *\n * `cause` is what the agent could never work out for itself. An `'agent'` change is one this\n * channel just performed; anything spotted by the perception poll or a pushed frame is\n * `'observed'` — someone else is driving, and saying so is the difference between the agent\n * knowing the page moved and knowing it is no longer the one moving it.\n *\n * Silent when the URL has not changed, which is not an optimisation but a requirement: the\n * perception poll runs every ~700ms and an unconditional note would bury the conversation in\n * hundreds of identical lines.\n */\n private notePageChange(url: string | null | undefined, cause: 'agent' | 'observed'): void {\n const next = (url ?? '').trim();\n if (next.length === 0) {\n return;\n }\n // The live-view bar is refreshed even when the URL is unchanged: it is idempotent, and in\n // streaming mode it is the only thing keeping the bar off \"No page loaded yet\".\n this.surface?.SetCurrentUrl(next);\n if (next === this.lastNotedUrl) {\n return;\n }\n const firstSighting = this.lastNotedUrl === null;\n this.lastNotedUrl = next;\n // A change seen WHILE the agent is driving is the agent's own, whichever feed spotted it first.\n const byAgent = cause === 'agent' || this.agentDrivingDepth > 0;\n this.Context?.SendContextNote(\n byAgent || firstSighting\n ? `[browser] current page: ${next}`\n : `[browser] the page changed to: ${next} — you did not navigate here, so someone else is driving. `\n + `Describe THIS page, not the one you last opened.`,\n );\n }\n\n /**\n * Runs one agent-initiated browser operation with {@link agentDrivingDepth} raised, so any page\n * change observed while it runs is attributed to the agent rather than to a phantom third party.\n *\n * `finally` and not a trailing decrement: the window must close on a thrown transport error too,\n * or one failed tool call would leave the channel permanently unable to report a real takeover.\n */\n private async whileAgentDrives<T>(work: () => Promise<T>): Promise<T> {\n this.agentDrivingDepth++;\n try {\n return await work();\n } finally {\n this.agentDrivingDepth--;\n }\n }\n\n /**\n * Executes ONE `browser_*` tool call: maps it to a server action and awaits the\n * `ExecuteRemoteBrowserAction` mutation, then returns a concise JSON result the model reads.\n * On success it also feeds the new page URL to the agent as a `[browser]` context note. Never\n * throws — bad arguments, no live session, and server failures all become a failed-result\n * payload so the model can narrate the problem.\n */\n public async ApplyAgentTool(toolName: string, argsJson: string): Promise<string> {\n // VISION-QUERY branch: the two interpreter tools OBSERVE the page (run a vision model over a screenshot)\n // rather than drive it, so they route to the separate interpret mutation, not MapToolToAction.\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.DescribePage) {\n return this.interpretPage(undefined);\n }\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.AchieveGoal) {\n return this.achieveGoal(argsJson);\n }\n if (toolName === REMOTE_BROWSER_TOOL_NAMES.LocateElement) {\n const description = this.asArgString(this.parseArgs(argsJson)['description']);\n if (!description) {\n return this.fail('browser_LocateElement requires a \"description\" of the element to find.');\n }\n return this.interpretPage(description);\n }\n\n let action: RemoteBrowserAction;\n try {\n action = MapToolToAction(toolName, this.parseArgs(argsJson));\n } catch (error) {\n const message = error instanceof RemoteBrowserToolArgError ? error.message : 'Invalid Remote Browser tool arguments.';\n return this.fail(message);\n }\n\n // Briefly WAIT for the session id rather than failing instantly: the model can fire a tool the\n // first beat it connects, before mintSession binds the id (the \"session id missing\" race).\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n // Diagnostic: distinguishes \"channel never Initialized (no Context)\" from \"session id never\n // resolved within the wait window\" — the two distinct causes of a null id at tool-execution time.\n console.warn('[RemoteBrowser] browser tool invoked but AgentSessionID is null', {\n tool: toolName,\n hasContext: !!this.Context,\n agentSessionID: this.Context?.AgentSessionID ?? null,\n });\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n\n return this.whileAgentDrives(async () => {\n const data = await this.Context?.ExecuteServerAction<ExecuteRemoteBrowserActionResult>(\n EXECUTE_REMOTE_BROWSER_ACTION_MUTATION,\n this.buildVariables(sessionId, action),\n );\n const result = data?.ExecuteRemoteBrowserAction ?? null;\n if (!result) {\n return this.fail('The browser action could not be executed (no response from the server).');\n }\n if (!result.Success) {\n return this.fail(result.Detail ?? 'The browser action failed.');\n }\n\n // PERCEPTION: tell the agent where the page is now (background — no spoken reply), and refresh\n // the live-view bar, which in streaming mode has no poll feeding it.\n this.notePageChange(result.CurrentUrl, 'agent');\n return this.ok(result.CurrentUrl, result.Detail);\n });\n }\n\n /** Builds the flat mutation variables from a normalized action (omitted fields ride as null). */\n private buildVariables(sessionId: string, action: RemoteBrowserAction): Record<string, JSONValue> {\n return {\n agentSessionID: sessionId,\n kind: action.Kind,\n url: action.Url ?? null,\n selector: action.Selector ?? null,\n x: action.X ?? null,\n y: action.Y ?? null,\n text: action.Text ?? null,\n key: action.Key ?? null,\n deltaX: action.DeltaX ?? null,\n deltaY: action.DeltaY ?? null,\n ms: action.Ms ?? null,\n };\n }\n\n /**\n * GOAL path for the `browser_AchieveGoal` tool: hands a high-level goal to the server's autonomous\n * browser agent (computer-use loop / native AI) via {@link EXECUTE_REMOTE_BROWSER_GOAL_MUTATION} and\n * returns a concise result for the model. Never throws — failures map to a `{ success: false }` string.\n *\n * @param argsJson The raw tool-call arguments (`{ goal, startUrl? }`).\n * @returns The model-readable result string.\n */\n private async achieveGoal(argsJson: string): Promise<string> {\n // Wait briefly for the session id (mint/reconnect race) before giving up — see ResolveAgentSessionId.\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n const args = this.parseArgs(argsJson);\n const goal = this.asArgString(args['goal']);\n if (!goal) {\n return this.fail('browser_AchieveGoal requires a \"goal\" describing what to accomplish.');\n }\n const startUrl = this.asArgString(args['startUrl']) ?? null;\n\n // START the goal (returns immediately with a GoalRunID) then POLL — a goal loop can run for\n // minutes, far longer than any single request survives, so we never hold one open for the loop.\n // The whole span is agent-driven: every page the loop opens is observed with nothing returned\n // yet, so without the window the agent would narrate its own goal as somebody else's takeover.\n return this.whileAgentDrives(async () => {\n const startData = await this.Context?.ExecuteServerAction<ExecuteRemoteBrowserGoalResult>(EXECUTE_REMOTE_BROWSER_GOAL_MUTATION, {\n agentSessionID: sessionId,\n goal,\n startUrl,\n });\n const started = startData?.ExecuteRemoteBrowserGoal ?? null;\n if (!started) {\n return this.fail('The browser goal could not be started (no response from the server).');\n }\n // Defensive: if the server ever returns a terminal status synchronously, use it directly.\n const result = started.Status === 'Running' && started.GoalRunID\n ? await this.pollGoalResult(sessionId, started.GoalRunID)\n : started;\n if (!result) {\n return this.fail('The browser goal is taking longer than expected and could not be confirmed. It may still be running.');\n }\n this.notePageChange(result.CurrentUrl, 'agent');\n if (!result.Success) {\n return this.fail(result.Detail ?? `The goal could not be completed (${result.Status ?? 'unknown'}).`);\n }\n return this.ok(result.CurrentUrl, result.Detail ?? `Goal completed (${result.Status ?? 'Completed'}, ${result.StepCount ?? 0} steps).`);\n });\n }\n\n /**\n * Polls {@link GET_REMOTE_BROWSER_GOAL_RESULT_QUERY} for a started goal run until it reports a\n * terminal status (anything other than `Running`), then returns that terminal payload. Each poll is\n * a short request, so no transport boundary times out while a long goal loop runs server-side.\n *\n * Returns `null` if the goal is still `Running` after {@link GoalPollTimeoutMs} (the loop keeps\n * running server-side; the caller maps this to a \"still running\" message), the session went away, or\n * the run id is no longer known (`Unknown` — expired/superseded).\n */\n private async pollGoalResult(sessionId: string, goalRunID: string): Promise<RemoteBrowserGoalPayload | null> {\n const interval = Math.max(1, this.GoalPollIntervalMs);\n for (let waited = 0; waited < this.GoalPollTimeoutMs; waited += interval) {\n await new Promise<void>((resolve) => setTimeout(resolve, interval));\n // The session ended mid-goal — stop polling (the live browser is gone).\n if (!this.Context?.AgentSessionID) {\n return null;\n }\n const data = await this.Context.ExecuteServerAction<GetRemoteBrowserGoalResultPayload>(GET_REMOTE_BROWSER_GOAL_RESULT_QUERY, {\n agentSessionID: sessionId,\n goalRunID,\n });\n const payload = data?.GetRemoteBrowserGoalResult ?? null;\n // A transient null (one failed poll) shouldn't abort — keep polling until the deadline.\n if (payload && payload.Status !== 'Running') {\n return payload;\n }\n }\n return null;\n }\n\n /**\n * Runs the VISION-QUERY path for the `browser_DescribePage` / `browser_LocateElement` tools: awaits the\n * `InterpretRemoteBrowserPage` mutation (server captures a screenshot + runs a fast vision model) and returns\n * a concise JSON string the model reads. For a describe (no `query`) it returns `{ description }`; for a locate\n * it returns `{ found, element, all }` so the agent can `browser_Click` the centroid. Never throws — a null\n * session, no response, or a server detail-only result all map to a result string the model can narrate.\n *\n * @param query The visual target to locate, or `undefined` for a plain page description.\n * @returns A JSON string describing the interpretation for the model.\n */\n private async interpretPage(query: string | undefined): Promise<string> {\n // Wait briefly for the session id (mint/reconnect race) before giving up — see ResolveAgentSessionId.\n const sessionId = await this.ResolveAgentSessionId();\n if (!sessionId) {\n console.warn('[RemoteBrowser] interpret tool invoked but AgentSessionID is null', {\n hasContext: !!this.Context,\n agentSessionID: this.Context?.AgentSessionID ?? null,\n });\n return this.fail('No live browser session is available yet — the realtime session may still be connecting; try again in a moment.');\n }\n\n const data = await this.Context?.ExecuteServerAction<InterpretRemoteBrowserPageResult>(INTERPRET_PAGE_MUTATION, {\n agentSessionID: sessionId,\n query: query ?? null,\n });\n const result = data?.InterpretRemoteBrowserPage ?? null;\n if (!result) {\n return this.fail('The page could not be interpreted (no response from the server).');\n }\n\n if (query === undefined) {\n // DescribePage — hand back the description (or the server's detail note when nothing was interpreted).\n return JSON.stringify({ description: result.Description ?? result.Detail ?? null });\n }\n\n // LocateElement — surface whether anything matched, the best match, and all candidates.\n const elements = result.Elements ?? [];\n const best = elements[0];\n return JSON.stringify({\n found: elements.length > 0,\n element: best ? { label: best.Label, x: best.X, y: best.Y } : null,\n all: elements,\n ...(result.Detail ? { detail: result.Detail } : {}),\n });\n }\n\n /** Coerces a parsed tool-arg to a non-empty string, or `undefined` when absent / wrong-typed. */\n private asArgString(value: JSONValue | undefined): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n }\n\n /** Parses the tool-args JSON into a plain object; returns `{}` for empty/malformed input. */\n private parseArgs(argsJson: string): Record<string, JSONValue> {\n const trimmed = argsJson?.trim();\n if (!trimmed) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(trimmed);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as Record<string, JSONValue>) : {};\n } catch {\n return {};\n }\n }\n\n /** Builds a successful tool-result JSON string for the model. */\n private ok(currentUrl: string | null, detail: string | null): string {\n const result: RemoteBrowserToolResult = { success: true };\n if (currentUrl) {\n result.currentUrl = currentUrl;\n }\n if (detail) {\n result.detail = detail;\n }\n return JSON.stringify(result);\n }\n\n /** Builds a failed tool-result JSON string for the model. */\n private fail(error: string): string {\n const result: RemoteBrowserToolResult = { success: false, error };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Tree-shaking prevention: the Remote Browser channel is resolved dynamically through the\n * ClassFactory (by the registry row's `ClientPluginClass` key), so this static call is what\n * keeps its `@RegisterClass` side effect from being eliminated by the bundler. Called from\n * `conversations.module.ts` alongside {@link LoadRealtimeWhiteboardChannel}.\n */\nexport function LoadRealtimeRemoteBrowserChannel(): void {\n // intentional no-op — the import side effect performs the registration\n}\n"]}
@@ -82,12 +82,13 @@ export type RemoteBrowserSelectionFetcher = () => Promise<string>;
82
82
  * tab's pane. It renders the SERVER-hosted browser the agent drives: a refreshing screenshot
83
83
  * `<img>` with the current URL above it and a small "live" indicator. The agent's
84
84
  * `browser_*` tools mutate the page through the channel plugin; this surface only PERCEIVES
85
- * it, polling its {@link Fetch} callback every {@link SNAPSHOT_POLL_MS} ms while bound.
85
+ * it, polling its {@link Fetch} callback every {@link SNAPSHOT_POLL_MS} ms while bound and on screen.
86
86
  *
87
87
  * The surface is transport-agnostic — it never touches GraphQL directly. The channel plugin
88
88
  * wires the {@link Fetch} callback (closing over the session id + provider) in `BindSurface`
89
89
  * before the surface's first change detection, so the `ngOnInit` poll has it. Polling stops
90
- * in `ngOnDestroy` (pane collapsed / overlay torn down) so no traffic continues after unbind.
90
+ * in `ngOnDestroy` (the channel left the session / the overlay was torn down) so no traffic
91
+ * continues after unbind, and pauses while the surface is out of sight ({@link Visible}).
91
92
  * View-only in v1 — there is no takeover input.
92
93
  *
93
94
  * ### Two render paths: pushed screencast (preferred) vs. snapshot poll (fallback)
@@ -107,6 +108,15 @@ export declare class RemoteBrowserSurfaceComponent implements OnInit, OnDestroy
107
108
  * copy is a no-op (the local clipboard is left untouched).
108
109
  */
109
110
  FetchSelection: RemoteBrowserSelectionFetcher | null;
111
+ /**
112
+ * Whether the surface is on screen, set by the channel plugin when the host reports it
113
+ * (`OnSurfaceVisibilityChange`). Out of sight, the snapshot poll pauses: nobody sees it, and the
114
+ * agent's frames come from the channel's own video bridge. Back in sight, the surface fetches a
115
+ * snapshot at once and polls again. The pushed screencast is unaffected.
116
+ */
117
+ set Visible(value: boolean);
118
+ get Visible(): boolean;
119
+ private _visible;
110
120
  /**
111
121
  * Whether the server is PUSHING live screencast frames for this session (the backend advertised the
112
122
  * `ScreenStreaming` capability and the start succeeded). When `true` the surface paints pushed frames
@@ -173,6 +183,8 @@ export declare class RemoteBrowserSurfaceComponent implements OnInit, OnDestroy
173
183
  private polling;
174
184
  /** Set on destroy so an in-flight poll's late resolution doesn't touch a torn-down view. */
175
185
  private destroyed;
186
+ /** Set in `ngOnInit`: polling starts there, so a visibility change before it must not start it early. */
187
+ private initialized;
176
188
  /** Reused decode target for pushed frames — avoids allocating an `Image` per frame. */
177
189
  private readonly frameImage;
178
190
  /** The most recent un-painted frame data URL, drained on the next animation frame (drop-old coalescing). */
@@ -227,6 +239,11 @@ export declare class RemoteBrowserSurfaceComponent implements OnInit, OnDestroy
227
239
  private readonly onCanvasBlur;
228
240
  ngOnInit(): void;
229
241
  ngOnDestroy(): void;
242
+ /**
243
+ * Polls now and every {@link SNAPSHOT_POLL_MS} ms, unless the server pushes frames (the poll would be redundant
244
+ * traffic) or the surface is out of sight.
245
+ */
246
+ private resumePolling;
230
247
  /** Starts the interval poll OUTSIDE Angular's zone so it doesn't trigger CD on every tick. */
231
248
  private startPolling;
232
249
  /** Stops the interval poll (no further snapshot requests are issued). */
@@ -374,6 +391,6 @@ export declare class RemoteBrowserSurfaceComponent implements OnInit, OnDestroy
374
391
  /** Maps a DOM `MouseEvent.button` (0/1/2) to the relayed button union, defaulting to `'left'`. */
375
392
  private mapButton;
376
393
  static ɵfac: i0.ɵɵFactoryDeclaration<RemoteBrowserSurfaceComponent, never>;
377
- static ɵcmp: i0.ɵɵComponentDeclaration<RemoteBrowserSurfaceComponent, "mj-realtime-remote-browser-surface", never, { "Fetch": { "alias": "Fetch"; "required": false; }; "FetchSelection": { "alias": "FetchSelection"; "required": false; }; "Streaming": { "alias": "Streaming"; "required": false; }; "Interactive": { "alias": "Interactive"; "required": false; }; "AudioAvailable": { "alias": "AudioAvailable"; "required": false; }; "AudioMuted": { "alias": "AudioMuted"; "required": false; }; }, { "HumanInput": "HumanInput"; "AudioMutedChange": "AudioMutedChange"; }, never, never, true, never>;
394
+ static ɵcmp: i0.ɵɵComponentDeclaration<RemoteBrowserSurfaceComponent, "mj-realtime-remote-browser-surface", never, { "Fetch": { "alias": "Fetch"; "required": false; }; "FetchSelection": { "alias": "FetchSelection"; "required": false; }; "Visible": { "alias": "Visible"; "required": false; }; "Streaming": { "alias": "Streaming"; "required": false; }; "Interactive": { "alias": "Interactive"; "required": false; }; "AudioAvailable": { "alias": "AudioAvailable"; "required": false; }; "AudioMuted": { "alias": "AudioMuted"; "required": false; }; }, { "HumanInput": "HumanInput"; "AudioMutedChange": "AudioMutedChange"; }, never, never, true, never>;
378
395
  }
379
396
  //# sourceMappingURL=remote-browser-surface.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-browser-surface.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/remote-browser/remote-browser-surface.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-browser-surface.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/remote-browser/remote-browser-surface.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAC8D,YAAY,EAAiB,SAAS,EACzG,MAAM,EACP,MAAM,eAAe,CAAC;;AAgBvB,0GAA0G;AAC1G,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,WAAW,4BAA4B;IAC3C,4BAA4B;IAC5B,IAAI,EAAE,cAAc,GAAG,eAAe,GAAG,cAAc,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IACnG,gDAAgD;IAChD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oGAAoG;IACpG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,SAAS,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAmBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAClE,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAOjC;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,2FAA2F;IAC3F,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,MAAM,4BAA4B,GAAG,MAAM,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAoMa,6BAA8B,YAAW,MAAM,EAAE,SAAS;IACrE,+FAA+F;IACtF,KAAK,EAAE,4BAA4B,GAAG,IAAI,CAAQ;IAE3D;;;;;OAKG;IACM,cAAc,EAAE,6BAA6B,GAAG,IAAI,CAAQ;IAErE;;;;;OAKG;IACH,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EAUzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,OAAO,CAAC,QAAQ,CAAQ;IAExB;;;;;;;;OAQG;IACH,IACI,SAAS,CAAC,KAAK,EAAE,OAAO,EAY3B;IACD,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;OAKG;IACH,IACI,WAAW,CAAC,KAAK,EAAE,OAAO,EAO7B;IACD,IAAI,WAAW,IAAI,OAAO,CAEzB;IACD,OAAO,CAAC,YAAY,CAAS;IAE7B,sGAAsG;IAC5F,UAAU,6CAAoD;IAExE;;;OAGG;IACM,cAAc,UAAS;IAEhC;;;;OAIG;IACM,UAAU,UAAS;IAE5B,+FAA+F;IACrF,gBAAgB,wBAA+B;IAEzD,0GAA0G;IACnG,gBAAgB,IAAI,IAAI;IAK/B,sGAAsG;IACtG,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED;;;;OAIG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAErC;IAED,4FAA4F;IACrF,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC/C,wEAAwE;IACjE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,qGAAqG;IAC9F,QAAQ,UAAS;IAExB,uGAAuG;IAC7E,OAAO,CAAC,WAAW,CAAC,CAAgC;IAE9E,2GAA2G;IAChF,OAAO,CAAC,YAAY,CAAC,CAAgC;IAEhF,gGAAgG;IAChG,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,yDAAyD;IACzD,OAAO,CAAC,SAAS,CAA+C;IAChE,qFAAqF;IACrF,OAAO,CAAC,OAAO,CAAS;IACxB,4FAA4F;IAC5F,OAAO,CAAC,SAAS,CAAS;IAC1B,yGAAyG;IACzG,OAAO,CAAC,WAAW,CAAS;IAC5B,uFAAuF;IACvF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,4GAA4G;IAC5G,OAAO,CAAC,mBAAmB,CAAuB;IAClD,gGAAgG;IAChG,OAAO,CAAC,mBAAmB,CAAS;IAEpC,6FAA6F;IAC7F,OAAO,CAAC,cAAc,CAAkC;IACxD,mGAAmG;IACnG,OAAO,CAAC,iBAAiB,CAAK;IAC9B,mGAAmG;IACnG,OAAO,CAAC,YAAY,CAAK;IACzB,8GAA8G;IAC9G,OAAO,CAAC,mBAAmB,CAAK;IAChC,4GAA4G;IAC5G,OAAO,CAAC,mBAAmB,CAAK;IAEhC,6GAA6G;IAC7G,OAAO,CAAC,mBAAmB,CAAyC;IACpE,+GAA+G;IAC/G,OAAO,CAAC,oBAAoB,CAAS;IAErC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB,CAAS;IAElC,uGAAuG;IACvG,OAAO,CAAC,cAAc,CAAyC;IAE/D;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAS;IAE/B,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAsD;IACxF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAsD;IACxF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoD;IACpF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuD;IACrF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqD;IACrF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAClF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmD;IAChF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAuC;IAC1E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgD;IAC9E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgD;IAE7E,QAAQ,IAAI,IAAI;IAKhB,WAAW,IAAI,IAAI;IAMnB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAQrB,8FAA8F;IAC9F,OAAO,CAAC,YAAY;IASpB,yEAAyE;IACzE,OAAO,CAAC,WAAW;IAOnB;;;;;OAKG;YACW,QAAQ;IAetB,0FAA0F;IAC1F,OAAO,CAAC,aAAa;IAgBrB;;;;;;;OAOG;IACI,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAY5C;;;;;;OAMG;IACI,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAQ1D,yFAAyF;IACzF,OAAO,CAAC,iBAAiB;IAWzB,wGAAwG;IACxG,OAAO,CAAC,cAAc;IA4BtB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAW7B,sHAAsH;IACtH,OAAO,CAAC,uBAAuB;IAwB/B,+GAA+G;IAC/G,OAAO,CAAC,uBAAuB;IA0B/B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAiBzB,8EAA8E;IAC9E,OAAO,CAAC,gBAAgB;IAKxB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAsBnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAcvB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAsBrB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAUnB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAoBlB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IASxB,yFAAyF;IACzF,OAAO,CAAC,SAAS;IAIjB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAiC5B,kGAAkG;IAClG,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IASvB,kGAAkG;IAClG,OAAO,CAAC,SAAS;yCAhuBN,6BAA6B;2CAA7B,6BAA6B;CAyuBzC"}