@memberjunction/ng-conversations 6.2.0-edge.2 → 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 (279) 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 +632 -55
  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 +2748 -624
  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 +121 -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 +307 -106
  27. package/dist/lib/components/message/message-input.component.js.map +1 -1
  28. package/dist/lib/components/message/message-item.component.d.ts +178 -5
  29. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  30. package/dist/lib/components/message/message-item.component.js +919 -306
  31. package/dist/lib/components/message/message-item.component.js.map +1 -1
  32. package/dist/lib/components/message/message-list.component.d.ts +92 -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 +337 -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/util/frame-zone.d.ts +10 -0
  260. package/dist/lib/util/frame-zone.d.ts.map +1 -0
  261. package/dist/lib/util/frame-zone.js +10 -0
  262. package/dist/lib/util/frame-zone.js.map +1 -0
  263. package/dist/lib/utils/conversation-branching.d.ts +4 -0
  264. package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
  265. package/dist/lib/utils/conversation-branching.js +5 -0
  266. package/dist/lib/utils/conversation-branching.js.map +1 -0
  267. package/dist/lib/utils/conversation-forks.d.ts +315 -0
  268. package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
  269. package/dist/lib/utils/conversation-forks.js +456 -0
  270. package/dist/lib/utils/conversation-forks.js.map +1 -0
  271. package/dist/public-api.d.ts +23 -1
  272. package/dist/public-api.d.ts.map +1 -1
  273. package/dist/public-api.js +30 -1
  274. package/dist/public-api.js.map +1 -1
  275. package/package.json +37 -32
  276. package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
  277. package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
  278. package/dist/lib/components/thread/thread-panel.component.js +0 -440
  279. package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-capture-model.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { BehaviorSubject, type Observable } from 'rxjs';\nimport type { JSONObject } from '@memberjunction/ai';\nimport type { CapturedDisplaySurface, MediaParticipant, MediaVideoSource, VideoSourceState } from '@memberjunction/ai-realtime-client/media';\nimport { REALTIME_CAPTURE_SOURCE_IDS, type RealtimeCaptureKind, type RealtimeCaptureState } from '@memberjunction/realtime-runtime';\n\n/** Where a capture channel stands, as the agent reads it (its `status` noun) and its surface shows it. */\nexport type RealtimeCaptureStatus = 'off' | 'asked' | 'starting' | 'on' | 'failed';\n\n/** What the capture surface shows. */\nexport interface RealtimeCaptureView {\n Kind: RealtimeCaptureKind;\n Status: RealtimeCaptureStatus;\n /** The agent's reason for asking, while its request stands. */\n Reason: string | null;\n /** Why the last start failed, while it stands. */\n Problem: string | null;\n /** The user's camera as `mj-self-view` takes it: while the camera is on, the same object for one stream. */\n Participant: MediaParticipant | null;\n /** The shared surface as `mj-share-preview` takes it: while a share is on, the same object for one stream. */\n Source: MediaVideoSource | null;\n /** What a share shows. */\n Surface: CapturedDisplaySurface;\n /** The shared panel's name, while the user shares one panel of the page; `null` otherwise. */\n PanelLabel: string | null;\n /**\n * Whether the agent sees the capture now: it is on, the channel lets the agent see pixels, and the model is being sent\n * its frames (its source among the session's video sources is on and active, which is what the \"Agent can see\" chip\n * reads). On a model that takes one video stream, a screen share started after the camera is the one sent, so the camera\n * is not seen until the user picks it again.\n */\n AgentCanSee: boolean;\n}\n\n/** The events a capture channel streams, by name. */\nexport type RealtimeCaptureEventName = 'asked' | 'declined' | 'started' | 'stopped' | 'failed';\n\n/** One change: the event to stream, if the change is one. */\nexport interface RealtimeCaptureChange {\n Event: { Name: RealtimeCaptureEventName; Payload: JSONObject } | null;\n}\n\n/**\n * The state of one capture channel (the Camera or the Screen Share channel): the agent's request, the runtime's capture,\n * and whether the agent sees it. Framework-free: the channel feeds it and streams its changes; the surface shows its\n * {@link View$}. It decides nothing about policy: the runtime refuses a capture its channel's policy does not allow, and\n * reports that as a failed capture.\n */\nexport class RealtimeCaptureModel {\n private reason: string | null = null;\n private capture: RealtimeCaptureState = { Status: 'off' };\n private agentCanSee = false;\n /**\n * Whether the model is being sent this capture's frames: its source is on and active. `null` until the host reports the\n * session's sources ({@link FollowVideoSources}); a host that never does leaves the channel's exposure alone to decide.\n */\n private framesSent: boolean | null = null;\n private onStream: { Stream: MediaStream; Participant: MediaParticipant | null; Source: MediaVideoSource | null } | null = null;\n private readonly view: BehaviorSubject<RealtimeCaptureView>;\n private changeHandler: ((change: RealtimeCaptureChange) => void) | null = null;\n\n constructor(public readonly Kind: RealtimeCaptureKind) {\n this.view = new BehaviorSubject<RealtimeCaptureView>(this.buildView());\n }\n\n /** What the surface shows now. */\n public get View(): RealtimeCaptureView {\n return this.view.value;\n }\n\n /** What the surface shows, now and on every change. */\n public get View$(): Observable<RealtimeCaptureView> {\n return this.view.asObservable();\n }\n\n /** Receives every change (one handler; `null` removes it). */\n public OnChange(handler: ((change: RealtimeCaptureChange) => void) | null): void {\n this.changeHandler = handler;\n }\n\n /**\n * The agent asks to see the capture. A request while the capture is starting or on changes nothing.\n *\n * @returns Whether the request stands (the user now sees it).\n */\n public Ask(reason: string | null): boolean {\n if (this.capture.Status === 'starting' || this.capture.Status === 'on') {\n return false;\n }\n this.reason = reason?.trim() ?? '';\n this.publish({ Name: 'asked', Payload: this.reason ? { reason: this.reason } : {} });\n return true;\n }\n\n /** The user said \"Not now\" to the agent's request. Nothing to decline without one. */\n public Decline(): void {\n if (this.reason === null) {\n return;\n }\n this.reason = null;\n this.publish({ Name: 'declined', Payload: {} });\n }\n\n /**\n * The runtime's capture changed. Turning on answers the agent's request, and so does a camera check that ends with the\n * camera off: the user said not now.\n */\n public FollowCapture(capture: RealtimeCaptureState): void {\n const was = this.capture;\n this.capture = capture;\n if (capture.Status === 'on') {\n this.reason = null;\n }\n if (was.Checking && capture.Status === 'off' && this.reason !== null) {\n this.reason = null;\n this.publish({ Name: 'declined', Payload: {} });\n return;\n }\n this.publish(this.eventFor(was.Status, capture));\n }\n\n /** Whether the channel lets the agent see pixels (its exposure). */\n public SetAgentCanSee(visible: boolean): void {\n if (visible !== this.agentCanSee) {\n this.agentCanSee = visible;\n this.publish(null);\n }\n }\n\n /**\n * The session's video sources changed (the runtime's `VideoSources$`). The model is sent this capture's frames only while\n * its source (`REALTIME_CAPTURE_SOURCE_IDS`) is on and active; a capture with no source yet, or none any more, is not\n * sent. Only the view changes: the channel's state is the same, so the change handler hears nothing and the agent is\n * told nothing (the arbiter tells the model what it now sees).\n */\n public FollowVideoSources(sources: readonly VideoSourceState[]): void {\n const sourceId = REALTIME_CAPTURE_SOURCE_IDS[this.Kind];\n const source = sources.find((s) => s.SourceID === sourceId);\n const sent = source !== undefined && source.Enabled && source.Active;\n if (sent !== this.framesSent) {\n this.framesSent = sent;\n this.view.next(this.buildView());\n }\n }\n\n /** The channel's state as the agent reads it. */\n public ToState(): JSONObject {\n const view = this.View;\n const state: JSONObject = { status: view.Status, reason: view.Reason ?? '', problem: view.Problem ?? '' };\n if (this.Kind === 'screen') {\n state['surface'] = view.Surface;\n }\n return state;\n }\n\n /** The event a capture change is, if it is one: started, stopped or failed. */\n private eventFor(was: RealtimeCaptureState['Status'], capture: RealtimeCaptureState): RealtimeCaptureChange['Event'] {\n if (capture.Status === 'on' && was !== 'on') {\n return { Name: 'started', Payload: this.Kind === 'screen' ? { surface: capture.Surface ?? 'unknown' } : {} };\n }\n if (capture.Status === 'off' && was === 'on') {\n return { Name: 'stopped', Payload: {} };\n }\n if (capture.Status === 'failed' && was !== 'failed') {\n return { Name: 'failed', Payload: { failure: capture.Failure ?? 'error', message: capture.Message ?? '' } };\n }\n return null;\n }\n\n private publish(event: RealtimeCaptureChange['Event']): void {\n this.view.next(this.buildView());\n this.changeHandler?.({ Event: event });\n }\n\n private buildView(): RealtimeCaptureView {\n const capture = this.capture;\n const shown = this.shownStream(capture);\n return {\n Kind: this.Kind,\n Status: this.statusOf(capture),\n Reason: this.reason,\n Problem: capture.Status === 'failed' ? (capture.Message ?? 'The capture could not start.') : null,\n Participant: shown?.Participant ?? null,\n Source: shown?.Source ?? null,\n Surface: capture.Surface ?? 'unknown',\n PanelLabel: capture.PanelLabel ?? null,\n AgentCanSee: capture.Status === 'on' && this.agentCanSee && (this.framesSent ?? true),\n };\n }\n\n private statusOf(capture: RealtimeCaptureState): RealtimeCaptureStatus {\n if (capture.Status === 'off') {\n return this.reason !== null ? 'asked' : 'off';\n }\n return capture.Status;\n }\n\n /** The stream as the surface shows it, built once per stream so a re-render keeps the same objects. */\n private shownStream(capture: RealtimeCaptureState): RealtimeCaptureModel['onStream'] {\n if (capture.Status !== 'on' || !capture.Stream) {\n this.onStream = null;\n return null;\n }\n if (this.onStream?.Stream !== capture.Stream) {\n const video: MediaVideoSource = { Kind: 'stream', Stream: capture.Stream };\n this.onStream =\n this.Kind === 'camera'\n ? { Stream: capture.Stream, Participant: { Identity: 'self', DisplayName: 'You', Role: 'self', IsSpeaking: false, Video: { camera: video } }, Source: null }\n : { Stream: capture.Stream, Participant: null, Source: video };\n }\n return this.onStream;\n }\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import { EventEmitter, OnDestroy } from '@angular/core';
2
+ import type { RealtimeCaptureModel, RealtimeCaptureView } from './realtime-capture-model';
3
+ import * as i0 from "@angular/core";
4
+ /** What the surface says for each capture. */
5
+ interface CaptureWording {
6
+ Icon: string;
7
+ Asks: string;
8
+ Off: string;
9
+ Start: string;
10
+ Starting: string;
11
+ Hint: string;
12
+ }
13
+ /**
14
+ * `mj-realtime-capture-surface`: the Camera or Screen Share channel's surface. While the capture is off it is the ask:
15
+ * what the agent wants to see and why, with Turn on camera (or Share your screen) and, while the agent's request stands,
16
+ * Not now. While on, it is the user's own view of it: their camera mirrored (`mj-self-view`), or what they share
17
+ * (`mj-share-preview`, with Stop sharing and Change). It owns no rules: the {@link RealtimeCaptureModel} decides what it
18
+ * shows, and the channel runs the user's buttons.
19
+ */
20
+ export declare class RealtimeCaptureSurfaceComponent implements OnDestroy {
21
+ private readonly cdr;
22
+ private model;
23
+ private viewSub;
24
+ /** What the surface shows now, or `null` until a model is bound. */
25
+ View: RealtimeCaptureView | null;
26
+ /** The agent's name, for "Sage asks to see your camera". */
27
+ AgentName: string;
28
+ /** The channel's state. */
29
+ set Model(value: RealtimeCaptureModel | null);
30
+ get Model(): RealtimeCaptureModel | null;
31
+ /** The user asked to turn the camera on, or to share a screen. */
32
+ StartRequested: EventEmitter<void>;
33
+ /** The user said "Not now" to the agent's request. */
34
+ DeclineRequested: EventEmitter<void>;
35
+ /** The user turned the camera off, or stopped sharing. */
36
+ StopRequested: EventEmitter<void>;
37
+ /** The user asked to share something else. */
38
+ ChangeRequested: EventEmitter<void>;
39
+ /** The words for this capture. */
40
+ get Wording(): CaptureWording;
41
+ /** The card's heading: the agent's request while it stands, else that the capture is off. */
42
+ get Heading(): string;
43
+ ngOnDestroy(): void;
44
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeCaptureSurfaceComponent, never>;
45
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeCaptureSurfaceComponent, "mj-realtime-capture-surface", never, { "AgentName": { "alias": "AgentName"; "required": false; }; "Model": { "alias": "Model"; "required": false; }; }, { "StartRequested": "StartRequested"; "DeclineRequested": "DeclineRequested"; "StopRequested": "StopRequested"; "ChangeRequested": "ChangeRequested"; }, never, never, true, never>;
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=realtime-capture-surface.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-capture-surface.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-surface.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,YAAY,EAAS,SAAS,EAAkB,MAAM,eAAe,CAAC;AAMtI,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;;AAE1F,8CAA8C;AAC9C,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAqBD;;;;;;GAMG;AACH,qBAQa,+BAAgC,YAAW,SAAS;IAC/D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,OAAO,CAA6B;IAE5C,oEAAoE;IAC7D,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAQ;IAE/C,4DAA4D;IACnD,SAAS,SAAmB;IAErC,2BAA2B;IAC3B,IACW,KAAK,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAWlD;IACD,IAAW,KAAK,IAAI,oBAAoB,GAAG,IAAI,CAE9C;IAED,kEAAkE;IACxD,cAAc,qBAA4B;IACpD,sDAAsD;IAC5C,gBAAgB,qBAA4B;IACtD,0DAA0D;IAChD,aAAa,qBAA4B;IACnD,8CAA8C;IACpC,eAAe,qBAA4B;IAErD,kCAAkC;IAClC,IAAW,OAAO,IAAI,cAAc,CAEnC;IAED,6FAA6F;IAC7F,IAAW,OAAO,IAAI,MAAM,CAE3B;IAEM,WAAW,IAAI,IAAI;yCAhDf,+BAA+B;2CAA/B,+BAA+B;CAoD3C"}
@@ -0,0 +1,205 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
2
+ import { MJButtonDirective } from '@memberjunction/ng-ui-components';
3
+ import { SelfViewComponent, SharePreviewComponent } from '@memberjunction/ng-realtime-media';
4
+ import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@memberjunction/ng-shared-generic";
7
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
8
+ const _r1 = i0.ɵɵgetCurrentView();
9
+ i0.ɵɵelementStart(0, "div", 2);
10
+ i0.ɵɵelement(1, "mj-self-view", 4);
11
+ i0.ɵɵelementStart(2, "div", 5)(3, "button", 6);
12
+ i0.ɵɵlistener("click", function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_0_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.StopRequested.emit()); });
13
+ i0.ɵɵtext(4, "Turn off camera");
14
+ i0.ɵɵelementEnd()()();
15
+ } if (rf & 2) {
16
+ const view_r3 = i0.ɵɵnextContext(2);
17
+ i0.ɵɵadvance();
18
+ i0.ɵɵproperty("Participant", view_r3.Participant)("AgentCanSee", view_r3.AgentCanSee)("ShowHide", false)("ShowMeter", false)("ShowConnectionQuality", false)("ShowActiveSpeakerRing", false);
19
+ } }
20
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
21
+ const _r4 = i0.ɵɵgetCurrentView();
22
+ i0.ɵɵelementStart(0, "mj-share-preview", 7);
23
+ i0.ɵɵlistener("StopRequested", function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_1_Template_mj_share_preview_StopRequested_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.StopRequested.emit()); })("ChangeRequested", function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_1_Template_mj_share_preview_ChangeRequested_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ChangeRequested.emit()); });
24
+ i0.ɵɵelementEnd();
25
+ } if (rf & 2) {
26
+ const view_r3 = i0.ɵɵnextContext(2);
27
+ i0.ɵɵproperty("Source", view_r3.Source)("Surface", view_r3.Surface)("PanelLabel", view_r3.PanelLabel);
28
+ } }
29
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Template(rf, ctx) { if (rf & 1) {
30
+ i0.ɵɵconditionalCreate(0, RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_0_Template, 5, 6, "div", 2)(1, RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Conditional_1_Template, 1, 3, "mj-share-preview", 3);
31
+ } if (rf & 2) {
32
+ const view_r3 = i0.ɵɵnextContext();
33
+ i0.ɵɵconditional(view_r3.Kind === "camera" ? 0 : 1);
34
+ } }
35
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_1_Template(rf, ctx) { if (rf & 1) {
36
+ i0.ɵɵelementStart(0, "div", 0);
37
+ i0.ɵɵelement(1, "mj-loading", 8);
38
+ i0.ɵɵelementEnd();
39
+ } if (rf & 2) {
40
+ const ctx_r1 = i0.ɵɵnextContext(2);
41
+ i0.ɵɵadvance();
42
+ i0.ɵɵproperty("Text", ctx_r1.Wording.Starting);
43
+ } }
44
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
45
+ i0.ɵɵelementStart(0, "p", 12);
46
+ i0.ɵɵtext(1);
47
+ i0.ɵɵelementEnd();
48
+ } if (rf & 2) {
49
+ const view_r3 = i0.ɵɵnextContext(2);
50
+ i0.ɵɵadvance();
51
+ i0.ɵɵtextInterpolate(view_r3.Reason);
52
+ } }
53
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
54
+ i0.ɵɵelementStart(0, "p", 13);
55
+ i0.ɵɵtext(1);
56
+ i0.ɵɵelementEnd();
57
+ } if (rf & 2) {
58
+ const view_r3 = i0.ɵɵnextContext(2);
59
+ i0.ɵɵadvance();
60
+ i0.ɵɵtextInterpolate(view_r3.Problem);
61
+ } }
62
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
63
+ const _r6 = i0.ɵɵgetCurrentView();
64
+ i0.ɵɵelementStart(0, "button", 18);
65
+ i0.ɵɵlistener("click", function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.DeclineRequested.emit()); });
66
+ i0.ɵɵtext(1, "Not now");
67
+ i0.ɵɵelementEnd();
68
+ } }
69
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Template(rf, ctx) { if (rf & 1) {
70
+ const _r5 = i0.ɵɵgetCurrentView();
71
+ i0.ɵɵelementStart(0, "div", 1)(1, "div", 9);
72
+ i0.ɵɵelement(2, "i", 10);
73
+ i0.ɵɵelementStart(3, "h3", 11);
74
+ i0.ɵɵtext(4);
75
+ i0.ɵɵelementEnd();
76
+ i0.ɵɵconditionalCreate(5, RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_5_Template, 2, 1, "p", 12);
77
+ i0.ɵɵconditionalCreate(6, RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_6_Template, 2, 1, "p", 13);
78
+ i0.ɵɵelementStart(7, "div", 14)(8, "button", 15);
79
+ i0.ɵɵlistener("click", function RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.StartRequested.emit()); });
80
+ i0.ɵɵtext(9);
81
+ i0.ɵɵelementEnd();
82
+ i0.ɵɵconditionalCreate(10, RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Conditional_10_Template, 2, 0, "button", 16);
83
+ i0.ɵɵelementEnd();
84
+ i0.ɵɵelementStart(11, "p", 17);
85
+ i0.ɵɵtext(12);
86
+ i0.ɵɵelementEnd()()();
87
+ } if (rf & 2) {
88
+ const view_r3 = i0.ɵɵnextContext();
89
+ const ctx_r1 = i0.ɵɵnextContext();
90
+ i0.ɵɵadvance(2);
91
+ i0.ɵɵclassMap(ctx_r1.Wording.Icon);
92
+ i0.ɵɵadvance(2);
93
+ i0.ɵɵtextInterpolate(ctx_r1.Heading);
94
+ i0.ɵɵadvance();
95
+ i0.ɵɵconditional(view_r3.Reason ? 5 : -1);
96
+ i0.ɵɵadvance();
97
+ i0.ɵɵconditional(view_r3.Problem ? 6 : -1);
98
+ i0.ɵɵadvance(3);
99
+ i0.ɵɵtextInterpolate(ctx_r1.Wording.Start);
100
+ i0.ɵɵadvance();
101
+ i0.ɵɵconditional(view_r3.Reason !== null ? 10 : -1);
102
+ i0.ɵɵadvance(2);
103
+ i0.ɵɵtextInterpolate(ctx_r1.Wording.Hint);
104
+ } }
105
+ function RealtimeCaptureSurfaceComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
106
+ i0.ɵɵconditionalCreate(0, RealtimeCaptureSurfaceComponent_Conditional_0_Case_0_Template, 2, 1)(1, RealtimeCaptureSurfaceComponent_Conditional_0_Case_1_Template, 2, 1, "div", 0)(2, RealtimeCaptureSurfaceComponent_Conditional_0_Case_2_Template, 13, 8, "div", 1);
107
+ } if (rf & 2) {
108
+ let tmp_2_0;
109
+ i0.ɵɵconditional((tmp_2_0 = ctx.Status) === "on" ? 0 : tmp_2_0 === "starting" ? 1 : 2);
110
+ } }
111
+ const WORDING = {
112
+ camera: {
113
+ Icon: 'fa-solid fa-video',
114
+ Asks: 'asks to see your camera',
115
+ Off: 'Your camera is off',
116
+ Start: 'Turn on camera',
117
+ Starting: 'Waiting for your camera…',
118
+ Hint: 'Only you can turn your camera on or off.',
119
+ },
120
+ screen: {
121
+ Icon: 'fa-solid fa-display',
122
+ Asks: 'asks to see your screen',
123
+ Off: 'Nothing is shared',
124
+ Start: 'Share your screen',
125
+ Starting: "Choose what to share in your browser's window.",
126
+ Hint: 'Only you choose what to share, and you can stop at any time.',
127
+ },
128
+ };
129
+ /**
130
+ * `mj-realtime-capture-surface`: the Camera or Screen Share channel's surface. While the capture is off it is the ask:
131
+ * what the agent wants to see and why, with Turn on camera (or Share your screen) and, while the agent's request stands,
132
+ * Not now. While on, it is the user's own view of it: their camera mirrored (`mj-self-view`), or what they share
133
+ * (`mj-share-preview`, with Stop sharing and Change). It owns no rules: the {@link RealtimeCaptureModel} decides what it
134
+ * shows, and the channel runs the user's buttons.
135
+ */
136
+ export class RealtimeCaptureSurfaceComponent {
137
+ cdr = inject(ChangeDetectorRef);
138
+ model = null;
139
+ viewSub = null;
140
+ /** What the surface shows now, or `null` until a model is bound. */
141
+ View = null;
142
+ /** The agent's name, for "Sage asks to see your camera". */
143
+ AgentName = 'The assistant';
144
+ /** The channel's state. */
145
+ set Model(value) {
146
+ if (value === this.model) {
147
+ return;
148
+ }
149
+ this.viewSub?.unsubscribe();
150
+ this.model = value;
151
+ this.viewSub =
152
+ value?.View$.subscribe((view) => {
153
+ this.View = view;
154
+ this.cdr.markForCheck();
155
+ }) ?? null;
156
+ }
157
+ get Model() {
158
+ return this.model;
159
+ }
160
+ /** The user asked to turn the camera on, or to share a screen. */
161
+ StartRequested = new EventEmitter();
162
+ /** The user said "Not now" to the agent's request. */
163
+ DeclineRequested = new EventEmitter();
164
+ /** The user turned the camera off, or stopped sharing. */
165
+ StopRequested = new EventEmitter();
166
+ /** The user asked to share something else. */
167
+ ChangeRequested = new EventEmitter();
168
+ /** The words for this capture. */
169
+ get Wording() {
170
+ return WORDING[this.View?.Kind ?? 'camera'];
171
+ }
172
+ /** The card's heading: the agent's request while it stands, else that the capture is off. */
173
+ get Heading() {
174
+ return this.View?.Reason !== null && this.View?.Reason !== undefined ? `${this.AgentName} ${this.Wording.Asks}` : this.Wording.Off;
175
+ }
176
+ ngOnDestroy() {
177
+ this.viewSub?.unsubscribe();
178
+ this.viewSub = null;
179
+ }
180
+ static ɵfac = function RealtimeCaptureSurfaceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeCaptureSurfaceComponent)(); };
181
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeCaptureSurfaceComponent, selectors: [["mj-realtime-capture-surface"]], inputs: { AgentName: "AgentName", Model: "Model" }, outputs: { StartRequested: "StartRequested", DeclineRequested: "DeclineRequested", StopRequested: "StopRequested", ChangeRequested: "ChangeRequested" }, decls: 1, vars: 1, consts: [["role", "status", 1, "capture", "capture--card"], [1, "capture", "capture--card"], [1, "capture", "capture--live"], [1, "capture", "capture--live", 3, "Source", "Surface", "PanelLabel"], [1, "capture__self", 3, "Participant", "AgentCanSee", "ShowHide", "ShowMeter", "ShowConnectionQuality", "ShowActiveSpeakerRing"], [1, "capture__bar"], ["type", "button", "mjButton", "", "Variant", "danger", "Size", "sm", 3, "click"], [1, "capture", "capture--live", 3, "StopRequested", "ChangeRequested", "Source", "Surface", "PanelLabel"], ["Size", "small", 1, "capture__loading", 3, "Text"], [1, "capture__ask"], ["aria-hidden", "true", 1, "capture__icon"], [1, "capture__title"], [1, "capture__reason"], ["role", "alert", 1, "capture__problem"], [1, "capture__actions"], ["type", "button", "mjButton", "", "Variant", "primary", 3, "click"], ["type", "button", "mjButton", "", "Variant", "secondary"], [1, "capture__hint"], ["type", "button", "mjButton", "", "Variant", "secondary", 3, "click"]], template: function RealtimeCaptureSurfaceComponent_Template(rf, ctx) { if (rf & 1) {
182
+ i0.ɵɵconditionalCreate(0, RealtimeCaptureSurfaceComponent_Conditional_0_Template, 3, 1);
183
+ } if (rf & 2) {
184
+ let tmp_0_0;
185
+ i0.ɵɵconditional((tmp_0_0 = ctx.View) ? 0 : -1, tmp_0_0);
186
+ } }, dependencies: [MJButtonDirective, SelfViewComponent, SharePreviewComponent, SharedGenericModule, i1.LoadingComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n box-sizing: border-box;\n height: 100%;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.capture[_ngcontent-%COMP%] {\n box-sizing: border-box;\n height: 100%;\n}\n\n.capture--live[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.capture__self[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.capture__bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: var(--mj-space-2, 8px);\n}\n\n.capture--card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n padding: var(--mj-space-3, 12px);\n text-align: center;\n overflow-y: auto;\n}\n\n\n.capture__ask[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n margin: auto 0;\n}\n\n.capture__loading[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n}\n\n.capture__icon[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n color: var(--mj-text-secondary);\n}\n\n.capture__title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.capture__hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.capture__reason[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.9375rem;\n color: var(--mj-text-primary);\n}\n\n.capture__problem[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-status-error-text);\n}\n\n.capture__actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: var(--mj-space-2, 8px);\n}"], changeDetection: 0 });
187
+ }
188
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeCaptureSurfaceComponent, [{
189
+ type: Component,
190
+ args: [{ standalone: true, selector: 'mj-realtime-capture-surface', imports: [MJButtonDirective, SelfViewComponent, SharePreviewComponent, SharedGenericModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (View; as view) {\n @switch (view.Status) {\n @case ('on') {\n @if (view.Kind === 'camera') {\n <div class=\"capture capture--live\">\n <mj-self-view\n class=\"capture__self\"\n [Participant]=\"view.Participant\"\n [AgentCanSee]=\"view.AgentCanSee\"\n [ShowHide]=\"false\"\n [ShowMeter]=\"false\"\n [ShowConnectionQuality]=\"false\"\n [ShowActiveSpeakerRing]=\"false\">\n </mj-self-view>\n <div class=\"capture__bar\">\n <button type=\"button\" mjButton Variant=\"danger\" Size=\"sm\" (click)=\"StopRequested.emit()\">Turn off camera</button>\n </div>\n </div>\n } @else {\n <mj-share-preview\n class=\"capture capture--live\"\n [Source]=\"view.Source\"\n [Surface]=\"view.Surface\"\n [PanelLabel]=\"view.PanelLabel\"\n (StopRequested)=\"StopRequested.emit()\"\n (ChangeRequested)=\"ChangeRequested.emit()\">\n </mj-share-preview>\n }\n }\n @case ('starting') {\n <div class=\"capture capture--card\" role=\"status\">\n <mj-loading class=\"capture__loading\" [Text]=\"Wording.Starting\" Size=\"small\"></mj-loading>\n </div>\n }\n @default {\n <!-- The ask centres itself while it fits and scrolls when the box is shorter than it. -->\n <div class=\"capture capture--card\">\n <div class=\"capture__ask\">\n <i class=\"capture__icon\" [class]=\"Wording.Icon\" aria-hidden=\"true\"></i>\n <h3 class=\"capture__title\">{{ Heading }}</h3>\n @if (view.Reason) {\n <p class=\"capture__reason\">{{ view.Reason }}</p>\n }\n @if (view.Problem) {\n <p class=\"capture__problem\" role=\"alert\">{{ view.Problem }}</p>\n }\n <div class=\"capture__actions\">\n <button type=\"button\" mjButton Variant=\"primary\" (click)=\"StartRequested.emit()\">{{ Wording.Start }}</button>\n @if (view.Reason !== null) {\n <button type=\"button\" mjButton Variant=\"secondary\" (click)=\"DeclineRequested.emit()\">Not now</button>\n }\n </div>\n <p class=\"capture__hint\">{{ Wording.Hint }}</p>\n </div>\n </div>\n }\n }\n}\n", styles: [":host {\n display: block;\n box-sizing: border-box;\n height: 100%;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.capture {\n box-sizing: border-box;\n height: 100%;\n}\n\n.capture--live {\n display: flex;\n flex-direction: column;\n}\n\n.capture__self {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.capture__bar {\n display: flex;\n justify-content: center;\n padding: var(--mj-space-2, 8px);\n}\n\n.capture--card {\n display: flex;\n flex-direction: column;\n padding: var(--mj-space-3, 12px);\n text-align: center;\n overflow-y: auto;\n}\n\n/* Auto margins centre the ask while it fits; unlike justify-content, they never push it past the top when it does not. */\n.capture__ask {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n margin: auto 0;\n}\n\n.capture__loading {\n flex: 1 1 auto;\n}\n\n.capture__icon {\n font-size: 1.5rem;\n color: var(--mj-text-secondary);\n}\n\n.capture__title {\n margin: 0;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.capture__hint {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.capture__reason {\n margin: 0;\n font-size: 0.9375rem;\n color: var(--mj-text-primary);\n}\n\n.capture__problem {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-status-error-text);\n}\n\n.capture__actions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: var(--mj-space-2, 8px);\n}\n"] }]
191
+ }], null, { AgentName: [{
192
+ type: Input
193
+ }], Model: [{
194
+ type: Input
195
+ }], StartRequested: [{
196
+ type: Output
197
+ }], DeclineRequested: [{
198
+ type: Output
199
+ }], StopRequested: [{
200
+ type: Output
201
+ }], ChangeRequested: [{
202
+ type: Output
203
+ }] }); })();
204
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeCaptureSurfaceComponent, { className: "RealtimeCaptureSurfaceComponent", filePath: "src/lib/components/realtime/capture/realtime-capture-surface.component.ts", lineNumber: 53 }); })();
205
+ //# sourceMappingURL=realtime-capture-surface.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-capture-surface.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-surface.component.ts","../../../../../src/lib/components/realtime/capture/realtime-capture-surface.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, Output, inject } from '@angular/core';\nimport type { Subscription } from 'rxjs';\nimport type { RealtimeCaptureKind } from '@memberjunction/realtime-runtime';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { SelfViewComponent, SharePreviewComponent } from '@memberjunction/ng-realtime-media';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\nimport type { RealtimeCaptureModel, RealtimeCaptureView } from './realtime-capture-model';\n\n/** What the surface says for each capture. */\ninterface CaptureWording {\n Icon: string;\n Asks: string;\n Off: string;\n Start: string;\n Starting: string;\n Hint: string;\n}\n\nconst WORDING: Record<RealtimeCaptureKind, CaptureWording> = {\n camera: {\n Icon: 'fa-solid fa-video',\n Asks: 'asks to see your camera',\n Off: 'Your camera is off',\n Start: 'Turn on camera',\n Starting: 'Waiting for your camera…',\n Hint: 'Only you can turn your camera on or off.',\n },\n screen: {\n Icon: 'fa-solid fa-display',\n Asks: 'asks to see your screen',\n Off: 'Nothing is shared',\n Start: 'Share your screen',\n Starting: \"Choose what to share in your browser's window.\",\n Hint: 'Only you choose what to share, and you can stop at any time.',\n },\n};\n\n/**\n * `mj-realtime-capture-surface`: the Camera or Screen Share channel's surface. While the capture is off it is the ask:\n * what the agent wants to see and why, with Turn on camera (or Share your screen) and, while the agent's request stands,\n * Not now. While on, it is the user's own view of it: their camera mirrored (`mj-self-view`), or what they share\n * (`mj-share-preview`, with Stop sharing and Change). It owns no rules: the {@link RealtimeCaptureModel} decides what it\n * shows, and the channel runs the user's buttons.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-capture-surface',\n imports: [MJButtonDirective, SelfViewComponent, SharePreviewComponent, SharedGenericModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './realtime-capture-surface.component.html',\n styleUrls: ['./realtime-capture-surface.component.css'],\n})\nexport class RealtimeCaptureSurfaceComponent implements OnDestroy {\n private readonly cdr = inject(ChangeDetectorRef);\n private model: RealtimeCaptureModel | null = null;\n private viewSub: Subscription | null = null;\n\n /** What the surface shows now, or `null` until a model is bound. */\n public View: RealtimeCaptureView | null = null;\n\n /** The agent's name, for \"Sage asks to see your camera\". */\n @Input() AgentName = 'The assistant';\n\n /** The channel's state. */\n @Input()\n public set Model(value: RealtimeCaptureModel | null) {\n if (value === this.model) {\n return;\n }\n this.viewSub?.unsubscribe();\n this.model = value;\n this.viewSub =\n value?.View$.subscribe((view) => {\n this.View = view;\n this.cdr.markForCheck();\n }) ?? null;\n }\n public get Model(): RealtimeCaptureModel | null {\n return this.model;\n }\n\n /** The user asked to turn the camera on, or to share a screen. */\n @Output() StartRequested = new EventEmitter<void>();\n /** The user said \"Not now\" to the agent's request. */\n @Output() DeclineRequested = new EventEmitter<void>();\n /** The user turned the camera off, or stopped sharing. */\n @Output() StopRequested = new EventEmitter<void>();\n /** The user asked to share something else. */\n @Output() ChangeRequested = new EventEmitter<void>();\n\n /** The words for this capture. */\n public get Wording(): CaptureWording {\n return WORDING[this.View?.Kind ?? 'camera'];\n }\n\n /** The card's heading: the agent's request while it stands, else that the capture is off. */\n public get Heading(): string {\n return this.View?.Reason !== null && this.View?.Reason !== undefined ? `${this.AgentName} ${this.Wording.Asks}` : this.Wording.Off;\n }\n\n public ngOnDestroy(): void {\n this.viewSub?.unsubscribe();\n this.viewSub = null;\n }\n}\n","@if (View; as view) {\n @switch (view.Status) {\n @case ('on') {\n @if (view.Kind === 'camera') {\n <div class=\"capture capture--live\">\n <mj-self-view\n class=\"capture__self\"\n [Participant]=\"view.Participant\"\n [AgentCanSee]=\"view.AgentCanSee\"\n [ShowHide]=\"false\"\n [ShowMeter]=\"false\"\n [ShowConnectionQuality]=\"false\"\n [ShowActiveSpeakerRing]=\"false\">\n </mj-self-view>\n <div class=\"capture__bar\">\n <button type=\"button\" mjButton Variant=\"danger\" Size=\"sm\" (click)=\"StopRequested.emit()\">Turn off camera</button>\n </div>\n </div>\n } @else {\n <mj-share-preview\n class=\"capture capture--live\"\n [Source]=\"view.Source\"\n [Surface]=\"view.Surface\"\n [PanelLabel]=\"view.PanelLabel\"\n (StopRequested)=\"StopRequested.emit()\"\n (ChangeRequested)=\"ChangeRequested.emit()\">\n </mj-share-preview>\n }\n }\n @case ('starting') {\n <div class=\"capture capture--card\" role=\"status\">\n <mj-loading class=\"capture__loading\" [Text]=\"Wording.Starting\" Size=\"small\"></mj-loading>\n </div>\n }\n @default {\n <!-- The ask centres itself while it fits and scrolls when the box is shorter than it. -->\n <div class=\"capture capture--card\">\n <div class=\"capture__ask\">\n <i class=\"capture__icon\" [class]=\"Wording.Icon\" aria-hidden=\"true\"></i>\n <h3 class=\"capture__title\">{{ Heading }}</h3>\n @if (view.Reason) {\n <p class=\"capture__reason\">{{ view.Reason }}</p>\n }\n @if (view.Problem) {\n <p class=\"capture__problem\" role=\"alert\">{{ view.Problem }}</p>\n }\n <div class=\"capture__actions\">\n <button type=\"button\" mjButton Variant=\"primary\" (click)=\"StartRequested.emit()\">{{ Wording.Start }}</button>\n @if (view.Reason !== null) {\n <button type=\"button\" mjButton Variant=\"secondary\" (click)=\"DeclineRequested.emit()\">Not now</button>\n }\n </div>\n <p class=\"capture__hint\">{{ Wording.Hint }}</p>\n </div>\n </div>\n }\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { RealtimeToolDefinition } from '@memberjunction/ai';
2
+ import { type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';
2
3
  import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
3
4
  /** The stable name of the single proxy tool this channel registers with the realtime provider. */
4
5
  export declare const CONTEXT_TOOL_NAME = "ContextTool";
@@ -19,11 +20,25 @@ export declare class ClientContextChannel extends BaseRealtimeChannelClient<obje
19
20
  /** Declares the single stable proxy tool. */
20
21
  GetToolDefinitions(): RealtimeToolDefinition[];
21
22
  /**
22
- * Routes a `ContextTool({ action, params })` call to the host's registered surface client tool.
23
+ * The channel's self-description. It has NO verbs of its own: it is the door, not a room — `ContextTool`
24
+ * runs app client tools, or addresses another channel through `target`. Declaring that explicitly keeps
25
+ * it from being addressed as if it were a channel with things to do.
26
+ */
27
+ GetDescriptor(): RealtimeChannelDescriptor;
28
+ /**
29
+ * Routes a `ContextTool({ action, params, target? })` call. With a `target` the call is handed to the
30
+ * runtime, which validates it against the addressed channel's verb schema (a malformed call comes back
31
+ * as a structured, model-recoverable error) and opens an `on-demand` channel when asked; without one it
32
+ * runs the host's registered surface client tool, exactly as before.
33
+ *
23
34
  * Tolerant: malformed args, a missing host executor, or an unknown/throwing tool all serialize to
24
35
  * a structured `{ success: false, output }` the model narrates (never throws).
25
36
  */
26
37
  ApplyAgentTool(toolName: string, argsJson: string): Promise<string>;
38
+ /** Runs a channel-addressed call through the runtime and serializes its structured outcome. */
39
+ private applyChannelAction;
40
+ /** The model-facing shape of a dispatch outcome: success carries the result; a refusal carries what to fix. */
41
+ private serializeDispatchOutcome;
27
42
  /** Headless — no surface to bind. */
28
43
  BindSurface(): void;
29
44
  /**
@@ -32,8 +47,10 @@ export declare class ClientContextChannel extends BaseRealtimeChannelClient<obje
32
47
  * (custom apps) simply get no streaming, and the session-start prompt injection still applies.
33
48
  */
34
49
  protected OnInitialize(): void;
35
- /** Tolerantly parses the `{ action, params }` arguments. */
50
+ /** Tolerantly parses the `{ action, params, target? }` arguments. */
36
51
  private parseArgs;
52
+ /** Reads a `target` — `{ channel, instance? }` — or `null` when absent or unusable (the call is then an app action). */
53
+ private parseTarget;
37
54
  /** Unsubscribes the app-context stream and tears down. */
38
55
  Dispose(): void;
39
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client-context-channel.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/client-context-channel.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAI5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AA0B/C;;;GAGG;AACH,qBACa,oBAAqB,SAAQ,yBAAyB,CAAC,MAAM,CAAC;IACzE,4FAA4F;IAC5F,OAAO,CAAC,aAAa,CAA6B;IAElD,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,0FAA0F;IAC1F,IAAW,cAAc,IAAI,MAAM,CAElC;IAED,kFAAkF;IAClF,IAAW,QAAQ,IAAI,MAAM,CAE5B;IACD,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,6CAA6C;IACtC,kBAAkB,IAAI,sBAAsB,EAAE;IAIrD;;;;OAIG;IACU,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBhF,qCAAqC;IAC9B,WAAW,IAAI,IAAI;IAI1B;;;;OAIG;cACgB,YAAY,IAAI,IAAI;IAkBvC,4DAA4D;IAC5D,OAAO,CAAC,SAAS;IAcjB,0DAA0D;IAC1C,OAAO,IAAI,IAAI;CAKhC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
1
+ {"version":3,"file":"client-context-channel.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/client-context-channel.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAc,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAA2D,KAAK,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGvI,OAAO,EAAE,yBAAyB,EAAoC,MAAM,kCAAkC,CAAC;AAE/G,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAsC/C;;;GAGG;AACH,qBACa,oBAAqB,SAAQ,yBAAyB,CAAC,MAAM,CAAC;IACzE,4FAA4F;IAC5F,OAAO,CAAC,aAAa,CAA6B;IAElD,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,0FAA0F;IAC1F,IAAW,cAAc,IAAI,MAAM,CAElC;IAED,kFAAkF;IAClF,IAAW,QAAQ,IAAI,MAAM,CAE5B;IACD,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,6CAA6C;IACtC,kBAAkB,IAAI,sBAAsB,EAAE;IAIrD;;;;OAIG;IACa,aAAa,IAAI,yBAAyB;IAgB1D;;;;;;;;OAQG;IACU,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBhF,+FAA+F;YACjF,kBAAkB;IAchC,+GAA+G;IAC/G,OAAO,CAAC,wBAAwB;IAahC,qCAAqC;IAC9B,WAAW,IAAI,IAAI;IAI1B;;;;OAIG;cACgB,YAAY,IAAI,IAAI;IAkBvC,qEAAqE;IACrE,OAAO,CAAC,SAAS;IAkBjB,wHAAwH;IACxH,OAAO,CAAC,WAAW;IAanB,0DAA0D;IAC1C,OAAO,IAAI,IAAI;CAKhC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
@@ -34,7 +34,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
34
34
  * @module @memberjunction/ng-conversations
35
35
  */
36
36
  import { RegisterClass } from '@memberjunction/global';
37
- import { FormatAppContextNote } from '@memberjunction/ai-core-plus';
37
+ import { FormatAppContextNote, REALTIME_CHANNEL_CONTRACT_VERSION } from '@memberjunction/ai-core-plus';
38
38
  import { distinctUntilChanged } from 'rxjs/operators';
39
39
  import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
40
40
  /** The stable name of the single proxy tool this channel registers with the realtime provider. */
@@ -42,10 +42,13 @@ export const CONTEXT_TOOL_NAME = 'ContextTool';
42
42
  /** The single stable proxy tool — declared once; the live catalog of valid `action`s rides context. */
43
43
  const CONTEXT_TOOL_DEFINITION = {
44
44
  Name: CONTEXT_TOOL_NAME,
45
- Description: "Perform an action in the application the user is currently in. The set of valid actions (the " +
46
- "client tools and the things you can do on the current surface) is provided to you continuously " +
47
- "as context — only call actions listed as currently available. Pass the action name and its " +
48
- "parameters.",
45
+ Description: "Perform an action in the application the user is currently in, or on one of the interactive " +
46
+ "channels listed in your channel notes. The set of valid actions (the client tools and the things " +
47
+ "you can do on the current surface) is provided to you continuously as context — only call actions " +
48
+ "listed as currently available. Pass the action name and its parameters. To act on an interactive " +
49
+ "channel instead of the app, also pass `target` naming the channel (and, for a channel that has " +
50
+ "several, the instance); to open a channel that is available but not open yet, use action \"open\" " +
51
+ "with that target.",
49
52
  ParametersSchema: {
50
53
  type: 'object',
51
54
  properties: {
@@ -56,6 +59,15 @@ const CONTEXT_TOOL_DEFINITION = {
56
59
  params: {
57
60
  type: 'object',
58
61
  description: "The action's parameters, matching its advertised input schema."
62
+ },
63
+ target: {
64
+ type: 'object',
65
+ description: 'Set this to act on an interactive channel rather than the app. Omit it for app actions.',
66
+ properties: {
67
+ channel: { type: 'string', description: 'The channel to address (from your channel notes).' },
68
+ instance: { type: 'string', description: 'Which instance, for a channel that has several. Usually omitted.' }
69
+ },
70
+ required: ['channel']
59
71
  }
60
72
  },
61
73
  required: ['action']
@@ -88,7 +100,30 @@ let ClientContextChannel = class ClientContextChannel extends BaseRealtimeChanne
88
100
  return [CONTEXT_TOOL_DEFINITION];
89
101
  }
90
102
  /**
91
- * Routes a `ContextTool({ action, params })` call to the host's registered surface client tool.
103
+ * The channel's self-description. It has NO verbs of its own: it is the door, not a room — `ContextTool`
104
+ * runs app client tools, or addresses another channel through `target`. Declaring that explicitly keeps
105
+ * it from being addressed as if it were a channel with things to do.
106
+ */
107
+ GetDescriptor() {
108
+ return {
109
+ Key: this.ChannelName,
110
+ Version: REALTIME_CHANNEL_CONTRACT_VERSION,
111
+ DisplayName: this.TabTitle,
112
+ Instructions: 'Keeps you aware of where the user is in the app and lets you act there through ContextTool. ' +
113
+ 'It is not itself something to operate.',
114
+ Nouns: [],
115
+ Verbs: [],
116
+ DisplayPolicy: 'headless',
117
+ DefaultAvailability: 'all-sessions',
118
+ MaxExposure: 'state'
119
+ };
120
+ }
121
+ /**
122
+ * Routes a `ContextTool({ action, params, target? })` call. With a `target` the call is handed to the
123
+ * runtime, which validates it against the addressed channel's verb schema (a malformed call comes back
124
+ * as a structured, model-recoverable error) and opens an `on-demand` channel when asked; without one it
125
+ * runs the host's registered surface client tool, exactly as before.
126
+ *
92
127
  * Tolerant: malformed args, a missing host executor, or an unknown/throwing tool all serialize to
93
128
  * a structured `{ success: false, output }` the model narrates (never throws).
94
129
  */
@@ -100,6 +135,9 @@ let ClientContextChannel = class ClientContextChannel extends BaseRealtimeChanne
100
135
  if (!parsed.action) {
101
136
  return JSON.stringify({ success: false, output: 'ContextTool requires an "action" naming the tool to run.' });
102
137
  }
138
+ if (parsed.target) {
139
+ return this.applyChannelAction(parsed.action, parsed.params, parsed.target);
140
+ }
103
141
  const executor = this.Context?.ExecuteClientTool;
104
142
  if (!executor) {
105
143
  return JSON.stringify({
@@ -112,6 +150,29 @@ let ClientContextChannel = class ClientContextChannel extends BaseRealtimeChanne
112
150
  ? JSON.stringify({ success: true, output: result.Result ?? 'Done.' })
113
151
  : JSON.stringify({ success: false, output: result.ErrorMessage ?? 'The action could not be performed.' });
114
152
  }
153
+ /** Runs a channel-addressed call through the runtime and serializes its structured outcome. */
154
+ async applyChannelAction(action, params, target) {
155
+ const dispatch = this.Context?.DispatchContextAction;
156
+ if (!dispatch) {
157
+ return JSON.stringify({ success: false, output: 'Channel actions are not available in this session.' });
158
+ }
159
+ // The params came off the wire as JSON, so they are JSON by construction.
160
+ const outcome = await dispatch({ Target: { Channel: target.channel, Instance: target.instance }, Action: action, Params: params });
161
+ return JSON.stringify(this.serializeDispatchOutcome(outcome));
162
+ }
163
+ /** The model-facing shape of a dispatch outcome: success carries the result; a refusal carries what to fix. */
164
+ serializeDispatchOutcome(outcome) {
165
+ if (outcome.Success) {
166
+ return { success: true, output: outcome.Result ?? 'Done.' };
167
+ }
168
+ return {
169
+ success: false,
170
+ output: outcome.ErrorMessage ?? 'The action could not be performed.',
171
+ errorCode: outcome.ErrorCode,
172
+ ...(outcome.Details ? { details: outcome.Details } : {}),
173
+ ...(outcome.Available ? { available: outcome.Available } : {})
174
+ };
175
+ }
115
176
  /** Headless — no surface to bind. */
116
177
  BindSurface() {
117
178
  /* no-op: this channel renders no surface */
@@ -138,7 +199,7 @@ let ClientContextChannel = class ClientContextChannel extends BaseRealtimeChanne
138
199
  }
139
200
  });
140
201
  }
141
- /** Tolerantly parses the `{ action, params }` arguments. */
202
+ /** Tolerantly parses the `{ action, params, target? }` arguments. */
142
203
  parseArgs(argsJson) {
143
204
  try {
144
205
  const parsed = JSON.parse(argsJson);
@@ -146,11 +207,24 @@ let ClientContextChannel = class ClientContextChannel extends BaseRealtimeChanne
146
207
  const params = parsed.params && typeof parsed.params === 'object' && !Array.isArray(parsed.params)
147
208
  ? parsed.params
148
209
  : {};
149
- return { action, params };
210
+ return { action, params, target: this.parseTarget(parsed.target) };
150
211
  }
151
212
  catch {
152
- return { action: null, params: {} };
213
+ return { action: null, params: {}, target: null };
214
+ }
215
+ }
216
+ /** Reads a `target` — `{ channel, instance? }` — or `null` when absent or unusable (the call is then an app action). */
217
+ parseTarget(raw) {
218
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
219
+ return null;
220
+ }
221
+ const target = raw;
222
+ const channel = typeof target.channel === 'string' ? target.channel.trim() : '';
223
+ if (channel.length === 0) {
224
+ return null;
153
225
  }
226
+ const instance = typeof target.instance === 'string' && target.instance.trim().length > 0 ? target.instance.trim() : undefined;
227
+ return instance ? { channel, instance } : { channel };
154
228
  }
155
229
  /** Unsubscribes the app-context stream and tears down. */
156
230
  Dispose() {
@@ -1 +1 @@
1
- {"version":3,"file":"client-context-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/client-context-channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview The headless **Client Context** channel — the browser half of the live wire that\n * keeps the realtime co-agent continuously aware of the user's app context and lets it act in the\n * app through a single stable proxy tool.\n *\n * Paired with `ClientContextChannelServer` (`@memberjunction/ai-agents`) via the seeded\n * `MJ: AI Agent Channels` row (`Name: 'ClientContextChannel'`, `IsHeadless: 1`,\n * `ClientPluginClass: 'ClientContextChannel'`).\n *\n * Two responsibilities, both client-side (no server round-trip in the client-direct topology):\n *\n * 1. **Perception (streaming).** It subscribes to the host's live app-context stream\n * ({@link RealtimeChannelContext.AppContext$}, fed by Explorer from `NavigationService`) and, on\n * every change, pushes a compact `SendContextNote` so the model always knows where the user is,\n * what they see, and which tools/agents are available — the *continuous* half of client-context\n * delivery (the session-start half is injected into the companion prompt server-side at mint).\n *\n * 2. **Action (the `ContextTool` proxy).** It declares ONE stable tool, `ContextTool`, so the\n * provider tool surface never changes mid-session (which connect-bound providers reject). The\n * model invokes any currently-available surface client tool via `ContextTool({ action, params })`;\n * the channel routes that to the host's {@link RealtimeChannelContext.ExecuteClientTool} (which runs\n * the surface handler the host registered from `SetAgentClientTools`) and returns a structured\n * result the model narrates.\n *\n * **Headless:** no surface component — it never mounts a tab (`GetSurfaceComponent` stays `null`;\n * `BindSurface` is a no-op). It is a wire, not a panel.\n *\n * @module @memberjunction/ng-conversations\n */\nimport { RegisterClass } from '@memberjunction/global';\nimport { RealtimeToolDefinition } from '@memberjunction/ai';\nimport { FormatAppContextNote } from '@memberjunction/ai-core-plus';\nimport { Subscription } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\nimport { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';\n\n/** The stable name of the single proxy tool this channel registers with the realtime provider. */\nexport const CONTEXT_TOOL_NAME = 'ContextTool';\n\n/** The single stable proxy tool — declared once; the live catalog of valid `action`s rides context. */\nconst CONTEXT_TOOL_DEFINITION: RealtimeToolDefinition = {\n Name: CONTEXT_TOOL_NAME,\n Description:\n \"Perform an action in the application the user is currently in. The set of valid actions (the \" +\n \"client tools and the things you can do on the current surface) is provided to you continuously \" +\n \"as context — only call actions listed as currently available. Pass the action name and its \" +\n \"parameters.\",\n ParametersSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n description: 'The name of a currently-available action/tool to run (from the context you were given).'\n },\n params: {\n type: 'object',\n description: \"The action's parameters, matching its advertised input schema.\"\n }\n },\n required: ['action']\n }\n};\n\n/**\n * The headless Client Context channel client. One instance per realtime session (created by the\n * session service from the `MJ: AI Agent Channels` registry — never construct directly).\n */\n@RegisterClass(BaseRealtimeChannelClient, 'ClientContextChannel')\nexport class ClientContextChannel extends BaseRealtimeChannelClient<object> {\n /** Subscription to the host app-context stream (perception); cleared on {@link Dispose}. */\n private appContextSub: Subscription | null = null;\n\n /** Matches the seeded `MJ: AI Agent Channels` row's `Name`. */\n public get ChannelName(): string {\n return 'ClientContextChannel';\n }\n\n /** Routing prefix — the single `ContextTool` matches `ContextTool`.startsWith(prefix). */\n public get ToolNamePrefix(): string {\n return CONTEXT_TOOL_NAME;\n }\n\n /** Headless — never rendered, but the abstract contract requires a label/icon. */\n public get TabTitle(): string {\n return 'App Context';\n }\n public get TabIcon(): string {\n return 'fa-solid fa-satellite-dish';\n }\n\n /** Declares the single stable proxy tool. */\n public GetToolDefinitions(): RealtimeToolDefinition[] {\n return [CONTEXT_TOOL_DEFINITION];\n }\n\n /**\n * Routes a `ContextTool({ action, params })` call to the host's registered surface client tool.\n * Tolerant: malformed args, a missing host executor, or an unknown/throwing tool all serialize to\n * a structured `{ success: false, output }` the model narrates (never throws).\n */\n public async ApplyAgentTool(toolName: string, argsJson: string): Promise<string> {\n if (toolName !== CONTEXT_TOOL_NAME) {\n return JSON.stringify({ success: false, output: `Unknown context tool \"${toolName}\".` });\n }\n const parsed = this.parseArgs(argsJson);\n if (!parsed.action) {\n return JSON.stringify({ success: false, output: 'ContextTool requires an \"action\" naming the tool to run.' });\n }\n const executor = this.Context?.ExecuteClientTool;\n if (!executor) {\n return JSON.stringify({\n success: false,\n output: 'No app surface is available to perform that action right now.'\n });\n }\n const result = await executor(parsed.action, parsed.params);\n return result.Success\n ? JSON.stringify({ success: true, output: result.Result ?? 'Done.' })\n : JSON.stringify({ success: false, output: result.ErrorMessage ?? 'The action could not be performed.' });\n }\n\n /** Headless — no surface to bind. */\n public BindSurface(): void {\n /* no-op: this channel renders no surface */\n }\n\n /**\n * Subscribes to the host's live app-context stream and streams each change to the model as a\n * compact context note (the perception half). Null-safe — hosts that supply no `AppContext$`\n * (custom apps) simply get no streaming, and the session-start prompt injection still applies.\n */\n protected override OnInitialize(): void {\n const stream = this.Context?.AppContext$;\n if (!stream) {\n return;\n }\n this.appContextSub = stream\n .pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)))\n .subscribe((snapshot) => {\n if (!snapshot) {\n return;\n }\n const note = FormatAppContextNote(snapshot);\n if (note) {\n this.Context?.SendContextNote(note);\n }\n });\n }\n\n /** Tolerantly parses the `{ action, params }` arguments. */\n private parseArgs(argsJson: string): { action: string | null; params: Record<string, unknown> } {\n try {\n const parsed = JSON.parse(argsJson) as { action?: unknown; params?: unknown };\n const action = typeof parsed.action === 'string' && parsed.action.trim().length > 0 ? parsed.action.trim() : null;\n const params =\n parsed.params && typeof parsed.params === 'object' && !Array.isArray(parsed.params)\n ? (parsed.params as Record<string, unknown>)\n : {};\n return { action, params };\n } catch {\n return { action: null, params: {} };\n }\n }\n\n /** Unsubscribes the app-context stream and tears down. */\n public override Dispose(): void {\n this.appContextSub?.unsubscribe();\n this.appContextSub = null;\n super.Dispose();\n }\n}\n\n/**\n * Tree-shaking prevention for {@link ClientContextChannel}'s `@RegisterClass` registration. Called\n * from a static code path in `conversations.module.ts` so the registration always executes —\n * mirroring every other realtime channel client.\n */\nexport function LoadClientContextChannel(): void {\n // no-op — the import + call create a static reference bundlers cannot eliminate\n}\n"]}
1
+ {"version":3,"file":"client-context-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/client-context-channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview The headless **Client Context** channel — the browser half of the live wire that\n * keeps the realtime co-agent continuously aware of the user's app context and lets it act in the\n * app through a single stable proxy tool.\n *\n * Paired with `ClientContextChannelServer` (`@memberjunction/ai-agents`) via the seeded\n * `MJ: AI Agent Channels` row (`Name: 'ClientContextChannel'`, `IsHeadless: 1`,\n * `ClientPluginClass: 'ClientContextChannel'`).\n *\n * Two responsibilities, both client-side (no server round-trip in the client-direct topology):\n *\n * 1. **Perception (streaming).** It subscribes to the host's live app-context stream\n * ({@link RealtimeChannelContext.AppContext$}, fed by Explorer from `NavigationService`) and, on\n * every change, pushes a compact `SendContextNote` so the model always knows where the user is,\n * what they see, and which tools/agents are available — the *continuous* half of client-context\n * delivery (the session-start half is injected into the companion prompt server-side at mint).\n *\n * 2. **Action (the `ContextTool` proxy).** It declares ONE stable tool, `ContextTool`, so the\n * provider tool surface never changes mid-session (which connect-bound providers reject). The\n * model invokes any currently-available surface client tool via `ContextTool({ action, params })`;\n * the channel routes that to the host's {@link RealtimeChannelContext.ExecuteClientTool} (which runs\n * the surface handler the host registered from `SetAgentClientTools`) and returns a structured\n * result the model narrates.\n *\n * **Headless:** no surface component — it never mounts a tab (`GetSurfaceComponent` stays `null`;\n * `BindSurface` is a no-op). It is a wire, not a panel.\n *\n * @module @memberjunction/ng-conversations\n */\nimport { RegisterClass } from '@memberjunction/global';\nimport { JSONObject, RealtimeToolDefinition } from '@memberjunction/ai';\nimport { FormatAppContextNote, REALTIME_CHANNEL_CONTRACT_VERSION, type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';\nimport { Subscription } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\nimport { BaseRealtimeChannelClient, type RealtimeContextActionResult } from '@memberjunction/realtime-runtime';\n\n/** The stable name of the single proxy tool this channel registers with the realtime provider. */\nexport const CONTEXT_TOOL_NAME = 'ContextTool';\n\n/** The single stable proxy tool — declared once; the live catalog of valid `action`s rides context. */\nconst CONTEXT_TOOL_DEFINITION: RealtimeToolDefinition = {\n Name: CONTEXT_TOOL_NAME,\n Description:\n \"Perform an action in the application the user is currently in, or on one of the interactive \" +\n \"channels listed in your channel notes. The set of valid actions (the client tools and the things \" +\n \"you can do on the current surface) is provided to you continuously as context — only call actions \" +\n \"listed as currently available. Pass the action name and its parameters. To act on an interactive \" +\n \"channel instead of the app, also pass `target` naming the channel (and, for a channel that has \" +\n \"several, the instance); to open a channel that is available but not open yet, use action \\\"open\\\" \" +\n \"with that target.\",\n ParametersSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n description: 'The name of a currently-available action/tool to run (from the context you were given).'\n },\n params: {\n type: 'object',\n description: \"The action's parameters, matching its advertised input schema.\"\n },\n target: {\n type: 'object',\n description: 'Set this to act on an interactive channel rather than the app. Omit it for app actions.',\n properties: {\n channel: { type: 'string', description: 'The channel to address (from your channel notes).' },\n instance: { type: 'string', description: 'Which instance, for a channel that has several. Usually omitted.' }\n },\n required: ['channel']\n }\n },\n required: ['action']\n }\n};\n\n/**\n * The headless Client Context channel client. One instance per realtime session (created by the\n * session service from the `MJ: AI Agent Channels` registry — never construct directly).\n */\n@RegisterClass(BaseRealtimeChannelClient, 'ClientContextChannel')\nexport class ClientContextChannel extends BaseRealtimeChannelClient<object> {\n /** Subscription to the host app-context stream (perception); cleared on {@link Dispose}. */\n private appContextSub: Subscription | null = null;\n\n /** Matches the seeded `MJ: AI Agent Channels` row's `Name`. */\n public get ChannelName(): string {\n return 'ClientContextChannel';\n }\n\n /** Routing prefix — the single `ContextTool` matches `ContextTool`.startsWith(prefix). */\n public get ToolNamePrefix(): string {\n return CONTEXT_TOOL_NAME;\n }\n\n /** Headless — never rendered, but the abstract contract requires a label/icon. */\n public get TabTitle(): string {\n return 'App Context';\n }\n public get TabIcon(): string {\n return 'fa-solid fa-satellite-dish';\n }\n\n /** Declares the single stable proxy tool. */\n public GetToolDefinitions(): RealtimeToolDefinition[] {\n return [CONTEXT_TOOL_DEFINITION];\n }\n\n /**\n * The channel's self-description. It has NO verbs of its own: it is the door, not a room — `ContextTool`\n * runs app client tools, or addresses another channel through `target`. Declaring that explicitly keeps\n * it from being addressed as if it were a channel with things to do.\n */\n public override GetDescriptor(): RealtimeChannelDescriptor {\n return {\n Key: this.ChannelName,\n Version: REALTIME_CHANNEL_CONTRACT_VERSION,\n DisplayName: this.TabTitle,\n Instructions:\n 'Keeps you aware of where the user is in the app and lets you act there through ContextTool. ' +\n 'It is not itself something to operate.',\n Nouns: [],\n Verbs: [],\n DisplayPolicy: 'headless',\n DefaultAvailability: 'all-sessions',\n MaxExposure: 'state'\n };\n }\n\n /**\n * Routes a `ContextTool({ action, params, target? })` call. With a `target` the call is handed to the\n * runtime, which validates it against the addressed channel's verb schema (a malformed call comes back\n * as a structured, model-recoverable error) and opens an `on-demand` channel when asked; without one it\n * runs the host's registered surface client tool, exactly as before.\n *\n * Tolerant: malformed args, a missing host executor, or an unknown/throwing tool all serialize to\n * a structured `{ success: false, output }` the model narrates (never throws).\n */\n public async ApplyAgentTool(toolName: string, argsJson: string): Promise<string> {\n if (toolName !== CONTEXT_TOOL_NAME) {\n return JSON.stringify({ success: false, output: `Unknown context tool \"${toolName}\".` });\n }\n const parsed = this.parseArgs(argsJson);\n if (!parsed.action) {\n return JSON.stringify({ success: false, output: 'ContextTool requires an \"action\" naming the tool to run.' });\n }\n if (parsed.target) {\n return this.applyChannelAction(parsed.action, parsed.params, parsed.target);\n }\n const executor = this.Context?.ExecuteClientTool;\n if (!executor) {\n return JSON.stringify({\n success: false,\n output: 'No app surface is available to perform that action right now.'\n });\n }\n const result = await executor(parsed.action, parsed.params);\n return result.Success\n ? JSON.stringify({ success: true, output: result.Result ?? 'Done.' })\n : JSON.stringify({ success: false, output: result.ErrorMessage ?? 'The action could not be performed.' });\n }\n\n /** Runs a channel-addressed call through the runtime and serializes its structured outcome. */\n private async applyChannelAction(\n action: string,\n params: Record<string, unknown>,\n target: { channel: string; instance?: string }\n ): Promise<string> {\n const dispatch = this.Context?.DispatchContextAction;\n if (!dispatch) {\n return JSON.stringify({ success: false, output: 'Channel actions are not available in this session.' });\n }\n // The params came off the wire as JSON, so they are JSON by construction.\n const outcome = await dispatch({ Target: { Channel: target.channel, Instance: target.instance }, Action: action, Params: params as JSONObject });\n return JSON.stringify(this.serializeDispatchOutcome(outcome));\n }\n\n /** The model-facing shape of a dispatch outcome: success carries the result; a refusal carries what to fix. */\n private serializeDispatchOutcome(outcome: RealtimeContextActionResult): Record<string, unknown> {\n if (outcome.Success) {\n return { success: true, output: outcome.Result ?? 'Done.' };\n }\n return {\n success: false,\n output: outcome.ErrorMessage ?? 'The action could not be performed.',\n errorCode: outcome.ErrorCode,\n ...(outcome.Details ? { details: outcome.Details } : {}),\n ...(outcome.Available ? { available: outcome.Available } : {})\n };\n }\n\n /** Headless — no surface to bind. */\n public BindSurface(): void {\n /* no-op: this channel renders no surface */\n }\n\n /**\n * Subscribes to the host's live app-context stream and streams each change to the model as a\n * compact context note (the perception half). Null-safe — hosts that supply no `AppContext$`\n * (custom apps) simply get no streaming, and the session-start prompt injection still applies.\n */\n protected override OnInitialize(): void {\n const stream = this.Context?.AppContext$;\n if (!stream) {\n return;\n }\n this.appContextSub = stream\n .pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)))\n .subscribe((snapshot) => {\n if (!snapshot) {\n return;\n }\n const note = FormatAppContextNote(snapshot);\n if (note) {\n this.Context?.SendContextNote(note);\n }\n });\n }\n\n /** Tolerantly parses the `{ action, params, target? }` arguments. */\n private parseArgs(argsJson: string): {\n action: string | null;\n params: Record<string, unknown>;\n target: { channel: string; instance?: string } | null;\n } {\n try {\n const parsed = JSON.parse(argsJson) as { action?: unknown; params?: unknown; target?: unknown };\n const action = typeof parsed.action === 'string' && parsed.action.trim().length > 0 ? parsed.action.trim() : null;\n const params =\n parsed.params && typeof parsed.params === 'object' && !Array.isArray(parsed.params)\n ? (parsed.params as Record<string, unknown>)\n : {};\n return { action, params, target: this.parseTarget(parsed.target) };\n } catch {\n return { action: null, params: {}, target: null };\n }\n }\n\n /** Reads a `target` — `{ channel, instance? }` — or `null` when absent or unusable (the call is then an app action). */\n private parseTarget(raw: unknown): { channel: string; instance?: string } | null {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return null;\n }\n const target = raw as { channel?: unknown; instance?: unknown };\n const channel = typeof target.channel === 'string' ? target.channel.trim() : '';\n if (channel.length === 0) {\n return null;\n }\n const instance = typeof target.instance === 'string' && target.instance.trim().length > 0 ? target.instance.trim() : undefined;\n return instance ? { channel, instance } : { channel };\n }\n\n /** Unsubscribes the app-context stream and tears down. */\n public override Dispose(): void {\n this.appContextSub?.unsubscribe();\n this.appContextSub = null;\n super.Dispose();\n }\n}\n\n/**\n * Tree-shaking prevention for {@link ClientContextChannel}'s `@RegisterClass` registration. Called\n * from a static code path in `conversations.module.ts` so the registration always executes —\n * mirroring every other realtime channel client.\n */\nexport function LoadClientContextChannel(): void {\n // no-op — the import + call create a static reference bundlers cannot eliminate\n}\n"]}