@memberjunction/ng-conversations 5.43.0 → 5.45.0

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 (405) hide show
  1. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +0 -1
  2. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
  3. package/dist/lib/components/active-tasks/active-tasks-panel.component.js +56 -52
  4. package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
  5. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +3 -1
  6. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
  7. package/dist/lib/components/artifact/artifact-share-modal.component.js +52 -52
  8. package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
  9. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  10. package/dist/lib/components/collection/collection-form-modal.component.js +10 -14
  11. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  12. package/dist/lib/components/collection/collection-share-modal.component.d.ts +3 -1
  13. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  14. package/dist/lib/components/collection/collection-share-modal.component.js +56 -56
  15. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  16. package/dist/lib/components/collection/collection-tree.component.d.ts +3 -1
  17. package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
  18. package/dist/lib/components/collection/collection-tree.component.js +10 -7
  19. package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
  20. package/dist/lib/components/collection/collection-view.component.d.ts +3 -1
  21. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  22. package/dist/lib/components/collection/collection-view.component.js +29 -41
  23. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  24. package/dist/lib/components/collection/collections-full-view.component.d.ts +4 -0
  25. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  26. package/dist/lib/components/collection/collections-full-view.component.js +134 -166
  27. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  28. package/dist/lib/components/composer/ai-composer.component.d.ts +103 -0
  29. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -0
  30. package/dist/lib/components/composer/ai-composer.component.js +263 -0
  31. package/dist/lib/components/composer/ai-composer.component.js.map +1 -0
  32. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +76 -12
  33. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  34. package/dist/lib/components/conversation/conversation-chat-area.component.js +522 -158
  35. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  36. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +1 -1
  37. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
  38. package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
  39. package/dist/lib/components/conversation/pinned-messages-panel.component.js +6 -9
  40. package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
  41. package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
  42. package/dist/lib/components/library/library-full-view.component.js +20 -24
  43. package/dist/lib/components/library/library-full-view.component.js.map +1 -1
  44. package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
  45. package/dist/lib/components/members/members-modal.component.js +10 -11
  46. package/dist/lib/components/members/members-modal.component.js.map +1 -1
  47. package/dist/lib/components/message/message-input.component.d.ts +87 -23
  48. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  49. package/dist/lib/components/message/message-input.component.js +245 -158
  50. package/dist/lib/components/message/message-input.component.js.map +1 -1
  51. package/dist/lib/components/message/message-item.component.d.ts +11 -3
  52. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  53. package/dist/lib/components/message/message-item.component.js +73 -21
  54. package/dist/lib/components/message/message-item.component.js.map +1 -1
  55. package/dist/lib/components/message/message-list.component.js +6 -9
  56. package/dist/lib/components/message/message-list.component.js.map +1 -1
  57. package/dist/lib/components/overlay/chat-overlay.component.d.ts +4 -1
  58. package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
  59. package/dist/lib/components/overlay/chat-overlay.component.js +9 -4
  60. package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
  61. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +45 -0
  62. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -1
  63. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +10 -0
  64. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -1
  65. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +46 -0
  66. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -0
  67. package/dist/lib/components/realtime/channels/client-context-channel.js +174 -0
  68. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -0
  69. package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts +123 -0
  70. package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts.map +1 -0
  71. package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js +397 -0
  72. package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js.map +1 -0
  73. package/dist/lib/components/realtime/media/media-channel-state.d.ts +103 -0
  74. package/dist/lib/components/realtime/media/media-channel-state.d.ts.map +1 -0
  75. package/dist/lib/components/realtime/media/media-channel-state.js +143 -0
  76. package/dist/lib/components/realtime/media/media-channel-state.js.map +1 -0
  77. package/dist/lib/components/realtime/media/media-channel-tools.d.ts +24 -0
  78. package/dist/lib/components/realtime/media/media-channel-tools.d.ts.map +1 -0
  79. package/dist/lib/components/realtime/media/media-channel-tools.js +107 -0
  80. package/dist/lib/components/realtime/media/media-channel-tools.js.map +1 -0
  81. package/dist/lib/components/realtime/media/media-channel.d.ts +89 -0
  82. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -0
  83. package/dist/lib/components/realtime/media/media-channel.js +253 -0
  84. package/dist/lib/components/realtime/media/media-channel.js.map +1 -0
  85. package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts +141 -0
  86. package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts.map +1 -0
  87. package/dist/lib/components/realtime/media/realtime-media-surface.component.js +574 -0
  88. package/dist/lib/components/realtime/media/realtime-media-surface.component.js.map +1 -0
  89. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +59 -14
  90. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
  91. package/dist/lib/components/realtime/realtime-activity-rail.component.js +277 -74
  92. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
  93. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +28 -27
  94. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  95. package/dist/lib/components/realtime/realtime-agent-banner.component.js +144 -143
  96. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  97. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +12 -0
  98. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
  99. package/dist/lib/components/realtime/realtime-agent-picker.component.js +105 -43
  100. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
  101. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +2 -2
  102. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
  103. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
  104. package/dist/lib/components/realtime/realtime-composer.component.d.ts +41 -7
  105. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  106. package/dist/lib/components/realtime/realtime-composer.component.js +216 -102
  107. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  108. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +0 -2
  109. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
  110. package/dist/lib/components/realtime/realtime-delegation-card.component.js +67 -71
  111. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
  112. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +364 -44
  113. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  114. package/dist/lib/components/realtime/realtime-session-overlay.component.js +839 -153
  115. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  116. package/dist/lib/components/realtime/realtime-session-state.d.ts +5 -5
  117. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
  118. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
  119. package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts +70 -0
  120. package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts.map +1 -0
  121. package/dist/lib/components/realtime/realtime-surface-tab-style.js +115 -0
  122. package/dist/lib/components/realtime/realtime-surface-tab-style.js.map +1 -0
  123. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +55 -57
  124. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  125. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +165 -143
  126. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  127. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +80 -71
  128. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  129. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +83 -113
  130. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  131. package/dist/lib/components/realtime/realtime-ui-config.d.ts +270 -0
  132. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -0
  133. package/dist/lib/components/realtime/realtime-ui-config.js +212 -0
  134. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -0
  135. package/dist/lib/components/search/search-panel.component.d.ts +2 -0
  136. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  137. package/dist/lib/components/search/search-panel.component.js +92 -101
  138. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  139. package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
  140. package/dist/lib/components/share/share-modal.component.js +10 -11
  141. package/dist/lib/components/share/share-modal.component.js.map +1 -1
  142. package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
  143. package/dist/lib/components/shared/user-picker.component.js +12 -15
  144. package/dist/lib/components/shared/user-picker.component.js.map +1 -1
  145. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +11 -3
  146. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
  147. package/dist/lib/components/sidebar/conversation-sidebar.component.js +34 -10
  148. package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
  149. package/dist/lib/components/sidebar/routines-section.component.d.ts +73 -0
  150. package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -0
  151. package/dist/lib/components/sidebar/routines-section.component.js +211 -0
  152. package/dist/lib/components/sidebar/routines-section.component.js.map +1 -0
  153. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +12 -0
  154. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
  155. package/dist/lib/components/tasks/tasks-dropdown.component.js +37 -1
  156. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  157. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +16 -5
  158. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  159. package/dist/lib/components/workspace/conversation-workspace.component.js +51 -31
  160. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  161. package/dist/lib/composer-plugins/agent-mention.provider.d.ts +16 -0
  162. package/dist/lib/composer-plugins/agent-mention.provider.d.ts.map +1 -0
  163. package/dist/lib/composer-plugins/agent-mention.provider.js +28 -0
  164. package/dist/lib/composer-plugins/agent-mention.provider.js.map +1 -0
  165. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +20 -0
  166. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -0
  167. package/dist/lib/composer-plugins/base-conversation-mention.provider.js +32 -0
  168. package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -0
  169. package/dist/lib/composer-plugins/load-composer-plugins.d.ts +9 -0
  170. package/dist/lib/composer-plugins/load-composer-plugins.d.ts.map +1 -0
  171. package/dist/lib/composer-plugins/load-composer-plugins.js +17 -0
  172. package/dist/lib/composer-plugins/load-composer-plugins.js.map +1 -0
  173. package/dist/lib/composer-plugins/record-mention.provider.d.ts +14 -0
  174. package/dist/lib/composer-plugins/record-mention.provider.d.ts.map +1 -0
  175. package/dist/lib/composer-plugins/record-mention.provider.js +26 -0
  176. package/dist/lib/composer-plugins/record-mention.provider.js.map +1 -0
  177. package/dist/lib/composer-plugins/skill-command.provider.d.ts +15 -0
  178. package/dist/lib/composer-plugins/skill-command.provider.d.ts.map +1 -0
  179. package/dist/lib/composer-plugins/skill-command.provider.js +27 -0
  180. package/dist/lib/composer-plugins/skill-command.provider.js.map +1 -0
  181. package/dist/lib/conversations.module.d.ts +68 -64
  182. package/dist/lib/conversations.module.d.ts.map +1 -1
  183. package/dist/lib/conversations.module.js +69 -18
  184. package/dist/lib/conversations.module.js.map +1 -1
  185. package/dist/lib/models/conversation-state.model.d.ts +6 -3
  186. package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
  187. package/dist/lib/models/conversation-state.model.js.map +1 -1
  188. package/dist/lib/services/conversation-agent.service.d.ts +9 -2
  189. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  190. package/dist/lib/services/conversation-agent.service.js +26 -2
  191. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  192. package/dist/lib/services/conversation-attachment.service.d.ts +1 -1
  193. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  194. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  195. package/dist/lib/services/mention-autocomplete.service.d.ts +42 -19
  196. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  197. package/dist/lib/services/mention-autocomplete.service.js +113 -18
  198. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  199. package/dist/lib/services/realtime-audio-recorder.d.ts +143 -0
  200. package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -0
  201. package/dist/lib/services/realtime-audio-recorder.js +379 -0
  202. package/dist/lib/services/realtime-audio-recorder.js.map +1 -0
  203. package/dist/lib/services/realtime-pcm-wav.d.ts +75 -0
  204. package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -0
  205. package/dist/lib/services/realtime-pcm-wav.js +205 -0
  206. package/dist/lib/services/realtime-pcm-wav.js.map +1 -0
  207. package/dist/lib/services/realtime-session-review.service.d.ts +28 -1
  208. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  209. package/dist/lib/services/realtime-session-review.service.js +12 -3
  210. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  211. package/dist/lib/services/realtime-session.service.d.ts +210 -20
  212. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  213. package/dist/lib/services/realtime-session.service.js +452 -21
  214. package/dist/lib/services/realtime-session.service.js.map +1 -1
  215. package/dist/lib/services/realtime-sessions-adapter.js +1 -1
  216. package/dist/lib/services/realtime-sessions-adapter.js.map +1 -1
  217. package/dist/lib/services/ui-command-handler.service.d.ts +7 -2
  218. package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
  219. package/dist/lib/services/ui-command-handler.service.js +6 -2
  220. package/dist/lib/services/ui-command-handler.service.js.map +1 -1
  221. package/dist/lib/utils/plan-mode-preference.d.ts +62 -0
  222. package/dist/lib/utils/plan-mode-preference.d.ts.map +1 -0
  223. package/dist/lib/utils/plan-mode-preference.js +130 -0
  224. package/dist/lib/utils/plan-mode-preference.js.map +1 -0
  225. package/dist/public-api.d.ts +29 -3
  226. package/dist/public-api.d.ts.map +1 -1
  227. package/dist/public-api.js +46 -3
  228. package/dist/public-api.js.map +1 -1
  229. package/package.json +30 -26
  230. package/dist/__tests__/attachment-badge.test.d.ts +0 -2
  231. package/dist/__tests__/attachment-badge.test.d.ts.map +0 -1
  232. package/dist/__tests__/attachment-badge.test.js +0 -66
  233. package/dist/__tests__/attachment-badge.test.js.map +0 -1
  234. package/dist/__tests__/channel-optional-surface.test.d.ts +0 -2
  235. package/dist/__tests__/channel-optional-surface.test.d.ts.map +0 -1
  236. package/dist/__tests__/channel-optional-surface.test.js +0 -53
  237. package/dist/__tests__/channel-optional-surface.test.js.map +0 -1
  238. package/dist/__tests__/chat-events.test.d.ts +0 -14
  239. package/dist/__tests__/chat-events.test.d.ts.map +0 -1
  240. package/dist/__tests__/chat-events.test.js +0 -109
  241. package/dist/__tests__/chat-events.test.js.map +0 -1
  242. package/dist/__tests__/collections-full-view.test.d.ts +0 -2
  243. package/dist/__tests__/collections-full-view.test.d.ts.map +0 -1
  244. package/dist/__tests__/collections-full-view.test.js +0 -225
  245. package/dist/__tests__/collections-full-view.test.js.map +0 -1
  246. package/dist/__tests__/conversation-cache.test.d.ts +0 -2
  247. package/dist/__tests__/conversation-cache.test.d.ts.map +0 -1
  248. package/dist/__tests__/conversation-cache.test.js +0 -233
  249. package/dist/__tests__/conversation-cache.test.js.map +0 -1
  250. package/dist/__tests__/conversation-naming.test.d.ts +0 -2
  251. package/dist/__tests__/conversation-naming.test.d.ts.map +0 -1
  252. package/dist/__tests__/conversation-naming.test.js +0 -110
  253. package/dist/__tests__/conversation-naming.test.js.map +0 -1
  254. package/dist/__tests__/delegation-result-parser.test.d.ts +0 -2
  255. package/dist/__tests__/delegation-result-parser.test.d.ts.map +0 -1
  256. package/dist/__tests__/delegation-result-parser.test.js +0 -107
  257. package/dist/__tests__/delegation-result-parser.test.js.map +0 -1
  258. package/dist/__tests__/distinct-artifacts.test.d.ts +0 -2
  259. package/dist/__tests__/distinct-artifacts.test.d.ts.map +0 -1
  260. package/dist/__tests__/distinct-artifacts.test.js +0 -56
  261. package/dist/__tests__/distinct-artifacts.test.js.map +0 -1
  262. package/dist/__tests__/event-wiring.test.d.ts +0 -15
  263. package/dist/__tests__/event-wiring.test.d.ts.map +0 -1
  264. package/dist/__tests__/event-wiring.test.js +0 -100
  265. package/dist/__tests__/event-wiring.test.js.map +0 -1
  266. package/dist/__tests__/index.test.d.ts +0 -2
  267. package/dist/__tests__/index.test.d.ts.map +0 -1
  268. package/dist/__tests__/index.test.js +0 -7
  269. package/dist/__tests__/index.test.js.map +0 -1
  270. package/dist/__tests__/narration-template.test.d.ts +0 -2
  271. package/dist/__tests__/narration-template.test.d.ts.map +0 -1
  272. package/dist/__tests__/narration-template.test.js +0 -76
  273. package/dist/__tests__/narration-template.test.js.map +0 -1
  274. package/dist/__tests__/notification-model.test.d.ts +0 -2
  275. package/dist/__tests__/notification-model.test.d.ts.map +0 -1
  276. package/dist/__tests__/notification-model.test.js +0 -68
  277. package/dist/__tests__/notification-model.test.js.map +0 -1
  278. package/dist/__tests__/realtime-agent-picker-models.test.d.ts +0 -2
  279. package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +0 -1
  280. package/dist/__tests__/realtime-agent-picker-models.test.js +0 -49
  281. package/dist/__tests__/realtime-agent-picker-models.test.js.map +0 -1
  282. package/dist/__tests__/realtime-audio-visuals.test.d.ts +0 -2
  283. package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +0 -1
  284. package/dist/__tests__/realtime-audio-visuals.test.js +0 -123
  285. package/dist/__tests__/realtime-audio-visuals.test.js.map +0 -1
  286. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +0 -2
  287. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +0 -1
  288. package/dist/__tests__/realtime-delegation-card-cancel.test.js +0 -48
  289. package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +0 -1
  290. package/dist/__tests__/realtime-disclosure.test.d.ts +0 -2
  291. package/dist/__tests__/realtime-disclosure.test.d.ts.map +0 -1
  292. package/dist/__tests__/realtime-disclosure.test.js +0 -164
  293. package/dist/__tests__/realtime-disclosure.test.js.map +0 -1
  294. package/dist/__tests__/realtime-pairing.test.d.ts +0 -2
  295. package/dist/__tests__/realtime-pairing.test.d.ts.map +0 -1
  296. package/dist/__tests__/realtime-pairing.test.js +0 -207
  297. package/dist/__tests__/realtime-pairing.test.js.map +0 -1
  298. package/dist/__tests__/realtime-review-lifecycle.test.d.ts +0 -2
  299. package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +0 -1
  300. package/dist/__tests__/realtime-review-lifecycle.test.js +0 -154
  301. package/dist/__tests__/realtime-review-lifecycle.test.js.map +0 -1
  302. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +0 -2
  303. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +0 -1
  304. package/dist/__tests__/realtime-session-cancel-usage.test.js +0 -230
  305. package/dist/__tests__/realtime-session-cancel-usage.test.js.map +0 -1
  306. package/dist/__tests__/realtime-session-channels.test.d.ts +0 -2
  307. package/dist/__tests__/realtime-session-channels.test.d.ts.map +0 -1
  308. package/dist/__tests__/realtime-session-channels.test.js +0 -252
  309. package/dist/__tests__/realtime-session-channels.test.js.map +0 -1
  310. package/dist/__tests__/realtime-session-client-tools.test.d.ts +0 -2
  311. package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +0 -1
  312. package/dist/__tests__/realtime-session-client-tools.test.js +0 -103
  313. package/dist/__tests__/realtime-session-client-tools.test.js.map +0 -1
  314. package/dist/__tests__/realtime-session-minimized.test.d.ts +0 -2
  315. package/dist/__tests__/realtime-session-minimized.test.d.ts.map +0 -1
  316. package/dist/__tests__/realtime-session-minimized.test.js +0 -32
  317. package/dist/__tests__/realtime-session-minimized.test.js.map +0 -1
  318. package/dist/__tests__/realtime-session-mint.test.d.ts +0 -2
  319. package/dist/__tests__/realtime-session-mint.test.d.ts.map +0 -1
  320. package/dist/__tests__/realtime-session-mint.test.js +0 -69
  321. package/dist/__tests__/realtime-session-mint.test.js.map +0 -1
  322. package/dist/__tests__/realtime-session-policy.test.d.ts +0 -2
  323. package/dist/__tests__/realtime-session-policy.test.d.ts.map +0 -1
  324. package/dist/__tests__/realtime-session-policy.test.js +0 -303
  325. package/dist/__tests__/realtime-session-policy.test.js.map +0 -1
  326. package/dist/__tests__/realtime-session-review.service.test.d.ts +0 -2
  327. package/dist/__tests__/realtime-session-review.service.test.d.ts.map +0 -1
  328. package/dist/__tests__/realtime-session-review.service.test.js +0 -743
  329. package/dist/__tests__/realtime-session-review.service.test.js.map +0 -1
  330. package/dist/__tests__/realtime-session-state.test.d.ts +0 -2
  331. package/dist/__tests__/realtime-session-state.test.d.ts.map +0 -1
  332. package/dist/__tests__/realtime-session-state.test.js +0 -83
  333. package/dist/__tests__/realtime-session-state.test.js.map +0 -1
  334. package/dist/__tests__/realtime-session-timeline-card.test.d.ts +0 -2
  335. package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +0 -1
  336. package/dist/__tests__/realtime-session-timeline-card.test.js +0 -106
  337. package/dist/__tests__/realtime-session-timeline-card.test.js.map +0 -1
  338. package/dist/__tests__/realtime-session-timeline.test.d.ts +0 -2
  339. package/dist/__tests__/realtime-session-timeline.test.d.ts.map +0 -1
  340. package/dist/__tests__/realtime-session-timeline.test.js +0 -142
  341. package/dist/__tests__/realtime-session-timeline.test.js.map +0 -1
  342. package/dist/__tests__/realtime-sessions-adapter.test.d.ts +0 -19
  343. package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +0 -1
  344. package/dist/__tests__/realtime-sessions-adapter.test.js +0 -188
  345. package/dist/__tests__/realtime-sessions-adapter.test.js.map +0 -1
  346. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +0 -2
  347. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +0 -1
  348. package/dist/__tests__/realtime-surface-panel-prefs.test.js +0 -100
  349. package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +0 -1
  350. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +0 -2
  351. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +0 -1
  352. package/dist/__tests__/realtime-surface-tabs-model.test.js +0 -193
  353. package/dist/__tests__/realtime-surface-tabs-model.test.js.map +0 -1
  354. package/dist/__tests__/remote-browser-audio-player.test.d.ts +0 -2
  355. package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +0 -1
  356. package/dist/__tests__/remote-browser-audio-player.test.js +0 -137
  357. package/dist/__tests__/remote-browser-audio-player.test.js.map +0 -1
  358. package/dist/__tests__/remote-browser-channel.test.d.ts +0 -2
  359. package/dist/__tests__/remote-browser-channel.test.d.ts.map +0 -1
  360. package/dist/__tests__/remote-browser-channel.test.js +0 -585
  361. package/dist/__tests__/remote-browser-channel.test.js.map +0 -1
  362. package/dist/__tests__/search-service.test.d.ts +0 -2
  363. package/dist/__tests__/search-service.test.d.ts.map +0 -1
  364. package/dist/__tests__/search-service.test.js +0 -114
  365. package/dist/__tests__/search-service.test.js.map +0 -1
  366. package/dist/__tests__/slot-defaults.test.d.ts +0 -24
  367. package/dist/__tests__/slot-defaults.test.d.ts.map +0 -1
  368. package/dist/__tests__/slot-defaults.test.js +0 -63
  369. package/dist/__tests__/slot-defaults.test.js.map +0 -1
  370. package/dist/__tests__/toast-service.test.d.ts +0 -2
  371. package/dist/__tests__/toast-service.test.d.ts.map +0 -1
  372. package/dist/__tests__/toast-service.test.js +0 -143
  373. package/dist/__tests__/toast-service.test.js.map +0 -1
  374. package/dist/__tests__/user-authorization.test.d.ts +0 -2
  375. package/dist/__tests__/user-authorization.test.d.ts.map +0 -1
  376. package/dist/__tests__/user-authorization.test.js +0 -97
  377. package/dist/__tests__/user-authorization.test.js.map +0 -1
  378. package/dist/__tests__/voice-session-narration.test.d.ts +0 -2
  379. package/dist/__tests__/voice-session-narration.test.d.ts.map +0 -1
  380. package/dist/__tests__/voice-session-narration.test.js +0 -609
  381. package/dist/__tests__/voice-session-narration.test.js.map +0 -1
  382. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +0 -2
  383. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +0 -1
  384. package/dist/__tests__/whiteboard-artifact-viewer.test.js +0 -101
  385. package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +0 -1
  386. package/dist/__tests__/whiteboard-channel.test.d.ts +0 -2
  387. package/dist/__tests__/whiteboard-channel.test.d.ts.map +0 -1
  388. package/dist/__tests__/whiteboard-channel.test.js +0 -260
  389. package/dist/__tests__/whiteboard-channel.test.js.map +0 -1
  390. package/dist/__tests__/whiteboard-restore-state.test.d.ts +0 -2
  391. package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +0 -1
  392. package/dist/__tests__/whiteboard-restore-state.test.js +0 -108
  393. package/dist/__tests__/whiteboard-restore-state.test.js.map +0 -1
  394. package/dist/lib/components/mention/mention-dropdown.component.d.ts +0 -53
  395. package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +0 -1
  396. package/dist/lib/components/mention/mention-dropdown.component.js +0 -276
  397. package/dist/lib/components/mention/mention-dropdown.component.js.map +0 -1
  398. package/dist/lib/components/mention/mention-editor.component.d.ts +0 -256
  399. package/dist/lib/components/mention/mention-editor.component.d.ts.map +0 -1
  400. package/dist/lib/components/mention/mention-editor.component.js +0 -1233
  401. package/dist/lib/components/mention/mention-editor.component.js.map +0 -1
  402. package/dist/lib/components/message/message-input-box.component.d.ts +0 -137
  403. package/dist/lib/components/message/message-input-box.component.d.ts.map +0 -1
  404. package/dist/lib/components/message/message-input-box.component.js +0 -321
  405. package/dist/lib/components/message/message-input-box.component.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';\nimport { Metadata, IMetadataProvider } from '@memberjunction/core';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';\nimport { MJGlobal } from '@memberjunction/global';\nimport { ClientRealtimeSessionConfig, JSONObject, JSONValue, RealtimeToolDefinition } from '@memberjunction/ai';\nimport {\n BaseRealtimeClient,\n LoadAssemblyAIRealtimeClient,\n LoadElevenLabsRealtimeClient,\n LoadGeminiRealtimeClient,\n LoadOpenAIRealtimeClient,\n LoadxAIRealtimeClient,\n RealtimeAudioActivity,\n RealtimeClientError,\n RealtimeClientState,\n RealtimeClientToolCall,\n RealtimeClientTranscript,\n RealtimeClientUsage\n} from '@memberjunction/ai-realtime-client';\nimport { BuildNarrationInstructions } from './narration-template';\nimport { ParseDelegationResultJson, ParsedDelegationArtifact } from './delegation-result-parser';\nimport { BaseRealtimeChannelClient, RealtimeChannelContext } from '../components/realtime/channels/base-realtime-channel-client';\n\n// Tree-shaking prevention: the OpenAI client is resolved dynamically through the\n// ClassFactory (by the server-reported Provider key), so this static call is what keeps\n// its @RegisterClass side effect from being eliminated by the bundler.\n// NOTE: the interactive-channel plugins (resolved dynamically from the `MJ: AI Agent\n// Channels` registry by ClientPluginClass key) get the same treatment, but their Load\n// calls live in `conversations.module.ts` — plugins carry Angular surface COMPONENTS,\n// and this service stays component-free (it must stay importable in plain-node tests).\nLoadOpenAIRealtimeClient();\nLoadGeminiRealtimeClient();\nLoadElevenLabsRealtimeClient();\nLoadAssemblyAIRealtimeClient();\nLoadxAIRealtimeClient();\n\n/**\n * Connection / turn state for a real-time voice session, surfaced to the UI overlay.\n * - `connecting` — negotiating the session + provider handshake\n * - `listening` — connected, mic open, waiting for / hearing the user\n * - `speaking` — the agent is producing audio\n * - `thinking` — the agent delegated work (tool call) and is waiting on a result\n * - `error` — a fatal error occurred; the session is no longer usable\n * - `closed` — the session has been torn down\n */\nexport type VoiceConnectionState =\n | 'connecting'\n | 'listening'\n | 'speaking'\n | 'thinking'\n | 'error'\n | 'closed';\n\n/** A single caption line (one side of the conversation) shown in the live-captions list. */\nexport interface VoiceCaption {\n Role: 'User' | 'Assistant';\n Text: string;\n}\n\n/**\n * A delegated-run progress update surfaced to the UI, emitted on {@link RealtimeSessionService.DelegationProgress$}.\n * These originate server-side during an `invoke-target-agent` delegation (e.g. while Sage works) and let a\n * future overlay render a \"working\" card while the realtime model narrates the same progress aloud.\n */\nexport interface VoiceDelegationProgress {\n /** The `invoke-target-agent` call this progress belongs to. */\n CallID: string;\n /** The delegation phase: `prompt_execution` | `action_execution` | `subagent_execution` | `decision_processing`. */\n Step: string;\n /** Human-readable progress message. */\n Message: string;\n /** Optional completion percentage (0–100) when the server can estimate it. */\n Percentage?: number;\n}\n\n/**\n * The terminal result of a delegated tool call, emitted on {@link RealtimeSessionService.DelegationResult$}\n * when the delegation finishes so the overlay can flip the \"working\" card into a result card with real\n * content + provenance.\n */\nexport interface VoiceDelegationResult {\n /** The `invoke-target-agent` call this result belongs to. */\n CallID: string;\n /** Whether the delegated work succeeded. */\n Success: boolean;\n /** The result text — the agent's output, or an error message on failure. */\n Output: string;\n /**\n * ID of the delegated agent run (`MJ: AI Agent Runs`) when the server reported one\n * (`runId` in the tool ResultJson). Powers the overlay's gear-gated \"Open run\" dev link.\n */\n RunID?: string;\n /**\n * Artifacts the delegated run produced, when the server reported any (`artifacts` in the\n * tool ResultJson). The overlay's tabbed surface panel auto-opens one artifact tab per\n * entry and focuses the newest on arrival.\n */\n Artifacts?: ParsedDelegationArtifact[];\n}\n\n/**\n * Handler for a CLIENT-EXECUTED UI tool (e.g. the live whiteboard's `Whiteboard_*` surface),\n * registered via {@link RealtimeSessionService.RegisterClientToolHandler}. Receives the tool name +\n * raw arguments JSON from the realtime model and returns the result JSON string fed back as the\n * `tool_response`. May be sync or async; thrown errors are wrapped into a\n * `{ success: false, error }` payload by the service so the model can narrate the failure.\n */\nexport type RealtimeClientToolHandler = (toolName: string, argsJson: string) => string | Promise<string>;\n\n/**\n * A channel's request to enter / leave the FOCUS layout, emitted on\n * {@link RealtimeSessionService.ChannelFocus$} when a plugin calls its context's\n * `SetFocusMode`. The overlay shell subscribes: it collapses/restores the main call column\n * and remembers which channel holds focus (so the floating pill's \"exit\" can be routed\n * back via {@link BaseRealtimeChannelClient.RequestFocusExit}).\n */\nexport interface RealtimeChannelFocusEvent {\n /** The channel plugin requesting the layout change. */\n Channel: BaseRealtimeChannelClient;\n /** `true` to enter focus mode (surface owns the screen), `false` to leave it. */\n Focused: boolean;\n}\n\n/**\n * The narrow projection of an ACTIVE `MJ: AI Agent Channels` registry row the service\n * reads at session start from {@link AIEngineBase}'s cached `AgentChannels`.\n */\ninterface RealtimeChannelDefinitionRow {\n ID: string;\n Name: string;\n ClientPluginClass: string;\n}\n\n/**\n * One EPHEMERAL spoken narration of delegated-run progress, emitted on\n * {@link RealtimeSessionService.DelegationNarration$}. These are the interim \"here's what's\n * happening\" utterances the realtime model speaks while a delegation runs. By product\n * decision they are NOT captions and NOT persisted as ConversationDetails — they exist\n * only as a live note in the overlay, replaced by each newer narration.\n */\nexport interface VoiceDelegationNarration {\n /** The narration transcript text. */\n Text: string;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic during a delegated run.\n * We filter on `resolver` + `type` before correlating by `agentSessionID`; normal agent runs publish\n * other shapes on the same topic and are ignored.\n */\ninterface RealtimeDelegationProgressPayload {\n resolver: string;\n type: string;\n agentSessionID: string;\n callID: string;\n step: string;\n message: string;\n percentage?: number;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic for each live Remote\n * Browser screencast frame (mirrors {@link RealtimeDelegationProgressPayload}, distinguished by\n * `resolver` + `type`). Routed to the active Remote Browser channel plugin — never narrated.\n */\ninterface RemoteBrowserScreencastPayload {\n type: 'RemoteBrowserScreencastFrame';\n agentSessionID: string;\n dataBase64: string;\n width: number;\n height: number;\n seq: number;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic for each live Remote\n * Browser tab-audio chunk (mirrors {@link RemoteBrowserScreencastPayload}, distinguished by `type`).\n * Routed to the active Remote Browser channel plugin's audio player — never narrated.\n */\ninterface RemoteBrowserAudioChunkPayload {\n type: 'RemoteBrowserAudioChunk';\n agentSessionID: string;\n dataBase64: string;\n codec: string;\n sampleRate: number;\n channels: number;\n seq: number;\n}\n\n/**\n * Result shape returned by the `StartRealtimeClientSession` server mutation.\n * The browser uses these values to open a client-direct realtime session.\n */\ninterface StartRealtimeClientSessionResult {\n AgentSessionId: string;\n ConversationId: string | null;\n Provider: string;\n Model: string;\n EphemeralToken: string;\n ExpiresAt: string;\n /** JSON.stringify of the provider session config (instructions + tools) to apply at connect. */\n SessionConfigJson: string;\n /** Display name of the realtime model the session uses (e.g. \"GPT Realtime 2\"). Null when unknown. */\n ModelName: string | null;\n /**\n * DB-driven progress-narration instruction template (contains a `{{ progressMessage }}`\n * placeholder). Null when the deployment hasn't synced the narration prompt — the client\n * falls back to its built-in wording.\n */\n NarrationInstructionsTemplate: string | null;\n /**\n * JSON map of the PRIOR session's saved channel states keyed by channel name (present only\n * when the start carried `lastSessionId` and the prior session — owned by the same user —\n * had saved states). Applied to the matching channel plugins via\n * {@link BaseRealtimeChannelClient.RestoreState} so e.g. the whiteboard resumes where the\n * last session left off.\n */\n PriorChannelStatesJson: string | null;\n}\n\n/**\n * Drives a **client-direct** real-time voice session: the browser mints an ephemeral\n * token from the MJ server, then connects DIRECTLY to the realtime provider. Audio\n * frames never transit the MJ server (low latency); only tool calls and final\n * transcripts are relayed back to MJ over GraphQL.\n *\n * This service is PROVIDER-AGNOSTIC policy/orchestration. All provider wire concerns\n * (transport, event translation, the response state machine, narration-kind tagging,\n * playback tracking) live in a {@link BaseRealtimeClient} driver resolved through the\n * MJ ClassFactory by the server-reported `Provider` key (e.g. `'openai'` →\n * `OpenAIRealtimeClient`). Future providers (Gemini Live, …) snap in by registering a\n * new driver — this service does not change.\n *\n * The Realtime Co-Agent (server-side) fronts the conversation's current agent — the server\n * bakes the companion instructions + tool set into `SessionConfigJson`, which the client\n * driver applies verbatim.\n *\n * Lifecycle: {@link StartVoiceSession} → live duplex → {@link EndVoiceSession}.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionService {\n // ── Reactive UI state ──────────────────────────────────────────────────────\n private _connectionState$ = new BehaviorSubject<VoiceConnectionState>('closed');\n private _captions$ = new BehaviorSubject<VoiceCaption[]>([]);\n private _active$ = new BehaviorSubject<boolean>(false);\n private _delegationProgress$ = new Subject<VoiceDelegationProgress>();\n private _delegationResult$ = new Subject<VoiceDelegationResult>();\n private _delegationNarration$ = new Subject<VoiceDelegationNarration>();\n private _agentName$ = new BehaviorSubject<string>('Sage');\n private _modelName$ = new BehaviorSubject<string | null>(null);\n private _minimized$ = new BehaviorSubject<boolean>(false);\n private _activeChannels$ = new BehaviorSubject<BaseRealtimeChannelClient[]>([]);\n private _channelFocus$ = new Subject<RealtimeChannelFocusEvent>();\n // ─── Generic session-lifecycle events (consumed by RealtimeSessionsAdapter to\n // bridge into @memberjunction/conversations-runtime's framework-agnostic\n // SessionsObserver). Why not derive from Active$ + agentSessionId? Because\n // Active$ flips true before mintSession resolves and sets agentSessionId —\n // a naive Active$ subscription would emit session-started with sessionId === null.\n // Emitting explicitly avoids the race entirely. ───\n private _sessionStarted$ = new Subject<{ sessionId: string; channelNames: string[] }>();\n private _sessionEnded$ = new Subject<{ sessionId: string; reason: 'explicit' | 'error' }>();\n private _channelActivity$ = new Subject<BaseRealtimeChannelClient>();\n\n /** Current connection / turn state. */\n public readonly ConnectionState$: Observable<VoiceConnectionState> = this._connectionState$.asObservable();\n /** Live captions for both sides of the conversation. */\n public readonly Captions$: Observable<VoiceCaption[]> = this._captions$.asObservable();\n /** True while a session is open (mic button active, overlay shown). */\n public readonly Active$: Observable<boolean> = this._active$.asObservable();\n /**\n * Progress updates from a delegated agent run (e.g. Sage) while the realtime model waits on it.\n * The future overlay subscribes to render a \"working\" card; the model also narrates these aloud.\n */\n public readonly DelegationProgress$: Observable<VoiceDelegationProgress> = this._delegationProgress$.asObservable();\n /** Terminal result of a delegation, so the overlay can complete the working card with real content. */\n public readonly DelegationResult$: Observable<VoiceDelegationResult> = this._delegationResult$.asObservable();\n /**\n * EPHEMERAL spoken progress narrations (see {@link VoiceDelegationNarration}). These are\n * deliberately kept OUT of {@link Captions$} and never relayed/persisted — the overlay\n * renders them as a transient \"live note\" near the active working card.\n */\n public readonly DelegationNarration$: Observable<VoiceDelegationNarration> = this._delegationNarration$.asObservable();\n /** Display name of the agent the active session fronts (set at session start). */\n public readonly AgentName$: Observable<string> = this._agentName$.asObservable();\n /**\n * Display name of the realtime MODEL the active session runs on (server-reported at session\n * start, e.g. \"GPT Realtime 2\"). `null` before a session starts / when the server didn't report\n * one. The overlay banner shows it subtly next to the agent identity.\n */\n public readonly ModelName$: Observable<string | null> = this._modelName$.asObservable();\n\n /**\n * True while the active call overlay is MINIMIZED to the host's floating \"on call\" pill\n * (e.g. after a dev link navigated away). The mic and session stay fully live — this is\n * pure presentation state, reset to `false` at session start and teardown.\n */\n public readonly Minimized$: Observable<boolean> = this._minimized$.asObservable();\n\n /**\n * The session's ACTIVE interactive-channel plugins, resolved from the `MJ: AI Agent\n * Channels` registry at session start (one instance per session, per channel). Emits\n * `[]` before a session starts and after teardown. The overlay subscribes to register\n * one surface tab per plugin — it never knows any concrete channel type.\n */\n public readonly ActiveChannels$: Observable<BaseRealtimeChannelClient[]> = this._activeChannels$.asObservable();\n\n /**\n * Channel requests to enter / leave the FOCUS layout (see\n * {@link RealtimeChannelFocusEvent}). Fired when a plugin calls its host context's\n * `SetFocusMode` — e.g. the whiteboard's \"Focus board\" toggle.\n */\n public readonly ChannelFocus$: Observable<RealtimeChannelFocusEvent> = this._channelFocus$.asObservable();\n\n /**\n * Fired EXACTLY ONCE per session after both `agentSessionId` is set AND the\n * realtime client is connected. Carries the server-issued `sessionId` and the\n * `ChannelName` of each plugin resolved at session mint. Consumed by\n * `RealtimeSessionsAdapter` (in this package) to feed\n * `@memberjunction/conversations-runtime`'s `SessionsObserver`.\n *\n * **Why this exists separately from `Active$`:** `Active$` flips `true` BEFORE\n * `mintSession` resolves, so `agentSessionId` is still `null` at that moment.\n * Subscribers correlating `(Active$, agentSessionId)` would race; this event\n * removes the race.\n */\n public readonly SessionStarted$: Observable<{ sessionId: string; channelNames: string[] }> =\n this._sessionStarted$.asObservable();\n\n /**\n * Fired EXACTLY ONCE per session as teardown begins, with the prior\n * `agentSessionId` (so subscribers can correlate against `SessionStarted$`'s\n * sessionId) and the client-distinguishable reason — `'explicit'` when the\n * user called `EndVoiceSession`, `'error'` when teardown ran from a catch\n * block. Server-side close paths (janitor, shutdown) do NOT propagate here —\n * they happen out-of-process and have no client push channel today.\n */\n public readonly SessionEnded$: Observable<{ sessionId: string; reason: 'explicit' | 'error' }> =\n this._sessionEnded$.asObservable();\n\n /**\n * Fires with the channel PLUGIN every time the agent ACTS on that channel (a tool call\n * was routed to its local executor — e.g. the agent drew on the whiteboard). The overlay\n * uses the FIRST emission per channel to auto-reveal + focus the channel's surface tab,\n * so the user discovers the surface the moment the agent starts using it. Finer-grained\n * than {@link SessionStarted$}/{@link SessionEnded$} (per tool call, not per session).\n */\n public readonly ChannelActivity$: Observable<BaseRealtimeChannelClient> = this._channelActivity$.asObservable();\n\n /** Synchronous access to the session's active interactive-channel plugins. */\n public get ActiveChannels(): readonly BaseRealtimeChannelClient[] {\n return this._activeChannels$.value;\n }\n\n /** Synchronous access to the display name of the agent the active session fronts. */\n public get CurrentAgentName(): string {\n return this._agentName$.value;\n }\n\n /**\n * ID of the active server-side agent session (`MJ: AI Agent Sessions`), or `null` when no\n * session is open / the session hasn't been minted yet. Powers the overlay's gear-gated\n * \"Open session\" dev link.\n */\n /** Conversation id the SERVER created for this session (null when the host supplied one). */\n private createdConversationId: string | null = null;\n /** The session's conversation id (supplied or server-created). */\n private sessionConversationId: string | null = null;\n /** First final user utterance of the live session (the naming seed). */\n private firstUserTranscript: string | null = null;\n\n /**\n * When the active/last session CREATED its conversation (started without one), the new\n * conversation's id — the host uses it to refresh the cached list, conditionally select\n * it on close, and auto-name it. Null when the session joined an existing conversation.\n */\n public get SessionCreatedConversationId(): string | null {\n return this.createdConversationId;\n }\n\n /** The first final user utterance of the session (naming seed); null before the user speaks. */\n public get FirstUserTranscript(): string | null {\n return this.firstUserTranscript;\n }\n\n public get CurrentAgentSessionId(): string | null {\n return this.agentSessionId;\n }\n\n /** Synchronous access to the minimized presentation state. */\n public get IsMinimized(): boolean {\n return this._minimized$.value;\n }\n\n /**\n * Minimizes / restores the active call overlay (host renders the floating pill while\n * minimized). Presentation-only — the live audio session is untouched.\n */\n public SetMinimized(minimized: boolean): void {\n if (this._minimized$.value !== minimized) {\n this._minimized$.next(minimized);\n }\n }\n\n // ── Session internals ──────────────────────────────────────────────────────\n /** The provider-direct realtime client driving the live session (ClassFactory-resolved). */\n private client: BaseRealtimeClient | null = null;\n /** The mic capture stream — acquired here (permission UX) and handed to the client. */\n private localStream: MediaStream | null = null;\n private agentSessionId: string | null = null;\n /**\n * The DB-driven narration instruction template (server-resolved at session start, containing a\n * `{{ progressMessage }}` placeholder). `null` when the deployment hasn't synced the narration\n * prompt — {@link buildNarrationInstructions} then falls back to the built-in wording.\n */\n private narrationTemplate: string | null = null;\n\n // ── Delegated-run progress streaming ───────────────────────────────────────\n /** First spoken update fires no earlier than this long after delegated work starts. */\n private static readonly FirstNarrationDelayMs = 5000;\n /** Minimum gap between SUBSEQUENT spoken updates (the 7–10s band; floods aggregate). */\n private static readonly NarrationIntervalMs = 8000;\n /** Retry delay when the fire moment finds the model busy / audio still playing. */\n private static readonly NarrationBusyRetryMs = 1500;\n /** Max progress messages aggregated into one spoken digest. */\n private static readonly MaxDigestMessages = 4;\n /** Max prior spoken narrations chained into the instructions (anti-repetition). */\n private static readonly MaxPriorNarrations = 3;\n /**\n * Aggregation buffer: distinct progress messages since the last spoken update (oldest\n * first, capped at {@link RealtimeSessionService.MaxDigestMessages}). A flood of small\n * updates becomes ONE digest; the buffer is discarded when the result lands first.\n */\n private pendingNarrationMessages: string[] = [];\n /**\n * Tool calls currently executing on the server. Progress events ride PubSub and can\n * lag the (fast) mutation result — any progress for a call NOT in this set is stale\n * (already completed) and is dropped, so we never narrate \"starting up\" after the\n * answer was already spoken.\n */\n private inFlightCallIds = new Set<string>();\n /** Timer for the deferred narration; cancelled when the delegation result lands first. */\n private narrationTimer: ReturnType<typeof setTimeout> | null = null;\n /**\n * Call ids the USER explicitly cancelled via {@link CancelDelegation} /\n * {@link CancelInFlightDelegations}. Their cards were already flipped to the\n * \"Cancelled by user\" failed result, so when the original tool mutation later resolves\n * with the aborted run's outcome, {@link emitDelegationResult} skips the duplicate card\n * emission (the model still receives the tool result). Cleared at teardown.\n */\n private cancelledCallIds = new Set<string>();\n\n // ── Usage telemetry relay (B7) ─────────────────────────────────────────────\n /** Debounce window for relaying accumulated usage deltas to the server. */\n private static readonly UsageFlushDebounceMs = 10000;\n /** Accumulated input-token delta since the last flush. */\n private pendingUsageInput = 0;\n /** Accumulated output-token delta since the last flush. */\n private pendingUsageOutput = 0;\n /** Pending debounced usage flush; also force-flushed at teardown. */\n private usageFlushTimer: ReturnType<typeof setTimeout> | null = null;\n /** Active push-status subscription that feeds delegation progress; cleared on teardown. */\n private delegationProgressSub: Subscription | null = null;\n /** Timestamp (ms) of the last narration we triggered; 0 = never. */\n private lastDelegationNarrationAt = 0;\n /** When the current delegation burst began (first in-flight call); anchors the 5s first update. */\n private delegationBurstStartedAt = 0;\n /** Spoken updates so far in this burst (1-based numbering for the instructions). */\n private narrationCount = 0;\n /** What the model actually SAID for prior updates this burst — chained in so it never repeats itself. */\n private spokenNarrations: string[] = [];\n /** Tail message of the last digest, so an identical trailing progress event isn't re-buffered. */\n private lastNarratedTail = '';\n\n /**\n * Registry of CLIENT-EXECUTED UI tool handlers, keyed by tool-name prefix (e.g.\n * `'Whiteboard_'`). Tool calls whose name matches a registered prefix run LOCALLY through the\n * handler (never relayed to the server); everything else takes the standard server-relay path.\n * Cleared at teardown.\n */\n private clientToolHandlers = new Map<string, RealtimeClientToolHandler>();\n\n // ── Interactive channels (registry-resolved plugins) ───────────────────────\n /** Debounce window for persisting a channel's state of record after a change burst. */\n private static readonly ChannelSaveDebounceMs = 3000;\n /**\n * Pending DEBOUNCED channel-state saves, keyed by channel name. Each entry keeps the\n * LATEST serialized state plus the session id captured while the session was live —\n * the teardown flush runs as the live id is being torn down, so the capture guarantees\n * the final save still lands on the just-closed session.\n */\n private pendingChannelSaves = new Map<string, {\n Timer: ReturnType<typeof setTimeout>;\n StateJson: string;\n SessionID: string | null;\n }>();\n\n private _provider: IMetadataProvider | null = null;\n\n /**\n * Metadata provider used for the GraphQL relay mutations. Falls back to the\n * global default when unset (single-provider apps see no change).\n */\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n }\n\n /** True when a session is currently open. */\n public get IsActive(): boolean {\n return this._active$.value;\n }\n\n /**\n * Start a client-direct voice session fronting `targetAgentId`.\n *\n * @param targetAgentId The agent the Realtime Co-Agent voices on behalf of.\n * @param conversationId Optional existing conversation to bind + seed context from.\n * @param lastSessionId Optional prior session to chain to (resume / continuation).\n * @param agentName Optional display name of the target agent — resolved by the caller\n * (which knows the conversation's routing context) and surfaced on {@link AgentName$}\n * so ANY host (composer trigger, chat-area overlay) can render it without re-resolving.\n * @param preferredModelId Optional EXPLICIT realtime model choice (`MJ: AI Models.ID`). When\n * set, the server uses exactly that model and FAILS with a clear reason if it can't (no\n * silent fallback). Omit for the server's automatic (highest-PowerRank) selection.\n * @param clientTools Optional EXTRA client-executed UI tool declarations to expose to the\n * realtime model alongside the server's stable tool set and the interactive-channel\n * tools (which are aggregated automatically from the registry-resolved plugins — see\n * {@link ActiveChannels$}). The server only DECLARES these — execution stays in the\n * browser via handlers registered with {@link RegisterClientToolHandler}. This is an\n * extension point for hosts with bespoke (non-channel) UI tools; most callers omit it.\n * @param coAgentId Optional EXPLICIT co-agent choice (`MJ: AI Agents.ID` of an Active,\n * Realtime-type agent) — the highest-precedence step of the server's co-agent resolution\n * chain. When set, the server uses exactly that co-agent and FAILS with a clear reason if\n * it can't (no silent fallback). Omit to let server metadata drive the choice: the target\n * agent's `DefaultCoAgentID`, then the type-level `AIAgentCoAgent` default row, then the global Realtime Co-Agent.\n * @param configOverridesJson Optional JSON payload of SESSION CONFIG overrides (e.g.\n * `{\"realtime\":{\"modelPreference\":\"<modelId>\"}}`), forwarded verbatim on the mint\n * mutation. The server enforces the `Realtime: Advanced Session Controls`\n * authorization on any overrides — hosts only populate this from authorization-gated\n * pickers, and never synthesize overrides beyond what the user explicitly chose.\n * Omit/`null` for the server's defaults (today's behavior).\n */\n public async StartVoiceSession(\n targetAgentId: string,\n conversationId?: string | null,\n lastSessionId?: string | null,\n agentName?: string | null,\n preferredModelId?: string | null,\n clientTools?: RealtimeToolDefinition[] | null,\n coAgentId?: string | null,\n configOverridesJson?: string | null\n ): Promise<void> {\n if (this.IsActive) {\n return; // a session is already running — ignore duplicate starts\n }\n\n if (agentName) {\n this._agentName$.next(agentName);\n }\n this.resetState();\n this._active$.next(true);\n this._connectionState$.next('connecting');\n\n try {\n // Resolve + initialize the interactive-channel plugins FIRST: their client-executed\n // tool sets must be declared to the realtime model at session mint.\n const allClientTools = [...(clientTools ?? []), ...(await this.startChannels())];\n const session = await this.mintSession(targetAgentId, conversationId, lastSessionId, preferredModelId, allClientTools, coAgentId, configOverridesJson);\n this.agentSessionId = session.AgentSessionId;\n // A null input conversationId means the SERVER created a fresh conversation for\n // this session — track it so the host can fold it into the cached list, select\n // it on close, and auto-name it (via the shared naming helper).\n this.createdConversationId = !conversationId && session.ConversationId ? session.ConversationId : null;\n this.sessionConversationId = session.ConversationId ?? conversationId ?? null;\n this.firstUserTranscript = null;\n this.narrationTemplate = session.NarrationInstructionsTemplate ?? null;\n this._modelName$.next(session.ModelName ?? null);\n // Resume continuity: rehydrate channel plugins from the PRIOR session's saved states\n // (e.g. the whiteboard) BEFORE any surface binds — tolerant, never blocks the start.\n this.applyPriorChannelStates(session.PriorChannelStatesJson);\n\n const client = this.createRealtimeClient(session.Provider);\n this.client = client;\n this.wireClientHandlers(client);\n\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n await client.Connect(this.buildClientConfig(session), this.localStream);\n\n this.subscribeDelegationProgress();\n // State advances to 'listening' once the provider control channel opens\n // (driven by the client's OnStateChange events).\n\n // Surface a generic session-started event for the conversations runtime\n // SessionsObserver bridge. Emitting AFTER Connect() guarantees both that\n // agentSessionId is set (line ~468) AND the realtime client is connected,\n // so consumers can act on it without re-checking either condition.\n this._sessionStarted$.next({\n sessionId: this.agentSessionId,\n channelNames: this._activeChannels$.value.map(c => c.ChannelName),\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to start session:', error);\n this._connectionState$.next('error');\n await this.teardown(false);\n }\n }\n\n /**\n * End the active session: stop the mic, tear down the provider connection, and close\n * the server-side agent session. Safe to call when no session is active.\n */\n public async EndVoiceSession(): Promise<void> {\n if (!this.IsActive && !this.agentSessionId) {\n return;\n }\n await this.teardown(true);\n }\n\n /**\n * Inject a typed message into the live session as a user turn.\n *\n * Decomposed into two steps, each mirroring an existing voice path so the typed\n * turn behaves identically to a spoken one:\n * 1. {@link BaseRealtimeClient.SendText} injects the text as user input and triggers a\n * reply through the SAME collision-safe path tool results use — so it queues behind\n * any in-flight response (progress narration / prior turn) instead of colliding.\n * 2. Relay the turn through the same caption + transcript paths user speech uses\n * ({@link onUserTranscript}) so it shows in the live thread AND persists to MJ.\n *\n * No-op when no session is open / the control channel isn't ready, or when the text is empty.\n */\n public SendText(text: string): void {\n const trimmed = text?.trim() ?? '';\n if (trimmed.length === 0) {\n return;\n }\n const client = this.client;\n if (!client || !this.isSessionLive()) {\n return;\n }\n client.SendText(trimmed);\n // Relay as a user turn — same path spoken input uses (caption + persisted transcript).\n void this.onUserTranscript(trimmed);\n }\n\n /** Mute / unmute the local microphone track. Returns the new muted state. */\n public ToggleMute(): boolean {\n const tracks = this.localStream?.getAudioTracks() ?? [];\n if (tracks.length === 0) {\n return false;\n }\n const muted = tracks[0].enabled; // currently enabled → becomes muted\n this.client?.SetMuted(muted);\n return muted;\n }\n\n // ── Client-executed UI tools ───────────────────────────────────────────────\n\n /**\n * Registers a handler for CLIENT-EXECUTED UI tools whose names start with `toolNamePrefix`\n * (e.g. `'Whiteboard_'` → all `Whiteboard_*` calls). Matching tool calls execute LOCALLY via\n * the handler — they are never relayed to the server — and the handler's result JSON is sent\n * back to the model as the `tool_response`. Re-registering the same prefix replaces the\n * handler. The registry is cleared at session teardown.\n */\n public RegisterClientToolHandler(toolNamePrefix: string, handler: RealtimeClientToolHandler): void {\n this.clientToolHandlers.set(toolNamePrefix, handler);\n }\n\n /** Removes the handler registered for `toolNamePrefix` (no-op when none is registered). */\n public UnregisterClientToolHandler(toolNamePrefix: string): void {\n this.clientToolHandlers.delete(toolNamePrefix);\n }\n\n /**\n * Feeds a background context note into the live model (no spoken reply is requested) — the\n * perception channel interactive surfaces use (e.g. the whiteboard's coalesced scene deltas).\n * No-op when no session is live.\n */\n public SendContextNote(text: string): void {\n const trimmed = text?.trim() ?? '';\n if (trimmed.length === 0 || !this.client || !this.isSessionLive()) {\n return;\n }\n this.client.SendContextNote(trimmed);\n }\n\n /**\n * The active client's current audio activity (per-direction RMS levels + spectrum\n * bins), or `null` when no session is live or the driver attached no audio meters.\n * Sampled by the overlay's animation-frame loop to drive the audio-reactive orb/EQ —\n * a cheap analyser read, never provider traffic.\n */\n public GetAudioActivity(): RealtimeAudioActivity | null {\n return this.client?.GetAudioActivity() ?? null;\n }\n\n // ── Interactive channels (registry-driven plugins) ─────────────────────────\n\n /**\n * Resolves, instantiates and initializes the session's interactive-channel plugins from\n * the `MJ: AI Agent Channels` registry, publishes them on {@link ActiveChannels$}, and\n * returns their aggregated client-executed tool declarations for the session mint.\n * Tolerant by design: registry/resolution failures degrade to \"no channels\" — the voice\n * session itself always proceeds.\n */\n private async startChannels(): Promise<RealtimeToolDefinition[]> {\n const channels = await this.loadActiveChannels();\n for (const plugin of channels) {\n this.initializeChannel(plugin);\n }\n this._activeChannels$.next(channels);\n return channels.flatMap(plugin => plugin.GetToolDefinitions());\n }\n\n /**\n * Loads the ACTIVE channel definitions from the registry and resolves each row's\n * `ClientPluginClass` through the MJ ClassFactory into a per-session plugin instance —\n * the client-side mirror of how realtime-model drivers resolve from `BaseRealtimeModel`\n * / `BaseRealtimeClient`. Rows whose plugin class isn't registered are skipped (logged),\n * never fatal.\n */\n private async loadActiveChannels(): Promise<BaseRealtimeChannelClient[]> {\n const rows = await this.fetchChannelDefinitions();\n const channels: BaseRealtimeChannelClient[] = [];\n for (const row of rows) {\n const plugin = this.resolveChannelPlugin(row);\n if (plugin) {\n channels.push(plugin);\n }\n }\n return channels;\n }\n\n /**\n * Reads the ACTIVE `MJ: AI Agent Channels` rows from {@link AIEngineBase}'s cached\n * `AgentChannels` (provider-scoped engine instance, lazy `Config` — no RunView\n * round-trip; the engine's BaseEntity-event reactivity keeps the registry fresh).\n * Failures are logged and degrade to an empty list — channel availability must\n * never block the voice session.\n */\n private async fetchChannelDefinitions(): Promise<RealtimeChannelDefinitionRow[]> {\n try {\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(this.Provider, AIEngineBase) as AIEngineBase;\n await engine.Config(false, undefined, this.Provider);\n return (engine.AgentChannels ?? [])\n .filter(c => c.IsActive)\n .map<RealtimeChannelDefinitionRow>(c => ({ ID: c.ID, Name: c.Name, ClientPluginClass: c.ClientPluginClass }));\n } catch (error) {\n console.warn('[RealtimeSession] Channel registry unavailable — starting with no channels:', error);\n return [];\n }\n }\n\n /**\n * Resolves one registry row's `ClientPluginClass` via the ClassFactory (registration\n * checked first, exactly like the realtime-client drivers) and instantiates a fresh\n * per-session plugin. Returns `null` (logged) when no plugin is registered for the key\n * — e.g. its Load function was never called or the package isn't included client-side.\n */\n private resolveChannelPlugin(row: RealtimeChannelDefinitionRow): BaseRealtimeChannelClient | null {\n const key = row.ClientPluginClass?.trim();\n if (!key) {\n console.warn(`[RealtimeSession] Channel '${row.Name}' has no ClientPluginClass — skipping.`);\n return null;\n }\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(BaseRealtimeChannelClient, key);\n if (!registration) {\n console.warn(`[RealtimeSession] No client plugin registered for channel '${row.Name}' (key '${key}') — skipping.`);\n return null;\n }\n const plugin = MJGlobal.Instance.ClassFactory.CreateInstance<BaseRealtimeChannelClient>(BaseRealtimeChannelClient, key);\n if (!plugin) {\n console.warn(`[RealtimeSession] Failed to instantiate client plugin for channel '${row.Name}' (key '${key}').`);\n return null;\n }\n return plugin;\n }\n\n /**\n * Wires one plugin into the session: hands it its host context and registers its\n * prefix-routed local tool executor (so `<ToolNamePrefix>*` calls run in the browser\n * through {@link BaseRealtimeChannelClient.ApplyAgentTool}, never the server relay).\n */\n private initializeChannel(plugin: BaseRealtimeChannelClient): void {\n plugin.Initialize(this.buildChannelContext(plugin));\n this.RegisterClientToolHandler(plugin.ToolNamePrefix, (toolName, argsJson) => {\n // The agent is ACTING on this channel — surface-discovery signal for the overlay\n // (first activity auto-reveals + focuses the channel tab) before the tool applies.\n this._channelActivity$.next(plugin);\n return plugin.ApplyAgentTool(toolName, argsJson);\n });\n }\n\n /** Builds the host-services context one channel plugin sees (its only line to the session). */\n private buildChannelContext(plugin: BaseRealtimeChannelClient): RealtimeChannelContext {\n // Capture the service in a local so the AgentSessionID getter reads the SERVICE's live\n // field (not the object literal's `this`) every time it's accessed.\n const service = this;\n return {\n AgentName: this.CurrentAgentName,\n SendContextNote: (text: string) => this.SendContextNote(text),\n RequestSpokenResponse: (instructions: string) => this.requestChannelSpokenResponse(instructions),\n RequestSave: (stateJson: string) => this.scheduleChannelSave(plugin.ChannelName, stateJson),\n SaveAsArtifact: (name: string, contentJson: string) => this.saveChannelArtifact(plugin.ChannelName, name, contentJson),\n SetFocusMode: (on: boolean) => this._channelFocus$.next({ Channel: plugin, Focused: on }),\n // Live session id + GraphQL escape hatch for SERVER-BACKED channels (e.g. Remote\n // Browser). `get` so a channel always reads the CURRENT id — it's null at Initialize\n // (the plugin is built before mintSession resolves) and set once the session is live.\n get AgentSessionID(): string | null {\n return service.agentSessionId;\n },\n ExecuteServerAction: <TResult>(query: string, variables: Record<string, JSONValue>) =>\n this.executeChannelServerAction<TResult>(query, variables)\n };\n }\n\n /**\n * Runs a channel-specific GraphQL operation through the live session's provider (the\n * {@link RealtimeChannelContext.ExecuteServerAction} implementation). Best-effort: any\n * transport/server error is logged and resolves to `null` so the calling channel can map\n * the failure to a model-readable result string without `try/catch`.\n */\n private async executeChannelServerAction<TResult>(query: string, variables: Record<string, JSONValue>): Promise<TResult | null> {\n try {\n const result = await this.gql().ExecuteGQL(query, variables);\n return (result as TResult) ?? null;\n } catch (error) {\n console.error('[RealtimeSession] Channel server action failed:', error);\n return null;\n }\n }\n\n /**\n * A channel asked the live model to SPEAK in reaction to channel input (e.g. a widget\n * submission) — routed through the client's spoken-update channel. No-op when the\n * session isn't live; empty instructions are dropped.\n */\n private requestChannelSpokenResponse(instructions: string): void {\n const trimmed = instructions?.trim() ?? '';\n if (trimmed.length === 0 || !this.client || !this.isSessionLive()) {\n return;\n }\n this.client.RequestSpokenUpdate(trimmed);\n }\n\n /**\n * Applies the PRIOR session's saved channel states (resume continuity): parses the\n * server-supplied map and offers each entry to the matching active plugin via\n * {@link BaseRealtimeChannelClient.RestoreState}. Fully tolerant — malformed payloads,\n * unknown channels, and plugin rejections are logged and skipped; the session start is\n * never affected.\n */\n private applyPriorChannelStates(statesJson: string | null | undefined): void {\n if (!statesJson) {\n return;\n }\n let states: Record<string, string>;\n try {\n const parsed: unknown = JSON.parse(statesJson);\n if (parsed === null || typeof parsed !== 'object') {\n return;\n }\n states = parsed as Record<string, string>;\n } catch {\n console.warn('[RealtimeSession] PriorChannelStatesJson was malformed — starting channels fresh');\n return;\n }\n for (const plugin of this._activeChannels$.value) {\n const state = states[plugin.ChannelName];\n if (typeof state === 'string' && state.length > 0) {\n try {\n const restored = plugin.RestoreState(state);\n if (!restored) {\n console.warn(`[RealtimeSession] Channel '${plugin.ChannelName}' declined its prior-session state — starting fresh`);\n }\n } catch (error) {\n console.warn(`[RealtimeSession] Channel '${plugin.ChannelName}' restore threw — starting fresh`, error);\n }\n }\n }\n }\n\n /**\n * Persists a channel's state as a first-class versioned artifact (`MJ: Artifacts`) via the\n * `SaveSessionChannelArtifact` mutation — the channel-context capability behind e.g. the\n * whiteboard's \"Save to artifacts\". Best-effort: returns the created Artifact ID, or null\n * on any failure (logged, never thrown). Uses the live session id, falling back to the\n * teardown-captured one so \"save my board\" works right after the call ends.\n */\n private async saveChannelArtifact(channelName: string, name: string, contentJson: string): Promise<string | null> {\n const sessionId = this.agentSessionId ?? this.lastKnownSessionIdForSaves();\n if (!sessionId || !name.trim() || !contentJson) {\n return null;\n }\n try {\n const result = await this.gql().ExecuteGQL(\n `mutation SaveSessionChannelArtifact($agentSessionId: String!, $channelName: String!, $name: String!, $contentJson: String!) {\n SaveSessionChannelArtifact(agentSessionId: $agentSessionId, channelName: $channelName, name: $name, contentJson: $contentJson) {\n Success\n ErrorMessage\n ArtifactID\n ArtifactVersionID\n }\n }`,\n { agentSessionId: sessionId, channelName, name: name.trim(), contentJson }\n ) as { SaveSessionChannelArtifact?: { Success: boolean; ErrorMessage?: string; ArtifactID?: string } };\n const payload = result?.SaveSessionChannelArtifact;\n if (!payload?.Success) {\n console.warn(`[RealtimeSession] Save-as-artifact failed for '${channelName}': ${payload?.ErrorMessage ?? 'unknown error'}`);\n return null;\n }\n return payload.ArtifactID ?? null;\n } catch (error) {\n console.warn(`[RealtimeSession] Save-as-artifact errored for '${channelName}':`, error);\n return null;\n }\n }\n\n /** Most recent session id captured by the save pipeline (post-teardown saves). */\n private lastKnownSessionIdForSaves(): string | null {\n for (const pending of this.pendingChannelSaves.values()) {\n if (pending.SessionID) {\n return pending.SessionID;\n }\n }\n return null;\n }\n\n /**\n * Schedules the DEBOUNCED state-of-record save for a channel: each request replaces the\n * pending payload (latest state wins) and re-arms the timer; the session id is captured\n * while live so the teardown flush can persist onto the just-closed session.\n */\n private scheduleChannelSave(channelName: string, stateJson: string): void {\n const pending = this.pendingChannelSaves.get(channelName);\n if (pending) {\n clearTimeout(pending.Timer);\n }\n this.pendingChannelSaves.set(channelName, {\n Timer: setTimeout(() => this.flushChannelSave(channelName), RealtimeSessionService.ChannelSaveDebounceMs),\n StateJson: stateJson,\n SessionID: this.agentSessionId ?? pending?.SessionID ?? null\n });\n }\n\n /** Fires one pending channel save (best-effort; {@link SaveChannelState} logs failures). */\n private flushChannelSave(channelName: string): void {\n const pending = this.pendingChannelSaves.get(channelName);\n if (!pending) {\n return;\n }\n this.pendingChannelSaves.delete(channelName);\n clearTimeout(pending.Timer);\n void this.SaveChannelState(channelName, pending.StateJson, pending.SessionID);\n }\n\n /** Final teardown flush: persist every channel's unsaved state immediately. */\n private flushAllChannelSaves(): void {\n for (const channelName of [...this.pendingChannelSaves.keys()]) {\n this.flushChannelSave(channelName);\n }\n }\n\n /** Disposes all channel plugins (errors contained per plugin) and clears the live set. */\n private disposeChannels(): void {\n for (const plugin of this._activeChannels$.value) {\n try {\n plugin.Dispose();\n } catch (error) {\n console.error(`[RealtimeSession] Channel '${plugin.ChannelName}' Dispose failed:`, error);\n }\n }\n if (this._activeChannels$.value.length > 0) {\n this._activeChannels$.next([]);\n }\n }\n\n // ── Realtime client resolution + wiring ────────────────────────────────────\n\n /**\n * Resolves the provider-direct realtime client for `provider` through the MJ\n * ClassFactory — the client-side mirror of how server drivers are resolved from\n * `BaseRealtimeModel`. Throws a clear error when no driver is registered for the\n * provider (e.g. its Load function was never called).\n */\n private createRealtimeClient(provider: string): BaseRealtimeClient {\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(BaseRealtimeClient, provider);\n if (!registration) {\n throw new Error(\n `No realtime client registered for provider '${provider}'. ` +\n `Ensure the provider's client driver package is imported and its Load function called.`\n );\n }\n const client = MJGlobal.Instance.ClassFactory.CreateInstance<BaseRealtimeClient>(BaseRealtimeClient, provider);\n if (!client) {\n throw new Error(`Failed to instantiate the realtime client for provider '${provider}'`);\n }\n return client;\n }\n\n /** Builds the client-direct session config the realtime client connects with. */\n private buildClientConfig(session: StartRealtimeClientSessionResult): ClientRealtimeSessionConfig {\n return {\n Provider: session.Provider,\n Model: session.Model,\n EphemeralToken: session.EphemeralToken,\n ExpiresAt: session.ExpiresAt,\n SessionConfig: this.parseSessionConfig(session.SessionConfigJson)\n };\n }\n\n /**\n * Parses the server-built session config JSON. On failure, logs and returns an empty\n * object — the client treats an empty config as \"nothing to apply\", so the session\n * still opens (mirroring the prior behavior of skipping the config update).\n */\n private parseSessionConfig(sessionConfigJson: string | null): JSONObject {\n if (!sessionConfigJson) {\n return {};\n }\n try {\n return JSON.parse(sessionConfigJson) as JSONObject;\n } catch (error) {\n console.error('[RealtimeSession] Failed to parse/apply SessionConfigJson:', error);\n return {};\n }\n }\n\n /** Subscribes this service's policy handlers to the realtime client's events. */\n private wireClientHandlers(client: BaseRealtimeClient): void {\n client.OnStateChange((state: RealtimeClientState) => this.onClientStateChange(state));\n client.OnTranscript((transcript: RealtimeClientTranscript) => {\n void this.onClientTranscript(transcript);\n });\n client.OnToolCall((call: RealtimeClientToolCall) => {\n void this.handleToolCall(call);\n });\n client.OnError((error: RealtimeClientError) => {\n console.error('[RealtimeSession] Provider error event:', error);\n });\n // Usage telemetry: accumulate the driver's per-response token DELTAS and relay them to\n // the server (onto the co-agent AIPromptRun) debounced + once at teardown. Providers\n // without usage events simply never emit — registering is always safe.\n client.OnUsage((usage: RealtimeClientUsage) => this.onUsageDelta(usage));\n // TRUE BARGE-IN (user input cut off active model output — the driver already stopped\n // the speech): the user took the floor, so any pending/queued progress narration is\n // stale — cancel it; the next progress event re-schedules at the session-global pace.\n // HOST POLICY (deliberate): barge-in does NOT abort in-flight delegated runs — the\n // narration design EXPECTS the user to keep talking while delegated work runs, so\n // killing the work on speech would cancel exactly the jobs the user asked for.\n // Explicit cancellation is a separate, intentional act: the overlay's per-card ✕\n // calls {@link CancelDelegation} (server cancel channel) instead.\n client.OnInterruption(() => {\n this.cancelPendingNarration();\n });\n }\n\n /** Maps a client state event onto the UI connection state. */\n private onClientStateChange(state: RealtimeClientState): void {\n const mapped = this.mapClientState(state);\n if (mapped) {\n this._connectionState$.next(mapped);\n }\n }\n\n /**\n * Translates {@link RealtimeClientState} into {@link VoiceConnectionState}. `'connected'`\n * is suppressed (the UI stays 'connecting' until the control channel opens → 'listening'),\n * and `'closed'` never overwrites a terminal 'error' the service itself recorded.\n */\n private mapClientState(state: RealtimeClientState): VoiceConnectionState | null {\n switch (state) {\n case 'connecting':\n return 'connecting';\n case 'connected':\n return null;\n case 'listening':\n return 'listening';\n case 'speaking':\n return 'speaking';\n case 'error':\n return 'error';\n case 'closed':\n return this._connectionState$.value === 'error' ? null : 'closed';\n }\n }\n\n /** True when the live control channel is usable (open and not torn down / failed). */\n private isSessionLive(): boolean {\n const state = this._connectionState$.value;\n return state === 'listening' || state === 'speaking' || state === 'thinking';\n }\n\n // ── Transcript policy ──────────────────────────────────────────────────────\n\n /**\n * Applies transcript policy to client transcript events. Interim deltas are ignored\n * (the client already drives the speaking state). Final NORMAL assistant turns become\n * captions + persisted transcripts; final NARRATION turns are EPHEMERAL by product\n * decision — emitted on {@link DelegationNarration$} only, never a caption, never\n * relayed/persisted. User turns ride the caption + relay path.\n */\n private async onClientTranscript(transcript: RealtimeClientTranscript): Promise<void> {\n if (!transcript.IsFinal) {\n return;\n }\n if (transcript.Role === 'Assistant') {\n if (transcript.Kind === 'narration') {\n this._delegationNarration$.next({ Text: transcript.Text });\n // Remember what was actually SAID so later updates build on it instead of repeating.\n this.spokenNarrations.push(transcript.Text);\n if (this.spokenNarrations.length > RealtimeSessionService.MaxPriorNarrations) {\n this.spokenNarrations.shift();\n }\n } else if (transcript.ReplacesPrevious) {\n // CORRECTION (e.g. ElevenLabs post-barge-in re-finalization): this final\n // SUPERSEDES the previous final assistant turn — replace the caption in place\n // and tell the server to update the persisted turn instead of appending.\n this.replaceLastCaption('Assistant', transcript.Text);\n await this.relayTranscript('assistant', transcript.Text, true);\n } else {\n this.appendCaption({ Role: 'Assistant', Text: transcript.Text });\n await this.relayTranscript('assistant', transcript.Text);\n }\n } else if (transcript.ReplacesPrevious) {\n // STREAMING user transcription: providers like Grok emit the growing utterance as repeated\n // events (each the full text so far), flagging all but the first ReplacesPrevious. Update the\n // in-place User caption + persisted turn instead of stacking a new bubble per increment — the\n // same correction semantics the assistant branch uses. (OpenAI sends one final → the else path.)\n this.replaceLastCaption('User', transcript.Text);\n await this.relayTranscript('user', transcript.Text, true);\n } else {\n await this.onUserTranscript(transcript.Text);\n }\n }\n\n /**\n * Replaces the LAST caption of `role` in place (correction semantics); falls back to a\n * plain append when no such caption exists yet (e.g. the superseded turn predates this\n * client's caption window).\n */\n private replaceLastCaption(role: 'User' | 'Assistant', text: string): void {\n const captions = this._captions$.value;\n for (let i = captions.length - 1; i >= 0; i--) {\n if (captions[i].Role === role) {\n const next = [...captions];\n next[i] = { Role: role, Text: text };\n this._captions$.next(next);\n return;\n }\n }\n this.appendCaption({ Role: role, Text: text });\n }\n\n /** Finalizes the user turn: push a caption + relay the final transcript. */\n private async onUserTranscript(transcript: string): Promise<void> {\n if (transcript.trim().length === 0) {\n return;\n }\n if (this.firstUserTranscript === null) {\n // First spoken user utterance — the naming seed for a session-created conversation.\n this.firstUserTranscript = transcript;\n }\n this.appendCaption({ Role: 'User', Text: transcript });\n await this.relayTranscript('user', transcript);\n }\n\n // ── Tool calling ───────────────────────────────────────────────────────────\n\n /**\n * Routes a provider tool call: names matching a registered client-tool prefix execute\n * LOCALLY (UI tools — see {@link RegisterClientToolHandler}); everything else executes on\n * the MJ server. Either way the result feeds back to the model via\n * {@link BaseRealtimeClient.SendToolResult} so it speaks the outcome.\n */\n private async handleToolCall(call: RealtimeClientToolCall): Promise<void> {\n const clientHandler = this.findClientToolHandler(call.ToolName);\n if (clientHandler) {\n // Local UI tool: no server relay, no 'thinking' turn-state / narration burst — these\n // are fast, in-browser surface mutations (e.g. drawing on the whiteboard).\n const resultJson = await this.executeClientTool(clientHandler, call);\n this.client?.SendToolResult(call.CallID, resultJson);\n // Observability: record the channel tool call on the co-agent's run (run-only — NOT a chat\n // turn). Without this the run shows speech but never the browser_/Whiteboard_ actions the\n // co-agent took. Fire-and-forget; never disturbs the live surface mutation.\n void this.relayToolTurn(call.ToolName, call.ArgumentsJson, resultJson);\n return;\n }\n this._connectionState$.next('thinking');\n if (this.inFlightCallIds.size === 0) {\n // A fresh delegation burst: anchor the first-update delay and clear the digest\n // buffer. Deliberately NOT reset: lastDelegationNarrationAt (the 8s spacing floor\n // is SESSION-global — sequential tool calls seconds apart must not re-arm the\n // faster first-update path, which read as \"no debounce\") and spokenNarrations\n // (so the story never repeats across closely-spaced calls).\n this.delegationBurstStartedAt = Date.now();\n this.narrationCount = 0;\n this.pendingNarrationMessages = [];\n this.lastNarratedTail = '';\n }\n this.inFlightCallIds.add(call.CallID);\n try {\n const resultJson = await this.executeSessionTool(call.CallID, call.ToolName, call.ArgumentsJson);\n this.emitDelegationResult(call.CallID, resultJson);\n this.client?.SendToolResult(call.CallID, resultJson);\n } catch (error) {\n console.error('[RealtimeSession] Tool execution failed:', error);\n // Feed the error back so the model can narrate it rather than going silent.\n // success:false matters: ParseDelegationResultJson treats anything else as\n // success, which would flip the overlay's working card to a SUCCESS card\n // carrying the error text (matches the server broker's failure shape).\n const errorJson = JSON.stringify({\n success: false,\n error: error instanceof Error ? error.message : String(error)\n });\n this.emitDelegationResult(call.CallID, errorJson);\n this.client?.SendToolResult(call.CallID, errorJson);\n }\n }\n\n /** Finds the registered client-tool handler whose prefix matches `toolName`, or `null`. */\n private findClientToolHandler(toolName: string): RealtimeClientToolHandler | null {\n for (const [prefix, handler] of this.clientToolHandlers) {\n if (toolName.startsWith(prefix)) {\n return handler;\n }\n }\n return null;\n }\n\n /**\n * Executes one client-tool call through its handler, wrapping any thrown error into a\n * `{ success: false, error }` JSON payload so the model can narrate the failure instead of\n * the call going silent.\n */\n private async executeClientTool(handler: RealtimeClientToolHandler, call: RealtimeClientToolCall): Promise<string> {\n try {\n return await handler(call.ToolName, call.ArgumentsJson);\n } catch (error) {\n console.error('[RealtimeSession] Client tool execution failed:', error);\n return JSON.stringify({\n success: false,\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n /**\n * Emits a delegation result so the overlay's \"working\" card flips to a result card with real\n * content. Parses the broker's `{success, output, runId}` | `{success:false, error}` shape via\n * {@link ParseDelegationResultJson}; if it isn't JSON, surfaces the raw string. Only delegation\n * cards (created from progress events) react — non-delegation tool results have no card and are\n * harmlessly ignored downstream. The `runId` (the delegated `MJ: AI Agent Runs` record) rides\n * along as {@link VoiceDelegationResult.RunID} for the overlay's dev links, and any `artifacts`\n * ride along as {@link VoiceDelegationResult.Artifacts} for the surface panel's artifact tabs.\n */\n private emitDelegationResult(callId: string, resultJson: string): void {\n // The result will be spoken next — a deferred interim update is now pointless\n // (this is what keeps fast agents like Sage from narrating over their own answer),\n // and any progress still in the PubSub pipe for this call is stale.\n this.inFlightCallIds.delete(callId);\n this.cancelPendingNarration();\n if (this.cancelledCallIds.delete(callId)) {\n // The user explicitly cancelled this call: its card already flipped to the\n // \"Cancelled by user\" failed result, so the aborted run's late outcome must not\n // overwrite it. (The tool result still flows back to the model via the caller.)\n return;\n }\n const parsed = ParseDelegationResultJson(resultJson);\n this._delegationResult$.next({\n CallID: callId,\n Success: parsed.Success,\n Output: parsed.Output,\n RunID: parsed.RunID,\n Artifacts: parsed.Artifacts\n });\n }\n\n // ── Explicit delegation cancellation (server cancel channel) ───────────────\n\n /**\n * Cancels ONE in-flight delegated tool call — the overlay's per-card ✕ affordance.\n *\n * EXPLICIT USER INTENT ONLY (deliberate host policy): true barge-in never aborts\n * delegations — the narration design expects the user to talk while delegated work runs.\n * Calls the `CancelRealtimeSessionTool` mutation (ownership-gated server-side); when the\n * server reports it aborted the run, the card is flipped immediately to a FAILED\n * \"Cancelled by user\" result and the eventual late result from the aborted run is\n * suppressed (see {@link emitDelegationResult}).\n *\n * @returns `true` when the server aborted the in-flight run; `false` when there was\n * nothing to cancel (the work finished first — its real result is already racing in)\n * or the mutation failed (logged, never thrown).\n */\n public async CancelDelegation(callId: string): Promise<boolean> {\n if (!this.agentSessionId || !this.inFlightCallIds.has(callId)) {\n return false;\n }\n const aborted = await this.cancelSessionTool(callId);\n if (aborted <= 0) {\n return false; // finished first / nothing in flight server-side — let the real result land\n }\n this.surfaceUserCancellation(callId);\n return true;\n }\n\n /**\n * Cancels EVERY in-flight delegated tool call for the active session (callId-less form of\n * the `CancelRealtimeSessionTool` mutation). Exposed for host policies that need a\n * sweep-cancel (e.g. an explicit \"stop everything\" affordance) — NOT wired to barge-in,\n * by the same deliberate policy as {@link CancelDelegation}.\n *\n * @returns The number of in-flight runs the server aborted (0 when nothing was tracked\n * in flight client-side, nothing was in flight server-side, or the mutation failed).\n */\n public async CancelInFlightDelegations(): Promise<number> {\n if (!this.agentSessionId || this.inFlightCallIds.size === 0) {\n return 0;\n }\n const aborted = await this.cancelSessionTool(null);\n if (aborted <= 0) {\n return 0;\n }\n for (const callId of [...this.inFlightCallIds]) {\n this.surfaceUserCancellation(callId);\n }\n return aborted;\n }\n\n /** Flips a cancelled call's card to the failed \"Cancelled by user\" result and suppresses the late real result. */\n private surfaceUserCancellation(callId: string): void {\n this.inFlightCallIds.delete(callId);\n this.cancelledCallIds.add(callId);\n this.cancelPendingNarration();\n this._delegationResult$.next({\n CallID: callId,\n Success: false,\n Output: 'Cancelled by user'\n });\n }\n\n /**\n * Calls the `CancelRealtimeSessionTool` mutation and unwraps its structured\n * `{ AbortedCount, Success, ErrorMessage }` result. Returns the aborted count —\n * 0 on a structured failure or a thrown transport error (both logged, never thrown).\n */\n private async cancelSessionTool(callId: string | null): Promise<number> {\n try {\n const mutation = `\n mutation CancelRealtimeSessionTool($agentSessionId: String!, $callId: String) {\n CancelRealtimeSessionTool(agentSessionId: $agentSessionId, callId: $callId) {\n AbortedCount\n Success\n ErrorMessage\n }\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, { agentSessionId: this.agentSessionId, callId });\n const payload = result?.CancelRealtimeSessionTool as\n | { AbortedCount?: number; Success?: boolean; ErrorMessage?: string }\n | undefined;\n if (!payload?.Success) {\n console.warn(`[RealtimeSession] Cancel reported failure: ${payload?.ErrorMessage ?? 'unknown error'}`);\n return 0;\n }\n return typeof payload.AbortedCount === 'number' ? payload.AbortedCount : 0;\n } catch (error) {\n console.error('[RealtimeSession] Failed to cancel in-flight delegation(s):', error);\n return 0;\n }\n }\n\n // ── Session minting (GraphQL) ──────────────────────────────────────────────\n\n /** Calls the `StartRealtimeClientSession` mutation to obtain an ephemeral token + config. */\n private async mintSession(\n targetAgentId: string,\n conversationId?: string | null,\n lastSessionId?: string | null,\n preferredModelId?: string | null,\n clientTools?: RealtimeToolDefinition[] | null,\n coAgentId?: string | null,\n configOverridesJson?: string | null\n ): Promise<StartRealtimeClientSessionResult> {\n const mutation = `\n mutation StartRealtimeClientSession($targetAgentId: String!, $conversationId: String, $lastSessionId: String, $preferredModelId: String, $clientToolsJson: String, $coAgentId: String, $configOverridesJson: String) {\n StartRealtimeClientSession(targetAgentId: $targetAgentId, conversationId: $conversationId, lastSessionId: $lastSessionId, preferredModelId: $preferredModelId, clientToolsJson: $clientToolsJson, coAgentId: $coAgentId, configOverridesJson: $configOverridesJson) {\n AgentSessionId\n ConversationId\n Provider\n Model\n EphemeralToken\n ExpiresAt\n SessionConfigJson\n ModelName\n NarrationInstructionsTemplate\n PriorChannelStatesJson\n }\n }\n `;\n const variables = {\n targetAgentId,\n conversationId: conversationId ?? null,\n lastSessionId: lastSessionId ?? null,\n preferredModelId: preferredModelId ?? null,\n clientToolsJson: clientTools && clientTools.length > 0 ? JSON.stringify(clientTools) : null,\n coAgentId: coAgentId ?? null,\n configOverridesJson: configOverridesJson ?? null\n };\n const result = await this.gql().ExecuteGQL(mutation, variables);\n const payload = result?.StartRealtimeClientSession as StartRealtimeClientSessionResult | undefined;\n if (!payload?.EphemeralToken) {\n throw new Error('StartRealtimeClientSession returned no ephemeral token');\n }\n return payload;\n }\n\n /** Calls the `ExecuteRealtimeSessionTool` mutation; returns the ResultJson string. */\n private async executeSessionTool(callId: string, toolName: string, argsJson: string): Promise<string> {\n if (!this.agentSessionId) {\n throw new Error('No active agent session for tool execution');\n }\n const mutation = `\n mutation ExecuteRealtimeSessionTool($agentSessionId: String!, $callId: String!, $toolName: String!, $argsJson: String!) {\n ExecuteRealtimeSessionTool(agentSessionId: $agentSessionId, callId: $callId, toolName: $toolName, argsJson: $argsJson)\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n callId,\n toolName,\n argsJson\n });\n return (result?.ExecuteRealtimeSessionTool as string) ?? '{}';\n }\n\n /**\n * Persists an interactive channel's state of record (e.g. the whiteboard's serialized scene)\n * onto the session's `MJ: AI Agent Session Channels` row via `SaveSessionChannelState`.\n *\n * @param channelName The channel definition name (e.g. `'Whiteboard'`).\n * @param stateJson The serialized channel state.\n * @param agentSessionId Optional EXPLICIT session id. The debounced channel-save pipeline\n * captures the id while the session is live and passes it here, so the final teardown\n * flush still lands on the just-closed session. Falls back to the active session's id;\n * returns `false` when neither is available.\n * @returns Whether the server persisted the state. Failures are logged, never thrown — channel\n * persistence is best-effort and must not disturb the live call.\n */\n public async SaveChannelState(channelName: string, stateJson: string, agentSessionId?: string | null): Promise<boolean> {\n const sessionId = agentSessionId ?? this.agentSessionId;\n if (!sessionId) {\n return false;\n }\n try {\n const mutation = `\n mutation SaveSessionChannelState($agentSessionId: String!, $channelName: String!, $stateJson: String!) {\n SaveSessionChannelState(agentSessionId: $agentSessionId, channelName: $channelName, stateJson: $stateJson)\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, { agentSessionId: sessionId, channelName, stateJson });\n return (result?.SaveSessionChannelState as boolean) ?? false;\n } catch (error) {\n console.error('[RealtimeSession] Failed to save channel state:', error);\n return false;\n }\n }\n\n // ── Transcript relay (GraphQL) ─────────────────────────────────────────────\n\n /**\n * Relays a final transcript turn to MJ via `RelayRealtimeTranscript`.\n * @param replacesPrevious CORRECTION semantics: the server updates the session's most\n * recent persisted turn of this role IN PLACE instead of appending (e.g. ElevenLabs'\n * post-barge-in `agent_response_correction`).\n */\n private async relayTranscript(role: 'user' | 'assistant', text: string, replacesPrevious: boolean = false): Promise<void> {\n if (!this.agentSessionId) {\n return;\n }\n try {\n const mutation = `\n mutation RelayRealtimeTranscript($agentSessionId: String!, $role: String!, $text: String!, $replacesPrevious: Boolean) {\n RelayRealtimeTranscript(agentSessionId: $agentSessionId, role: $role, text: $text, replacesPrevious: $replacesPrevious)\n }\n `;\n await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n role,\n text,\n replacesPrevious\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay transcript:', error);\n }\n }\n\n /**\n * Relays a co-agent CHANNEL tool-call turn (browser_ / Whiteboard_ etc.) to the session's run for\n * observability via `RelayRealtimeToolTurn` — so the co-agent's AIPromptRun shows what it DID, not\n * just what it said. Run-only by design: deliberately NOT a `ConversationDetail` turn, so the chat\n * thread stays speech-only. Best-effort — a failed relay never disturbs the live call.\n */\n private async relayToolTurn(toolName: string, argsJson: string, resultJson: string): Promise<void> {\n if (!this.agentSessionId) {\n return;\n }\n try {\n const mutation = `\n mutation RelayRealtimeToolTurn($agentSessionId: String!, $toolName: String!, $argsJson: String, $resultJson: String) {\n RelayRealtimeToolTurn(agentSessionId: $agentSessionId, toolName: $toolName, argsJson: $argsJson, resultJson: $resultJson)\n }\n `;\n await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n toolName,\n argsJson,\n resultJson\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay tool turn:', error);\n }\n }\n\n // ── Usage telemetry relay (B7) ─────────────────────────────────────────────\n\n /**\n * Accumulates one usage DELTA from the realtime client (per-response token counts —\n * the `OnUsage` contract shape) and schedules the debounced relay. Negative / non-finite\n * values are clamped to 0; an all-zero delta is dropped without arming the timer.\n */\n private onUsageDelta(usage: RealtimeClientUsage): void {\n const input = this.clampUsageDelta(usage.InputTokens);\n const output = this.clampUsageDelta(usage.OutputTokens);\n if (input === 0 && output === 0) {\n return;\n }\n this.pendingUsageInput += input;\n this.pendingUsageOutput += output;\n if (!this.usageFlushTimer) {\n this.usageFlushTimer = setTimeout(() => {\n this.usageFlushTimer = null;\n void this.flushPendingUsage();\n }, RealtimeSessionService.UsageFlushDebounceMs);\n }\n }\n\n /** Clamps a driver-reported token delta: undefined / negative / non-finite become 0. */\n private clampUsageDelta(value: number | undefined): number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;\n }\n\n /**\n * Relays the accumulated usage deltas to the server via `RelayRealtimeUsage` (which\n * accumulates them onto the co-agent `AIPromptRun`). Best-effort: a failed relay\n * re-accumulates the captured deltas so the next debounce / teardown flush retries —\n * usage telemetry must never disturb the live call.\n *\n * @param agentSessionId Optional EXPLICIT session id (the teardown flush runs while the\n * live id is still set, but accepts it as a parameter for symmetry with channel saves).\n */\n private async flushPendingUsage(agentSessionId?: string | null): Promise<void> {\n const sessionId = agentSessionId ?? this.agentSessionId;\n const input = this.pendingUsageInput;\n const output = this.pendingUsageOutput;\n if (!sessionId || (input === 0 && output === 0)) {\n return;\n }\n this.pendingUsageInput = 0;\n this.pendingUsageOutput = 0;\n try {\n const mutation = `\n mutation RelayRealtimeUsage($agentSessionId: String!, $inputTokens: Int!, $outputTokens: Int!) {\n RelayRealtimeUsage(agentSessionId: $agentSessionId, inputTokens: $inputTokens, outputTokens: $outputTokens)\n }\n `;\n await this.gql().ExecuteGQL(mutation, { agentSessionId: sessionId, inputTokens: input, outputTokens: output });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay usage telemetry:', error);\n // Re-accumulate so a later debounce / the teardown flush retries the same deltas.\n this.pendingUsageInput += input;\n this.pendingUsageOutput += output;\n }\n }\n\n /** Cancels the pending debounced usage flush and zeroes the accumulators (teardown tail). */\n private resetUsageRelay(): void {\n if (this.usageFlushTimer) {\n clearTimeout(this.usageFlushTimer);\n this.usageFlushTimer = null;\n }\n this.pendingUsageInput = 0;\n this.pendingUsageOutput = 0;\n }\n\n // ── Delegated-run progress streaming ───────────────────────────────────────\n\n /**\n * Subscribes to the server's push-status topic (scoped by the GraphQL transport\n * sessionId) to receive delegated-run progress for the active voice session.\n * Each matching event is surfaced on {@link DelegationProgress$} and narrated.\n */\n private subscribeDelegationProgress(): void {\n if (this.delegationProgressSub) {\n return; // already subscribed for this session\n }\n const transportSessionId = this.gql().sessionId;\n this.lastDelegationNarrationAt = 0;\n this.delegationProgressSub = this.gql()\n .PushStatusUpdates(transportSessionId)\n .subscribe({\n next: (raw: string) => this.onDelegationStatusMessage(raw),\n error: (err: unknown) => console.error('[RealtimeSession] Delegation progress stream error:', err)\n });\n }\n\n /**\n * Parses one push-status message and routes it: a Remote Browser screencast frame goes to the active\n * Remote Browser channel's canvas; a delegation-progress event is dispatched + narrated. Other shapes\n * (normal agent-run streams) are ignored. Screencast frames are checked FIRST and short-circuit, so the\n * delegation path is untouched.\n */\n private onDelegationStatusMessage(raw: string): void {\n const frame = this.parseScreencastFrame(raw);\n if (frame) {\n this.routeScreencastFrame(frame);\n return;\n }\n const audio = this.parseAudioChunk(raw);\n if (audio) {\n this.routeAudioChunk(audio);\n return;\n }\n const progress = this.parseProgress(raw);\n if (progress) {\n this.dispatchProgress(progress);\n }\n }\n\n /**\n * Parses a push-status message and returns it only when it's a Remote Browser screencast frame for the\n * active session — otherwise `null` (ignored, so delegation progress falls through). Matched by\n * `resolver` + `type`, then scoped to THIS session by `agentSessionID`.\n */\n private parseScreencastFrame(raw: string): RemoteBrowserScreencastPayload | null {\n let payload: { resolver?: string } & Partial<RemoteBrowserScreencastPayload>;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n const matches =\n payload?.resolver === 'RemoteBrowserActionResolver' &&\n payload?.type === 'RemoteBrowserScreencastFrame' &&\n payload?.agentSessionID === this.agentSessionId &&\n typeof payload?.dataBase64 === 'string';\n return matches ? (payload as RemoteBrowserScreencastPayload) : null;\n }\n\n /**\n * Forwards a screencast frame to the active Remote Browser channel plugin so it paints the frame on its\n * surface canvas. The plugin is found among the session's active channels by its `ChannelName`; located\n * via a structural guard so the service stays decoupled from the concrete channel class.\n */\n private routeScreencastFrame(frame: RemoteBrowserScreencastPayload): void {\n for (const channel of this._activeChannels$.value) {\n if (channel.ChannelName === 'Remote Browser' && this.hasOnScreencastFrame(channel)) {\n channel.OnScreencastFrame(frame.dataBase64);\n return;\n }\n }\n }\n\n /** Structural guard: true when the channel exposes an `OnScreencastFrame(dataBase64)` method. */\n private hasOnScreencastFrame(\n channel: BaseRealtimeChannelClient,\n ): channel is BaseRealtimeChannelClient & { OnScreencastFrame(dataBase64: string): void } {\n return typeof (channel as { OnScreencastFrame?: unknown }).OnScreencastFrame === 'function';\n }\n\n /**\n * Parses a push-status message and returns it only when it's a Remote Browser audio chunk for the active\n * session — otherwise `null` (ignored). Matched by `resolver` + `type`, then scoped to THIS session by\n * `agentSessionID`.\n */\n private parseAudioChunk(raw: string): RemoteBrowserAudioChunkPayload | null {\n let payload: { resolver?: string } & Partial<RemoteBrowserAudioChunkPayload>;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n const matches =\n payload?.resolver === 'RemoteBrowserActionResolver' &&\n payload?.type === 'RemoteBrowserAudioChunk' &&\n payload?.agentSessionID === this.agentSessionId &&\n typeof payload?.dataBase64 === 'string';\n return matches ? (payload as RemoteBrowserAudioChunkPayload) : null;\n }\n\n /**\n * Forwards an audio chunk to the active Remote Browser channel plugin so it plays the chunk through its\n * client-side audio player. The plugin is found among the session's active channels by its `ChannelName`;\n * located via a structural guard so the service stays decoupled from the concrete channel class.\n */\n private routeAudioChunk(chunk: RemoteBrowserAudioChunkPayload): void {\n for (const channel of this._activeChannels$.value) {\n if (channel.ChannelName === 'Remote Browser' && this.hasOnAudioChunk(channel)) {\n channel.OnAudioChunk({\n dataBase64: chunk.dataBase64,\n codec: chunk.codec,\n sampleRate: chunk.sampleRate,\n channels: chunk.channels,\n seq: chunk.seq,\n });\n return;\n }\n }\n }\n\n /** Structural guard: true when the channel exposes an `OnAudioChunk(chunk)` method. */\n private hasOnAudioChunk(\n channel: BaseRealtimeChannelClient,\n ): channel is BaseRealtimeChannelClient & { OnAudioChunk(chunk: { dataBase64: string; codec: string; sampleRate: number; channels: number; seq: number }): void } {\n return typeof (channel as { OnAudioChunk?: unknown }).OnAudioChunk === 'function';\n }\n\n /**\n * Parses a push-status message and returns it only when it's a delegation\n * progress event for the active voice session — otherwise `null` (ignored).\n */\n private parseProgress(raw: string): VoiceDelegationProgress | null {\n let payload: RealtimeDelegationProgressPayload;\n try {\n payload = JSON.parse(raw) as RealtimeDelegationProgressPayload;\n } catch {\n return null; // non-JSON or unrelated frame\n }\n const matches =\n payload?.resolver === 'RealtimeClientSessionResolver' &&\n payload?.type === 'RealtimeDelegationProgress' &&\n payload?.agentSessionID === this.agentSessionId;\n if (!matches) {\n return null;\n }\n return {\n CallID: payload.callID,\n Step: payload.step,\n Message: payload.message,\n Percentage: payload.percentage\n };\n }\n\n /** Emits the progress to the UI observable and feeds it to the realtime model. */\n private dispatchProgress(progress: VoiceDelegationProgress): void {\n // Drop stale progress: PubSub delivery can lag the mutation result, so events for a\n // call that already completed (or was never seen) must not update cards or narrate.\n if (!this.inFlightCallIds.has(progress.CallID)) {\n return;\n }\n this._delegationProgress$.next(progress);\n this.narrateProgress(progress);\n }\n\n /**\n * Injects the progress into the model's context as a background note every time,\n * then (throttled) asks the model to briefly voice a reassuring update so the\n * background work doesn't sit in silence — without chattering or interrupting.\n */\n private narrateProgress(progress: VoiceDelegationProgress): void {\n const client = this.client;\n if (!client) {\n return;\n }\n client.SendContextNote(`[delegated-agent progress] ${progress.Message}`);\n // Floods of small updates AGGREGATE: each distinct message joins the digest buffer,\n // and ONE spoken update fires per window (first at ~5s into the burst, then every\n // ~8s). The buffer is discarded if the final result lands first.\n this.bufferNarrationMessage(progress.Message);\n if (this.pendingNarrationMessages.length > 0 && !this.narrationTimer) {\n this.narrationTimer = setTimeout(() => this.fireDeferredNarration(), this.nextNarrationDelayMs());\n }\n }\n\n /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */\n private bufferNarrationMessage(message: string): void {\n if (message === this.lastNarratedTail || this.pendingNarrationMessages.includes(message)) {\n return;\n }\n this.pendingNarrationMessages.push(message);\n if (this.pendingNarrationMessages.length > RealtimeSessionService.MaxDigestMessages) {\n this.pendingNarrationMessages.shift();\n }\n }\n\n /**\n * ms until the next spoken update is allowed. Two constraints, BOTH enforced:\n * - first update of a burst: no earlier than ~5s after the burst started;\n * - ~8s since the last spoken update, SESSION-global — so sequential tool calls\n * that reset the burst can never narrate faster than the interval.\n */\n private nextNarrationDelayMs(): number {\n const now = Date.now();\n const firstAnchor = this.narrationCount === 0\n ? this.delegationBurstStartedAt + RealtimeSessionService.FirstNarrationDelayMs\n : 0;\n const spacingFloor = this.lastDelegationNarrationAt > 0\n ? this.lastDelegationNarrationAt + RealtimeSessionService.NarrationIntervalMs\n : 0;\n return Math.max(250, Math.max(firstAnchor, spacingFloor) - now);\n }\n\n /**\n * Speaks the aggregated progress digest — unless the work already finished (buffer\n * cancelled) or the model is busy / audio is still playing, in which case it retries\n * shortly with the buffer intact (work is still running, so the update stays relevant).\n */\n private fireDeferredNarration(): void {\n this.narrationTimer = null;\n const client = this.client;\n if (this.pendingNarrationMessages.length === 0 || !client || this.inFlightCallIds.size === 0) {\n this.pendingNarrationMessages = [];\n return;\n }\n if (client.IsBusy || client.IsAudioPlaying) {\n this.narrationTimer = setTimeout(() => this.fireDeferredNarration(), RealtimeSessionService.NarrationBusyRetryMs);\n return;\n }\n const digest = this.pendingNarrationMessages.join(' → ');\n this.lastNarratedTail = this.pendingNarrationMessages[this.pendingNarrationMessages.length - 1];\n this.pendingNarrationMessages = [];\n this.narrationCount++;\n this.lastDelegationNarrationAt = Date.now();\n client.RequestSpokenUpdate(this.buildNarrationInstructions(digest));\n }\n\n /** Cancels any deferred narration — the result is about to be spoken, so it's moot. */\n private cancelPendingNarration(): void {\n if (this.narrationTimer) {\n clearTimeout(this.narrationTimer);\n this.narrationTimer = null;\n }\n this.pendingNarrationMessages = [];\n }\n\n /**\n * Builds the one-off instructions for a short spoken update that conveys THIS specific\n * progress message naturally — strictly first person, since the co-agent owns the work.\n * The wording is DB-driven: the server-resolved `Realtime Co-Agent - Progress Narration`\n * template (substituting `{{ progressMessage }}`) when present, otherwise the built-in\n * fallback so deployments that haven't synced the prompt behave exactly as before.\n * The client tags the resulting turn as narration, keeping it EPHEMERAL — surfaced on\n * {@link DelegationNarration$} instead of becoming a caption / persisted ConversationDetail.\n */\n private buildNarrationInstructions(digest: string): string {\n return BuildNarrationInstructions(this.narrationTemplate, digest, {\n PriorNarrations: this.spokenNarrations.slice(-RealtimeSessionService.MaxPriorNarrations),\n UpdateNumber: this.narrationCount\n });\n }\n\n /** Tears down the delegation progress subscription and resets the narration throttle. */\n private teardownDelegationProgress(): void {\n if (this.delegationProgressSub) {\n this.delegationProgressSub.unsubscribe();\n this.delegationProgressSub = null;\n }\n this.cancelPendingNarration();\n this.inFlightCallIds.clear();\n this.cancelledCallIds.clear();\n this.lastDelegationNarrationAt = 0;\n this.delegationBurstStartedAt = 0;\n this.narrationCount = 0;\n this.spokenNarrations = [];\n this.lastNarratedTail = '';\n }\n\n // ── Teardown ───────────────────────────────────────────────────────────────\n\n /**\n * Tears down all client resources and (optionally) closes the server session.\n * @param closeServerSession when true, calls `CloseAgentSession` on the server.\n */\n private async teardown(closeServerSession: boolean): Promise<void> {\n this.teardownDelegationProgress();\n\n // Channels first: flush any unsaved channel state WHILE the live session id is still\n // set (the captured per-save id covers the race anyway), then dispose the plugins.\n this.flushAllChannelSaves();\n this.disposeChannels();\n\n // Defensive: stop the mic even when Connect never ran (the client also stops the\n // tracks it was handed — track.stop() is idempotent).\n this.localStream?.getTracks().forEach(t => t.stop());\n this.localStream = null;\n\n if (this.client) {\n await this.client.Disconnect();\n this.client = null;\n }\n\n // Final usage flush WHILE the live session id is still set (the relay mutation also\n // accepts a Closed session, so ordering vs. CloseAgentSession is belt-and-braces).\n if (this.usageFlushTimer) {\n clearTimeout(this.usageFlushTimer);\n this.usageFlushTimer = null;\n }\n await this.flushPendingUsage(this.agentSessionId);\n this.resetUsageRelay();\n\n if (closeServerSession && this.agentSessionId) {\n await this.closeServerSession(this.agentSessionId);\n }\n\n // Capture the session id BEFORE we null it so the lifecycle emit carries it.\n // Skip emitting when there was no live session (defensive — teardown is safe\n // to call without an active session).\n const closedSessionId = this.agentSessionId;\n this.agentSessionId = null;\n this.narrationTemplate = null;\n this.clientToolHandlers.clear();\n this._modelName$.next(null);\n this.SetMinimized(false);\n this._active$.next(false);\n if (this._connectionState$.value !== 'error') {\n this._connectionState$.next('closed');\n }\n\n // Surface generic session-ended for the conversations runtime bridge.\n // `closeServerSession=true` means the user explicitly called EndVoiceSession;\n // `false` means teardown ran from a catch block (start path error path).\n if (closedSessionId) {\n this._sessionEnded$.next({\n sessionId: closedSessionId,\n reason: closeServerSession ? 'explicit' : 'error',\n });\n }\n }\n\n /** Calls the `CloseAgentSession` mutation (provisioned in P4b). */\n private async closeServerSession(agentSessionId: string): Promise<void> {\n try {\n const mutation = `\n mutation CloseAgentSession($agentSessionId: String!) {\n CloseAgentSession(agentSessionId: $agentSessionId)\n }\n `;\n await this.gql().ExecuteGQL(mutation, { agentSessionId });\n } catch (error) {\n console.error('[RealtimeSession] Failed to close server session:', error);\n }\n }\n\n // ── Helpers ────────────────────────────────────────────────────────────────\n\n /** Pushes a caption onto the live list (immutable update for change detection). */\n private appendCaption(caption: VoiceCaption): void {\n this._captions$.next([...this._captions$.value, caption]);\n }\n\n /** Resets reactive + internal state at the start of a session. */\n private resetState(): void {\n this._captions$.next([]);\n this.SetMinimized(false);\n }\n\n /** The GraphQL provider used for relay mutations. */\n private gql(): GraphQLDataProvider {\n return this.Provider as GraphQLDataProvider;\n }\n}\n"]}
1
+ {"version":3,"file":"realtime-session.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';\nimport { Metadata, IMetadataProvider } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';\nimport { MJGlobal } from '@memberjunction/global';\nimport { ClientRealtimeSessionConfig, JSONObject, JSONValue, RealtimeToolDefinition } from '@memberjunction/ai';\nimport { AppContextSnapshot } from '@memberjunction/ai-core-plus';\nimport {\n BaseRealtimeClient,\n LoadAssemblyAIRealtimeClient,\n LoadElevenLabsRealtimeClient,\n LoadGeminiRealtimeClient,\n LoadOpenAIRealtimeClient,\n LoadxAIRealtimeClient,\n RealtimeAudioActivity,\n RealtimeClientError,\n RealtimeClientState,\n RealtimeClientToolCall,\n RealtimeClientTranscript,\n RealtimeClientUsage\n} from '@memberjunction/ai-realtime-client';\nimport { BuildNarrationInstructions } from './narration-template';\nimport { ParseDelegationResultJson, ParsedDelegationArtifact } from './delegation-result-parser';\nimport { BaseRealtimeChannelClient, RealtimeChannelContext } from '../components/realtime/channels/base-realtime-channel-client';\nimport { RealtimeAudioRecorder } from './realtime-audio-recorder';\n\n/**\n * `MJ: User Settings` key for the per-user \"record this voice call\" consent toggle. Stored as\n * the literal string `'true'`/`'false'` (read with `=== 'true'`), cross-device via\n * {@link UserInfoEngine}. The pre-call picker writes it; the session service reads it as the\n * default when the caller doesn't pass an explicit consent value.\n */\nexport const REALTIME_RECORDING_CONSENT_KEY = 'mj.realtimeVoice.recordingConsent.v1';\n\n// Tree-shaking prevention: the OpenAI client is resolved dynamically through the\n// ClassFactory (by the server-reported Provider key), so this static call is what keeps\n// its @RegisterClass side effect from being eliminated by the bundler.\n// NOTE: the interactive-channel plugins (resolved dynamically from the `MJ: AI Agent\n// Channels` registry by ClientPluginClass key) get the same treatment, but their Load\n// calls live in `conversations.module.ts` — plugins carry Angular surface COMPONENTS,\n// and this service stays component-free (it must stay importable in plain-node tests).\nLoadOpenAIRealtimeClient();\nLoadGeminiRealtimeClient();\nLoadElevenLabsRealtimeClient();\nLoadAssemblyAIRealtimeClient();\nLoadxAIRealtimeClient();\n\n/**\n * Connection / turn state for a real-time voice session, surfaced to the UI overlay.\n * - `connecting` — negotiating the session + provider handshake\n * - `listening` — connected, mic open, waiting for / hearing the user\n * - `speaking` — the agent is producing audio\n * - `thinking` — the agent delegated work (tool call) and is waiting on a result\n * - `error` — a fatal error occurred; the session is no longer usable\n * - `closed` — the session has been torn down\n */\nexport type RealtimeConnectionState =\n | 'connecting'\n | 'listening'\n | 'speaking'\n | 'thinking'\n | 'error'\n | 'closed';\n\n/** A single caption line (one side of the conversation) shown in the live-captions list. */\nexport interface RealtimeCaption {\n Role: 'User' | 'Assistant';\n Text: string;\n}\n\n/**\n * A delegated-run progress update surfaced to the UI, emitted on {@link RealtimeSessionService.DelegationProgress$}.\n * These originate server-side during an `invoke-target-agent` delegation (e.g. while Sage works) and let a\n * future overlay render a \"working\" card while the realtime model narrates the same progress aloud.\n */\nexport interface RealtimeDelegationProgress {\n /** The `invoke-target-agent` call this progress belongs to. */\n CallID: string;\n /** The delegation phase: `prompt_execution` | `action_execution` | `subagent_execution` | `decision_processing`. */\n Step: string;\n /** Human-readable progress message. */\n Message: string;\n /** Optional completion percentage (0–100) when the server can estimate it. */\n Percentage?: number;\n}\n\n/**\n * The terminal result of a delegated tool call, emitted on {@link RealtimeSessionService.DelegationResult$}\n * when the delegation finishes so the overlay can flip the \"working\" card into a result card with real\n * content + provenance.\n */\nexport interface RealtimeDelegationResult {\n /** The `invoke-target-agent` call this result belongs to. */\n CallID: string;\n /** Whether the delegated work succeeded. */\n Success: boolean;\n /** The result text — the agent's output, or an error message on failure. */\n Output: string;\n /**\n * ID of the delegated agent run (`MJ: AI Agent Runs`) when the server reported one\n * (`runId` in the tool ResultJson). Powers the overlay's gear-gated \"Open run\" dev link.\n */\n RunID?: string;\n /**\n * Artifacts the delegated run produced, when the server reported any (`artifacts` in the\n * tool ResultJson). The overlay's tabbed surface panel auto-opens one artifact tab per\n * entry and focuses the newest on arrival.\n */\n Artifacts?: ParsedDelegationArtifact[];\n}\n\n/**\n * Handler for a CLIENT-EXECUTED UI tool (e.g. the live whiteboard's `Whiteboard_*` surface),\n * registered via {@link RealtimeSessionService.RegisterClientToolHandler}. Receives the tool name +\n * raw arguments JSON from the realtime model and returns the result JSON string fed back as the\n * `tool_response`. May be sync or async; thrown errors are wrapped into a\n * `{ success: false, error }` payload by the service so the model can narrate the failure.\n */\nexport type RealtimeClientToolHandler = (toolName: string, argsJson: string) => string | Promise<string>;\n\n/**\n * A channel's request to enter / leave the FOCUS layout, emitted on\n * {@link RealtimeSessionService.ChannelFocus$} when a plugin calls its context's\n * `SetFocusMode`. The overlay shell subscribes: it collapses/restores the main call column\n * and remembers which channel holds focus (so the floating pill's \"exit\" can be routed\n * back via {@link BaseRealtimeChannelClient.RequestFocusExit}).\n */\nexport interface RealtimeChannelFocusEvent {\n /** The channel plugin requesting the layout change. */\n Channel: BaseRealtimeChannelClient;\n /** `true` to enter focus mode (surface owns the screen), `false` to leave it. */\n Focused: boolean;\n}\n\n/**\n * The narrow projection of an ACTIVE `MJ: AI Agent Channels` registry row the service\n * reads at session start from {@link AIEngineBase}'s cached `AgentChannels`.\n */\ninterface RealtimeChannelDefinitionRow {\n ID: string;\n Name: string;\n ClientPluginClass: string;\n}\n\n/**\n * One EPHEMERAL spoken narration of delegated-run progress, emitted on\n * {@link RealtimeSessionService.DelegationNarration$}. These are the interim \"here's what's\n * happening\" utterances the realtime model speaks while a delegation runs. By product\n * decision they are NOT captions and NOT persisted as ConversationDetails — they exist\n * only as a live note in the overlay, replaced by each newer narration.\n */\nexport interface RealtimeDelegationNarration {\n /** The narration transcript text. */\n Text: string;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic during a delegated run.\n * We filter on `resolver` + `type` before correlating by `agentSessionID`; normal agent runs publish\n * other shapes on the same topic and are ignored.\n */\ninterface RealtimeDelegationProgressPayload {\n resolver: string;\n type: string;\n agentSessionID: string;\n callID: string;\n step: string;\n message: string;\n percentage?: number;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic for each live Remote\n * Browser screencast frame (mirrors {@link RealtimeDelegationProgressPayload}, distinguished by\n * `resolver` + `type`). Routed to the active Remote Browser channel plugin — never narrated.\n */\ninterface RemoteBrowserScreencastPayload {\n type: 'RemoteBrowserScreencastFrame';\n agentSessionID: string;\n dataBase64: string;\n width: number;\n height: number;\n seq: number;\n}\n\n/**\n * Raw shape of the JSON `message` the server publishes on the push-status topic for each live Remote\n * Browser tab-audio chunk (mirrors {@link RemoteBrowserScreencastPayload}, distinguished by `type`).\n * Routed to the active Remote Browser channel plugin's audio player — never narrated.\n */\ninterface RemoteBrowserAudioChunkPayload {\n type: 'RemoteBrowserAudioChunk';\n agentSessionID: string;\n dataBase64: string;\n codec: string;\n sampleRate: number;\n channels: number;\n seq: number;\n}\n\n/**\n * Result shape returned by the `StartRealtimeClientSession` server mutation.\n * The browser uses these values to open a client-direct realtime session.\n */\ninterface StartRealtimeClientSessionResult {\n AgentSessionId: string;\n ConversationId: string | null;\n Provider: string;\n Model: string;\n EphemeralToken: string;\n ExpiresAt: string;\n /** JSON.stringify of the provider session config (instructions + tools) to apply at connect. */\n SessionConfigJson: string;\n /** Display name of the realtime model the session uses (e.g. \"GPT Realtime 2\"). Null when unknown. */\n ModelName: string | null;\n /**\n * DB-driven progress-narration instruction template (contains a `{{ progressMessage }}`\n * placeholder). Null when the deployment hasn't synced the narration prompt — the client\n * falls back to its built-in wording.\n */\n NarrationInstructionsTemplate: string | null;\n /**\n * JSON map of the PRIOR session's saved channel states keyed by channel name (present only\n * when the start carried `lastSessionId` and the prior session — owned by the same user —\n * had saved states). Applied to the matching channel plugins via\n * {@link BaseRealtimeChannelClient.RestoreState} so e.g. the whiteboard resumes where the\n * last session left off.\n */\n PriorChannelStatesJson: string | null;\n}\n\n/**\n * Drives a **client-direct** real-time voice session: the browser mints an ephemeral\n * token from the MJ server, then connects DIRECTLY to the realtime provider. Audio\n * frames never transit the MJ server (low latency); only tool calls and final\n * transcripts are relayed back to MJ over GraphQL.\n *\n * This service is PROVIDER-AGNOSTIC policy/orchestration. All provider wire concerns\n * (transport, event translation, the response state machine, narration-kind tagging,\n * playback tracking) live in a {@link BaseRealtimeClient} driver resolved through the\n * MJ ClassFactory by the server-reported `Provider` key (e.g. `'openai'` →\n * `OpenAIRealtimeClient`). Future providers (Gemini Live, …) snap in by registering a\n * new driver — this service does not change.\n *\n * The Realtime Co-Agent (server-side) fronts the conversation's current agent — the server\n * bakes the companion instructions + tool set into `SessionConfigJson`, which the client\n * driver applies verbatim.\n *\n * Lifecycle: {@link StartRealtimeSession} → live duplex → {@link EndRealtimeSession}.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionService {\n // ── Reactive UI state ──────────────────────────────────────────────────────\n private _connectionState$ = new BehaviorSubject<RealtimeConnectionState>('closed');\n private _captions$ = new BehaviorSubject<RealtimeCaption[]>([]);\n private _active$ = new BehaviorSubject<boolean>(false);\n private _delegationProgress$ = new Subject<RealtimeDelegationProgress>();\n private _delegationResult$ = new Subject<RealtimeDelegationResult>();\n private _delegationNarration$ = new Subject<RealtimeDelegationNarration>();\n private _agentName$ = new BehaviorSubject<string>('Sage');\n private _modelName$ = new BehaviorSubject<string | null>(null);\n private _minimized$ = new BehaviorSubject<boolean>(false);\n private _activeChannels$ = new BehaviorSubject<BaseRealtimeChannelClient[]>([]);\n private _channelFocus$ = new Subject<RealtimeChannelFocusEvent>();\n // ─── Generic session-lifecycle events (consumed by RealtimeSessionsAdapter to\n // bridge into @memberjunction/conversations-runtime's framework-agnostic\n // SessionsObserver). Why not derive from Active$ + agentSessionId? Because\n // Active$ flips true before mintSession resolves and sets agentSessionId —\n // a naive Active$ subscription would emit session-started with sessionId === null.\n // Emitting explicitly avoids the race entirely. ───\n private _sessionStarted$ = new Subject<{ sessionId: string; channelNames: string[] }>();\n private _sessionEnded$ = new Subject<{ sessionId: string; reason: 'explicit' | 'error' }>();\n private _channelActivity$ = new Subject<BaseRealtimeChannelClient>();\n\n /** Current connection / turn state. */\n public readonly ConnectionState$: Observable<RealtimeConnectionState> = this._connectionState$.asObservable();\n /** Live captions for both sides of the conversation. */\n public readonly Captions$: Observable<RealtimeCaption[]> = this._captions$.asObservable();\n /** True while a session is open (mic button active, overlay shown). */\n public readonly Active$: Observable<boolean> = this._active$.asObservable();\n /**\n * Progress updates from a delegated agent run (e.g. Sage) while the realtime model waits on it.\n * The future overlay subscribes to render a \"working\" card; the model also narrates these aloud.\n */\n public readonly DelegationProgress$: Observable<RealtimeDelegationProgress> = this._delegationProgress$.asObservable();\n /** Terminal result of a delegation, so the overlay can complete the working card with real content. */\n public readonly DelegationResult$: Observable<RealtimeDelegationResult> = this._delegationResult$.asObservable();\n /**\n * EPHEMERAL spoken progress narrations (see {@link RealtimeDelegationNarration}). These are\n * deliberately kept OUT of {@link Captions$} and never relayed/persisted — the overlay\n * renders them as a transient \"live note\" near the active working card.\n */\n public readonly DelegationNarration$: Observable<RealtimeDelegationNarration> = this._delegationNarration$.asObservable();\n /** Display name of the agent the active session fronts (set at session start). */\n public readonly AgentName$: Observable<string> = this._agentName$.asObservable();\n /**\n * Display name of the realtime MODEL the active session runs on (server-reported at session\n * start, e.g. \"GPT Realtime 2\"). `null` before a session starts / when the server didn't report\n * one. The overlay banner shows it subtly next to the agent identity.\n */\n public readonly ModelName$: Observable<string | null> = this._modelName$.asObservable();\n\n /**\n * True while the active call overlay is MINIMIZED to the host's floating \"on call\" pill\n * (e.g. after a dev link navigated away). The mic and session stay fully live — this is\n * pure presentation state, reset to `false` at session start and teardown.\n */\n public readonly Minimized$: Observable<boolean> = this._minimized$.asObservable();\n\n /**\n * The session's ACTIVE interactive-channel plugins, resolved from the `MJ: AI Agent\n * Channels` registry at session start (one instance per session, per channel). Emits\n * `[]` before a session starts and after teardown. The overlay subscribes to register\n * one surface tab per plugin — it never knows any concrete channel type.\n */\n public readonly ActiveChannels$: Observable<BaseRealtimeChannelClient[]> = this._activeChannels$.asObservable();\n\n /**\n * Channel requests to enter / leave the FOCUS layout (see\n * {@link RealtimeChannelFocusEvent}). Fired when a plugin calls its host context's\n * `SetFocusMode` — e.g. the whiteboard's \"Focus board\" toggle.\n */\n public readonly ChannelFocus$: Observable<RealtimeChannelFocusEvent> = this._channelFocus$.asObservable();\n\n /**\n * Fired EXACTLY ONCE per session after both `agentSessionId` is set AND the\n * realtime client is connected. Carries the server-issued `sessionId` and the\n * `ChannelName` of each plugin resolved at session mint. Consumed by\n * `RealtimeSessionsAdapter` (in this package) to feed\n * `@memberjunction/conversations-runtime`'s `SessionsObserver`.\n *\n * **Why this exists separately from `Active$`:** `Active$` flips `true` BEFORE\n * `mintSession` resolves, so `agentSessionId` is still `null` at that moment.\n * Subscribers correlating `(Active$, agentSessionId)` would race; this event\n * removes the race.\n */\n public readonly SessionStarted$: Observable<{ sessionId: string; channelNames: string[] }> =\n this._sessionStarted$.asObservable();\n\n /**\n * Fired EXACTLY ONCE per session as teardown begins, with the prior\n * `agentSessionId` (so subscribers can correlate against `SessionStarted$`'s\n * sessionId) and the client-distinguishable reason — `'explicit'` when the\n * user called `EndRealtimeSession`, `'error'` when teardown ran from a catch\n * block. Server-side close paths (janitor, shutdown) do NOT propagate here —\n * they happen out-of-process and have no client push channel today.\n */\n public readonly SessionEnded$: Observable<{ sessionId: string; reason: 'explicit' | 'error' }> =\n this._sessionEnded$.asObservable();\n\n /**\n * Fires with the channel PLUGIN every time the agent ACTS on that channel (a tool call\n * was routed to its local executor — e.g. the agent drew on the whiteboard). The overlay\n * uses the FIRST emission per channel to auto-reveal + focus the channel's surface tab,\n * so the user discovers the surface the moment the agent starts using it. Finer-grained\n * than {@link SessionStarted$}/{@link SessionEnded$} (per tool call, not per session).\n */\n public readonly ChannelActivity$: Observable<BaseRealtimeChannelClient> = this._channelActivity$.asObservable();\n\n /** Synchronous access to the session's active interactive-channel plugins. */\n public get ActiveChannels(): readonly BaseRealtimeChannelClient[] {\n return this._activeChannels$.value;\n }\n\n /**\n * The `ChannelName`s the agent has used (acted on) at least once this session. The overlay\n * uses this to register a channel's surface tab only after it has come into play. A fresh\n * Set snapshot so callers can't mutate the service's tracking.\n */\n public get UsedChannelNames(): ReadonlySet<string> {\n return new Set(this.usedChannelNames);\n }\n\n /** Whether the agent has used (acted on) the named channel at least once this session. */\n public HasChannelBeenUsed(channelName: string): boolean {\n return this.usedChannelNames.has(channelName);\n }\n\n /** Synchronous access to the display name of the agent the active session fronts. */\n public get CurrentAgentName(): string {\n return this._agentName$.value;\n }\n\n /**\n * ID of the active server-side agent session (`MJ: AI Agent Sessions`), or `null` when no\n * session is open / the session hasn't been minted yet. Powers the overlay's gear-gated\n * \"Open session\" dev link.\n */\n /** Conversation id the SERVER created for this session (null when the host supplied one). */\n private createdConversationId: string | null = null;\n /** The session's conversation id (supplied or server-created). */\n private sessionConversationId: string | null = null;\n /** First final user utterance of the live session (the naming seed). */\n private firstUserTranscript: string | null = null;\n\n /**\n * When the active/last session CREATED its conversation (started without one), the new\n * conversation's id — the host uses it to refresh the cached list, conditionally select\n * it on close, and auto-name it. Null when the session joined an existing conversation.\n */\n public get SessionCreatedConversationId(): string | null {\n return this.createdConversationId;\n }\n\n /** The first final user utterance of the session (naming seed); null before the user speaks. */\n public get FirstUserTranscript(): string | null {\n return this.firstUserTranscript;\n }\n\n public get CurrentAgentSessionId(): string | null {\n return this.agentSessionId;\n }\n\n /** Synchronous access to the minimized presentation state. */\n public get IsMinimized(): boolean {\n return this._minimized$.value;\n }\n\n /**\n * Minimizes / restores the active call overlay (host renders the floating pill while\n * minimized). Presentation-only — the live audio session is untouched.\n */\n public SetMinimized(minimized: boolean): void {\n if (this._minimized$.value !== minimized) {\n this._minimized$.next(minimized);\n }\n }\n\n // ── Session internals ──────────────────────────────────────────────────────\n /** The provider-direct realtime client driving the live session (ClassFactory-resolved). */\n private client: BaseRealtimeClient | null = null;\n /** The mic capture stream — acquired here (permission UX) and handed to the client. */\n private localStream: MediaStream | null = null;\n private agentSessionId: string | null = null;\n /**\n * The application the active session runs in (sources the server-side app config cascade +\n * RelevantAgents → allowed-agent union, and the default-agent chain). `null` when no app context\n * was supplied. Set at {@link StartRealtimeSession}; sent to the mint mutation.\n */\n private applicationId: string | null = null;\n /**\n * The live app-context snapshot (where the user is, what they see, the capability manifest),\n * pushed by the host (Explorer) at session start and on subsequent changes via\n * {@link UpdateAppContext}. The headless {@link import('../components/realtime/channels/client-context-channel').ClientContextChannel}\n * subscribes to {@link AppContext$} and streams deltas to the model via `SendContextNote`.\n */\n private readonly _appContext$ = new BehaviorSubject<AppContextSnapshot | null>(null);\n /** Observable of the live app-context snapshot (see {@link _appContext$}). */\n public readonly AppContext$: Observable<AppContextSnapshot | null> = this._appContext$.asObservable();\n\n /**\n * Push an updated app-context snapshot mid-session (the continuous-streaming half of client-context\n * delivery). The host (Explorer) calls this when the user navigates / the active surface's state or\n * capability manifest changes; the ClientContextChannel turns the delta into a `SendContextNote`.\n * No-op semantics when no session is live — the channel simply re-reads on next start.\n *\n * @param snapshot The latest app-context snapshot (or null to clear).\n */\n public UpdateAppContext(snapshot: AppContextSnapshot | null): void {\n this._appContext$.next(snapshot);\n }\n\n /**\n * The DB-driven narration instruction template (server-resolved at session start, containing a\n * `{{ progressMessage }}` placeholder). `null` when the deployment hasn't synced the narration\n * prompt — {@link buildNarrationInstructions} then falls back to the built-in wording.\n */\n private narrationTemplate: string | null = null;\n\n // ── Browser-side call recording ────────────────────────────────────────────\n /**\n * The active session's audio recorder (mic + agent mix), or `null` when the user didn't\n * consent or the browser can't record. Created after the client connects; stopped + uploaded\n * at teardown.\n */\n private recorder: RealtimeAudioRecorder | null = null;\n /** ISO timestamp of when recording started — sent to the server on session start. */\n private recordingStartedAtIso: string | null = null;\n /** Interval that flushes ~15s crash-recovery shards to the server during a recording. */\n private segmentTimer: ReturnType<typeof setInterval> | null = null;\n /** 0-based index of the next recording shard to upload. */\n private segmentIndex = 0;\n /** How often crash-recovery shards are flushed during a recording. */\n private static readonly SegmentFlushMs = 15000;\n /**\n * Recording-relative ms offset at which the IN-FLIGHT (not-yet-finalized) turn's audio\n * actually BEGAN — captured the moment that turn's audio/text starts flowing (its first\n * interim transcript), NOT inherited from the previous turn's end. `null` before the first\n * turn / between turns (until the next turn's audio starts). Sent as `utteranceStartMs` on\n * the turn's final transcript so per-turn timing lines up with the recording even when a\n * tool-call / silence gap sits between turns (the inherit-previous-end model mis-stamped\n * the post-gap turn at the pre-gap offset). See {@link markTurnAudioStart}.\n */\n private currentTurnStartMs: number | null = null;\n /**\n * Per-turn guard for {@link markTurnAudioStart}: `true` once the in-flight turn's audio-start\n * offset has been captured, so mid-turn interim deltas don't overwrite it. Reset to `false`\n * at each finalization so the NEXT turn re-stamps from where ITS audio begins.\n */\n private turnAudioStartCaptured = false;\n\n // ── Delegated-run progress streaming ───────────────────────────────────────\n /** First spoken update fires no earlier than this long after delegated work starts. */\n private static readonly FirstNarrationDelayMs = 5000;\n /** Minimum gap between SUBSEQUENT spoken updates (the 7–10s band; floods aggregate). */\n private static readonly NarrationIntervalMs = 8000;\n /** Retry delay when the fire moment finds the model busy / audio still playing. */\n private static readonly NarrationBusyRetryMs = 1500;\n /** Max progress messages aggregated into one spoken digest. */\n private static readonly MaxDigestMessages = 4;\n /** Max prior spoken narrations chained into the instructions (anti-repetition). */\n private static readonly MaxPriorNarrations = 3;\n /**\n * Aggregation buffer: distinct progress messages since the last spoken update (oldest\n * first, capped at {@link RealtimeSessionService.MaxDigestMessages}). A flood of small\n * updates becomes ONE digest; the buffer is discarded when the result lands first.\n */\n private pendingNarrationMessages: string[] = [];\n /**\n * Tool calls currently executing on the server. Progress events ride PubSub and can\n * lag the (fast) mutation result — any progress for a call NOT in this set is stale\n * (already completed) and is dropped, so we never narrate \"starting up\" after the\n * answer was already spoken.\n */\n private inFlightCallIds = new Set<string>();\n /** Timer for the deferred narration; cancelled when the delegation result lands first. */\n private narrationTimer: ReturnType<typeof setTimeout> | null = null;\n /**\n * Call ids the USER explicitly cancelled via {@link CancelDelegation} /\n * {@link CancelInFlightDelegations}. Their cards were already flipped to the\n * \"Cancelled by user\" failed result, so when the original tool mutation later resolves\n * with the aborted run's outcome, {@link emitDelegationResult} skips the duplicate card\n * emission (the model still receives the tool result). Cleared at teardown.\n */\n private cancelledCallIds = new Set<string>();\n\n // ── Usage telemetry relay (B7) ─────────────────────────────────────────────\n /** Debounce window for relaying accumulated usage deltas to the server. */\n private static readonly UsageFlushDebounceMs = 10000;\n /** Accumulated input-token delta since the last flush. */\n private pendingUsageInput = 0;\n /** Accumulated output-token delta since the last flush. */\n private pendingUsageOutput = 0;\n /** Pending debounced usage flush; also force-flushed at teardown. */\n private usageFlushTimer: ReturnType<typeof setTimeout> | null = null;\n /** Active push-status subscription that feeds delegation progress; cleared on teardown. */\n private delegationProgressSub: Subscription | null = null;\n /** Timestamp (ms) of the last narration we triggered; 0 = never. */\n private lastDelegationNarrationAt = 0;\n /** When the current delegation burst began (first in-flight call); anchors the 5s first update. */\n private delegationBurstStartedAt = 0;\n /** Spoken updates so far in this burst (1-based numbering for the instructions). */\n private narrationCount = 0;\n /** What the model actually SAID for prior updates this burst — chained in so it never repeats itself. */\n private spokenNarrations: string[] = [];\n /** Tail message of the last digest, so an identical trailing progress event isn't re-buffered. */\n private lastNarratedTail = '';\n\n /**\n * Registry of CLIENT-EXECUTED UI tool handlers, keyed by tool-name prefix (e.g.\n * `'Whiteboard_'`). Tool calls whose name matches a registered prefix run LOCALLY through the\n * handler (never relayed to the server); everything else takes the standard server-relay path.\n * Cleared at teardown.\n */\n private clientToolHandlers = new Map<string, RealtimeClientToolHandler>();\n\n // ── Interactive channels (registry-resolved plugins) ───────────────────────\n /** Debounce window for persisting a channel's state of record after a change burst. */\n private static readonly ChannelSaveDebounceMs = 3000;\n /**\n * Pending DEBOUNCED channel-state saves, keyed by channel name. Each entry keeps the\n * LATEST serialized state plus the session id captured while the session was live —\n * the teardown flush runs as the live id is being torn down, so the capture guarantees\n * the final save still lands on the just-closed session.\n */\n private pendingChannelSaves = new Map<string, {\n Timer: ReturnType<typeof setTimeout>;\n StateJson: string;\n SessionID: string | null;\n }>();\n\n /**\n * `ChannelName`s the agent has ACTED ON at least once this session (the channel's first\n * tool call routed to its local executor). The overlay reads this to decide which channel\n * surface tabs to register: a channel earns its tab only once it's been used (the\n * whiteboard is the sole exception — it tabs immediately, since a user may draw first).\n * Reset at session start via {@link resetState}.\n */\n private usedChannelNames = new Set<string>();\n\n private _provider: IMetadataProvider | null = null;\n\n /**\n * Metadata provider used for the GraphQL relay mutations. Falls back to the\n * global default when unset (single-provider apps see no change).\n */\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n }\n\n /** True when a session is currently open. */\n public get IsActive(): boolean {\n return this._active$.value;\n }\n\n /**\n * Start a client-direct voice session fronting `targetAgentId`.\n *\n * @param targetAgentId The agent the Realtime Co-Agent voices on behalf of.\n * @param conversationId Optional existing conversation to bind + seed context from.\n * @param lastSessionId Optional prior session to chain to (resume / continuation).\n * @param agentName Optional display name of the target agent — resolved by the caller\n * (which knows the conversation's routing context) and surfaced on {@link AgentName$}\n * so ANY host (composer trigger, chat-area overlay) can render it without re-resolving.\n * @param preferredModelId Optional EXPLICIT realtime model choice (`MJ: AI Models.ID`). When\n * set, the server uses exactly that model and FAILS with a clear reason if it can't (no\n * silent fallback). Omit for the server's automatic (highest-PowerRank) selection.\n * @param clientTools Optional EXTRA client-executed UI tool declarations to expose to the\n * realtime model alongside the server's stable tool set and the interactive-channel\n * tools (which are aggregated automatically from the registry-resolved plugins — see\n * {@link ActiveChannels$}). The server only DECLARES these — execution stays in the\n * browser via handlers registered with {@link RegisterClientToolHandler}. This is an\n * extension point for hosts with bespoke (non-channel) UI tools; most callers omit it.\n * @param coAgentId Optional EXPLICIT co-agent choice (`MJ: AI Agents.ID` of an Active,\n * Realtime-type agent) — the highest-precedence step of the server's co-agent resolution\n * chain. When set, the server uses exactly that co-agent and FAILS with a clear reason if\n * it can't (no silent fallback). Omit to let server metadata drive the choice: the target\n * agent's `DefaultCoAgentID`, then the type-level `AIAgentCoAgent` default row, then the global Realtime Co-Agent.\n * @param configOverridesJson Optional JSON payload of SESSION CONFIG overrides (e.g.\n * `{\"realtime\":{\"modelPreference\":\"<modelId>\"}}`), forwarded verbatim on the mint\n * mutation. The server enforces the `Realtime: Advanced Session Controls`\n * authorization on any overrides — hosts only populate this from authorization-gated\n * pickers, and never synthesize overrides beyond what the user explicitly chose.\n * Omit/`null` for the server's defaults (today's behavior).\n * @param recordingConsent Optional EXPLICIT \"record this call\" consent for THIS session. When\n * `true`, the browser records a mic + agent-audio mix and uploads it at session end. When\n * omitted/`null`, the per-user persisted preference (`mj.realtimeVoice.recordingConsent.v1`\n * via {@link UserInfoEngine}) is read as the default. `false` never records.\n * @param mediaCollectionId Optional per-session media-kit override (`MJ: Collections.ID`). When set,\n * the server-side Media channel resolves THIS collection as the agent's media kit for the session,\n * taking precedence over the agent's `DefaultMediaCollectionID`. The server UUID-validates it\n * (malformed ⇒ ignored, the agent default applies). Omit/`null` to use the agent default kit.\n */\n public async StartRealtimeSession(\n targetAgentId: string,\n conversationId?: string | null,\n lastSessionId?: string | null,\n agentName?: string | null,\n preferredModelId?: string | null,\n clientTools?: RealtimeToolDefinition[] | null,\n coAgentId?: string | null,\n configOverridesJson?: string | null,\n recordingConsent?: boolean | null,\n mediaCollectionId?: string | null,\n applicationId?: string | null,\n appContext?: AppContextSnapshot | null\n ): Promise<void> {\n if (this.IsActive) {\n return; // a session is already running — ignore duplicate starts\n }\n\n // App awareness (Move 1/3/4): the application the session runs in (sources the app config\n // cascade + RelevantAgents → allowed-agent union) and the live app-context snapshot injected\n // into the companion prompt at mint. Stored so the ClientContextChannel can stream subsequent\n // deltas. Absent ⇒ no app layer / no mint-time context (the pre-app behavior).\n this.applicationId = applicationId ?? null;\n // Prefer the explicit param, but fall back to the snapshot the host has ALREADY pushed via\n // UpdateAppContext (explorer-app streams the live snapshot continuously). The overlay's\n // [appContext] binding can still read null at the instant the mic is clicked — without this\n // fallback, StartRealtimeSession(null) would clobber a perfectly good snapshot and mint the\n // companion prompt with no app context (no NavigableApps / no tool schemas → the co-agent guesses\n // parameter names and navigation fails). Never overwrite a good value with null.\n const effectiveAppContext = appContext ?? this._appContext$.value;\n this._appContext$.next(effectiveAppContext);\n\n if (agentName) {\n this._agentName$.next(agentName);\n }\n this.resetState();\n this._active$.next(true);\n this._connectionState$.next('connecting');\n\n // Resolve recording consent for this session: explicit value wins, else the per-user\n // persisted preference. Computed before mint so it can be reported to the server.\n const consent = recordingConsent ?? this.readPersistedRecordingConsent();\n this.recordingStartedAtIso = consent ? new Date().toISOString() : null;\n\n try {\n // Resolve + initialize the interactive-channel plugins FIRST: their client-executed\n // tool sets must be declared to the realtime model at session mint.\n const allClientTools = [...(clientTools ?? []), ...(await this.startChannels())];\n const session = await this.mintSession(targetAgentId, conversationId, lastSessionId, preferredModelId, allClientTools, coAgentId, configOverridesJson, consent, this.recordingStartedAtIso, mediaCollectionId, this.applicationId, effectiveAppContext);\n this.agentSessionId = session.AgentSessionId;\n // A null input conversationId means the SERVER created a fresh conversation for\n // this session — track it so the host can fold it into the cached list, select\n // it on close, and auto-name it (via the shared naming helper).\n this.createdConversationId = !conversationId && session.ConversationId ? session.ConversationId : null;\n this.sessionConversationId = session.ConversationId ?? conversationId ?? null;\n this.firstUserTranscript = null;\n this.narrationTemplate = session.NarrationInstructionsTemplate ?? null;\n this._modelName$.next(session.ModelName ?? null);\n // Resume continuity: rehydrate channel plugins from the PRIOR session's saved states\n // (e.g. the whiteboard) BEFORE any surface binds — tolerant, never blocks the start.\n this.applyPriorChannelStates(session.PriorChannelStatesJson);\n\n const client = this.createRealtimeClient(session.Provider);\n this.client = client;\n this.wireClientHandlers(client);\n\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n await client.Connect(this.buildClientConfig(session), this.localStream);\n\n // Start browser-side recording (mic + agent mix) when consented. Best-effort: an\n // unsupported browser / missing remote stream degrades gracefully (mic-only or off)\n // and never blocks the call. The remote stream may still be null here (the WebRTC\n // ontrack can land slightly after Connect resolves) — the recorder mixes the mic now\n // and the agent audio rides through whenever its track is already attached.\n if (consent) {\n this.startRecording(client);\n }\n\n this.subscribeDelegationProgress();\n // State advances to 'listening' once the provider control channel opens\n // (driven by the client's OnStateChange events).\n\n // Surface a generic session-started event for the conversations runtime\n // SessionsObserver bridge. Emitting AFTER Connect() guarantees both that\n // agentSessionId is set (line ~468) AND the realtime client is connected,\n // so consumers can act on it without re-checking either condition.\n this._sessionStarted$.next({\n sessionId: this.agentSessionId,\n channelNames: this._activeChannels$.value.map(c => c.ChannelName),\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to start session:', error);\n this._connectionState$.next('error');\n await this.teardown(false);\n }\n }\n\n /**\n * End the active session: stop the mic, tear down the provider connection, and close\n * the server-side agent session. Safe to call when no session is active.\n */\n public async EndRealtimeSession(): Promise<void> {\n if (!this.IsActive && !this.agentSessionId) {\n return;\n }\n await this.teardown(true);\n }\n\n /**\n * Inject a typed message into the live session as a user turn.\n *\n * Decomposed into two steps, each mirroring an existing voice path so the typed\n * turn behaves identically to a spoken one:\n * 1. {@link BaseRealtimeClient.SendText} injects the text as user input and triggers a\n * reply through the SAME collision-safe path tool results use — so it queues behind\n * any in-flight response (progress narration / prior turn) instead of colliding.\n * 2. Relay the turn through the same caption + transcript paths user speech uses\n * ({@link onUserTranscript}) so it shows in the live thread AND persists to MJ.\n *\n * No-op when no session is open / the control channel isn't ready, or when the text is empty.\n */\n public SendText(text: string): void {\n const trimmed = text?.trim() ?? '';\n if (trimmed.length === 0) {\n return;\n }\n const client = this.client;\n if (!client || !this.isSessionLive()) {\n return;\n }\n client.SendText(trimmed);\n // Relay as a user turn — same path spoken input uses (caption + persisted transcript).\n void this.onUserTranscript(trimmed);\n }\n\n /** Mute / unmute the local microphone track. Returns the new muted state. */\n public ToggleMute(): boolean {\n const tracks = this.localStream?.getAudioTracks() ?? [];\n if (tracks.length === 0) {\n return false;\n }\n const muted = tracks[0].enabled; // currently enabled → becomes muted\n this.client?.SetMuted(muted);\n return muted;\n }\n\n // ── Client-executed UI tools ───────────────────────────────────────────────\n\n /**\n * Registers a handler for CLIENT-EXECUTED UI tools whose names start with `toolNamePrefix`\n * (e.g. `'Whiteboard_'` → all `Whiteboard_*` calls). Matching tool calls execute LOCALLY via\n * the handler — they are never relayed to the server — and the handler's result JSON is sent\n * back to the model as the `tool_response`. Re-registering the same prefix replaces the\n * handler. The registry is cleared at session teardown.\n */\n public RegisterClientToolHandler(toolNamePrefix: string, handler: RealtimeClientToolHandler): void {\n this.clientToolHandlers.set(toolNamePrefix, handler);\n }\n\n /** Removes the handler registered for `toolNamePrefix` (no-op when none is registered). */\n public UnregisterClientToolHandler(toolNamePrefix: string): void {\n this.clientToolHandlers.delete(toolNamePrefix);\n }\n\n /**\n * Feeds a background context note into the live model (no spoken reply is requested) — the\n * perception channel interactive surfaces use (e.g. the whiteboard's coalesced scene deltas).\n * No-op when no session is live.\n */\n public SendContextNote(text: string): void {\n const trimmed = text?.trim() ?? '';\n if (trimmed.length === 0 || !this.client || !this.isSessionLive()) {\n return;\n }\n this.client.SendContextNote(trimmed);\n }\n\n /**\n * The active client's current audio activity (per-direction RMS levels + spectrum\n * bins), or `null` when no session is live or the driver attached no audio meters.\n * Sampled by the overlay's animation-frame loop to drive the audio-reactive orb/EQ —\n * a cheap analyser read, never provider traffic.\n */\n public GetAudioActivity(): RealtimeAudioActivity | null {\n return this.client?.GetAudioActivity() ?? null;\n }\n\n // ── Browser-side call recording ────────────────────────────────────────────\n\n /**\n * Reads the per-user recording-consent preference from `MJ: User Settings` (via\n * {@link UserInfoEngine}'s synchronous cache). Defensive: any failure resolves to `false`\n * (don't record) so a settings hiccup can never opt a user into recording.\n */\n private readPersistedRecordingConsent(): boolean {\n try {\n return UserInfoEngine.Instance.GetSetting(REALTIME_RECORDING_CONSENT_KEY) === 'true';\n } catch {\n return false;\n }\n }\n\n /**\n * Starts the browser-side recorder (mic + agent-audio mix). Best-effort — any failure is\n * contained so it never disturbs the live call; an unsupported browser simply records\n * nothing (the recorder disables itself).\n */\n private startRecording(client: BaseRealtimeClient): void {\n try {\n if (!this.localStream) {\n return;\n }\n const remoteStream = client.GetRemoteMediaStream?.() ?? null;\n const recorder = new RealtimeAudioRecorder();\n recorder.Start(this.localStream, remoteStream);\n this.recorder = recorder.IsRecording ? recorder : null;\n // First turn's audio starts at ~0 (recording begins right as the call goes live). Seed it\n // here so the very first turn has a sane start even if its first interim is missed; later\n // turns re-stamp from where THEIR audio begins via markTurnAudioStart (handles tool gaps).\n this.currentTurnStartMs = recorder.IsRecording ? 0 : null;\n this.turnAudioStartCaptured = false;\n if (this.recorder) {\n // The agent's WebRTC audio track usually lands AFTER Connect() resolves, so `remoteStream`\n // above is typically null and we'd capture mic-only. Attach the agent stream whenever it\n // arrives (fires immediately if already present) so the recording includes the agent voice.\n client.OnRemoteMediaStream?.((stream) => this.recorder?.AttachRemoteStream(stream));\n this.startSegmentFlushing();\n }\n } catch (error) {\n console.warn('[RealtimeSession] Failed to start call recording:', error);\n this.recorder = null;\n }\n }\n\n /** Begins flushing ~15s crash-recovery shards to the server for the duration of the recording. */\n private startSegmentFlushing(): void {\n this.segmentIndex = 0;\n this.segmentTimer = setInterval(() => { void this.flushRecordingSegment(); }, RealtimeSessionService.SegmentFlushMs);\n }\n\n /** Stops the periodic crash-recovery shard flush. */\n private stopSegmentFlushing(): void {\n if (this.segmentTimer) {\n clearInterval(this.segmentTimer);\n this.segmentTimer = null;\n }\n }\n\n /**\n * Uploads the chunks captured since the last flush as one crash-recovery shard (durability only;\n * the canonical file is still the full upload at teardown). Best-effort — never disturbs the call.\n */\n private async flushRecordingSegment(): Promise<void> {\n const recorder = this.recorder;\n const agentSessionId = this.agentSessionId;\n if (!recorder || !agentSessionId) {\n return;\n }\n const segment = recorder.SnapshotNewSegment();\n if (!segment || segment.size === 0) {\n return;\n }\n try {\n const audioBase64 = await this.blobToBase64(segment);\n if (!audioBase64) {\n return;\n }\n const index = this.segmentIndex++;\n const mutation = `\n mutation UploadRealtimeRecordingSegment($agentSessionId: String!, $segmentIndex: Int!, $audioBase64: String!, $mimeType: String!) {\n UploadRealtimeRecordingSegment(agentSessionId: $agentSessionId, segmentIndex: $segmentIndex, audioBase64: $audioBase64, mimeType: $mimeType)\n }\n `;\n // Shards are HEADER-LESS raw little-endian PCM16 (mime audio/L16 with the capture sample rate),\n // NOT individually-playable WAV — recovery is concatenate-in-order then WAV-wrap. The canonical\n // seekable WAV is the consolidated end-of-call upload below.\n const shardMime = `audio/L16;rate=${recorder.SampleRate}`;\n await this.gql().ExecuteGQL(mutation, { agentSessionId, segmentIndex: index, audioBase64, mimeType: shardMime });\n } catch (error) {\n console.warn('[RealtimeSession] Failed to flush recording shard:', error);\n }\n }\n\n /**\n * Stops the active recorder and uploads the captured audio via `UploadRealtimeRecording`.\n * Fully best-effort and wrapped in try/catch — recording upload must NEVER block teardown.\n * No-op when nothing was recorded or there's no session id to attach the file to.\n */\n private async stopAndUploadRecording(agentSessionId: string | null): Promise<void> {\n this.stopSegmentFlushing();\n const recorder = this.recorder;\n this.recorder = null;\n this.currentTurnStartMs = null;\n this.turnAudioStartCaptured = false;\n if (!recorder) {\n return;\n }\n try {\n // Capture the recorder MIME (now 'audio/wav') BEFORE Stop() — the getter reads '' once stopped.\n const mimeType = recorder.MimeType;\n const blob = await recorder.Stop();\n // Read the real waveform peaks computed during capture (survives Stop via the recorder's snapshot).\n const peaks = recorder.GetPeaks();\n if (!blob || blob.size === 0 || !agentSessionId) {\n console.warn('[RealtimeSession] ⚠️ recording NOT uploaded — empty blob or no session id.');\n return;\n }\n const audioBase64 = await this.blobToBase64(blob);\n if (!audioBase64) {\n console.warn('[RealtimeSession] ⚠️ recording NOT uploaded — base64 encoding failed.');\n return;\n }\n await this.uploadRecording(agentSessionId, audioBase64, mimeType, peaks);\n } catch (error) {\n console.warn('[RealtimeSession] Failed to stop/upload call recording:', error);\n }\n }\n\n /**\n * Runs the `UploadRealtimeRecording` mutation; failures are logged, never thrown. Sends the\n * capture-time waveform `peaks` (max-abs per bucket, normalized 0..1) so the server can persist a\n * `peaks.json` sidecar for fast waveform rendering without re-decoding the audio.\n */\n private async uploadRecording(agentSessionId: string, audioBase64: string, mimeType: string, peaks: number[]): Promise<void> {\n const mutation = `\n mutation UploadRealtimeRecording($agentSessionId: String!, $audioBase64: String!, $mimeType: String!, $consent: Boolean, $peaks: [Float!]) {\n UploadRealtimeRecording(agentSessionId: $agentSessionId, audioBase64: $audioBase64, mimeType: $mimeType, consent: $consent, peaks: $peaks) {\n Success\n FileID\n ErrorMessage\n }\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, {\n agentSessionId,\n audioBase64,\n mimeType,\n consent: true,\n peaks\n });\n const payload = result?.UploadRealtimeRecording as { Success?: boolean; FileID?: string; ErrorMessage?: string } | undefined;\n if (!payload?.Success) {\n console.warn(`[RealtimeSession] ❌ recording upload reported failure: ${payload?.ErrorMessage ?? 'unknown error'} (full result: ${JSON.stringify(result)})`);\n }\n }\n\n /**\n * Encodes a {@link Blob} as a base64 string (the data: prefix stripped) via {@link FileReader}.\n * Resolves `''` on any read failure so the upload path can bail cleanly.\n */\n private blobToBase64(blob: Blob): Promise<string> {\n return new Promise<string>((resolve) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n const result = typeof reader.result === 'string' ? reader.result : '';\n const commaIndex = result.indexOf(',');\n resolve(commaIndex >= 0 ? result.slice(commaIndex + 1) : '');\n };\n reader.onerror = () => resolve('');\n reader.readAsDataURL(blob);\n });\n }\n\n // ── Interactive channels (registry-driven plugins) ─────────────────────────\n\n /**\n * Resolves, instantiates and initializes the session's interactive-channel plugins from\n * the `MJ: AI Agent Channels` registry, publishes them on {@link ActiveChannels$}, and\n * returns their aggregated client-executed tool declarations for the session mint.\n * Tolerant by design: registry/resolution failures degrade to \"no channels\" — the voice\n * session itself always proceeds.\n */\n private async startChannels(): Promise<RealtimeToolDefinition[]> {\n const channels = await this.loadActiveChannels();\n for (const plugin of channels) {\n this.initializeChannel(plugin);\n }\n this._activeChannels$.next(channels);\n return channels.flatMap(plugin => plugin.GetToolDefinitions());\n }\n\n /**\n * Loads the ACTIVE channel definitions from the registry and resolves each row's\n * `ClientPluginClass` through the MJ ClassFactory into a per-session plugin instance —\n * the client-side mirror of how realtime-model drivers resolve from `BaseRealtimeModel`\n * / `BaseRealtimeClient`. Rows whose plugin class isn't registered are skipped (logged),\n * never fatal.\n */\n private async loadActiveChannels(): Promise<BaseRealtimeChannelClient[]> {\n const rows = await this.fetchChannelDefinitions();\n const channels: BaseRealtimeChannelClient[] = [];\n for (const row of rows) {\n const plugin = this.resolveChannelPlugin(row);\n if (plugin) {\n channels.push(plugin);\n }\n }\n return channels;\n }\n\n /**\n * Reads the ACTIVE `MJ: AI Agent Channels` rows from {@link AIEngineBase}'s cached\n * `AgentChannels` (provider-scoped engine instance, lazy `Config` — no RunView\n * round-trip; the engine's BaseEntity-event reactivity keeps the registry fresh).\n * Failures are logged and degrade to an empty list — channel availability must\n * never block the voice session.\n */\n private async fetchChannelDefinitions(): Promise<RealtimeChannelDefinitionRow[]> {\n try {\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(this.Provider, AIEngineBase) as AIEngineBase;\n await engine.Config(false, undefined, this.Provider);\n return (engine.AgentChannels ?? [])\n .filter(c => c.IsActive)\n .map<RealtimeChannelDefinitionRow>(c => ({ ID: c.ID, Name: c.Name, ClientPluginClass: c.ClientPluginClass }));\n } catch (error) {\n console.warn('[RealtimeSession] Channel registry unavailable — starting with no channels:', error);\n return [];\n }\n }\n\n /**\n * Resolves one registry row's `ClientPluginClass` via the ClassFactory (registration\n * checked first, exactly like the realtime-client drivers) and instantiates a fresh\n * per-session plugin. Returns `null` (logged) when no plugin is registered for the key\n * — e.g. its Load function was never called or the package isn't included client-side.\n */\n private resolveChannelPlugin(row: RealtimeChannelDefinitionRow): BaseRealtimeChannelClient | null {\n const key = row.ClientPluginClass?.trim();\n if (!key) {\n console.warn(`[RealtimeSession] Channel '${row.Name}' has no ClientPluginClass — skipping.`);\n return null;\n }\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(BaseRealtimeChannelClient, key);\n if (!registration) {\n console.warn(`[RealtimeSession] No client plugin registered for channel '${row.Name}' (key '${key}') — skipping.`);\n return null;\n }\n const plugin = MJGlobal.Instance.ClassFactory.CreateInstance<BaseRealtimeChannelClient>(BaseRealtimeChannelClient, key);\n if (!plugin) {\n console.warn(`[RealtimeSession] Failed to instantiate client plugin for channel '${row.Name}' (key '${key}').`);\n return null;\n }\n return plugin;\n }\n\n /**\n * Wires one plugin into the session: hands it its host context and registers its\n * prefix-routed local tool executor (so `<ToolNamePrefix>*` calls run in the browser\n * through {@link BaseRealtimeChannelClient.ApplyAgentTool}, never the server relay).\n */\n private initializeChannel(plugin: BaseRealtimeChannelClient): void {\n plugin.Initialize(this.buildChannelContext(plugin));\n this.RegisterClientToolHandler(plugin.ToolNamePrefix, (toolName, argsJson) => {\n // The agent is ACTING on this channel — surface-discovery signal for the overlay\n // (first activity registers + auto-reveals + focuses the channel tab) before the\n // tool applies. Record the channel as USED so the overlay tabs it (channels other\n // than the whiteboard are tab-less until they're first used).\n this.usedChannelNames.add(plugin.ChannelName);\n this._channelActivity$.next(plugin);\n return plugin.ApplyAgentTool(toolName, argsJson);\n });\n }\n\n /** Builds the host-services context one channel plugin sees (its only line to the session). */\n private buildChannelContext(plugin: BaseRealtimeChannelClient): RealtimeChannelContext {\n // Capture the service in a local so the AgentSessionID getter reads the SERVICE's live\n // field (not the object literal's `this`) every time it's accessed.\n const service = this;\n return {\n AgentName: this.CurrentAgentName,\n // The live session's provider — threaded by channels into MJ-backed surfaces (e.g. the Media\n // channel's mj-storage-media-player / CreateMediaAccessToken). `get` so it stays current.\n get Provider(): IMetadataProvider {\n return service.Provider;\n },\n SendContextNote: (text: string) => this.SendContextNote(text),\n RequestSpokenResponse: (instructions: string) => this.requestChannelSpokenResponse(instructions),\n RequestSave: (stateJson: string) => this.scheduleChannelSave(plugin.ChannelName, stateJson),\n SaveAsArtifact: (name: string, contentJson: string) => this.saveChannelArtifact(plugin.ChannelName, name, contentJson),\n SetFocusMode: (on: boolean) => this._channelFocus$.next({ Channel: plugin, Focused: on }),\n // Live session id + GraphQL escape hatch for SERVER-BACKED channels (e.g. Remote\n // Browser). `get` so a channel always reads the CURRENT id — it's null at Initialize\n // (the plugin is built before mintSession resolves) and set once the session is live.\n get AgentSessionID(): string | null {\n return service.agentSessionId;\n },\n ExecuteServerAction: <TResult>(query: string, variables: Record<string, JSONValue>) =>\n this.executeChannelServerAction<TResult>(query, variables),\n // App-context stream + client-tool execution for the headless ClientContextChannel. The host\n // (Explorer) feeds both; absent on hosts that supply no app context / register no client tools.\n AppContext$: this.AppContext$,\n ExecuteClientTool: (name: string, params: Record<string, unknown>) =>\n this.executeAppClientTool(name, params)\n };\n }\n\n /**\n * Host registry of surface CLIENT TOOLS (Name → handler), fed by the host (Explorer) from the\n * active surface's `SetAgentClientTools`. The headless ClientContextChannel's `ContextTool` proxy\n * executes against this via {@link executeAppClientTool}. Keys are lower-cased for case-insensitive\n * model-supplied action names.\n */\n private readonly appClientToolHandlers = new Map<string, (params: Record<string, unknown>) => Promise<unknown> | unknown>();\n\n /**\n * Replaces the set of host-registered surface client tools the realtime ContextTool can execute.\n * The host calls this at session start and whenever the active surface's tool set changes (the\n * continuous-capability half of client-context delivery). Passing `[]` clears them.\n *\n * @param tools The current surface client tools (name + handler). Descriptions/schemas ride the\n * app-context manifest separately; only the executable handler is needed here.\n */\n public RegisterAppClientTools(\n tools: ReadonlyArray<{ Name: string; Handler: (params: Record<string, unknown>) => Promise<unknown> | unknown }>\n ): void {\n this.appClientToolHandlers.clear();\n for (const tool of tools) {\n if (tool?.Name && typeof tool.Handler === 'function') {\n this.appClientToolHandlers.set(tool.Name.trim().toLowerCase(), tool.Handler);\n }\n }\n }\n\n /**\n * Executes a host-registered surface client tool by name (the {@link RealtimeChannelContext.ExecuteClientTool}\n * implementation). Tolerant: an unknown tool or a thrown handler resolves to a structured\n * `Success: false` result the channel narrates — never throws.\n *\n * @param name The tool name (the model's `action`).\n * @param params The tool parameters.\n * @returns A structured result for the channel to serialize back to the model.\n */\n private async executeAppClientTool(\n name: string,\n params: Record<string, unknown>\n ): Promise<{ Success: boolean; Result?: unknown; ErrorMessage?: string }> {\n const handler = this.appClientToolHandlers.get((name ?? '').trim().toLowerCase());\n if (!handler) {\n const available = Array.from(this.appClientToolHandlers.keys()).join(', ');\n return {\n Success: false,\n ErrorMessage: `No client tool named \"${name}\" is available on this surface. Available: ${available || '(none)'}.`\n };\n }\n try {\n const result = await handler(params ?? {});\n return { Success: true, Result: result };\n } catch (error) {\n return { Success: false, ErrorMessage: error instanceof Error ? error.message : String(error) };\n }\n }\n\n /**\n * Runs a channel-specific GraphQL operation through the live session's provider (the\n * {@link RealtimeChannelContext.ExecuteServerAction} implementation). Best-effort: any\n * transport/server error is logged and resolves to `null` so the calling channel can map\n * the failure to a model-readable result string without `try/catch`.\n */\n private async executeChannelServerAction<TResult>(query: string, variables: Record<string, JSONValue>): Promise<TResult | null> {\n try {\n const result = await this.gql().ExecuteGQL(query, variables);\n return (result as TResult) ?? null;\n } catch (error) {\n console.error('[RealtimeSession] Channel server action failed:', error);\n return null;\n }\n }\n\n /**\n * A channel asked the live model to SPEAK in reaction to channel input (e.g. a widget\n * submission) — routed through the client's spoken-update channel. No-op when the\n * session isn't live; empty instructions are dropped.\n */\n private requestChannelSpokenResponse(instructions: string): void {\n const trimmed = instructions?.trim() ?? '';\n if (trimmed.length === 0 || !this.client || !this.isSessionLive()) {\n return;\n }\n this.client.RequestSpokenUpdate(trimmed);\n }\n\n /**\n * Applies the PRIOR session's saved channel states (resume continuity): parses the\n * server-supplied map and offers each entry to the matching active plugin via\n * {@link BaseRealtimeChannelClient.RestoreState}. Fully tolerant — malformed payloads,\n * unknown channels, and plugin rejections are logged and skipped; the session start is\n * never affected.\n */\n private applyPriorChannelStates(statesJson: string | null | undefined): void {\n if (!statesJson) {\n return;\n }\n let states: Record<string, string>;\n try {\n const parsed: unknown = JSON.parse(statesJson);\n if (parsed === null || typeof parsed !== 'object') {\n return;\n }\n states = parsed as Record<string, string>;\n } catch {\n console.warn('[RealtimeSession] PriorChannelStatesJson was malformed — starting channels fresh');\n return;\n }\n for (const plugin of this._activeChannels$.value) {\n const state = states[plugin.ChannelName];\n if (typeof state === 'string' && state.length > 0) {\n try {\n const restored = plugin.RestoreState(state);\n if (!restored) {\n console.warn(`[RealtimeSession] Channel '${plugin.ChannelName}' declined its prior-session state — starting fresh`);\n }\n } catch (error) {\n console.warn(`[RealtimeSession] Channel '${plugin.ChannelName}' restore threw — starting fresh`, error);\n }\n }\n }\n }\n\n /**\n * Persists a channel's state as a first-class versioned artifact (`MJ: Artifacts`) via the\n * `SaveSessionChannelArtifact` mutation — the channel-context capability behind e.g. the\n * whiteboard's \"Save to artifacts\". Best-effort: returns the created Artifact ID, or null\n * on any failure (logged, never thrown). Uses the live session id, falling back to the\n * teardown-captured one so \"save my board\" works right after the call ends.\n */\n private async saveChannelArtifact(channelName: string, name: string, contentJson: string): Promise<string | null> {\n const sessionId = this.agentSessionId ?? this.lastKnownSessionIdForSaves();\n if (!sessionId || !name.trim() || !contentJson) {\n return null;\n }\n try {\n const result = await this.gql().ExecuteGQL(\n `mutation SaveSessionChannelArtifact($agentSessionId: String!, $channelName: String!, $name: String!, $contentJson: String!) {\n SaveSessionChannelArtifact(agentSessionId: $agentSessionId, channelName: $channelName, name: $name, contentJson: $contentJson) {\n Success\n ErrorMessage\n ArtifactID\n ArtifactVersionID\n }\n }`,\n { agentSessionId: sessionId, channelName, name: name.trim(), contentJson }\n ) as { SaveSessionChannelArtifact?: { Success: boolean; ErrorMessage?: string; ArtifactID?: string } };\n const payload = result?.SaveSessionChannelArtifact;\n if (!payload?.Success) {\n console.warn(`[RealtimeSession] Save-as-artifact failed for '${channelName}': ${payload?.ErrorMessage ?? 'unknown error'}`);\n return null;\n }\n return payload.ArtifactID ?? null;\n } catch (error) {\n console.warn(`[RealtimeSession] Save-as-artifact errored for '${channelName}':`, error);\n return null;\n }\n }\n\n /** Most recent session id captured by the save pipeline (post-teardown saves). */\n private lastKnownSessionIdForSaves(): string | null {\n for (const pending of this.pendingChannelSaves.values()) {\n if (pending.SessionID) {\n return pending.SessionID;\n }\n }\n return null;\n }\n\n /**\n * Schedules the DEBOUNCED state-of-record save for a channel: each request replaces the\n * pending payload (latest state wins) and re-arms the timer; the session id is captured\n * while live so the teardown flush can persist onto the just-closed session.\n */\n private scheduleChannelSave(channelName: string, stateJson: string): void {\n const pending = this.pendingChannelSaves.get(channelName);\n if (pending) {\n clearTimeout(pending.Timer);\n }\n this.pendingChannelSaves.set(channelName, {\n Timer: setTimeout(() => this.flushChannelSave(channelName), RealtimeSessionService.ChannelSaveDebounceMs),\n StateJson: stateJson,\n SessionID: this.agentSessionId ?? pending?.SessionID ?? null\n });\n }\n\n /** Fires one pending channel save (best-effort; {@link SaveChannelState} logs failures). */\n private flushChannelSave(channelName: string): void {\n const pending = this.pendingChannelSaves.get(channelName);\n if (!pending) {\n return;\n }\n this.pendingChannelSaves.delete(channelName);\n clearTimeout(pending.Timer);\n void this.SaveChannelState(channelName, pending.StateJson, pending.SessionID);\n }\n\n /** Final teardown flush: persist every channel's unsaved state immediately. */\n private flushAllChannelSaves(): void {\n for (const channelName of [...this.pendingChannelSaves.keys()]) {\n this.flushChannelSave(channelName);\n }\n }\n\n /** Disposes all channel plugins (errors contained per plugin) and clears the live set. */\n private disposeChannels(): void {\n for (const plugin of this._activeChannels$.value) {\n try {\n plugin.Dispose();\n } catch (error) {\n console.error(`[RealtimeSession] Channel '${plugin.ChannelName}' Dispose failed:`, error);\n }\n }\n if (this._activeChannels$.value.length > 0) {\n this._activeChannels$.next([]);\n }\n this.usedChannelNames.clear();\n }\n\n // ── Realtime client resolution + wiring ────────────────────────────────────\n\n /**\n * Resolves the provider-direct realtime client for `provider` through the MJ\n * ClassFactory — the client-side mirror of how server drivers are resolved from\n * `BaseRealtimeModel`. Throws a clear error when no driver is registered for the\n * provider (e.g. its Load function was never called).\n */\n private createRealtimeClient(provider: string): BaseRealtimeClient {\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(BaseRealtimeClient, provider);\n if (!registration) {\n throw new Error(\n `No realtime client registered for provider '${provider}'. ` +\n `Ensure the provider's client driver package is imported and its Load function called.`\n );\n }\n const client = MJGlobal.Instance.ClassFactory.CreateInstance<BaseRealtimeClient>(BaseRealtimeClient, provider);\n if (!client) {\n throw new Error(`Failed to instantiate the realtime client for provider '${provider}'`);\n }\n return client;\n }\n\n /** Builds the client-direct session config the realtime client connects with. */\n private buildClientConfig(session: StartRealtimeClientSessionResult): ClientRealtimeSessionConfig {\n return {\n Provider: session.Provider,\n Model: session.Model,\n EphemeralToken: session.EphemeralToken,\n ExpiresAt: session.ExpiresAt,\n SessionConfig: this.parseSessionConfig(session.SessionConfigJson)\n };\n }\n\n /**\n * Parses the server-built session config JSON. On failure, logs and returns an empty\n * object — the client treats an empty config as \"nothing to apply\", so the session\n * still opens (mirroring the prior behavior of skipping the config update).\n */\n private parseSessionConfig(sessionConfigJson: string | null): JSONObject {\n if (!sessionConfigJson) {\n return {};\n }\n try {\n return JSON.parse(sessionConfigJson) as JSONObject;\n } catch (error) {\n console.error('[RealtimeSession] Failed to parse/apply SessionConfigJson:', error);\n return {};\n }\n }\n\n /** Subscribes this service's policy handlers to the realtime client's events. */\n private wireClientHandlers(client: BaseRealtimeClient): void {\n client.OnStateChange((state: RealtimeClientState) => this.onClientStateChange(state));\n client.OnTranscript((transcript: RealtimeClientTranscript) => {\n void this.onClientTranscript(transcript);\n });\n client.OnToolCall((call: RealtimeClientToolCall) => {\n void this.handleToolCall(call);\n });\n client.OnError((error: RealtimeClientError) => {\n console.error('[RealtimeSession] Provider error event:', error);\n });\n // Usage telemetry: accumulate the driver's per-response token DELTAS and relay them to\n // the server (onto the co-agent AIPromptRun) debounced + once at teardown. Providers\n // without usage events simply never emit — registering is always safe.\n client.OnUsage((usage: RealtimeClientUsage) => this.onUsageDelta(usage));\n // TRUE BARGE-IN (user input cut off active model output — the driver already stopped\n // the speech): the user took the floor, so any pending/queued progress narration is\n // stale — cancel it; the next progress event re-schedules at the session-global pace.\n // HOST POLICY (deliberate): barge-in does NOT abort in-flight delegated runs — the\n // narration design EXPECTS the user to keep talking while delegated work runs, so\n // killing the work on speech would cancel exactly the jobs the user asked for.\n // Explicit cancellation is a separate, intentional act: the overlay's per-card ✕\n // calls {@link CancelDelegation} (server cancel channel) instead.\n client.OnInterruption(() => {\n this.cancelPendingNarration();\n });\n }\n\n /** Maps a client state event onto the UI connection state. */\n private onClientStateChange(state: RealtimeClientState): void {\n const mapped = this.mapClientState(state);\n if (mapped) {\n this._connectionState$.next(mapped);\n }\n }\n\n /**\n * Translates {@link RealtimeClientState} into {@link RealtimeConnectionState}. `'connected'`\n * is suppressed (the UI stays 'connecting' until the control channel opens → 'listening'),\n * and `'closed'` never overwrites a terminal 'error' the service itself recorded.\n */\n private mapClientState(state: RealtimeClientState): RealtimeConnectionState | null {\n switch (state) {\n case 'connecting':\n return 'connecting';\n case 'connected':\n return null;\n case 'listening':\n return 'listening';\n case 'speaking':\n return 'speaking';\n case 'error':\n return 'error';\n case 'closed':\n return this._connectionState$.value === 'error' ? null : 'closed';\n }\n }\n\n /** True when the live control channel is usable (open and not torn down / failed). */\n private isSessionLive(): boolean {\n const state = this._connectionState$.value;\n return state === 'listening' || state === 'speaking' || state === 'thinking';\n }\n\n // ── Transcript policy ──────────────────────────────────────────────────────\n\n /**\n * Applies transcript policy to client transcript events. Interim deltas don't become\n * captions/turns (the client already drives the speaking state) but DO mark this turn's\n * audio-start offset against the recording (the first interim fires as the audio/text\n * starts flowing — see {@link markTurnAudioStart}). Final NORMAL assistant turns become\n * captions + persisted transcripts; final NARRATION turns are EPHEMERAL by product\n * decision — emitted on {@link DelegationNarration$} only, never a caption, never\n * relayed/persisted. User turns ride the caption + relay path.\n */\n private async onClientTranscript(transcript: RealtimeClientTranscript): Promise<void> {\n if (!transcript.IsFinal) {\n // First interim of a NEW turn = that turn's audio is starting NOW. Stamp the\n // recording-relative start here so a turn whose audio begins AFTER a tool-call /\n // silence gap is timed where its audio really is — not inherited from the prior\n // turn's end. Narration interims are ephemeral and excluded (Kind guard inside).\n this.markTurnAudioStart(transcript.Kind);\n return;\n }\n if (transcript.Role === 'Assistant') {\n if (transcript.Kind === 'narration') {\n this._delegationNarration$.next({ Text: transcript.Text });\n // Remember what was actually SAID so later updates build on it instead of repeating.\n this.spokenNarrations.push(transcript.Text);\n if (this.spokenNarrations.length > RealtimeSessionService.MaxPriorNarrations) {\n this.spokenNarrations.shift();\n }\n } else if (transcript.ReplacesPrevious) {\n // CORRECTION (e.g. ElevenLabs post-barge-in re-finalization): this final\n // SUPERSEDES the previous final assistant turn — replace the caption in place\n // and tell the server to update the persisted turn instead of appending.\n this.replaceLastCaption('Assistant', transcript.Text);\n await this.relayTranscript('assistant', transcript.Text, true);\n } else {\n this.appendCaption({ Role: 'Assistant', Text: transcript.Text });\n await this.relayTranscript('assistant', transcript.Text);\n }\n } else if (transcript.ReplacesPrevious) {\n // STREAMING user transcription: providers like Grok emit the growing utterance as repeated\n // events (each the full text so far), flagging all but the first ReplacesPrevious. Update the\n // in-place User caption + persisted turn instead of stacking a new bubble per increment — the\n // same correction semantics the assistant branch uses. (OpenAI sends one final → the else path.)\n this.replaceLastCaption('User', transcript.Text);\n await this.relayTranscript('user', transcript.Text, true);\n } else {\n await this.onUserTranscript(transcript.Text);\n }\n }\n\n /**\n * Stamps the recording-relative offset at which the IN-FLIGHT turn's audio actually began,\n * the moment that turn's audio/text first starts flowing (its FIRST interim transcript).\n *\n * This is the fix for transcript cues drifting out of sync with the audio when a tool-call /\n * silence gap sits between turns: the old model inherited the next turn's start from the\n * PREVIOUS turn's end (assumes contiguous turns), so a post-gap turn's cue pointed ~gap-length\n * too early. Capturing the start where the audio truly begins keeps the cue aligned.\n *\n * Guards:\n * - only when recording ({@link recorder} present),\n * - only ONCE per turn ({@link turnAudioStartCaptured}) so mid-turn interim deltas don't move it,\n * - NORMAL turns only — NARRATION interims are ephemeral and never persisted, so they must not\n * claim the next real turn's start slot.\n *\n * Works for any role whose driver surfaces interim deltas (all drivers for the assistant; the\n * relevant case here — the post-tool-gap assistant answer — and user-interim drivers like\n * Gemini/AssemblyAI). For final-only user turns (OpenAI/xAI/ElevenLabs) no interim arrives, so\n * {@link relayTranscript} falls back to the seeded/prior start — the gap case that drifts is the\n * assistant answer, which always has interims.\n */\n private markTurnAudioStart(kind: 'normal' | 'narration'): void {\n if (!this.recorder || this.turnAudioStartCaptured || kind === 'narration') {\n return;\n }\n this.currentTurnStartMs = this.recorder.NowOffsetMs();\n this.turnAudioStartCaptured = true;\n }\n\n /**\n * Replaces the LAST caption of `role` in place (correction semantics); falls back to a\n * plain append when no such caption exists yet (e.g. the superseded turn predates this\n * client's caption window).\n */\n private replaceLastCaption(role: 'User' | 'Assistant', text: string): void {\n const captions = this._captions$.value;\n for (let i = captions.length - 1; i >= 0; i--) {\n if (captions[i].Role === role) {\n const next = [...captions];\n next[i] = { Role: role, Text: text };\n this._captions$.next(next);\n return;\n }\n }\n this.appendCaption({ Role: role, Text: text });\n }\n\n /** Finalizes the user turn: push a caption + relay the final transcript. */\n private async onUserTranscript(transcript: string): Promise<void> {\n if (transcript.trim().length === 0) {\n return;\n }\n if (this.firstUserTranscript === null) {\n // First spoken user utterance — the naming seed for a session-created conversation.\n this.firstUserTranscript = transcript;\n }\n this.appendCaption({ Role: 'User', Text: transcript });\n await this.relayTranscript('user', transcript);\n }\n\n // ── Tool calling ───────────────────────────────────────────────────────────\n\n /**\n * Routes a provider tool call: names matching a registered client-tool prefix execute\n * LOCALLY (UI tools — see {@link RegisterClientToolHandler}); everything else executes on\n * the MJ server. Either way the result feeds back to the model via\n * {@link BaseRealtimeClient.SendToolResult} so it speaks the outcome.\n */\n private async handleToolCall(call: RealtimeClientToolCall): Promise<void> {\n const clientHandler = this.findClientToolHandler(call.ToolName);\n if (clientHandler) {\n // Local UI tool: no server relay, no 'thinking' turn-state / narration burst — these\n // are fast, in-browser surface mutations (e.g. drawing on the whiteboard).\n const resultJson = await this.executeClientTool(clientHandler, call);\n this.client?.SendToolResult(call.CallID, resultJson);\n // Observability: record the channel tool call on the co-agent's run (run-only — NOT a chat\n // turn). Without this the run shows speech but never the browser_/Whiteboard_ actions the\n // co-agent took. Fire-and-forget; never disturbs the live surface mutation.\n void this.relayToolTurn(call.ToolName, call.ArgumentsJson, resultJson);\n return;\n }\n this._connectionState$.next('thinking');\n if (this.inFlightCallIds.size === 0) {\n // A fresh delegation burst: anchor the first-update delay and clear the digest\n // buffer. Deliberately NOT reset: lastDelegationNarrationAt (the 8s spacing floor\n // is SESSION-global — sequential tool calls seconds apart must not re-arm the\n // faster first-update path, which read as \"no debounce\") and spokenNarrations\n // (so the story never repeats across closely-spaced calls).\n this.delegationBurstStartedAt = Date.now();\n this.narrationCount = 0;\n this.pendingNarrationMessages = [];\n this.lastNarratedTail = '';\n }\n this.inFlightCallIds.add(call.CallID);\n try {\n const resultJson = await this.executeSessionTool(call.CallID, call.ToolName, call.ArgumentsJson);\n this.emitDelegationResult(call.CallID, resultJson);\n this.client?.SendToolResult(call.CallID, resultJson);\n } catch (error) {\n console.error('[RealtimeSession] Tool execution failed:', error);\n // Feed the error back so the model can narrate it rather than going silent.\n // success:false matters: ParseDelegationResultJson treats anything else as\n // success, which would flip the overlay's working card to a SUCCESS card\n // carrying the error text (matches the server broker's failure shape).\n const errorJson = JSON.stringify({\n success: false,\n error: error instanceof Error ? error.message : String(error)\n });\n this.emitDelegationResult(call.CallID, errorJson);\n this.client?.SendToolResult(call.CallID, errorJson);\n }\n }\n\n /** Finds the registered client-tool handler whose prefix matches `toolName`, or `null`. */\n private findClientToolHandler(toolName: string): RealtimeClientToolHandler | null {\n for (const [prefix, handler] of this.clientToolHandlers) {\n if (toolName.startsWith(prefix)) {\n return handler;\n }\n }\n return null;\n }\n\n /**\n * Executes one client-tool call through its handler, wrapping any thrown error into a\n * `{ success: false, error }` JSON payload so the model can narrate the failure instead of\n * the call going silent.\n */\n private async executeClientTool(handler: RealtimeClientToolHandler, call: RealtimeClientToolCall): Promise<string> {\n try {\n return await handler(call.ToolName, call.ArgumentsJson);\n } catch (error) {\n console.error('[RealtimeSession] Client tool execution failed:', error);\n return JSON.stringify({\n success: false,\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n /**\n * Emits a delegation result so the overlay's \"working\" card flips to a result card with real\n * content. Parses the broker's `{success, output, runId}` | `{success:false, error}` shape via\n * {@link ParseDelegationResultJson}; if it isn't JSON, surfaces the raw string. Only delegation\n * cards (created from progress events) react — non-delegation tool results have no card and are\n * harmlessly ignored downstream. The `runId` (the delegated `MJ: AI Agent Runs` record) rides\n * along as {@link RealtimeDelegationResult.RunID} for the overlay's dev links, and any `artifacts`\n * ride along as {@link RealtimeDelegationResult.Artifacts} for the surface panel's artifact tabs.\n */\n private emitDelegationResult(callId: string, resultJson: string): void {\n // The result will be spoken next — a deferred interim update is now pointless\n // (this is what keeps fast agents like Sage from narrating over their own answer),\n // and any progress still in the PubSub pipe for this call is stale.\n this.inFlightCallIds.delete(callId);\n this.cancelPendingNarration();\n if (this.cancelledCallIds.delete(callId)) {\n // The user explicitly cancelled this call: its card already flipped to the\n // \"Cancelled by user\" failed result, so the aborted run's late outcome must not\n // overwrite it. (The tool result still flows back to the model via the caller.)\n return;\n }\n const parsed = ParseDelegationResultJson(resultJson);\n this._delegationResult$.next({\n CallID: callId,\n Success: parsed.Success,\n Output: parsed.Output,\n RunID: parsed.RunID,\n Artifacts: parsed.Artifacts\n });\n }\n\n // ── Explicit delegation cancellation (server cancel channel) ───────────────\n\n /**\n * Cancels ONE in-flight delegated tool call — the overlay's per-card ✕ affordance.\n *\n * EXPLICIT USER INTENT ONLY (deliberate host policy): true barge-in never aborts\n * delegations — the narration design expects the user to talk while delegated work runs.\n * Calls the `CancelRealtimeSessionTool` mutation (ownership-gated server-side); when the\n * server reports it aborted the run, the card is flipped immediately to a FAILED\n * \"Cancelled by user\" result and the eventual late result from the aborted run is\n * suppressed (see {@link emitDelegationResult}).\n *\n * @returns `true` when the server aborted the in-flight run; `false` when there was\n * nothing to cancel (the work finished first — its real result is already racing in)\n * or the mutation failed (logged, never thrown).\n */\n public async CancelDelegation(callId: string): Promise<boolean> {\n if (!this.agentSessionId || !this.inFlightCallIds.has(callId)) {\n return false;\n }\n const aborted = await this.cancelSessionTool(callId);\n if (aborted <= 0) {\n return false; // finished first / nothing in flight server-side — let the real result land\n }\n this.surfaceUserCancellation(callId);\n return true;\n }\n\n /**\n * Cancels EVERY in-flight delegated tool call for the active session (callId-less form of\n * the `CancelRealtimeSessionTool` mutation). Exposed for host policies that need a\n * sweep-cancel (e.g. an explicit \"stop everything\" affordance) — NOT wired to barge-in,\n * by the same deliberate policy as {@link CancelDelegation}.\n *\n * @returns The number of in-flight runs the server aborted (0 when nothing was tracked\n * in flight client-side, nothing was in flight server-side, or the mutation failed).\n */\n public async CancelInFlightDelegations(): Promise<number> {\n if (!this.agentSessionId || this.inFlightCallIds.size === 0) {\n return 0;\n }\n const aborted = await this.cancelSessionTool(null);\n if (aborted <= 0) {\n return 0;\n }\n for (const callId of [...this.inFlightCallIds]) {\n this.surfaceUserCancellation(callId);\n }\n return aborted;\n }\n\n /** Flips a cancelled call's card to the failed \"Cancelled by user\" result and suppresses the late real result. */\n private surfaceUserCancellation(callId: string): void {\n this.inFlightCallIds.delete(callId);\n this.cancelledCallIds.add(callId);\n this.cancelPendingNarration();\n this._delegationResult$.next({\n CallID: callId,\n Success: false,\n Output: 'Cancelled by user'\n });\n }\n\n /**\n * Calls the `CancelRealtimeSessionTool` mutation and unwraps its structured\n * `{ AbortedCount, Success, ErrorMessage }` result. Returns the aborted count —\n * 0 on a structured failure or a thrown transport error (both logged, never thrown).\n */\n private async cancelSessionTool(callId: string | null): Promise<number> {\n try {\n const mutation = `\n mutation CancelRealtimeSessionTool($agentSessionId: String!, $callId: String) {\n CancelRealtimeSessionTool(agentSessionId: $agentSessionId, callId: $callId) {\n AbortedCount\n Success\n ErrorMessage\n }\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, { agentSessionId: this.agentSessionId, callId });\n const payload = result?.CancelRealtimeSessionTool as\n | { AbortedCount?: number; Success?: boolean; ErrorMessage?: string }\n | undefined;\n if (!payload?.Success) {\n console.warn(`[RealtimeSession] Cancel reported failure: ${payload?.ErrorMessage ?? 'unknown error'}`);\n return 0;\n }\n return typeof payload.AbortedCount === 'number' ? payload.AbortedCount : 0;\n } catch (error) {\n console.error('[RealtimeSession] Failed to cancel in-flight delegation(s):', error);\n return 0;\n }\n }\n\n // ── Session minting (GraphQL) ──────────────────────────────────────────────\n\n /** Calls the `StartRealtimeClientSession` mutation to obtain an ephemeral token + config. */\n private async mintSession(\n targetAgentId: string,\n conversationId?: string | null,\n lastSessionId?: string | null,\n preferredModelId?: string | null,\n clientTools?: RealtimeToolDefinition[] | null,\n coAgentId?: string | null,\n configOverridesJson?: string | null,\n recordingConsent?: boolean | null,\n recordingStartedAt?: string | null,\n mediaCollectionId?: string | null,\n applicationId?: string | null,\n appContext?: AppContextSnapshot | null\n ): Promise<StartRealtimeClientSessionResult> {\n const mutation = `\n mutation StartRealtimeClientSession($targetAgentId: String!, $conversationId: String, $lastSessionId: String, $preferredModelId: String, $clientToolsJson: String, $coAgentId: String, $configOverridesJson: String, $recordingConsent: Boolean, $recordingStartedAt: String, $mediaCollectionId: String, $applicationId: String, $appContextJson: String) {\n StartRealtimeClientSession(targetAgentId: $targetAgentId, conversationId: $conversationId, lastSessionId: $lastSessionId, preferredModelId: $preferredModelId, clientToolsJson: $clientToolsJson, coAgentId: $coAgentId, configOverridesJson: $configOverridesJson, recordingConsent: $recordingConsent, recordingStartedAt: $recordingStartedAt, mediaCollectionId: $mediaCollectionId, applicationId: $applicationId, appContextJson: $appContextJson) {\n AgentSessionId\n ConversationId\n Provider\n Model\n EphemeralToken\n ExpiresAt\n SessionConfigJson\n ModelName\n NarrationInstructionsTemplate\n PriorChannelStatesJson\n }\n }\n `;\n const variables = {\n targetAgentId,\n conversationId: conversationId ?? null,\n lastSessionId: lastSessionId ?? null,\n preferredModelId: preferredModelId ?? null,\n clientToolsJson: clientTools && clientTools.length > 0 ? JSON.stringify(clientTools) : null,\n coAgentId: coAgentId ?? null,\n configOverridesJson: configOverridesJson ?? null,\n recordingConsent: recordingConsent ?? false,\n recordingStartedAt: recordingStartedAt ?? null,\n mediaCollectionId: mediaCollectionId ?? null,\n applicationId: applicationId ?? null,\n appContextJson: appContext ? JSON.stringify(appContext) : null\n };\n const result = await this.gql().ExecuteGQL(mutation, variables);\n const payload = result?.StartRealtimeClientSession as StartRealtimeClientSessionResult | undefined;\n if (!payload?.EphemeralToken) {\n throw new Error('StartRealtimeClientSession returned no ephemeral token');\n }\n return payload;\n }\n\n /** Calls the `ExecuteRealtimeSessionTool` mutation; returns the ResultJson string. */\n private async executeSessionTool(callId: string, toolName: string, argsJson: string): Promise<string> {\n if (!this.agentSessionId) {\n throw new Error('No active agent session for tool execution');\n }\n const mutation = `\n mutation ExecuteRealtimeSessionTool($agentSessionId: String!, $callId: String!, $toolName: String!, $argsJson: String!) {\n ExecuteRealtimeSessionTool(agentSessionId: $agentSessionId, callId: $callId, toolName: $toolName, argsJson: $argsJson)\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n callId,\n toolName,\n argsJson\n });\n return (result?.ExecuteRealtimeSessionTool as string) ?? '{}';\n }\n\n /**\n * Persists an interactive channel's state of record (e.g. the whiteboard's serialized scene)\n * onto the session's `MJ: AI Agent Session Channels` row via `SaveSessionChannelState`.\n *\n * @param channelName The channel definition name (e.g. `'Whiteboard'`).\n * @param stateJson The serialized channel state.\n * @param agentSessionId Optional EXPLICIT session id. The debounced channel-save pipeline\n * captures the id while the session is live and passes it here, so the final teardown\n * flush still lands on the just-closed session. Falls back to the active session's id;\n * returns `false` when neither is available.\n * @returns Whether the server persisted the state. Failures are logged, never thrown — channel\n * persistence is best-effort and must not disturb the live call.\n */\n public async SaveChannelState(channelName: string, stateJson: string, agentSessionId?: string | null): Promise<boolean> {\n const sessionId = agentSessionId ?? this.agentSessionId;\n if (!sessionId) {\n return false;\n }\n try {\n const mutation = `\n mutation SaveSessionChannelState($agentSessionId: String!, $channelName: String!, $stateJson: String!) {\n SaveSessionChannelState(agentSessionId: $agentSessionId, channelName: $channelName, stateJson: $stateJson)\n }\n `;\n const result = await this.gql().ExecuteGQL(mutation, { agentSessionId: sessionId, channelName, stateJson });\n return (result?.SaveSessionChannelState as boolean) ?? false;\n } catch (error) {\n console.error('[RealtimeSession] Failed to save channel state:', error);\n return false;\n }\n }\n\n // ── Transcript relay (GraphQL) ─────────────────────────────────────────────\n\n /**\n * Relays a final transcript turn to MJ via `RelayRealtimeTranscript`.\n *\n * When the session is being recorded, per-turn timing rides along: `utteranceEndMs` is the\n * recording-relative offset at finalization, and `utteranceStartMs` is the offset captured by\n * {@link markTurnAudioStart} when THIS turn's audio actually began (its first interim) — NOT\n * inherited from the previous turn's end. That distinction is the timing fix: when a tool-call\n * / silence gap sits between turns, the post-gap turn's audio starts much later, so inheriting\n * the prior turn's end stamped the cue ~gap-length too early. Both are omitted (left `null`)\n * when the session isn't being recorded.\n *\n * A correction (`replacesPrevious`) doesn't open a new turn, so it carries no start and doesn't\n * reset the per-turn start guard. After a normal finalization the guard is cleared so the NEXT\n * turn re-stamps its start from where ITS audio begins.\n *\n * @param replacesPrevious CORRECTION semantics: the server updates the session's most\n * recent persisted turn of this role IN PLACE instead of appending (e.g. ElevenLabs'\n * post-barge-in `agent_response_correction`).\n */\n private async relayTranscript(role: 'user' | 'assistant', text: string, replacesPrevious: boolean = false): Promise<void> {\n if (!this.agentSessionId) {\n return;\n }\n // Per-turn timing against the recording (when recording). `utteranceStartMs` is where this\n // turn's audio actually began (captured by markTurnAudioStart on the first interim); the\n // `?? 0` fallback covers a turn whose interim was missed / a final-only first turn.\n const utteranceEndMs = this.recorder ? this.recorder.NowOffsetMs() : null;\n const utteranceStartMs = this.recorder && !replacesPrevious ? (this.currentTurnStartMs ?? 0) : null;\n if (this.recorder && !replacesPrevious) {\n // This turn is finalized — arm the NEXT turn to re-stamp its start from its own first\n // interim (handles a tool-call gap before the next turn). Stop inheriting this end as the\n // next start. `null` means \"not yet captured\"; relay falls back to `?? 0` if no interim fires.\n this.currentTurnStartMs = null;\n this.turnAudioStartCaptured = false;\n }\n try {\n const mutation = `\n mutation RelayRealtimeTranscript($agentSessionId: String!, $role: String!, $text: String!, $replacesPrevious: Boolean, $utteranceStartMs: Int, $utteranceEndMs: Int) {\n RelayRealtimeTranscript(agentSessionId: $agentSessionId, role: $role, text: $text, replacesPrevious: $replacesPrevious, utteranceStartMs: $utteranceStartMs, utteranceEndMs: $utteranceEndMs)\n }\n `;\n await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n role,\n text,\n replacesPrevious,\n utteranceStartMs,\n utteranceEndMs\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay transcript:', error);\n }\n }\n\n /**\n * Relays a co-agent CHANNEL tool-call turn (browser_ / Whiteboard_ etc.) to the session's run for\n * observability via `RelayRealtimeToolTurn` — so the co-agent's AIPromptRun shows what it DID, not\n * just what it said. Run-only by design: deliberately NOT a `ConversationDetail` turn, so the chat\n * thread stays speech-only. Best-effort — a failed relay never disturbs the live call.\n */\n private async relayToolTurn(toolName: string, argsJson: string, resultJson: string): Promise<void> {\n if (!this.agentSessionId) {\n return;\n }\n try {\n const mutation = `\n mutation RelayRealtimeToolTurn($agentSessionId: String!, $toolName: String!, $argsJson: String, $resultJson: String) {\n RelayRealtimeToolTurn(agentSessionId: $agentSessionId, toolName: $toolName, argsJson: $argsJson, resultJson: $resultJson)\n }\n `;\n await this.gql().ExecuteGQL(mutation, {\n agentSessionId: this.agentSessionId,\n toolName,\n argsJson,\n resultJson\n });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay tool turn:', error);\n }\n }\n\n // ── Usage telemetry relay (B7) ─────────────────────────────────────────────\n\n /**\n * Accumulates one usage DELTA from the realtime client (per-response token counts —\n * the `OnUsage` contract shape) and schedules the debounced relay. Negative / non-finite\n * values are clamped to 0; an all-zero delta is dropped without arming the timer.\n */\n private onUsageDelta(usage: RealtimeClientUsage): void {\n const input = this.clampUsageDelta(usage.InputTokens);\n const output = this.clampUsageDelta(usage.OutputTokens);\n if (input === 0 && output === 0) {\n return;\n }\n this.pendingUsageInput += input;\n this.pendingUsageOutput += output;\n if (!this.usageFlushTimer) {\n this.usageFlushTimer = setTimeout(() => {\n this.usageFlushTimer = null;\n void this.flushPendingUsage();\n }, RealtimeSessionService.UsageFlushDebounceMs);\n }\n }\n\n /** Clamps a driver-reported token delta: undefined / negative / non-finite become 0. */\n private clampUsageDelta(value: number | undefined): number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;\n }\n\n /**\n * Relays the accumulated usage deltas to the server via `RelayRealtimeUsage` (which\n * accumulates them onto the co-agent `AIPromptRun`). Best-effort: a failed relay\n * re-accumulates the captured deltas so the next debounce / teardown flush retries —\n * usage telemetry must never disturb the live call.\n *\n * @param agentSessionId Optional EXPLICIT session id (the teardown flush runs while the\n * live id is still set, but accepts it as a parameter for symmetry with channel saves).\n */\n private async flushPendingUsage(agentSessionId?: string | null): Promise<void> {\n const sessionId = agentSessionId ?? this.agentSessionId;\n const input = this.pendingUsageInput;\n const output = this.pendingUsageOutput;\n if (!sessionId || (input === 0 && output === 0)) {\n return;\n }\n this.pendingUsageInput = 0;\n this.pendingUsageOutput = 0;\n try {\n const mutation = `\n mutation RelayRealtimeUsage($agentSessionId: String!, $inputTokens: Int!, $outputTokens: Int!) {\n RelayRealtimeUsage(agentSessionId: $agentSessionId, inputTokens: $inputTokens, outputTokens: $outputTokens)\n }\n `;\n await this.gql().ExecuteGQL(mutation, { agentSessionId: sessionId, inputTokens: input, outputTokens: output });\n } catch (error) {\n console.error('[RealtimeSession] Failed to relay usage telemetry:', error);\n // Re-accumulate so a later debounce / the teardown flush retries the same deltas.\n this.pendingUsageInput += input;\n this.pendingUsageOutput += output;\n }\n }\n\n /** Cancels the pending debounced usage flush and zeroes the accumulators (teardown tail). */\n private resetUsageRelay(): void {\n if (this.usageFlushTimer) {\n clearTimeout(this.usageFlushTimer);\n this.usageFlushTimer = null;\n }\n this.pendingUsageInput = 0;\n this.pendingUsageOutput = 0;\n }\n\n // ── Delegated-run progress streaming ───────────────────────────────────────\n\n /**\n * Subscribes to the server's push-status topic (scoped by the GraphQL transport\n * sessionId) to receive delegated-run progress for the active voice session.\n * Each matching event is surfaced on {@link DelegationProgress$} and narrated.\n */\n private subscribeDelegationProgress(): void {\n if (this.delegationProgressSub) {\n return; // already subscribed for this session\n }\n const transportSessionId = this.gql().sessionId;\n this.lastDelegationNarrationAt = 0;\n this.delegationProgressSub = this.gql()\n .PushStatusUpdates(transportSessionId)\n .subscribe({\n next: (raw: string) => this.onDelegationStatusMessage(raw),\n error: (err: unknown) => console.error('[RealtimeSession] Delegation progress stream error:', err)\n });\n }\n\n /**\n * Parses one push-status message and routes it: a Remote Browser screencast frame goes to the active\n * Remote Browser channel's canvas; a delegation-progress event is dispatched + narrated. Other shapes\n * (normal agent-run streams) are ignored. Screencast frames are checked FIRST and short-circuit, so the\n * delegation path is untouched.\n */\n private onDelegationStatusMessage(raw: string): void {\n const frame = this.parseScreencastFrame(raw);\n if (frame) {\n this.routeScreencastFrame(frame);\n return;\n }\n const audio = this.parseAudioChunk(raw);\n if (audio) {\n this.routeAudioChunk(audio);\n return;\n }\n const progress = this.parseProgress(raw);\n if (progress) {\n this.dispatchProgress(progress);\n }\n }\n\n /**\n * Parses a push-status message and returns it only when it's a Remote Browser screencast frame for the\n * active session — otherwise `null` (ignored, so delegation progress falls through). Matched by\n * `resolver` + `type`, then scoped to THIS session by `agentSessionID`.\n */\n private parseScreencastFrame(raw: string): RemoteBrowserScreencastPayload | null {\n let payload: { resolver?: string } & Partial<RemoteBrowserScreencastPayload>;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n const matches =\n payload?.resolver === 'RemoteBrowserActionResolver' &&\n payload?.type === 'RemoteBrowserScreencastFrame' &&\n payload?.agentSessionID === this.agentSessionId &&\n typeof payload?.dataBase64 === 'string';\n return matches ? (payload as RemoteBrowserScreencastPayload) : null;\n }\n\n /**\n * Forwards a screencast frame to the active Remote Browser channel plugin so it paints the frame on its\n * surface canvas. The plugin is found among the session's active channels by its `ChannelName`; located\n * via a structural guard so the service stays decoupled from the concrete channel class.\n */\n private routeScreencastFrame(frame: RemoteBrowserScreencastPayload): void {\n for (const channel of this._activeChannels$.value) {\n if (channel.ChannelName === 'Remote Browser' && this.hasOnScreencastFrame(channel)) {\n channel.OnScreencastFrame(frame.dataBase64);\n return;\n }\n }\n }\n\n /** Structural guard: true when the channel exposes an `OnScreencastFrame(dataBase64)` method. */\n private hasOnScreencastFrame(\n channel: BaseRealtimeChannelClient,\n ): channel is BaseRealtimeChannelClient & { OnScreencastFrame(dataBase64: string): void } {\n return typeof (channel as { OnScreencastFrame?: unknown }).OnScreencastFrame === 'function';\n }\n\n /**\n * Parses a push-status message and returns it only when it's a Remote Browser audio chunk for the active\n * session — otherwise `null` (ignored). Matched by `resolver` + `type`, then scoped to THIS session by\n * `agentSessionID`.\n */\n private parseAudioChunk(raw: string): RemoteBrowserAudioChunkPayload | null {\n let payload: { resolver?: string } & Partial<RemoteBrowserAudioChunkPayload>;\n try {\n payload = JSON.parse(raw);\n } catch {\n return null;\n }\n const matches =\n payload?.resolver === 'RemoteBrowserActionResolver' &&\n payload?.type === 'RemoteBrowserAudioChunk' &&\n payload?.agentSessionID === this.agentSessionId &&\n typeof payload?.dataBase64 === 'string';\n return matches ? (payload as RemoteBrowserAudioChunkPayload) : null;\n }\n\n /**\n * Forwards an audio chunk to the active Remote Browser channel plugin so it plays the chunk through its\n * client-side audio player. The plugin is found among the session's active channels by its `ChannelName`;\n * located via a structural guard so the service stays decoupled from the concrete channel class.\n */\n private routeAudioChunk(chunk: RemoteBrowserAudioChunkPayload): void {\n for (const channel of this._activeChannels$.value) {\n if (channel.ChannelName === 'Remote Browser' && this.hasOnAudioChunk(channel)) {\n channel.OnAudioChunk({\n dataBase64: chunk.dataBase64,\n codec: chunk.codec,\n sampleRate: chunk.sampleRate,\n channels: chunk.channels,\n seq: chunk.seq,\n });\n return;\n }\n }\n }\n\n /** Structural guard: true when the channel exposes an `OnAudioChunk(chunk)` method. */\n private hasOnAudioChunk(\n channel: BaseRealtimeChannelClient,\n ): channel is BaseRealtimeChannelClient & { OnAudioChunk(chunk: { dataBase64: string; codec: string; sampleRate: number; channels: number; seq: number }): void } {\n return typeof (channel as { OnAudioChunk?: unknown }).OnAudioChunk === 'function';\n }\n\n /**\n * Parses a push-status message and returns it only when it's a delegation\n * progress event for the active voice session — otherwise `null` (ignored).\n */\n private parseProgress(raw: string): RealtimeDelegationProgress | null {\n let payload: RealtimeDelegationProgressPayload;\n try {\n payload = JSON.parse(raw) as RealtimeDelegationProgressPayload;\n } catch {\n return null; // non-JSON or unrelated frame\n }\n const matches =\n payload?.resolver === 'RealtimeClientSessionResolver' &&\n payload?.type === 'RealtimeDelegationProgress' &&\n payload?.agentSessionID === this.agentSessionId;\n if (!matches) {\n return null;\n }\n return {\n CallID: payload.callID,\n Step: payload.step,\n Message: payload.message,\n Percentage: payload.percentage\n };\n }\n\n /** Emits the progress to the UI observable and feeds it to the realtime model. */\n private dispatchProgress(progress: RealtimeDelegationProgress): void {\n // Drop stale progress: PubSub delivery can lag the mutation result, so events for a\n // call that already completed (or was never seen) must not update cards or narrate.\n if (!this.inFlightCallIds.has(progress.CallID)) {\n return;\n }\n this._delegationProgress$.next(progress);\n this.narrateProgress(progress);\n }\n\n /**\n * Injects the progress into the model's context as a background note every time,\n * then (throttled) asks the model to briefly voice a reassuring update so the\n * background work doesn't sit in silence — without chattering or interrupting.\n */\n private narrateProgress(progress: RealtimeDelegationProgress): void {\n const client = this.client;\n if (!client) {\n return;\n }\n client.SendContextNote(`[delegated-agent progress] ${progress.Message}`);\n // Floods of small updates AGGREGATE: each distinct message joins the digest buffer,\n // and ONE spoken update fires per window (first at ~5s into the burst, then every\n // ~8s). The buffer is discarded if the final result lands first.\n this.bufferNarrationMessage(progress.Message);\n if (this.pendingNarrationMessages.length > 0 && !this.narrationTimer) {\n this.narrationTimer = setTimeout(() => this.fireDeferredNarration(), this.nextNarrationDelayMs());\n }\n }\n\n /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */\n private bufferNarrationMessage(message: string): void {\n if (message === this.lastNarratedTail || this.pendingNarrationMessages.includes(message)) {\n return;\n }\n this.pendingNarrationMessages.push(message);\n if (this.pendingNarrationMessages.length > RealtimeSessionService.MaxDigestMessages) {\n this.pendingNarrationMessages.shift();\n }\n }\n\n /**\n * ms until the next spoken update is allowed. Two constraints, BOTH enforced:\n * - first update of a burst: no earlier than ~5s after the burst started;\n * - ~8s since the last spoken update, SESSION-global — so sequential tool calls\n * that reset the burst can never narrate faster than the interval.\n */\n private nextNarrationDelayMs(): number {\n const now = Date.now();\n const firstAnchor = this.narrationCount === 0\n ? this.delegationBurstStartedAt + RealtimeSessionService.FirstNarrationDelayMs\n : 0;\n const spacingFloor = this.lastDelegationNarrationAt > 0\n ? this.lastDelegationNarrationAt + RealtimeSessionService.NarrationIntervalMs\n : 0;\n return Math.max(250, Math.max(firstAnchor, spacingFloor) - now);\n }\n\n /**\n * Speaks the aggregated progress digest — unless the work already finished (buffer\n * cancelled) or the model is busy / audio is still playing, in which case it retries\n * shortly with the buffer intact (work is still running, so the update stays relevant).\n */\n private fireDeferredNarration(): void {\n this.narrationTimer = null;\n const client = this.client;\n if (this.pendingNarrationMessages.length === 0 || !client || this.inFlightCallIds.size === 0) {\n this.pendingNarrationMessages = [];\n return;\n }\n if (client.IsBusy || client.IsAudioPlaying) {\n this.narrationTimer = setTimeout(() => this.fireDeferredNarration(), RealtimeSessionService.NarrationBusyRetryMs);\n return;\n }\n const digest = this.pendingNarrationMessages.join(' → ');\n this.lastNarratedTail = this.pendingNarrationMessages[this.pendingNarrationMessages.length - 1];\n this.pendingNarrationMessages = [];\n this.narrationCount++;\n this.lastDelegationNarrationAt = Date.now();\n client.RequestSpokenUpdate(this.buildNarrationInstructions(digest));\n }\n\n /** Cancels any deferred narration — the result is about to be spoken, so it's moot. */\n private cancelPendingNarration(): void {\n if (this.narrationTimer) {\n clearTimeout(this.narrationTimer);\n this.narrationTimer = null;\n }\n this.pendingNarrationMessages = [];\n }\n\n /**\n * Builds the one-off instructions for a short spoken update that conveys THIS specific\n * progress message naturally — strictly first person, since the co-agent owns the work.\n * The wording is DB-driven: the server-resolved `Realtime Co-Agent - Progress Narration`\n * template (substituting `{{ progressMessage }}`) when present, otherwise the built-in\n * fallback so deployments that haven't synced the prompt behave exactly as before.\n * The client tags the resulting turn as narration, keeping it EPHEMERAL — surfaced on\n * {@link DelegationNarration$} instead of becoming a caption / persisted ConversationDetail.\n */\n private buildNarrationInstructions(digest: string): string {\n return BuildNarrationInstructions(this.narrationTemplate, digest, {\n PriorNarrations: this.spokenNarrations.slice(-RealtimeSessionService.MaxPriorNarrations),\n UpdateNumber: this.narrationCount\n });\n }\n\n /** Tears down the delegation progress subscription and resets the narration throttle. */\n private teardownDelegationProgress(): void {\n if (this.delegationProgressSub) {\n this.delegationProgressSub.unsubscribe();\n this.delegationProgressSub = null;\n }\n this.cancelPendingNarration();\n this.inFlightCallIds.clear();\n this.cancelledCallIds.clear();\n this.lastDelegationNarrationAt = 0;\n this.delegationBurstStartedAt = 0;\n this.narrationCount = 0;\n this.spokenNarrations = [];\n this.lastNarratedTail = '';\n }\n\n // ── Teardown ───────────────────────────────────────────────────────────────\n\n /**\n * Tears down all client resources and (optionally) closes the server session.\n * @param closeServerSession when true, calls `CloseAgentSession` on the server.\n */\n private async teardown(closeServerSession: boolean): Promise<void> {\n this.teardownDelegationProgress();\n\n // Channels first: flush any unsaved channel state WHILE the live session id is still\n // set (the captured per-save id covers the race anyway), then dispose the plugins.\n this.flushAllChannelSaves();\n this.disposeChannels();\n\n // Defensive: stop the mic even when Connect never ran (the client also stops the\n // tracks it was handed — track.stop() is idempotent).\n this.localStream?.getTracks().forEach(t => t.stop());\n this.localStream = null;\n\n if (this.client) {\n await this.client.Disconnect();\n this.client = null;\n }\n\n // Stop + upload the call recording WHILE the live session id is still set (the file is\n // attached to it). Best-effort and never blocks teardown — stopAndUploadRecording swallows\n // its own errors. No-op when nothing was recorded.\n await this.stopAndUploadRecording(this.agentSessionId);\n this.recordingStartedAtIso = null;\n\n // Final usage flush WHILE the live session id is still set (the relay mutation also\n // accepts a Closed session, so ordering vs. CloseAgentSession is belt-and-braces).\n if (this.usageFlushTimer) {\n clearTimeout(this.usageFlushTimer);\n this.usageFlushTimer = null;\n }\n await this.flushPendingUsage(this.agentSessionId);\n this.resetUsageRelay();\n\n if (closeServerSession && this.agentSessionId) {\n await this.closeServerSession(this.agentSessionId);\n }\n\n // Capture the session id BEFORE we null it so the lifecycle emit carries it.\n // Skip emitting when there was no live session (defensive — teardown is safe\n // to call without an active session).\n const closedSessionId = this.agentSessionId;\n this.agentSessionId = null;\n this.narrationTemplate = null;\n this.clientToolHandlers.clear();\n this._modelName$.next(null);\n this.SetMinimized(false);\n this._active$.next(false);\n if (this._connectionState$.value !== 'error') {\n this._connectionState$.next('closed');\n }\n\n // Surface generic session-ended for the conversations runtime bridge.\n // `closeServerSession=true` means the user explicitly called EndRealtimeSession;\n // `false` means teardown ran from a catch block (start path error path).\n if (closedSessionId) {\n this._sessionEnded$.next({\n sessionId: closedSessionId,\n reason: closeServerSession ? 'explicit' : 'error',\n });\n }\n }\n\n /** Calls the `CloseAgentSession` mutation (provisioned in P4b). */\n private async closeServerSession(agentSessionId: string): Promise<void> {\n try {\n const mutation = `\n mutation CloseAgentSession($agentSessionId: String!) {\n CloseAgentSession(agentSessionId: $agentSessionId)\n }\n `;\n await this.gql().ExecuteGQL(mutation, { agentSessionId });\n } catch (error) {\n console.error('[RealtimeSession] Failed to close server session:', error);\n }\n }\n\n // ── Helpers ────────────────────────────────────────────────────────────────\n\n /** Pushes a caption onto the live list (immutable update for change detection). */\n private appendCaption(caption: RealtimeCaption): void {\n this._captions$.next([...this._captions$.value, caption]);\n }\n\n /** Resets reactive + internal state at the start of a session. */\n private resetState(): void {\n this._captions$.next([]);\n this.SetMinimized(false);\n this.stopSegmentFlushing();\n this.segmentIndex = 0;\n this.recorder = null;\n this.recordingStartedAtIso = null;\n this.currentTurnStartMs = null;\n this.turnAudioStartCaptured = false;\n this.usedChannelNames.clear();\n }\n\n /** The GraphQL provider used for relay mutations. */\n private gql(): GraphQLDataProvider {\n return this.Provider as GraphQLDataProvider;\n }\n}\n"]}