@memberjunction/ng-conversations 5.40.1 → 5.41.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 (378) hide show
  1. package/README.md +57 -0
  2. package/dist/__tests__/channel-optional-surface.test.d.ts +2 -0
  3. package/dist/__tests__/channel-optional-surface.test.d.ts.map +1 -0
  4. package/dist/__tests__/channel-optional-surface.test.js +53 -0
  5. package/dist/__tests__/channel-optional-surface.test.js.map +1 -0
  6. package/dist/__tests__/chat-events.test.d.ts +14 -0
  7. package/dist/__tests__/chat-events.test.d.ts.map +1 -0
  8. package/dist/__tests__/chat-events.test.js +109 -0
  9. package/dist/__tests__/chat-events.test.js.map +1 -0
  10. package/dist/__tests__/conversation-naming.test.d.ts +2 -0
  11. package/dist/__tests__/conversation-naming.test.d.ts.map +1 -0
  12. package/dist/__tests__/conversation-naming.test.js +110 -0
  13. package/dist/__tests__/conversation-naming.test.js.map +1 -0
  14. package/dist/__tests__/delegation-result-parser.test.d.ts +2 -0
  15. package/dist/__tests__/delegation-result-parser.test.d.ts.map +1 -0
  16. package/dist/__tests__/delegation-result-parser.test.js +107 -0
  17. package/dist/__tests__/delegation-result-parser.test.js.map +1 -0
  18. package/dist/__tests__/event-wiring.test.d.ts +15 -0
  19. package/dist/__tests__/event-wiring.test.d.ts.map +1 -0
  20. package/dist/__tests__/event-wiring.test.js +100 -0
  21. package/dist/__tests__/event-wiring.test.js.map +1 -0
  22. package/dist/__tests__/narration-template.test.d.ts +2 -0
  23. package/dist/__tests__/narration-template.test.d.ts.map +1 -0
  24. package/dist/__tests__/narration-template.test.js +76 -0
  25. package/dist/__tests__/narration-template.test.js.map +1 -0
  26. package/dist/__tests__/realtime-agent-picker-models.test.d.ts +2 -0
  27. package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +1 -0
  28. package/dist/__tests__/realtime-agent-picker-models.test.js +49 -0
  29. package/dist/__tests__/realtime-agent-picker-models.test.js.map +1 -0
  30. package/dist/__tests__/realtime-audio-visuals.test.d.ts +2 -0
  31. package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +1 -0
  32. package/dist/__tests__/realtime-audio-visuals.test.js +123 -0
  33. package/dist/__tests__/realtime-audio-visuals.test.js.map +1 -0
  34. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +2 -0
  35. package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +1 -0
  36. package/dist/__tests__/realtime-delegation-card-cancel.test.js +48 -0
  37. package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +1 -0
  38. package/dist/__tests__/realtime-disclosure.test.d.ts +2 -0
  39. package/dist/__tests__/realtime-disclosure.test.d.ts.map +1 -0
  40. package/dist/__tests__/realtime-disclosure.test.js +164 -0
  41. package/dist/__tests__/realtime-disclosure.test.js.map +1 -0
  42. package/dist/__tests__/realtime-pairing.test.d.ts +2 -0
  43. package/dist/__tests__/realtime-pairing.test.d.ts.map +1 -0
  44. package/dist/__tests__/realtime-pairing.test.js +207 -0
  45. package/dist/__tests__/realtime-pairing.test.js.map +1 -0
  46. package/dist/__tests__/realtime-review-lifecycle.test.d.ts +2 -0
  47. package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +1 -0
  48. package/dist/__tests__/realtime-review-lifecycle.test.js +154 -0
  49. package/dist/__tests__/realtime-review-lifecycle.test.js.map +1 -0
  50. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +2 -0
  51. package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +1 -0
  52. package/dist/__tests__/realtime-session-cancel-usage.test.js +230 -0
  53. package/dist/__tests__/realtime-session-cancel-usage.test.js.map +1 -0
  54. package/dist/__tests__/realtime-session-channels.test.d.ts +2 -0
  55. package/dist/__tests__/realtime-session-channels.test.d.ts.map +1 -0
  56. package/dist/__tests__/realtime-session-channels.test.js +252 -0
  57. package/dist/__tests__/realtime-session-channels.test.js.map +1 -0
  58. package/dist/__tests__/realtime-session-client-tools.test.d.ts +2 -0
  59. package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +1 -0
  60. package/dist/__tests__/realtime-session-client-tools.test.js +103 -0
  61. package/dist/__tests__/realtime-session-client-tools.test.js.map +1 -0
  62. package/dist/__tests__/realtime-session-minimized.test.d.ts +2 -0
  63. package/dist/__tests__/realtime-session-minimized.test.d.ts.map +1 -0
  64. package/dist/__tests__/realtime-session-minimized.test.js +32 -0
  65. package/dist/__tests__/realtime-session-minimized.test.js.map +1 -0
  66. package/dist/__tests__/realtime-session-mint.test.d.ts +2 -0
  67. package/dist/__tests__/realtime-session-mint.test.d.ts.map +1 -0
  68. package/dist/__tests__/realtime-session-mint.test.js +69 -0
  69. package/dist/__tests__/realtime-session-mint.test.js.map +1 -0
  70. package/dist/__tests__/realtime-session-policy.test.d.ts +2 -0
  71. package/dist/__tests__/realtime-session-policy.test.d.ts.map +1 -0
  72. package/dist/__tests__/realtime-session-policy.test.js +303 -0
  73. package/dist/__tests__/realtime-session-policy.test.js.map +1 -0
  74. package/dist/__tests__/realtime-session-review.service.test.d.ts +2 -0
  75. package/dist/__tests__/realtime-session-review.service.test.d.ts.map +1 -0
  76. package/dist/__tests__/realtime-session-review.service.test.js +743 -0
  77. package/dist/__tests__/realtime-session-review.service.test.js.map +1 -0
  78. package/dist/__tests__/realtime-session-state.test.d.ts +2 -0
  79. package/dist/__tests__/realtime-session-state.test.d.ts.map +1 -0
  80. package/dist/__tests__/realtime-session-state.test.js +83 -0
  81. package/dist/__tests__/realtime-session-state.test.js.map +1 -0
  82. package/dist/__tests__/realtime-session-timeline-card.test.d.ts +2 -0
  83. package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +1 -0
  84. package/dist/__tests__/realtime-session-timeline-card.test.js +106 -0
  85. package/dist/__tests__/realtime-session-timeline-card.test.js.map +1 -0
  86. package/dist/__tests__/realtime-session-timeline.test.d.ts +2 -0
  87. package/dist/__tests__/realtime-session-timeline.test.d.ts.map +1 -0
  88. package/dist/__tests__/realtime-session-timeline.test.js +142 -0
  89. package/dist/__tests__/realtime-session-timeline.test.js.map +1 -0
  90. package/dist/__tests__/realtime-sessions-adapter.test.d.ts +19 -0
  91. package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +1 -0
  92. package/dist/__tests__/realtime-sessions-adapter.test.js +188 -0
  93. package/dist/__tests__/realtime-sessions-adapter.test.js.map +1 -0
  94. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +2 -0
  95. package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +1 -0
  96. package/dist/__tests__/realtime-surface-panel-prefs.test.js +100 -0
  97. package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +1 -0
  98. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +2 -0
  99. package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +1 -0
  100. package/dist/__tests__/realtime-surface-tabs-model.test.js +193 -0
  101. package/dist/__tests__/realtime-surface-tabs-model.test.js.map +1 -0
  102. package/dist/__tests__/remote-browser-audio-player.test.d.ts +2 -0
  103. package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +1 -0
  104. package/dist/__tests__/remote-browser-audio-player.test.js +137 -0
  105. package/dist/__tests__/remote-browser-audio-player.test.js.map +1 -0
  106. package/dist/__tests__/remote-browser-channel.test.d.ts +2 -0
  107. package/dist/__tests__/remote-browser-channel.test.d.ts.map +1 -0
  108. package/dist/__tests__/remote-browser-channel.test.js +423 -0
  109. package/dist/__tests__/remote-browser-channel.test.js.map +1 -0
  110. package/dist/__tests__/slot-defaults.test.d.ts +24 -0
  111. package/dist/__tests__/slot-defaults.test.d.ts.map +1 -0
  112. package/dist/__tests__/slot-defaults.test.js +63 -0
  113. package/dist/__tests__/slot-defaults.test.js.map +1 -0
  114. package/dist/__tests__/user-authorization.test.d.ts +2 -0
  115. package/dist/__tests__/user-authorization.test.d.ts.map +1 -0
  116. package/dist/__tests__/user-authorization.test.js +97 -0
  117. package/dist/__tests__/user-authorization.test.js.map +1 -0
  118. package/dist/__tests__/voice-session-narration.test.d.ts +2 -0
  119. package/dist/__tests__/voice-session-narration.test.d.ts.map +1 -0
  120. package/dist/__tests__/voice-session-narration.test.js +609 -0
  121. package/dist/__tests__/voice-session-narration.test.js.map +1 -0
  122. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +2 -0
  123. package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +1 -0
  124. package/dist/__tests__/whiteboard-artifact-viewer.test.js +101 -0
  125. package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +1 -0
  126. package/dist/__tests__/whiteboard-channel.test.d.ts +2 -0
  127. package/dist/__tests__/whiteboard-channel.test.d.ts.map +1 -0
  128. package/dist/__tests__/whiteboard-channel.test.js +260 -0
  129. package/dist/__tests__/whiteboard-channel.test.js.map +1 -0
  130. package/dist/__tests__/whiteboard-restore-state.test.d.ts +2 -0
  131. package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +1 -0
  132. package/dist/__tests__/whiteboard-restore-state.test.js +108 -0
  133. package/dist/__tests__/whiteboard-restore-state.test.js.map +1 -0
  134. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +205 -3
  135. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  136. package/dist/lib/components/conversation/conversation-chat-area.component.js +911 -342
  137. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  138. package/dist/lib/components/mention/mention-dropdown.component.js +35 -17
  139. package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
  140. package/dist/lib/components/mention/mention-editor.component.d.ts +4 -0
  141. package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
  142. package/dist/lib/components/mention/mention-editor.component.js +43 -19
  143. package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
  144. package/dist/lib/components/message/message-input-box.component.d.ts +17 -1
  145. package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
  146. package/dist/lib/components/message/message-input-box.component.js +73 -15
  147. package/dist/lib/components/message/message-input-box.component.js.map +1 -1
  148. package/dist/lib/components/message/message-input.component.d.ts +142 -6
  149. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  150. package/dist/lib/components/message/message-input.component.js +328 -82
  151. package/dist/lib/components/message/message-input.component.js.map +1 -1
  152. package/dist/lib/components/message/message-item.component.d.ts +28 -3
  153. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  154. package/dist/lib/components/message/message-item.component.js +180 -108
  155. package/dist/lib/components/message/message-item.component.js.map +1 -1
  156. package/dist/lib/components/message/message-list.component.d.ts +81 -2
  157. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  158. package/dist/lib/components/message/message-list.component.js +252 -87
  159. package/dist/lib/components/message/message-list.component.js.map +1 -1
  160. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +282 -0
  161. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -0
  162. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +158 -0
  163. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -0
  164. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +25 -0
  165. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -0
  166. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js +140 -0
  167. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -0
  168. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +35 -0
  169. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -0
  170. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +58 -0
  171. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -0
  172. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +63 -0
  173. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -0
  174. package/dist/lib/components/realtime/realtime-activity-rail.component.js +260 -0
  175. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -0
  176. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +117 -0
  177. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -0
  178. package/dist/lib/components/realtime/realtime-agent-banner.component.js +504 -0
  179. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -0
  180. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +168 -0
  181. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -0
  182. package/dist/lib/components/realtime/realtime-agent-picker.component.js +556 -0
  183. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -0
  184. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +97 -0
  185. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -0
  186. package/dist/lib/components/realtime/realtime-audio-visuals.js +139 -0
  187. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -0
  188. package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts +29 -0
  189. package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts.map +1 -0
  190. package/dist/lib/components/realtime/realtime-channel-strip.component.js +69 -0
  191. package/dist/lib/components/realtime/realtime-channel-strip.component.js.map +1 -0
  192. package/dist/lib/components/realtime/realtime-composer.component.d.ts +65 -0
  193. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -0
  194. package/dist/lib/components/realtime/realtime-composer.component.js +256 -0
  195. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -0
  196. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +71 -0
  197. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -0
  198. package/dist/lib/components/realtime/realtime-delegation-card.component.js +324 -0
  199. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -0
  200. package/dist/lib/components/realtime/realtime-disclosure.d.ts +135 -0
  201. package/dist/lib/components/realtime/realtime-disclosure.d.ts.map +1 -0
  202. package/dist/lib/components/realtime/realtime-disclosure.js +188 -0
  203. package/dist/lib/components/realtime/realtime-disclosure.js.map +1 -0
  204. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +491 -0
  205. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -0
  206. package/dist/lib/components/realtime/realtime-session-overlay.component.js +1274 -0
  207. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -0
  208. package/dist/lib/components/realtime/realtime-session-state.d.ts +191 -0
  209. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -0
  210. package/dist/lib/components/realtime/realtime-session-state.js +244 -0
  211. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -0
  212. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +56 -0
  213. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -0
  214. package/dist/lib/components/realtime/realtime-session-thread.component.js +246 -0
  215. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -0
  216. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +51 -0
  217. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -0
  218. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +193 -0
  219. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -0
  220. package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts +77 -0
  221. package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts.map +1 -0
  222. package/dist/lib/components/realtime/realtime-surface-panel-prefs.js +114 -0
  223. package/dist/lib/components/realtime/realtime-surface-panel-prefs.js.map +1 -0
  224. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +173 -0
  225. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -0
  226. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +496 -0
  227. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -0
  228. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +181 -0
  229. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -0
  230. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +223 -0
  231. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -0
  232. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts +163 -0
  233. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts.map +1 -0
  234. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js +309 -0
  235. package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js.map +1 -0
  236. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +168 -0
  237. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -0
  238. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +524 -0
  239. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -0
  240. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +346 -0
  241. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -0
  242. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +851 -0
  243. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -0
  244. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts +86 -0
  245. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts.map +1 -0
  246. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js +210 -0
  247. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js.map +1 -0
  248. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts +48 -0
  249. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts.map +1 -0
  250. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js +180 -0
  251. package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js.map +1 -0
  252. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +119 -0
  253. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -0
  254. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +274 -0
  255. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -0
  256. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts +11 -0
  257. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts.map +1 -0
  258. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js +98 -0
  259. package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js.map +1 -0
  260. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts +9 -0
  261. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts.map +1 -0
  262. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js +35 -0
  263. package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js.map +1 -0
  264. package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts +28 -0
  265. package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts.map +1 -0
  266. package/dist/lib/components/slots/mj-chat-empty-state-default.component.js +104 -0
  267. package/dist/lib/components/slots/mj-chat-empty-state-default.component.js.map +1 -0
  268. package/dist/lib/components/slots/mj-chat-header-default.component.d.ts +11 -0
  269. package/dist/lib/components/slots/mj-chat-header-default.component.d.ts.map +1 -0
  270. package/dist/lib/components/slots/mj-chat-header-default.component.js +103 -0
  271. package/dist/lib/components/slots/mj-chat-header-default.component.js.map +1 -0
  272. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts +15 -0
  273. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts.map +1 -0
  274. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js +73 -0
  275. package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js.map +1 -0
  276. package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts +9 -0
  277. package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts.map +1 -0
  278. package/dist/lib/components/slots/mj-chat-message-extra-default.component.js +34 -0
  279. package/dist/lib/components/slots/mj-chat-message-extra-default.component.js.map +1 -0
  280. package/dist/lib/components/slots/slot-interfaces.d.ts +95 -0
  281. package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -0
  282. package/dist/lib/components/slots/slot-interfaces.js +18 -0
  283. package/dist/lib/components/slots/slot-interfaces.js.map +1 -0
  284. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +11 -0
  285. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  286. package/dist/lib/components/workspace/conversation-workspace.component.js +28 -4
  287. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  288. package/dist/lib/conversations.module.d.ts +12 -1
  289. package/dist/lib/conversations.module.d.ts.map +1 -1
  290. package/dist/lib/conversations.module.js +93 -5
  291. package/dist/lib/conversations.module.js.map +1 -1
  292. package/dist/lib/directives/chat-slot.directive.d.ts +44 -0
  293. package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -0
  294. package/dist/lib/directives/chat-slot.directive.js +54 -0
  295. package/dist/lib/directives/chat-slot.directive.js.map +1 -0
  296. package/dist/lib/events/chat-events.d.ts +137 -0
  297. package/dist/lib/events/chat-events.d.ts.map +1 -0
  298. package/dist/lib/events/chat-events.js +189 -0
  299. package/dist/lib/events/chat-events.js.map +1 -0
  300. package/dist/lib/models/conversation-state.model.d.ts +2 -1
  301. package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
  302. package/dist/lib/models/conversation-state.model.js.map +1 -1
  303. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  304. package/dist/lib/services/artifact-state.service.js +23 -6
  305. package/dist/lib/services/artifact-state.service.js.map +1 -1
  306. package/dist/lib/services/conversation-agent.service.d.ts +60 -74
  307. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  308. package/dist/lib/services/conversation-agent.service.js +100 -313
  309. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  310. package/dist/lib/services/conversation-bridge.service.d.ts +11 -70
  311. package/dist/lib/services/conversation-bridge.service.d.ts.map +1 -1
  312. package/dist/lib/services/conversation-bridge.service.js +51 -85
  313. package/dist/lib/services/conversation-bridge.service.js.map +1 -1
  314. package/dist/lib/services/conversation-naming.d.ts +63 -0
  315. package/dist/lib/services/conversation-naming.d.ts.map +1 -0
  316. package/dist/lib/services/conversation-naming.js +58 -0
  317. package/dist/lib/services/conversation-naming.js.map +1 -0
  318. package/dist/lib/services/conversation-streaming.service.d.ts +24 -154
  319. package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
  320. package/dist/lib/services/conversation-streaming.service.js +39 -361
  321. package/dist/lib/services/conversation-streaming.service.js.map +1 -1
  322. package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts +10 -0
  323. package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts.map +1 -0
  324. package/dist/lib/services/conversations-runtime-bootstrap.service.js +104 -0
  325. package/dist/lib/services/conversations-runtime-bootstrap.service.js.map +1 -0
  326. package/dist/lib/services/delegation-result-parser.d.ts +45 -0
  327. package/dist/lib/services/delegation-result-parser.d.ts.map +1 -0
  328. package/dist/lib/services/delegation-result-parser.js +48 -0
  329. package/dist/lib/services/delegation-result-parser.js.map +1 -0
  330. package/dist/lib/services/mention-autocomplete.service.d.ts +19 -4
  331. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  332. package/dist/lib/services/mention-autocomplete.service.js +65 -4
  333. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  334. package/dist/lib/services/mention-parser.service.d.ts +8 -53
  335. package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
  336. package/dist/lib/services/mention-parser.service.js +32 -243
  337. package/dist/lib/services/mention-parser.service.js.map +1 -1
  338. package/dist/lib/services/narration-template.d.ts +42 -0
  339. package/dist/lib/services/narration-template.d.ts.map +1 -0
  340. package/dist/lib/services/narration-template.js +73 -0
  341. package/dist/lib/services/narration-template.js.map +1 -0
  342. package/dist/lib/services/realtime-pairing.d.ts +120 -0
  343. package/dist/lib/services/realtime-pairing.d.ts.map +1 -0
  344. package/dist/lib/services/realtime-pairing.js +150 -0
  345. package/dist/lib/services/realtime-pairing.js.map +1 -0
  346. package/dist/lib/services/realtime-session-review.service.d.ts +233 -0
  347. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -0
  348. package/dist/lib/services/realtime-session-review.service.js +417 -0
  349. package/dist/lib/services/realtime-session-review.service.js.map +1 -0
  350. package/dist/lib/services/realtime-session.service.d.ts +739 -0
  351. package/dist/lib/services/realtime-session.service.d.ts.map +1 -0
  352. package/dist/lib/services/realtime-session.service.js +1647 -0
  353. package/dist/lib/services/realtime-session.service.js.map +1 -0
  354. package/dist/lib/services/realtime-sessions-adapter.d.ts +54 -0
  355. package/dist/lib/services/realtime-sessions-adapter.d.ts.map +1 -0
  356. package/dist/lib/services/realtime-sessions-adapter.js +154 -0
  357. package/dist/lib/services/realtime-sessions-adapter.js.map +1 -0
  358. package/dist/lib/services/user-authorization.d.ts +67 -0
  359. package/dist/lib/services/user-authorization.d.ts.map +1 -0
  360. package/dist/lib/services/user-authorization.js +66 -0
  361. package/dist/lib/services/user-authorization.js.map +1 -0
  362. package/dist/lib/utils/realtime-session-timeline.d.ts +84 -0
  363. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -0
  364. package/dist/lib/utils/realtime-session-timeline.js +94 -0
  365. package/dist/lib/utils/realtime-session-timeline.js.map +1 -0
  366. package/dist/public-api.d.ts +41 -0
  367. package/dist/public-api.d.ts.map +1 -1
  368. package/dist/public-api.js +50 -0
  369. package/dist/public-api.js.map +1 -1
  370. package/package.json +27 -24
  371. package/dist/__tests__/conversation-bridge.service.test.d.ts +0 -2
  372. package/dist/__tests__/conversation-bridge.service.test.d.ts.map +0 -1
  373. package/dist/__tests__/conversation-bridge.service.test.js +0 -98
  374. package/dist/__tests__/conversation-bridge.service.test.js.map +0 -1
  375. package/dist/__tests__/mention-parser.test.d.ts +0 -2
  376. package/dist/__tests__/mention-parser.test.d.ts.map +0 -1
  377. package/dist/__tests__/mention-parser.test.js +0 -154
  378. package/dist/__tests__/mention-parser.test.js.map +0 -1
@@ -0,0 +1,303 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { RealtimeSessionService } from '../lib/services/realtime-session.service';
3
+ /**
4
+ * Provider-agnostic POLICY surfaces of the voice session service that no other suite
5
+ * covered: typed-text injection (`SendText`), mic mute toggling, the client→UI
6
+ * connection-state mapping (incl. the 'connected' suppression and the error latch),
7
+ * session-config parsing resilience, and the `SaveChannelState` failure paths.
8
+ *
9
+ * Same narrow typed-seam approach as the sibling voice-session suites: a fake realtime
10
+ * client + fake Provider, with private members reached through a typed internals cast.
11
+ */
12
+ class FakeRealtimeClient {
13
+ TextsSent = [];
14
+ MuteCalls = [];
15
+ ToolResults = [];
16
+ SendText(text) {
17
+ this.TextsSent.push(text);
18
+ }
19
+ SetMuted(muted) {
20
+ this.MuteCalls.push(muted);
21
+ }
22
+ SendToolResult(callId, resultJson) {
23
+ this.ToolResults.push({ CallID: callId, ResultJson: resultJson });
24
+ }
25
+ async Disconnect() {
26
+ // no-op
27
+ }
28
+ }
29
+ function internals(service) {
30
+ return service;
31
+ }
32
+ function latestState(service) {
33
+ let state = 'closed';
34
+ service.ConnectionState$.subscribe(s => (state = s)).unsubscribe();
35
+ return state;
36
+ }
37
+ describe('RealtimeSessionService — SendText (typed turn injection)', () => {
38
+ let service;
39
+ let client;
40
+ let executeGQL;
41
+ beforeEach(() => {
42
+ service = new RealtimeSessionService();
43
+ client = new FakeRealtimeClient();
44
+ executeGQL = vi.fn(async () => ({}));
45
+ service.Provider = { ExecuteGQL: executeGQL };
46
+ internals(service).client = client;
47
+ internals(service).agentSessionId = 'sess-1';
48
+ });
49
+ it('injects the trimmed text and relays it through the SAME user-turn path as speech', async () => {
50
+ internals(service).onClientStateChange('listening');
51
+ service.SendText(' hello there ');
52
+ await vi.waitFor(() => expect(executeGQL).toHaveBeenCalled());
53
+ expect(client.TextsSent).toEqual(['hello there']);
54
+ let captions = [];
55
+ service.Captions$.subscribe(c => (captions = c)).unsubscribe();
56
+ expect(captions).toEqual([{ Role: 'User', Text: 'hello there' }]);
57
+ expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('RelayRealtimeTranscript'), expect.objectContaining({ agentSessionId: 'sess-1', role: 'user', text: 'hello there' }));
58
+ });
59
+ it('is a no-op for empty / whitespace-only text', () => {
60
+ internals(service).onClientStateChange('listening');
61
+ service.SendText('');
62
+ service.SendText(' ');
63
+ expect(client.TextsSent).toEqual([]);
64
+ expect(executeGQL).not.toHaveBeenCalled();
65
+ });
66
+ it('is a no-op when the session is not live (state closed)', () => {
67
+ service.SendText('hello');
68
+ expect(client.TextsSent).toEqual([]);
69
+ expect(executeGQL).not.toHaveBeenCalled();
70
+ });
71
+ it('is a no-op when there is no client', () => {
72
+ internals(service).onClientStateChange('listening');
73
+ internals(service).client = null;
74
+ service.SendText('hello');
75
+ expect(executeGQL).not.toHaveBeenCalled();
76
+ });
77
+ it('still captions the turn when no agent session id exists (relay silently skipped)', async () => {
78
+ internals(service).onClientStateChange('listening');
79
+ internals(service).agentSessionId = null;
80
+ service.SendText('typed while minting');
81
+ await Promise.resolve(); // let the relay microtask settle
82
+ expect(client.TextsSent).toEqual(['typed while minting']);
83
+ let captions = [];
84
+ service.Captions$.subscribe(c => (captions = c)).unsubscribe();
85
+ expect(captions).toEqual([{ Role: 'User', Text: 'typed while minting' }]);
86
+ expect(executeGQL).not.toHaveBeenCalled();
87
+ });
88
+ });
89
+ describe('RealtimeSessionService — ToggleMute', () => {
90
+ let service;
91
+ let client;
92
+ beforeEach(() => {
93
+ service = new RealtimeSessionService();
94
+ client = new FakeRealtimeClient();
95
+ internals(service).client = client;
96
+ });
97
+ it('returns false and touches nothing when there is no local stream', () => {
98
+ expect(service.ToggleMute()).toBe(false);
99
+ expect(client.MuteCalls).toEqual([]);
100
+ });
101
+ it('returns false when the stream has no audio tracks', () => {
102
+ internals(service).localStream = { getAudioTracks: () => [], getTracks: () => [] };
103
+ expect(service.ToggleMute()).toBe(false);
104
+ expect(client.MuteCalls).toEqual([]);
105
+ });
106
+ it('mutes via the client when the track is currently enabled', () => {
107
+ const track = { enabled: true, stop: () => undefined };
108
+ internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };
109
+ expect(service.ToggleMute()).toBe(true);
110
+ expect(client.MuteCalls).toEqual([true]);
111
+ });
112
+ it('unmutes via the client when the track is currently disabled', () => {
113
+ const track = { enabled: false, stop: () => undefined };
114
+ internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };
115
+ expect(service.ToggleMute()).toBe(false);
116
+ expect(client.MuteCalls).toEqual([false]);
117
+ });
118
+ });
119
+ describe('RealtimeSessionService — client→UI connection-state mapping', () => {
120
+ let service;
121
+ beforeEach(() => {
122
+ service = new RealtimeSessionService();
123
+ });
124
+ it("maps 'connecting' / 'listening' / 'speaking' straight through", () => {
125
+ internals(service).onClientStateChange('connecting');
126
+ expect(latestState(service)).toBe('connecting');
127
+ internals(service).onClientStateChange('listening');
128
+ expect(latestState(service)).toBe('listening');
129
+ internals(service).onClientStateChange('speaking');
130
+ expect(latestState(service)).toBe('speaking');
131
+ });
132
+ it("suppresses 'connected' — the UI stays in its prior state until the control channel opens", () => {
133
+ internals(service).onClientStateChange('connecting');
134
+ internals(service).onClientStateChange('connected');
135
+ expect(latestState(service)).toBe('connecting');
136
+ });
137
+ it("maps 'closed' through when no error was recorded", () => {
138
+ internals(service).onClientStateChange('listening');
139
+ internals(service).onClientStateChange('closed');
140
+ expect(latestState(service)).toBe('closed');
141
+ });
142
+ it("never lets a trailing 'closed' overwrite a terminal 'error'", () => {
143
+ internals(service).onClientStateChange('error');
144
+ internals(service).onClientStateChange('closed');
145
+ expect(latestState(service)).toBe('error');
146
+ });
147
+ });
148
+ describe('RealtimeSessionService — parseSessionConfig resilience', () => {
149
+ let service;
150
+ beforeEach(() => {
151
+ service = new RealtimeSessionService();
152
+ });
153
+ it('parses a valid config JSON', () => {
154
+ expect(internals(service).parseSessionConfig('{"instructions":"be brief"}')).toEqual({ instructions: 'be brief' });
155
+ });
156
+ it('returns an empty config for null (nothing to apply — the session still opens)', () => {
157
+ expect(internals(service).parseSessionConfig(null)).toEqual({});
158
+ });
159
+ it('returns an empty config (logged) for malformed JSON', () => {
160
+ const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);
161
+ expect(internals(service).parseSessionConfig('{not json')).toEqual({});
162
+ expect(error).toHaveBeenCalledWith(expect.stringContaining('SessionConfigJson'), expect.any(Error));
163
+ });
164
+ });
165
+ describe('RealtimeSessionService — EndVoiceSession / teardown lifecycle', () => {
166
+ let service;
167
+ let client;
168
+ let executeGQL;
169
+ beforeEach(() => {
170
+ service = new RealtimeSessionService();
171
+ client = new FakeRealtimeClient();
172
+ executeGQL = vi.fn(async () => ({}));
173
+ service.Provider = { ExecuteGQL: executeGQL };
174
+ });
175
+ it('is a safe no-op when no session is active and none was minted', async () => {
176
+ await service.EndVoiceSession();
177
+ expect(executeGQL).not.toHaveBeenCalled();
178
+ expect(latestState(service)).toBe('closed');
179
+ });
180
+ it('closes the server session, disconnects the client, stops the mic, and resets state', async () => {
181
+ const track = { enabled: true, stop: vi.fn() };
182
+ const disconnect = vi.spyOn(client, 'Disconnect');
183
+ internals(service).client = client;
184
+ internals(service).agentSessionId = 'sess-9';
185
+ internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };
186
+ internals(service).onClientStateChange('listening');
187
+ service.SetMinimized(true);
188
+ await service.EndVoiceSession();
189
+ expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('CloseAgentSession'), { agentSessionId: 'sess-9' });
190
+ expect(disconnect).toHaveBeenCalledTimes(1);
191
+ expect(track.stop).toHaveBeenCalled();
192
+ expect(service.CurrentAgentSessionId).toBeNull();
193
+ expect(service.IsMinimized).toBe(false);
194
+ expect(service.IsActive).toBe(false);
195
+ expect(latestState(service)).toBe('closed');
196
+ });
197
+ it('teardown clears the client-tool handler registry', async () => {
198
+ internals(service).agentSessionId = 'sess-9';
199
+ const handler = vi.fn(() => '{"success":true}');
200
+ service.RegisterClientToolHandler('Whiteboard_', handler);
201
+ await service.EndVoiceSession();
202
+ // After teardown the prefix no longer routes locally — the registry was cleared.
203
+ internals(service).client = client;
204
+ internals(service).agentSessionId = 'sess-10';
205
+ await service
206
+ .handleToolCall({ CallID: 'c1', ToolName: 'Whiteboard_AddNote', ArgumentsJson: '{}' });
207
+ expect(handler).not.toHaveBeenCalled();
208
+ });
209
+ it('a CloseAgentSession failure is contained (logged) and teardown still completes', async () => {
210
+ const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);
211
+ executeGQL.mockRejectedValueOnce(new Error('server gone'));
212
+ internals(service).agentSessionId = 'sess-9';
213
+ await service.EndVoiceSession();
214
+ expect(service.CurrentAgentSessionId).toBeNull();
215
+ expect(error).toHaveBeenCalledWith(expect.stringContaining('Failed to close server session'), expect.any(Error));
216
+ });
217
+ it("teardown preserves a terminal 'error' state instead of overwriting it with 'closed'", async () => {
218
+ internals(service).agentSessionId = 'sess-9';
219
+ internals(service).onClientStateChange('error');
220
+ await service.EndVoiceSession();
221
+ expect(latestState(service)).toBe('error');
222
+ });
223
+ });
224
+ describe('RealtimeSessionService — SaveChannelState (explicit id + failure paths)', () => {
225
+ let service;
226
+ let executeGQL;
227
+ beforeEach(() => {
228
+ service = new RealtimeSessionService();
229
+ executeGQL = vi.fn(async () => ({ SaveSessionChannelState: true }));
230
+ service.Provider = { ExecuteGQL: executeGQL };
231
+ });
232
+ it('uses the EXPLICIT session id even when no live session exists (the teardown-flush case)', async () => {
233
+ const saved = await service.SaveChannelState('Whiteboard', '{"v":1}', 'closed-session-7');
234
+ expect(saved).toBe(true);
235
+ expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('SaveSessionChannelState'), { agentSessionId: 'closed-session-7', channelName: 'Whiteboard', stateJson: '{"v":1}' });
236
+ });
237
+ it('prefers the explicit id over the live session id', async () => {
238
+ internals(service).agentSessionId = 'live-session';
239
+ await service.SaveChannelState('Whiteboard', '{}', 'captured-session');
240
+ expect(executeGQL.mock.calls[0][1]).toMatchObject({ agentSessionId: 'captured-session' });
241
+ });
242
+ it('returns false (logged, never thrown) when the mutation throws', async () => {
243
+ const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);
244
+ executeGQL.mockRejectedValueOnce(new Error('network down'));
245
+ const saved = await service.SaveChannelState('Whiteboard', '{}', 'sess-1');
246
+ expect(saved).toBe(false);
247
+ expect(error).toHaveBeenCalledWith(expect.stringContaining('Failed to save channel state'), expect.any(Error));
248
+ });
249
+ it('returns false when the server reports a falsy result', async () => {
250
+ executeGQL.mockResolvedValueOnce({ SaveSessionChannelState: false });
251
+ expect(await service.SaveChannelState('Whiteboard', '{}', 'sess-1')).toBe(false);
252
+ executeGQL.mockResolvedValueOnce({});
253
+ expect(await service.SaveChannelState('Whiteboard', '{}', 'sess-1')).toBe(false);
254
+ });
255
+ });
256
+ describe('RealtimeSessionService — transcript correction (ReplacesPrevious)', () => {
257
+ let service;
258
+ let executeGQL;
259
+ function transcriptInternals(s) {
260
+ return s;
261
+ }
262
+ function captionsOf(s) {
263
+ let captions = [];
264
+ s.Captions$.subscribe(c => (captions = c)).unsubscribe();
265
+ return captions;
266
+ }
267
+ beforeEach(() => {
268
+ service = new RealtimeSessionService();
269
+ executeGQL = vi.fn(async () => ({}));
270
+ service.Provider = { ExecuteGQL: executeGQL };
271
+ internals(service).agentSessionId = 'sess-1';
272
+ });
273
+ it('a correction REPLACES the last assistant caption in place and relays update semantics', async () => {
274
+ const t = transcriptInternals(service);
275
+ await t.onClientTranscript({ Role: 'Assistant', Text: 'The answer is forty-two and', IsFinal: true, Kind: 'normal' });
276
+ await t.onClientTranscript({ Role: 'Assistant', Text: 'The answer is', IsFinal: true, Kind: 'normal', ReplacesPrevious: true });
277
+ expect(captionsOf(service)).toEqual([{ Role: 'Assistant', Text: 'The answer is' }]); // replaced, not appended
278
+ expect(executeGQL).toHaveBeenLastCalledWith(expect.stringContaining('RelayRealtimeTranscript'), expect.objectContaining({ role: 'assistant', text: 'The answer is', replacesPrevious: true }));
279
+ });
280
+ it('a correction replaces the LAST assistant caption, leaving later user turns alone', async () => {
281
+ const t = transcriptInternals(service);
282
+ await t.onClientTranscript({ Role: 'Assistant', Text: 'truncated turn that', IsFinal: true, Kind: 'normal' });
283
+ await t.onClientTranscript({ Role: 'User', Text: 'wait, stop', IsFinal: true, Kind: 'normal' });
284
+ await t.onClientTranscript({ Role: 'Assistant', Text: 'truncated turn', IsFinal: true, Kind: 'normal', ReplacesPrevious: true });
285
+ expect(captionsOf(service)).toEqual([
286
+ { Role: 'Assistant', Text: 'truncated turn' },
287
+ { Role: 'User', Text: 'wait, stop' }
288
+ ]);
289
+ });
290
+ it('a correction with NO prior assistant caption appends (never lost)', async () => {
291
+ await transcriptInternals(service).onClientTranscript({
292
+ Role: 'Assistant', Text: 'orphan correction', IsFinal: true, Kind: 'normal', ReplacesPrevious: true
293
+ });
294
+ expect(captionsOf(service)).toEqual([{ Role: 'Assistant', Text: 'orphan correction' }]);
295
+ });
296
+ it('ordinary finals relay with replacesPrevious=false', async () => {
297
+ await transcriptInternals(service).onClientTranscript({
298
+ Role: 'Assistant', Text: 'normal turn', IsFinal: true, Kind: 'normal'
299
+ });
300
+ expect(executeGQL).toHaveBeenLastCalledWith(expect.stringContaining('RelayRealtimeTranscript'), expect.objectContaining({ replacesPrevious: false }));
301
+ });
302
+ });
303
+ //# sourceMappingURL=realtime-session-policy.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-session-policy.test.js","sourceRoot":"","sources":["../../src/__tests__/realtime-session-policy.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport { IMetadataProvider } from '@memberjunction/core';\nimport { JSONObject } from '@memberjunction/ai';\nimport { RealtimeSessionService, VoiceCaption, VoiceConnectionState } from '../lib/services/realtime-session.service';\n\n/**\n * Provider-agnostic POLICY surfaces of the voice session service that no other suite\n * covered: typed-text injection (`SendText`), mic mute toggling, the client→UI\n * connection-state mapping (incl. the 'connected' suppression and the error latch),\n * session-config parsing resilience, and the `SaveChannelState` failure paths.\n *\n * Same narrow typed-seam approach as the sibling voice-session suites: a fake realtime\n * client + fake Provider, with private members reached through a typed internals cast.\n */\n\nclass FakeRealtimeClient {\n public TextsSent: string[] = [];\n public MuteCalls: boolean[] = [];\n public ToolResults: Array<{ CallID: string; ResultJson: string }> = [];\n public SendText(text: string): void {\n this.TextsSent.push(text);\n }\n public SetMuted(muted: boolean): void {\n this.MuteCalls.push(muted);\n }\n public SendToolResult(callId: string, resultJson: string): void {\n this.ToolResults.push({ CallID: callId, ResultJson: resultJson });\n }\n public async Disconnect(): Promise<void> {\n // no-op\n }\n}\n\n/** A minimal MediaStreamTrack stand-in (node tests have no real media stack). */\ninterface FakeTrack {\n enabled: boolean;\n stop(): void;\n}\n\n/** The private surface the tests drive — no `any`, just the members under test. */\ninterface RealtimeSessionPolicyInternals {\n client: FakeRealtimeClient | null;\n agentSessionId: string | null;\n localStream: { getAudioTracks(): FakeTrack[]; getTracks(): FakeTrack[] } | null;\n onClientStateChange(state: 'connecting' | 'connected' | 'listening' | 'speaking' | 'closed' | 'error'): void;\n parseSessionConfig(sessionConfigJson: string | null): JSONObject;\n}\n\nfunction internals(service: RealtimeSessionService): RealtimeSessionPolicyInternals {\n return service as unknown as RealtimeSessionPolicyInternals;\n}\n\nfunction latestState(service: RealtimeSessionService): VoiceConnectionState {\n let state: VoiceConnectionState = 'closed';\n service.ConnectionState$.subscribe(s => (state = s)).unsubscribe();\n return state;\n}\n\ndescribe('RealtimeSessionService — SendText (typed turn injection)', () => {\n let service: RealtimeSessionService;\n let client: FakeRealtimeClient;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n client = new FakeRealtimeClient();\n executeGQL = vi.fn(async () => ({}));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n internals(service).client = client;\n internals(service).agentSessionId = 'sess-1';\n });\n\n it('injects the trimmed text and relays it through the SAME user-turn path as speech', async () => {\n internals(service).onClientStateChange('listening');\n\n service.SendText(' hello there ');\n await vi.waitFor(() => expect(executeGQL).toHaveBeenCalled());\n\n expect(client.TextsSent).toEqual(['hello there']);\n let captions: VoiceCaption[] = [];\n service.Captions$.subscribe(c => (captions = c)).unsubscribe();\n expect(captions).toEqual([{ Role: 'User', Text: 'hello there' }]);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('RelayRealtimeTranscript'),\n expect.objectContaining({ agentSessionId: 'sess-1', role: 'user', text: 'hello there' })\n );\n });\n\n it('is a no-op for empty / whitespace-only text', () => {\n internals(service).onClientStateChange('listening');\n\n service.SendText('');\n service.SendText(' ');\n\n expect(client.TextsSent).toEqual([]);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('is a no-op when the session is not live (state closed)', () => {\n service.SendText('hello');\n\n expect(client.TextsSent).toEqual([]);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('is a no-op when there is no client', () => {\n internals(service).onClientStateChange('listening');\n internals(service).client = null;\n\n service.SendText('hello');\n\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('still captions the turn when no agent session id exists (relay silently skipped)', async () => {\n internals(service).onClientStateChange('listening');\n internals(service).agentSessionId = null;\n\n service.SendText('typed while minting');\n await Promise.resolve(); // let the relay microtask settle\n\n expect(client.TextsSent).toEqual(['typed while minting']);\n let captions: VoiceCaption[] = [];\n service.Captions$.subscribe(c => (captions = c)).unsubscribe();\n expect(captions).toEqual([{ Role: 'User', Text: 'typed while minting' }]);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n});\n\ndescribe('RealtimeSessionService — ToggleMute', () => {\n let service: RealtimeSessionService;\n let client: FakeRealtimeClient;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n client = new FakeRealtimeClient();\n internals(service).client = client;\n });\n\n it('returns false and touches nothing when there is no local stream', () => {\n expect(service.ToggleMute()).toBe(false);\n expect(client.MuteCalls).toEqual([]);\n });\n\n it('returns false when the stream has no audio tracks', () => {\n internals(service).localStream = { getAudioTracks: () => [], getTracks: () => [] };\n expect(service.ToggleMute()).toBe(false);\n expect(client.MuteCalls).toEqual([]);\n });\n\n it('mutes via the client when the track is currently enabled', () => {\n const track: FakeTrack = { enabled: true, stop: () => undefined };\n internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };\n\n expect(service.ToggleMute()).toBe(true);\n expect(client.MuteCalls).toEqual([true]);\n });\n\n it('unmutes via the client when the track is currently disabled', () => {\n const track: FakeTrack = { enabled: false, stop: () => undefined };\n internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };\n\n expect(service.ToggleMute()).toBe(false);\n expect(client.MuteCalls).toEqual([false]);\n });\n});\n\ndescribe('RealtimeSessionService — client→UI connection-state mapping', () => {\n let service: RealtimeSessionService;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n });\n\n it(\"maps 'connecting' / 'listening' / 'speaking' straight through\", () => {\n internals(service).onClientStateChange('connecting');\n expect(latestState(service)).toBe('connecting');\n\n internals(service).onClientStateChange('listening');\n expect(latestState(service)).toBe('listening');\n\n internals(service).onClientStateChange('speaking');\n expect(latestState(service)).toBe('speaking');\n });\n\n it(\"suppresses 'connected' — the UI stays in its prior state until the control channel opens\", () => {\n internals(service).onClientStateChange('connecting');\n internals(service).onClientStateChange('connected');\n expect(latestState(service)).toBe('connecting');\n });\n\n it(\"maps 'closed' through when no error was recorded\", () => {\n internals(service).onClientStateChange('listening');\n internals(service).onClientStateChange('closed');\n expect(latestState(service)).toBe('closed');\n });\n\n it(\"never lets a trailing 'closed' overwrite a terminal 'error'\", () => {\n internals(service).onClientStateChange('error');\n internals(service).onClientStateChange('closed');\n expect(latestState(service)).toBe('error');\n });\n});\n\ndescribe('RealtimeSessionService — parseSessionConfig resilience', () => {\n let service: RealtimeSessionService;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n });\n\n it('parses a valid config JSON', () => {\n expect(internals(service).parseSessionConfig('{\"instructions\":\"be brief\"}')).toEqual({ instructions: 'be brief' });\n });\n\n it('returns an empty config for null (nothing to apply — the session still opens)', () => {\n expect(internals(service).parseSessionConfig(null)).toEqual({});\n });\n\n it('returns an empty config (logged) for malformed JSON', () => {\n const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n expect(internals(service).parseSessionConfig('{not json')).toEqual({});\n expect(error).toHaveBeenCalledWith(expect.stringContaining('SessionConfigJson'), expect.any(Error));\n });\n});\n\ndescribe('RealtimeSessionService — EndVoiceSession / teardown lifecycle', () => {\n let service: RealtimeSessionService;\n let client: FakeRealtimeClient;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n client = new FakeRealtimeClient();\n executeGQL = vi.fn(async () => ({}));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n });\n\n it('is a safe no-op when no session is active and none was minted', async () => {\n await service.EndVoiceSession();\n expect(executeGQL).not.toHaveBeenCalled();\n expect(latestState(service)).toBe('closed');\n });\n\n it('closes the server session, disconnects the client, stops the mic, and resets state', async () => {\n const track: FakeTrack = { enabled: true, stop: vi.fn() };\n const disconnect = vi.spyOn(client, 'Disconnect');\n internals(service).client = client;\n internals(service).agentSessionId = 'sess-9';\n internals(service).localStream = { getAudioTracks: () => [track], getTracks: () => [track] };\n internals(service).onClientStateChange('listening');\n service.SetMinimized(true);\n\n await service.EndVoiceSession();\n\n expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('CloseAgentSession'), { agentSessionId: 'sess-9' });\n expect(disconnect).toHaveBeenCalledTimes(1);\n expect(track.stop).toHaveBeenCalled();\n expect(service.CurrentAgentSessionId).toBeNull();\n expect(service.IsMinimized).toBe(false);\n expect(service.IsActive).toBe(false);\n expect(latestState(service)).toBe('closed');\n });\n\n it('teardown clears the client-tool handler registry', async () => {\n internals(service).agentSessionId = 'sess-9';\n const handler = vi.fn(() => '{\"success\":true}');\n service.RegisterClientToolHandler('Whiteboard_', handler);\n\n await service.EndVoiceSession();\n\n // After teardown the prefix no longer routes locally — the registry was cleared.\n internals(service).client = client;\n internals(service).agentSessionId = 'sess-10';\n await (service as unknown as { handleToolCall(c: { CallID: string; ToolName: string; ArgumentsJson: string }): Promise<void> })\n .handleToolCall({ CallID: 'c1', ToolName: 'Whiteboard_AddNote', ArgumentsJson: '{}' });\n expect(handler).not.toHaveBeenCalled();\n });\n\n it('a CloseAgentSession failure is contained (logged) and teardown still completes', async () => {\n const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n executeGQL.mockRejectedValueOnce(new Error('server gone'));\n internals(service).agentSessionId = 'sess-9';\n\n await service.EndVoiceSession();\n\n expect(service.CurrentAgentSessionId).toBeNull();\n expect(error).toHaveBeenCalledWith(expect.stringContaining('Failed to close server session'), expect.any(Error));\n });\n\n it(\"teardown preserves a terminal 'error' state instead of overwriting it with 'closed'\", async () => {\n internals(service).agentSessionId = 'sess-9';\n internals(service).onClientStateChange('error');\n\n await service.EndVoiceSession();\n\n expect(latestState(service)).toBe('error');\n });\n});\n\ndescribe('RealtimeSessionService — SaveChannelState (explicit id + failure paths)', () => {\n let service: RealtimeSessionService;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n executeGQL = vi.fn(async () => ({ SaveSessionChannelState: true }));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n });\n\n it('uses the EXPLICIT session id even when no live session exists (the teardown-flush case)', async () => {\n const saved = await service.SaveChannelState('Whiteboard', '{\"v\":1}', 'closed-session-7');\n\n expect(saved).toBe(true);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('SaveSessionChannelState'),\n { agentSessionId: 'closed-session-7', channelName: 'Whiteboard', stateJson: '{\"v\":1}' }\n );\n });\n\n it('prefers the explicit id over the live session id', async () => {\n internals(service).agentSessionId = 'live-session';\n\n await service.SaveChannelState('Whiteboard', '{}', 'captured-session');\n\n expect(executeGQL.mock.calls[0][1]).toMatchObject({ agentSessionId: 'captured-session' });\n });\n\n it('returns false (logged, never thrown) when the mutation throws', async () => {\n const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n executeGQL.mockRejectedValueOnce(new Error('network down'));\n\n const saved = await service.SaveChannelState('Whiteboard', '{}', 'sess-1');\n\n expect(saved).toBe(false);\n expect(error).toHaveBeenCalledWith(expect.stringContaining('Failed to save channel state'), expect.any(Error));\n });\n\n it('returns false when the server reports a falsy result', async () => {\n executeGQL.mockResolvedValueOnce({ SaveSessionChannelState: false });\n expect(await service.SaveChannelState('Whiteboard', '{}', 'sess-1')).toBe(false);\n\n executeGQL.mockResolvedValueOnce({});\n expect(await service.SaveChannelState('Whiteboard', '{}', 'sess-1')).toBe(false);\n });\n});\n\ndescribe('RealtimeSessionService — transcript correction (ReplacesPrevious)', () => {\n let service: RealtimeSessionService;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n /** The private transcript entry point the client driver feeds. */\n interface TranscriptInternals {\n onClientTranscript(t: {\n Role: 'User' | 'Assistant'; Text: string; IsFinal: boolean;\n Kind: 'normal' | 'narration'; ReplacesPrevious?: boolean;\n }): Promise<void>;\n }\n\n function transcriptInternals(s: RealtimeSessionService): TranscriptInternals {\n return s as unknown as TranscriptInternals;\n }\n\n function captionsOf(s: RealtimeSessionService): VoiceCaption[] {\n let captions: VoiceCaption[] = [];\n s.Captions$.subscribe(c => (captions = c)).unsubscribe();\n return captions;\n }\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n executeGQL = vi.fn(async () => ({}));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n internals(service).agentSessionId = 'sess-1';\n });\n\n it('a correction REPLACES the last assistant caption in place and relays update semantics', async () => {\n const t = transcriptInternals(service);\n await t.onClientTranscript({ Role: 'Assistant', Text: 'The answer is forty-two and', IsFinal: true, Kind: 'normal' });\n await t.onClientTranscript({ Role: 'Assistant', Text: 'The answer is', IsFinal: true, Kind: 'normal', ReplacesPrevious: true });\n\n expect(captionsOf(service)).toEqual([{ Role: 'Assistant', Text: 'The answer is' }]); // replaced, not appended\n expect(executeGQL).toHaveBeenLastCalledWith(\n expect.stringContaining('RelayRealtimeTranscript'),\n expect.objectContaining({ role: 'assistant', text: 'The answer is', replacesPrevious: true })\n );\n });\n\n it('a correction replaces the LAST assistant caption, leaving later user turns alone', async () => {\n const t = transcriptInternals(service);\n await t.onClientTranscript({ Role: 'Assistant', Text: 'truncated turn that', IsFinal: true, Kind: 'normal' });\n await t.onClientTranscript({ Role: 'User', Text: 'wait, stop', IsFinal: true, Kind: 'normal' });\n await t.onClientTranscript({ Role: 'Assistant', Text: 'truncated turn', IsFinal: true, Kind: 'normal', ReplacesPrevious: true });\n\n expect(captionsOf(service)).toEqual([\n { Role: 'Assistant', Text: 'truncated turn' },\n { Role: 'User', Text: 'wait, stop' }\n ]);\n });\n\n it('a correction with NO prior assistant caption appends (never lost)', async () => {\n await transcriptInternals(service).onClientTranscript({\n Role: 'Assistant', Text: 'orphan correction', IsFinal: true, Kind: 'normal', ReplacesPrevious: true\n });\n expect(captionsOf(service)).toEqual([{ Role: 'Assistant', Text: 'orphan correction' }]);\n });\n\n it('ordinary finals relay with replacesPrevious=false', async () => {\n await transcriptInternals(service).onClientTranscript({\n Role: 'Assistant', Text: 'normal turn', IsFinal: true, Kind: 'normal'\n });\n expect(executeGQL).toHaveBeenLastCalledWith(\n expect.stringContaining('RelayRealtimeTranscript'),\n expect.objectContaining({ replacesPrevious: false })\n );\n });\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=realtime-session-review.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-session-review.service.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/realtime-session-review.service.test.ts"],"names":[],"mappings":""}