@memberjunction/ng-conversations 5.40.2 → 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 @@
1
+ {"version":3,"file":"realtime-agent-picker.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n OnInit,\n Output,\n ViewChild,\n AfterViewInit,\n inject,\n} from '@angular/core';\nimport type { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { REALTIME_ADVANCED_SESSION_CONTROLS, UserHoldsAuthorization } from '../../services/user-authorization';\nimport {\n BuildRealtimeModelOptions,\n ConstrainTargetsToPairings,\n DefaultPairedTargetId,\n LoadCoAgentPairings,\n RealtimeModelOption,\n RealtimePairedAgentRow,\n} from '../../services/realtime-pairing';\n\n/**\n * The user's confirmed choice from the realtime picker: the agent to call, an optional\n * EXPLICIT realtime model (`null` = \"Auto (recommended)\", i.e. let the server pick —\n * always `null` for users without the `Realtime: Advanced Session Controls`\n * authorization, who never see the model selector), and an optional EXPLICIT co-agent\n * (`null` = the server's co-agent resolution chain).\n */\nexport interface RealtimeAgentPick {\n /** The agent the voice call should front. */\n Agent: MJAIAgentEntityExtended;\n /** Explicit realtime model id, or `null` for the server's automatic selection. */\n PreferredModelId: string | null;\n /** Explicit co-agent id (`MJ: AI Agents.ID`, Realtime type), or `null` for the server's resolution chain. */\n CoAgentId: string | null;\n}\n\n/**\n * Compact anchored popover that lets the user choose WHICH agent a realtime\n * voice call should front — shown by {@link MessageInputComponent} when the\n * phone button is clicked on a conversation with **no prior agent\n * participation** (new / empty conversation), and on demand via the caret\n * button next to the phone (any conversation), where it doubles as the way\n * to pick a specific **co-agent** (the Realtime-type agent that voices the\n * call) and — for authorized users — a specific **voice model**. The plain\n * phone click on an existing conversation keeps its friction-free \"call the\n * resolved agent immediately\" behavior.\n *\n * Mostly dumb: the host supplies the agent list (the same cached set the\n * @mention autocomplete / routing logic uses), the Realtime-type co-agent\n * candidates (filtered from that same set), and the defaults to preselect;\n * the picker emits the user's choice. The data it loads itself:\n * - the compact \"Voice model\" option list (active Realtime models via a\n * narrow RunView) — loaded and rendered ONLY when the current user holds\n * the `Realtime: Advanced Session Controls` authorization (pure UX\n * disclosure; the server enforces the authorization on the mint), and\n * - the chosen co-agent's pairing rows (`MJ: AI Agent Co Agents`, Active 'CoAgent'-type rows): a\n * co-agent with pairing rows may only front its paired targets, so the\n * agent list constrains to those rows (Sequence order) with the IsDefault\n * row preselected; a co-agent with zero rows is universal and the list is\n * untouched.\n *\n * It does NOT persist anything (the host persists the co-agent preference\n * via `UserInfoEngine`; `mj-conversation-agent-picker` pins\n * `MJConversationEntity.DefaultAgentID` — different jobs, which is why this\n * is a separate component).\n *\n * Anchors itself bottom-right above the composer — the host's\n * `.message-input-wrapper` is `position: relative`.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-picker',\n imports: [MJButtonDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-voice-picker\" (click)=\"$event.stopPropagation()\">\n <div class=\"mj-voice-picker__header\">\n <i class=\"fa-solid fa-phone\"></i>\n <span>Start a voice call with…</span>\n </div>\n @if (ShowCoAgentSelect) {\n <div class=\"mj-voice-picker__select-row\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjVoiceCoAgentSelect\">\n <i class=\"fa-solid fa-headset\"></i>\n <span>Co-agent</span>\n </label>\n <select\n #coAgentSelect\n id=\"mjVoiceCoAgentSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedCoAgentId ?? ''\"\n (change)=\"OnCoAgentChange(coAgentSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (coAgent of CoAgents; track coAgent.ID) {\n <option [value]=\"coAgent.ID\">{{ coAgent.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"mj-voice-picker__search\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n #searchInput\n type=\"text\"\n placeholder=\"Search agents\"\n [value]=\"SearchText\"\n (input)=\"OnSearchInput(searchInput.value)\"\n (keydown.enter)=\"StartCall()\"\n (keydown.arrowdown)=\"MoveSelection(1); $event.preventDefault()\"\n (keydown.arrowup)=\"MoveSelection(-1); $event.preventDefault()\" />\n </div>\n <div class=\"mj-voice-picker__list\">\n @if (FilteredAgents.length === 0) {\n <div class=\"mj-voice-picker__empty\">{{ IsConstrainedByPairings ? 'No paired agents available' : 'No matching agents' }}</div>\n } @else {\n @for (agent of FilteredAgents; track agent.ID) {\n <button\n type=\"button\"\n class=\"mj-voice-picker__item\"\n [class.mj-voice-picker__item--selected]=\"IsSelected(agent)\"\n [title]=\"agent.Description || agent.Name\"\n (click)=\"Select(agent)\"\n (dblclick)=\"Pick(agent)\">\n <i [class]=\"IconClassFor(agent)\"></i>\n <span class=\"mj-voice-picker__item-name\">{{ agent.Name }}</span>\n @if (IsDefaultChoice(agent)) {\n <span class=\"mj-voice-picker__default-badge\">default</span>\n }\n </button>\n }\n }\n </div>\n @if (CanOverrideSessionConfig && Models.length > 0) {\n <div class=\"mj-voice-picker__select-row mj-voice-picker__select-row--model\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjVoiceModelSelect\">\n <i class=\"fa-solid fa-microchip\"></i>\n <span>Voice model</span>\n </label>\n <select\n #modelSelect\n id=\"mjVoiceModelSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedModelId ?? ''\"\n (change)=\"OnModelChange(modelSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (model of Models; track model.ID) {\n <option [value]=\"model.ID\">{{ model.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"mj-voice-picker__footer\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"!SelectedAgent\" (click)=\"StartCall()\">\n <i class=\"fa-solid fa-phone\"></i> Start\n </button>\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n `,\n styles: [`\n :host {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 8px;\n z-index: 60;\n }\n .mj-voice-picker {\n width: 300px;\n display: flex; flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);\n overflow: hidden;\n }\n .mj-voice-picker__header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px 8px;\n font-size: 13px; font-weight: 600;\n color: var(--mj-text-primary);\n }\n .mj-voice-picker__header i { color: var(--mj-brand-primary); }\n .mj-voice-picker__search {\n display: flex; align-items: center; gap: 8px;\n margin: 0 12px 8px;\n padding: 0 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n }\n .mj-voice-picker__search i { font-size: 12px; color: var(--mj-text-muted); }\n .mj-voice-picker__search input {\n flex: 1; min-width: 0;\n padding: 7px 0;\n background: transparent; border: none; outline: none;\n font-size: 13px; color: var(--mj-text-primary);\n }\n .mj-voice-picker__search input::placeholder { color: var(--mj-text-disabled); }\n .mj-voice-picker__search:focus-within { border-color: var(--mj-border-focus); }\n .mj-voice-picker__list {\n max-height: 220px; overflow-y: auto;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n padding: 4px 0;\n }\n .mj-voice-picker__item {\n display: flex; align-items: center; gap: 8px; width: 100%;\n padding: 7px 12px;\n background: transparent; border: none; cursor: pointer;\n color: var(--mj-text-primary); font-size: 13px; text-align: left;\n }\n .mj-voice-picker__item i { width: 16px; text-align: center; color: var(--mj-text-secondary); }\n .mj-voice-picker__item:hover { background: var(--mj-bg-surface-hover); }\n .mj-voice-picker__item--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n .mj-voice-picker__item--selected i { color: var(--mj-brand-primary); }\n .mj-voice-picker__item-name {\n flex: 1; min-width: 0;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n }\n .mj-voice-picker__default-badge {\n flex-shrink: 0;\n padding: 1px 6px;\n border-radius: 999px;\n font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n .mj-voice-picker__empty {\n padding: 12px; font-size: 12px; color: var(--mj-text-muted); text-align: center;\n }\n .mj-voice-picker__select-row {\n display: flex; align-items: center; gap: 8px;\n padding: 0 12px 8px;\n }\n .mj-voice-picker__select-row--model {\n padding: 8px 12px 0;\n }\n .mj-voice-picker__select-label {\n display: flex; align-items: center; gap: 6px;\n flex-shrink: 0;\n font-size: 12px; color: var(--mj-text-secondary);\n }\n .mj-voice-picker__select-label i { font-size: 11px; color: var(--mj-text-muted); }\n .mj-voice-picker__select {\n flex: 1; min-width: 0;\n padding: 5px 8px;\n font-size: 12px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n outline: none;\n }\n .mj-voice-picker__select:focus { border-color: var(--mj-border-focus); }\n .mj-voice-picker__footer {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px;\n }\n `]\n})\nexport class RealtimeAgentPickerComponent extends BaseAngularComponent implements OnInit, AfterViewInit {\n /** Agents the user can call — same cached set the @mention / routing logic uses. */\n @Input() Agents: MJAIAgentEntityExtended[] = [];\n\n /** The agent the default resolution would pick — preselected and listed first. */\n @Input() DefaultAgentId: string | null = null;\n\n /**\n * The ACTIVE Realtime-type co-agent candidates the user can run (host-filtered from\n * the same cached, run-permission-filtered agent set as {@link Agents}). The co-agent\n * selector renders only when MORE THAN ONE candidate exists — with zero or one\n * there's nothing meaningful to choose and the server's resolution chain applies.\n */\n @Input() CoAgents: MJAIAgentEntityExtended[] = [];\n\n /**\n * The user's persisted co-agent preference (host-loaded via `UserInfoEngine`) —\n * preselected in the co-agent selector when it's still a valid candidate.\n */\n @Input() DefaultCoAgentId: string | null = null;\n\n /** Emitted with the chosen agent + optional explicit voice model / co-agent when the user confirms. */\n @Output() AgentPicked = new EventEmitter<RealtimeAgentPick>();\n\n /** Emitted when the user dismisses without starting a call. */\n @Output() Cancelled = new EventEmitter<void>();\n\n @ViewChild('searchInput') private searchInput?: ElementRef<HTMLInputElement>;\n\n public SearchText = '';\n public SelectedAgentId: string | null = null;\n\n /** Active Realtime models the model selector offers (loaded only for authorized users). */\n public Models: RealtimeModelOption[] = [];\n\n /** The explicitly chosen voice model id, or `null` for \"Auto (recommended)\" (the default). */\n public SelectedModelId: string | null = null;\n\n /** The explicitly chosen co-agent id, or `null` for \"Auto (recommended)\" (the server's chain). */\n public SelectedCoAgentId: string | null = null;\n\n /**\n * Whether the current user holds the `Realtime: Advanced Session Controls`\n * authorization. Gates the voice-model selector (and any future config-override\n * controls) — pure disclosure; the server enforces the authorization on the mint.\n */\n public CanOverrideSessionConfig = false;\n\n /** The selected co-agent's pairing rows; empty = universal co-agent (no constraint). */\n public Pairings: RealtimePairedAgentRow[] = [];\n\n // Template helper — expose the shared UUID comparator to the view.\n public readonly UUIDsEqual = UUIDsEqual;\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n /** Monotonic guard so a stale pairing load can't clobber a newer co-agent choice. */\n private pairingLoadToken = 0;\n\n /** Co-agent selector visibility: only when there is a real choice to make. */\n public get ShowCoAgentSelect(): boolean {\n return this.CoAgents.length > 1;\n }\n\n /** True while the agent list is constrained to the selected co-agent's paired targets. */\n public get IsConstrainedByPairings(): boolean {\n return this.Pairings.length > 0;\n }\n\n public ngOnInit(): void {\n const initial = this.DefaultAgentId && this.findAgent(this.DefaultAgentId)\n ? this.DefaultAgentId\n : this.FilteredAgents[0]?.ID ?? null;\n this.SelectedAgentId = initial;\n this.CanOverrideSessionConfig = UserHoldsAuthorization(\n this.ProviderToUse?.CurrentUser,\n REALTIME_ADVANCED_SESSION_CONTROLS,\n this.ProviderToUse\n );\n if (this.CanOverrideSessionConfig) {\n void this.loadVoiceModels();\n }\n // Preselect the persisted co-agent preference when it's still a valid candidate.\n if (this.DefaultCoAgentId && this.CoAgents.some(a => UUIDsEqual(a.ID, this.DefaultCoAgentId))) {\n this.SelectedCoAgentId = this.DefaultCoAgentId;\n void this.reloadPairings();\n }\n }\n\n /**\n * Loads the \"Voice model\" options: active models whose type is `Realtime`, filtered from\n * {@link AIEngineBase}'s already-cached `Models` (provider-scoped engine instance, lazy\n * `Config` — no RunView round-trip). Called ONLY for users who hold the\n * advanced-session-controls authorization. Tolerant — a failure simply leaves\n * the selector hidden (the server's automatic selection still applies).\n */\n private async loadVoiceModels(): Promise<void> {\n try {\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(this.ProviderToUse, AIEngineBase) as AIEngineBase;\n await engine.Config(false, undefined, this.ProviderToUse);\n this.Models = BuildRealtimeModelOptions(engine.Models ?? []);\n } catch (error) {\n console.error('[RealtimeAgentPicker] Failed to load realtime models:', error);\n this.Models = [];\n }\n this.cdr.markForCheck();\n }\n\n /** Records the voice-model choice (`''` = Auto → `null`). */\n public OnModelChange(value: string): void {\n this.SelectedModelId = value && value.length > 0 ? value : null;\n this.cdr.markForCheck();\n }\n\n /** Records the co-agent choice (`''` = Auto → `null`) and refreshes the pairing constraint. */\n public OnCoAgentChange(value: string): void {\n this.SelectedCoAgentId = value && value.length > 0 ? value : null;\n void this.reloadPairings();\n }\n\n /**\n * Loads the selected co-agent's pairing rows and re-applies the target constraint:\n * with rows present, the agent list narrows to the paired targets (Sequence order)\n * and the IsDefault row's target is preselected; with zero rows (or Auto co-agent)\n * the list returns to the unconstrained default. Guarded against stale loads when\n * the user changes co-agents quickly.\n */\n private async reloadPairings(): Promise<void> {\n const token = ++this.pairingLoadToken;\n const coAgentId = this.SelectedCoAgentId;\n const pairings = coAgentId ? await LoadCoAgentPairings(this.ProviderToUse, coAgentId) : [];\n if (token !== this.pairingLoadToken) {\n return; // a newer co-agent choice superseded this load\n }\n this.Pairings = pairings;\n this.ensureSelectionVisible();\n this.cdr.markForCheck();\n }\n\n /**\n * Keeps the target selection coherent after the visible list changes: prefers the\n * pairing default (when constrained), then the host default, then keeps the current\n * selection when still visible, then the first visible row.\n */\n private ensureSelectionVisible(): void {\n const visible = this.FilteredAgents;\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n if (pairedDefault && visible.some(a => UUIDsEqual(a.ID, pairedDefault))) {\n this.SelectedAgentId = pairedDefault;\n return;\n }\n }\n if (this.SelectedAgentId && visible.some(a => UUIDsEqual(a.ID, this.SelectedAgentId))) {\n return; // current selection still valid\n }\n if (this.DefaultAgentId && visible.some(a => UUIDsEqual(a.ID, this.DefaultAgentId))) {\n this.SelectedAgentId = this.DefaultAgentId;\n return;\n }\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n\n public ngAfterViewInit(): void {\n // Microtask so focus lands after the popover renders without\n // triggering ExpressionChangedAfterItHasBeenChecked.\n Promise.resolve().then(() => this.searchInput?.nativeElement.focus());\n }\n\n /**\n * The visible target list: pairing-constrained first (a co-agent WITH pairing rows may\n * only front its paired targets, kept in pairing Sequence order), then search-filtered.\n * Unconstrained lists keep the default-first + alphabetical ordering.\n */\n public get FilteredAgents(): MJAIAgentEntityExtended[] {\n const base = ConstrainTargetsToPairings(this.Agents, this.Pairings);\n const needle = this.SearchText.trim().toLowerCase();\n const filtered = base.filter(a => !needle || (a.Name ?? '').toLowerCase().includes(needle));\n if (this.IsConstrainedByPairings) {\n return filtered; // pairing Sequence order is the canonical order\n }\n return filtered.sort((a, b) => {\n const aDefault = this.isDefault(a) ? 0 : 1;\n const bDefault = this.isDefault(b) ? 0 : 1;\n if (aDefault !== bDefault) return aDefault - bDefault;\n return (a.Name ?? '').localeCompare(b.Name ?? '');\n });\n }\n\n public get SelectedAgent(): MJAIAgentEntityExtended | null {\n return this.SelectedAgentId ? this.findAgent(this.SelectedAgentId) : null;\n }\n\n public IsSelected(agent: MJAIAgentEntityExtended): boolean {\n return !!this.SelectedAgentId && UUIDsEqual(agent.ID, this.SelectedAgentId);\n }\n\n /**\n * Whether `agent` carries the \"default\" badge: under a pairing constraint that's the\n * co-agent's IsDefault target; otherwise the host-resolved default agent.\n */\n public IsDefaultChoice(agent: MJAIAgentEntityExtended): boolean {\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n return !!pairedDefault && UUIDsEqual(agent.ID, pairedDefault);\n }\n return this.isDefault(agent);\n }\n\n public IconClassFor(agent: MJAIAgentEntityExtended): string {\n return agent.IconClass?.trim() || 'fa-solid fa-robot';\n }\n\n public OnSearchInput(value: string): void {\n this.SearchText = value;\n // Keep the selection on a visible row.\n const visible = this.FilteredAgents;\n if (!visible.some(a => this.IsSelected(a))) {\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n this.cdr.markForCheck();\n }\n\n /** Arrow-key navigation through the filtered list. */\n public MoveSelection(delta: number): void {\n const visible = this.FilteredAgents;\n if (visible.length === 0) return;\n const currentIndex = visible.findIndex(a => this.IsSelected(a));\n const nextIndex = currentIndex < 0\n ? 0\n : Math.min(visible.length - 1, Math.max(0, currentIndex + delta));\n this.SelectedAgentId = visible[nextIndex].ID;\n this.cdr.markForCheck();\n }\n\n public Select(agent: MJAIAgentEntityExtended): void {\n this.SelectedAgentId = agent.ID;\n this.cdr.markForCheck();\n }\n\n /** Confirm a specific agent immediately (double-click shortcut). */\n public Pick(agent: MJAIAgentEntityExtended): void {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n\n public StartCall(): void {\n const agent = this.SelectedAgent;\n if (agent) {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n }\n\n public Cancel(): void {\n this.Cancelled.emit();\n }\n\n /** Dismiss when the user clicks anywhere outside the popover. (The phone\n * button that opens it stops propagation, so the opening click never\n * reaches this handler.) */\n @HostListener('document:click', ['$event'])\n public OnDocumentClick(event: MouseEvent): void {\n if (!this.elementRef.nativeElement.contains(event.target as Node)) {\n this.Cancelled.emit();\n }\n }\n\n @HostListener('document:keydown.escape')\n public OnEscape(): void {\n this.Cancelled.emit();\n }\n\n /**\n * Assembles the emitted pick. The model preference is hard-gated on the\n * authorization here (defense in depth — unauthorized users never see the selector,\n * so `SelectedModelId` should already be null).\n */\n private buildPick(agent: MJAIAgentEntityExtended): RealtimeAgentPick {\n return {\n Agent: agent,\n PreferredModelId: this.CanOverrideSessionConfig ? this.SelectedModelId : null,\n CoAgentId: this.SelectedCoAgentId\n };\n }\n\n private isDefault(agent: MJAIAgentEntityExtended): boolean {\n return !!this.DefaultAgentId && UUIDsEqual(agent.ID, this.DefaultAgentId);\n }\n\n private findAgent(id: string): MJAIAgentEntityExtended | null {\n return this.Agents.find(a => UUIDsEqual(a.ID, id)) ?? null;\n }\n}\n"]}
@@ -0,0 +1,97 @@
1
+ import { RealtimeAudioActivity } from '@memberjunction/ai-realtime-client';
2
+ /**
3
+ * @fileoverview AUDIO-REACTIVE VISUAL SMOOTHING for the call overlay — the framework-free
4
+ * math between raw per-frame {@link RealtimeAudioActivity} samples and the CSS variables
5
+ * that make the hero orb vibrate like a speaker cone and the EQ render a true spectrum.
6
+ *
7
+ * Raw analyser levels are jittery; rendering them directly strobes. This module applies:
8
+ * - **Attack/decay envelope smoothing** ({@link SmoothLevel}) — fast attack so speech
9
+ * onset feels instant, slow decay so the cone "rings down" instead of snapping shut.
10
+ * - **Direction resolution with hysteresis** — who is audibly speaking (`agent` / `user` /
11
+ * `none`) with a presence floor and a hold window, so the direction color never
12
+ * flickers across syllable gaps.
13
+ *
14
+ * Owned by the overlay's requestAnimationFrame loop (outside Angular); kept pure so every
15
+ * rule unit-tests without Web Audio or a browser clock.
16
+ */
17
+ /** Who is audibly speaking right now (drives the orb/EQ direction color). */
18
+ export type RealtimeVoiceDirection = 'agent' | 'user' | 'none';
19
+ /** One smoothed, render-ready visual frame. */
20
+ export interface RealtimeAudioVisualFrame {
21
+ /** Smoothed agent-output level, 0..1. */
22
+ OutputLevel: number;
23
+ /** Smoothed user-mic level, 0..1. */
24
+ InputLevel: number;
25
+ /** Smoothed spectrum bins (length {@link AUDIO_VISUAL_BIN_COUNT}) of the dominant direction. */
26
+ Bins: number[];
27
+ /** Resolved speaking direction (hysteresis-stable). */
28
+ Direction: RealtimeVoiceDirection;
29
+ }
30
+ /** Number of EQ bars the hero renders (matches the meter's bin count). */
31
+ export declare const AUDIO_VISUAL_BIN_COUNT = 9;
32
+ /** Levels below this are treated as silence for direction purposes. */
33
+ export declare const AUDIO_PRESENCE_FLOOR = 0.045;
34
+ /** How long a direction is HELD after its audio drops below the floor (syllable-gap proofing). */
35
+ export declare const AUDIO_DIRECTION_HOLD_MS = 280;
36
+ /** The factor by which the other side must dominate to steal the direction mid-speech. */
37
+ export declare const AUDIO_DIRECTION_STEAL_FACTOR = 1.15;
38
+ /**
39
+ * NOISE GATES (per direction): raw analyser levels at/below the gate render as TRUE
40
+ * silence — without this, an idle microphone's room-noise/auto-gain floor keeps the EQ
41
+ * dancing and the direction stuck on "user" while nobody is speaking. The mic gate sits
42
+ * a touch above the output gate (playback silence is actual zero; mic silence isn't), but
43
+ * NOT so high it swallows normal speech: 0.08 over-gated — typical Mac-mic normalized speech
44
+ * peaks well under it, so the meter read silence the whole time the user was talking. 0.045
45
+ * (≈ the presence floor) suppresses idle room-noise while letting real speech drive the EQ.
46
+ */
47
+ export declare const AUDIO_OUTPUT_NOISE_GATE = 0.03;
48
+ export declare const AUDIO_INPUT_NOISE_GATE = 0.045;
49
+ /**
50
+ * Soft-knee noise gate: at/below `gate` → 0; above it the remaining range rescales to
51
+ * 0..1 (so the gate never visibly "clips" the bottom off real speech). Pure.
52
+ */
53
+ export declare function GateLevel(level: number, gate: number): number;
54
+ /**
55
+ * One smoothing step: fast attack (speech onset reads instantly), slow decay (the level
56
+ * rings down like a speaker cone instead of snapping). Pure.
57
+ */
58
+ export declare function SmoothLevel(previous: number, next: number, attack?: number, decay?: number): number;
59
+ /**
60
+ * Per-overlay smoothing state machine. Feed it one raw {@link RealtimeAudioActivity}
61
+ * sample per animation frame via {@link Next}; render the returned frame. `null` in →
62
+ * `null` out (the driver attached no meters — the host keeps turn-state visuals).
63
+ */
64
+ export declare class RealtimeAudioVisualSmoother {
65
+ private outputLevel;
66
+ private inputLevel;
67
+ private bins;
68
+ private direction;
69
+ /** Last time (ms) the current direction's level was at/above the presence floor. */
70
+ private directionHeldAt;
71
+ /** Resets all smoothing state (call between sessions). */
72
+ Reset(): void;
73
+ /**
74
+ * Advances the smoother with one raw sample.
75
+ * @param raw The client's current audio activity (`null` = no metering capability).
76
+ * @param nowMs A monotonic clock reading (e.g. `performance.now()`).
77
+ * @returns The render-ready frame, or `null` when un-metered.
78
+ */
79
+ Next(raw: RealtimeAudioActivity | null, nowMs: number): RealtimeAudioVisualFrame | null;
80
+ /**
81
+ * The spectrum follows whichever direction is louder (falling back to whichever
82
+ * exists) — but a side whose GATED level is silence contributes no spectrum at all:
83
+ * an idle mic's room-noise bins must not keep the EQ dancing.
84
+ */
85
+ private pickRawBins;
86
+ private smoothBins;
87
+ /**
88
+ * Direction rules (hysteresis):
89
+ * - silence adopts nothing; speech from silence adopts the louder side immediately;
90
+ * - a live direction RENEWS its hold while at/above the presence floor;
91
+ * - the other side steals the direction only by dominating ({@link AUDIO_DIRECTION_STEAL_FACTOR});
92
+ * - a direction releases to `none` only after {@link AUDIO_DIRECTION_HOLD_MS} of silence —
93
+ * syllable gaps never flicker the color.
94
+ */
95
+ private resolveDirection;
96
+ }
97
+ //# sourceMappingURL=realtime-audio-visuals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-audio-visuals.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AAEH,6EAA6E;AAC7E,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/D,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,uDAAuD;IACvD,SAAS,EAAE,sBAAsB,CAAC;CACnC;AAED,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,kGAAkG;AAClG,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,0FAA0F;AAC1F,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,EAAE,KAAK,GAAE,MAAa,GAAG,MAAM,CAI9G;AAED;;;;GAIG;AACH,qBAAa,2BAA2B;IACtC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,IAAI,CAA+D;IAC3E,OAAO,CAAC,SAAS,CAAkC;IACnD,oFAAoF;IACpF,OAAO,CAAC,eAAe,CAAK;IAE5B,0DAA0D;IACnD,KAAK,IAAI,IAAI;IAQpB;;;;;OAKG;IACI,IAAI,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI;IAmB9F;;;;OAIG;IACH,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,UAAU;IASlB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;CA4BzB"}
@@ -0,0 +1,139 @@
1
+ /** Number of EQ bars the hero renders (matches the meter's bin count). */
2
+ export const AUDIO_VISUAL_BIN_COUNT = 9;
3
+ /** Levels below this are treated as silence for direction purposes. */
4
+ export const AUDIO_PRESENCE_FLOOR = 0.045;
5
+ /** How long a direction is HELD after its audio drops below the floor (syllable-gap proofing). */
6
+ export const AUDIO_DIRECTION_HOLD_MS = 280;
7
+ /** The factor by which the other side must dominate to steal the direction mid-speech. */
8
+ export const AUDIO_DIRECTION_STEAL_FACTOR = 1.15;
9
+ /**
10
+ * NOISE GATES (per direction): raw analyser levels at/below the gate render as TRUE
11
+ * silence — without this, an idle microphone's room-noise/auto-gain floor keeps the EQ
12
+ * dancing and the direction stuck on "user" while nobody is speaking. The mic gate sits
13
+ * a touch above the output gate (playback silence is actual zero; mic silence isn't), but
14
+ * NOT so high it swallows normal speech: 0.08 over-gated — typical Mac-mic normalized speech
15
+ * peaks well under it, so the meter read silence the whole time the user was talking. 0.045
16
+ * (≈ the presence floor) suppresses idle room-noise while letting real speech drive the EQ.
17
+ */
18
+ export const AUDIO_OUTPUT_NOISE_GATE = 0.03;
19
+ export const AUDIO_INPUT_NOISE_GATE = 0.045;
20
+ /**
21
+ * Soft-knee noise gate: at/below `gate` → 0; above it the remaining range rescales to
22
+ * 0..1 (so the gate never visibly "clips" the bottom off real speech). Pure.
23
+ */
24
+ export function GateLevel(level, gate) {
25
+ if (!Number.isFinite(level) || level <= gate) {
26
+ return 0;
27
+ }
28
+ return Math.min(1, (level - gate) / (1 - gate));
29
+ }
30
+ /**
31
+ * One smoothing step: fast attack (speech onset reads instantly), slow decay (the level
32
+ * rings down like a speaker cone instead of snapping). Pure.
33
+ */
34
+ export function SmoothLevel(previous, next, attack = 0.5, decay = 0.12) {
35
+ const factor = next > previous ? attack : decay;
36
+ const value = previous + (next - previous) * factor;
37
+ return Math.min(1, Math.max(0, value));
38
+ }
39
+ /**
40
+ * Per-overlay smoothing state machine. Feed it one raw {@link RealtimeAudioActivity}
41
+ * sample per animation frame via {@link Next}; render the returned frame. `null` in →
42
+ * `null` out (the driver attached no meters — the host keeps turn-state visuals).
43
+ */
44
+ export class RealtimeAudioVisualSmoother {
45
+ outputLevel = 0;
46
+ inputLevel = 0;
47
+ bins = new Array(AUDIO_VISUAL_BIN_COUNT).fill(0);
48
+ direction = 'none';
49
+ /** Last time (ms) the current direction's level was at/above the presence floor. */
50
+ directionHeldAt = 0;
51
+ /** Resets all smoothing state (call between sessions). */
52
+ Reset() {
53
+ this.outputLevel = 0;
54
+ this.inputLevel = 0;
55
+ this.bins = new Array(AUDIO_VISUAL_BIN_COUNT).fill(0);
56
+ this.direction = 'none';
57
+ this.directionHeldAt = 0;
58
+ }
59
+ /**
60
+ * Advances the smoother with one raw sample.
61
+ * @param raw The client's current audio activity (`null` = no metering capability).
62
+ * @param nowMs A monotonic clock reading (e.g. `performance.now()`).
63
+ * @returns The render-ready frame, or `null` when un-metered.
64
+ */
65
+ Next(raw, nowMs) {
66
+ if (!raw) {
67
+ return null;
68
+ }
69
+ // Gate BEFORE smoothing: silence is true zero, the decay still rings down smoothly.
70
+ const gatedOut = GateLevel(raw.OutputLevel ?? 0, AUDIO_OUTPUT_NOISE_GATE);
71
+ const gatedIn = GateLevel(raw.InputLevel ?? 0, AUDIO_INPUT_NOISE_GATE);
72
+ this.outputLevel = SmoothLevel(this.outputLevel, gatedOut);
73
+ this.inputLevel = SmoothLevel(this.inputLevel, gatedIn);
74
+ this.smoothBins(this.pickRawBins(raw, gatedOut, gatedIn));
75
+ this.resolveDirection(nowMs);
76
+ return {
77
+ OutputLevel: this.outputLevel,
78
+ InputLevel: this.inputLevel,
79
+ Bins: [...this.bins],
80
+ Direction: this.direction
81
+ };
82
+ }
83
+ /**
84
+ * The spectrum follows whichever direction is louder (falling back to whichever
85
+ * exists) — but a side whose GATED level is silence contributes no spectrum at all:
86
+ * an idle mic's room-noise bins must not keep the EQ dancing.
87
+ */
88
+ pickRawBins(raw, gatedOut, gatedIn) {
89
+ const outBins = gatedOut > 0 ? raw.OutputBins : null;
90
+ const inBins = gatedIn > 0 ? raw.InputBins : null;
91
+ if (outBins && inBins) {
92
+ return this.outputLevel >= this.inputLevel ? outBins : inBins;
93
+ }
94
+ return outBins ?? inBins;
95
+ }
96
+ smoothBins(rawBins) {
97
+ if (!rawBins) {
98
+ // No spectrum available — decay the bars toward silence.
99
+ this.bins = this.bins.map(b => SmoothLevel(b, 0));
100
+ return;
101
+ }
102
+ this.bins = this.bins.map((prev, i) => SmoothLevel(prev, rawBins[i] ?? 0));
103
+ }
104
+ /**
105
+ * Direction rules (hysteresis):
106
+ * - silence adopts nothing; speech from silence adopts the louder side immediately;
107
+ * - a live direction RENEWS its hold while at/above the presence floor;
108
+ * - the other side steals the direction only by dominating ({@link AUDIO_DIRECTION_STEAL_FACTOR});
109
+ * - a direction releases to `none` only after {@link AUDIO_DIRECTION_HOLD_MS} of silence —
110
+ * syllable gaps never flicker the color.
111
+ */
112
+ resolveDirection(nowMs) {
113
+ const out = this.outputLevel;
114
+ const inp = this.inputLevel;
115
+ const audible = out >= AUDIO_PRESENCE_FLOOR || inp >= AUDIO_PRESENCE_FLOOR;
116
+ const louder = out >= inp ? 'agent' : 'user';
117
+ if (this.direction === 'none') {
118
+ if (audible) {
119
+ this.direction = louder;
120
+ this.directionHeldAt = nowMs;
121
+ }
122
+ return;
123
+ }
124
+ const currentLevel = this.direction === 'agent' ? out : inp;
125
+ const otherLevel = this.direction === 'agent' ? inp : out;
126
+ if (currentLevel >= AUDIO_PRESENCE_FLOOR) {
127
+ this.directionHeldAt = nowMs;
128
+ }
129
+ if (otherLevel >= AUDIO_PRESENCE_FLOOR && otherLevel >= currentLevel * AUDIO_DIRECTION_STEAL_FACTOR) {
130
+ this.direction = this.direction === 'agent' ? 'user' : 'agent';
131
+ this.directionHeldAt = nowMs;
132
+ return;
133
+ }
134
+ if (!audible && nowMs - this.directionHeldAt > AUDIO_DIRECTION_HOLD_MS) {
135
+ this.direction = 'none';
136
+ }
137
+ }
138
+ }
139
+ //# sourceMappingURL=realtime-audio-visuals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-audio-visuals.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"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","sourcesContent":["import { RealtimeAudioActivity } from '@memberjunction/ai-realtime-client';\n\n/**\n * @fileoverview AUDIO-REACTIVE VISUAL SMOOTHING for the call overlay — the framework-free\n * math between raw per-frame {@link RealtimeAudioActivity} samples and the CSS variables\n * that make the hero orb vibrate like a speaker cone and the EQ render a true spectrum.\n *\n * Raw analyser levels are jittery; rendering them directly strobes. This module applies:\n * - **Attack/decay envelope smoothing** ({@link SmoothLevel}) — fast attack so speech\n * onset feels instant, slow decay so the cone \"rings down\" instead of snapping shut.\n * - **Direction resolution with hysteresis** — who is audibly speaking (`agent` / `user` /\n * `none`) with a presence floor and a hold window, so the direction color never\n * flickers across syllable gaps.\n *\n * Owned by the overlay's requestAnimationFrame loop (outside Angular); kept pure so every\n * rule unit-tests without Web Audio or a browser clock.\n */\n\n/** Who is audibly speaking right now (drives the orb/EQ direction color). */\nexport type RealtimeVoiceDirection = 'agent' | 'user' | 'none';\n\n/** One smoothed, render-ready visual frame. */\nexport interface RealtimeAudioVisualFrame {\n /** Smoothed agent-output level, 0..1. */\n OutputLevel: number;\n /** Smoothed user-mic level, 0..1. */\n InputLevel: number;\n /** Smoothed spectrum bins (length {@link AUDIO_VISUAL_BIN_COUNT}) of the dominant direction. */\n Bins: number[];\n /** Resolved speaking direction (hysteresis-stable). */\n Direction: RealtimeVoiceDirection;\n}\n\n/** Number of EQ bars the hero renders (matches the meter's bin count). */\nexport const AUDIO_VISUAL_BIN_COUNT = 9;\n\n/** Levels below this are treated as silence for direction purposes. */\nexport const AUDIO_PRESENCE_FLOOR = 0.045;\n\n/** How long a direction is HELD after its audio drops below the floor (syllable-gap proofing). */\nexport const AUDIO_DIRECTION_HOLD_MS = 280;\n\n/** The factor by which the other side must dominate to steal the direction mid-speech. */\nexport const AUDIO_DIRECTION_STEAL_FACTOR = 1.15;\n\n/**\n * NOISE GATES (per direction): raw analyser levels at/below the gate render as TRUE\n * silence — without this, an idle microphone's room-noise/auto-gain floor keeps the EQ\n * dancing and the direction stuck on \"user\" while nobody is speaking. The mic gate sits\n * a touch above the output gate (playback silence is actual zero; mic silence isn't), but\n * NOT so high it swallows normal speech: 0.08 over-gated — typical Mac-mic normalized speech\n * peaks well under it, so the meter read silence the whole time the user was talking. 0.045\n * (≈ the presence floor) suppresses idle room-noise while letting real speech drive the EQ.\n */\nexport const AUDIO_OUTPUT_NOISE_GATE = 0.03;\nexport const AUDIO_INPUT_NOISE_GATE = 0.045;\n\n/**\n * Soft-knee noise gate: at/below `gate` → 0; above it the remaining range rescales to\n * 0..1 (so the gate never visibly \"clips\" the bottom off real speech). Pure.\n */\nexport function GateLevel(level: number, gate: number): number {\n if (!Number.isFinite(level) || level <= gate) {\n return 0;\n }\n return Math.min(1, (level - gate) / (1 - gate));\n}\n\n/**\n * One smoothing step: fast attack (speech onset reads instantly), slow decay (the level\n * rings down like a speaker cone instead of snapping). Pure.\n */\nexport function SmoothLevel(previous: number, next: number, attack: number = 0.5, decay: number = 0.12): number {\n const factor = next > previous ? attack : decay;\n const value = previous + (next - previous) * factor;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Per-overlay smoothing state machine. Feed it one raw {@link RealtimeAudioActivity}\n * sample per animation frame via {@link Next}; render the returned frame. `null` in →\n * `null` out (the driver attached no meters — the host keeps turn-state visuals).\n */\nexport class RealtimeAudioVisualSmoother {\n private outputLevel = 0;\n private inputLevel = 0;\n private bins: number[] = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n private direction: RealtimeVoiceDirection = 'none';\n /** Last time (ms) the current direction's level was at/above the presence floor. */\n private directionHeldAt = 0;\n\n /** Resets all smoothing state (call between sessions). */\n public Reset(): void {\n this.outputLevel = 0;\n this.inputLevel = 0;\n this.bins = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n this.direction = 'none';\n this.directionHeldAt = 0;\n }\n\n /**\n * Advances the smoother with one raw sample.\n * @param raw The client's current audio activity (`null` = no metering capability).\n * @param nowMs A monotonic clock reading (e.g. `performance.now()`).\n * @returns The render-ready frame, or `null` when un-metered.\n */\n public Next(raw: RealtimeAudioActivity | null, nowMs: number): RealtimeAudioVisualFrame | null {\n if (!raw) {\n return null;\n }\n // Gate BEFORE smoothing: silence is true zero, the decay still rings down smoothly.\n const gatedOut = GateLevel(raw.OutputLevel ?? 0, AUDIO_OUTPUT_NOISE_GATE);\n const gatedIn = GateLevel(raw.InputLevel ?? 0, AUDIO_INPUT_NOISE_GATE);\n this.outputLevel = SmoothLevel(this.outputLevel, gatedOut);\n this.inputLevel = SmoothLevel(this.inputLevel, gatedIn);\n this.smoothBins(this.pickRawBins(raw, gatedOut, gatedIn));\n this.resolveDirection(nowMs);\n return {\n OutputLevel: this.outputLevel,\n InputLevel: this.inputLevel,\n Bins: [...this.bins],\n Direction: this.direction\n };\n }\n\n /**\n * The spectrum follows whichever direction is louder (falling back to whichever\n * exists) — but a side whose GATED level is silence contributes no spectrum at all:\n * an idle mic's room-noise bins must not keep the EQ dancing.\n */\n private pickRawBins(raw: RealtimeAudioActivity, gatedOut: number, gatedIn: number): number[] | null {\n const outBins = gatedOut > 0 ? raw.OutputBins : null;\n const inBins = gatedIn > 0 ? raw.InputBins : null;\n if (outBins && inBins) {\n return this.outputLevel >= this.inputLevel ? outBins : inBins;\n }\n return outBins ?? inBins;\n }\n\n private smoothBins(rawBins: number[] | null): void {\n if (!rawBins) {\n // No spectrum available — decay the bars toward silence.\n this.bins = this.bins.map(b => SmoothLevel(b, 0));\n return;\n }\n this.bins = this.bins.map((prev, i) => SmoothLevel(prev, rawBins[i] ?? 0));\n }\n\n /**\n * Direction rules (hysteresis):\n * - silence adopts nothing; speech from silence adopts the louder side immediately;\n * - a live direction RENEWS its hold while at/above the presence floor;\n * - the other side steals the direction only by dominating ({@link AUDIO_DIRECTION_STEAL_FACTOR});\n * - a direction releases to `none` only after {@link AUDIO_DIRECTION_HOLD_MS} of silence —\n * syllable gaps never flicker the color.\n */\n private resolveDirection(nowMs: number): void {\n const out = this.outputLevel;\n const inp = this.inputLevel;\n const audible = out >= AUDIO_PRESENCE_FLOOR || inp >= AUDIO_PRESENCE_FLOOR;\n const louder: RealtimeVoiceDirection = out >= inp ? 'agent' : 'user';\n\n if (this.direction === 'none') {\n if (audible) {\n this.direction = louder;\n this.directionHeldAt = nowMs;\n }\n return;\n }\n\n const currentLevel = this.direction === 'agent' ? out : inp;\n const otherLevel = this.direction === 'agent' ? inp : out;\n if (currentLevel >= AUDIO_PRESENCE_FLOOR) {\n this.directionHeldAt = nowMs;\n }\n if (otherLevel >= AUDIO_PRESENCE_FLOOR && otherLevel >= currentLevel * AUDIO_DIRECTION_STEAL_FACTOR) {\n this.direction = this.direction === 'agent' ? 'user' : 'agent';\n this.directionHeldAt = nowMs;\n return;\n }\n if (!audible && nowMs - this.directionHeldAt > AUDIO_DIRECTION_HOLD_MS) {\n this.direction = 'none';\n }\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import * as i0 from "@angular/core";
2
+ /** A single channel chip in the session's channel strip. */
3
+ export interface RealtimeChannel {
4
+ /** Stable id for tracking. */
5
+ Id: string;
6
+ /** Display label (e.g. "Voice", "Text"). */
7
+ Label: string;
8
+ /** Font Awesome icon class (e.g. "fa-microphone-lines"). */
9
+ Icon: string;
10
+ /** Channel status — drives the chip styling + live dot. */
11
+ Status: 'live' | 'opening' | 'off';
12
+ }
13
+ /**
14
+ * The channel strip (mirrors `.channel-bar` in live-session.html + the `.chan-strip` in
15
+ * session-channels.html). Renders a LIST of channel chips so additional channels (whiteboard,
16
+ * screen-share, …) slot in later without markup changes. Defaults to the always-present
17
+ * "🎙 Voice live now" channel; hosts can override via {@link Channels}.
18
+ */
19
+ export declare class RealtimeChannelStripComponent {
20
+ private _channels;
21
+ /** The channels to render. Defaults to a single live Voice channel. */
22
+ set Channels(value: RealtimeChannel[] | null);
23
+ get Channels(): RealtimeChannel[];
24
+ /** track fn for the channel @for. */
25
+ TrackChannel(_index: number, channel: RealtimeChannel): string;
26
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeChannelStripComponent, never>;
27
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeChannelStripComponent, "mj-realtime-channel-strip", never, { "Channels": { "alias": "Channels"; "required": false; }; }, {}, never, never, true, never>;
28
+ }
29
+ //# sourceMappingURL=realtime-channel-strip.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-channel-strip.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-channel-strip.component.ts"],"names":[],"mappings":";AAGA,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;CACpC;AAED;;;;;GAKG;AACH,qBAOa,6BAA6B;IACxC,OAAO,CAAC,SAAS,CAEf;IAEF,uEAAuE;IACvE,IACI,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,IAAI,EAE3C;IACD,IAAI,QAAQ,IAAI,eAAe,EAAE,CAEhC;IAED,qCAAqC;IAC9B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM;yCAf1D,6BAA6B;2CAA7B,6BAA6B;CAkBzC"}
@@ -0,0 +1,69 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "@angular/common";
5
+ function RealtimeChannelStripComponent_For_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
6
+ i0.ɵɵelement(0, "span", 5);
7
+ } }
8
+ function RealtimeChannelStripComponent_For_4_Conditional_4_Template(rf, ctx) { if (rf & 1) {
9
+ i0.ɵɵelementStart(0, "span", 6);
10
+ i0.ɵɵtext(1, "opening\u2026");
11
+ i0.ɵɵelementEnd();
12
+ } }
13
+ function RealtimeChannelStripComponent_For_4_Template(rf, ctx) { if (rf & 1) {
14
+ i0.ɵɵelementStart(0, "span", 3);
15
+ i0.ɵɵelement(1, "i", 4);
16
+ i0.ɵɵtext(2);
17
+ i0.ɵɵconditionalCreate(3, RealtimeChannelStripComponent_For_4_Conditional_3_Template, 1, 0, "span", 5)(4, RealtimeChannelStripComponent_For_4_Conditional_4_Template, 2, 0, "span", 6);
18
+ i0.ɵɵelementEnd();
19
+ } if (rf & 2) {
20
+ const channel_r1 = ctx.$implicit;
21
+ i0.ɵɵclassProp("chan-chip--live", channel_r1.Status === "live")("chan-chip--opening", channel_r1.Status === "opening")("chan-chip--off", channel_r1.Status === "off");
22
+ i0.ɵɵadvance();
23
+ i0.ɵɵproperty("ngClass", channel_r1.Icon);
24
+ i0.ɵɵadvance();
25
+ i0.ɵɵtextInterpolate1(" ", channel_r1.Label, " ");
26
+ i0.ɵɵadvance();
27
+ i0.ɵɵconditional(channel_r1.Status === "live" ? 3 : channel_r1.Status === "opening" ? 4 : -1);
28
+ } }
29
+ /**
30
+ * The channel strip (mirrors `.channel-bar` in live-session.html + the `.chan-strip` in
31
+ * session-channels.html). Renders a LIST of channel chips so additional channels (whiteboard,
32
+ * screen-share, …) slot in later without markup changes. Defaults to the always-present
33
+ * "🎙 Voice live now" channel; hosts can override via {@link Channels}.
34
+ */
35
+ export class RealtimeChannelStripComponent {
36
+ _channels = [
37
+ { Id: 'voice', Label: 'Voice', Icon: 'fa-microphone-lines', Status: 'live' }
38
+ ];
39
+ /** The channels to render. Defaults to a single live Voice channel. */
40
+ set Channels(value) {
41
+ this._channels = value && value.length > 0 ? value : this._channels;
42
+ }
43
+ get Channels() {
44
+ return this._channels;
45
+ }
46
+ /** track fn for the channel @for. */
47
+ TrackChannel(_index, channel) {
48
+ return channel.Id;
49
+ }
50
+ static ɵfac = function RealtimeChannelStripComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeChannelStripComponent)(); };
51
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeChannelStripComponent, selectors: [["mj-realtime-channel-strip"]], inputs: { Channels: "Channels" }, decls: 5, vars: 0, consts: [[1, "channel-strip"], [1, "channel-strip__label"], [1, "chan-chip", 3, "chan-chip--live", "chan-chip--opening", "chan-chip--off"], [1, "chan-chip"], ["aria-hidden", "true", 1, "fa-solid", 3, "ngClass"], ["aria-hidden", "true", 1, "live-dot"], [1, "muted"]], template: function RealtimeChannelStripComponent_Template(rf, ctx) { if (rf & 1) {
52
+ i0.ɵɵelementStart(0, "div", 0)(1, "span", 1);
53
+ i0.ɵɵtext(2, "Channels");
54
+ i0.ɵɵelementEnd();
55
+ i0.ɵɵrepeaterCreate(3, RealtimeChannelStripComponent_For_4_Template, 5, 9, "span", 2, ctx.TrackChannel, true);
56
+ i0.ɵɵelementEnd();
57
+ } if (rf & 2) {
58
+ i0.ɵɵadvance(3);
59
+ i0.ɵɵrepeater(ctx.Channels);
60
+ } }, dependencies: [CommonModule, i1.NgClass], styles: ["[_nghost-%COMP%] {\n display: block;\n}\n\n.channel-strip[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n padding: 12px 22px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.channel-strip__label[_ngcontent-%COMP%] {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n font-weight: 700;\n margin-right: 4px;\n}\n\n.chan-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 6px 12px;\n font-size: 12.5px;\n font-weight: 600;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n.chan-chip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n.chan-chip--live[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.chan-chip--opening[_ngcontent-%COMP%] {\n border-style: dashed;\n color: var(--mj-text-muted);\n animation: _ngcontent-%COMP%_chip-pulse 1.4s ease-in-out infinite;\n}\n.chan-chip--off[_ngcontent-%COMP%] {\n opacity: 0.55;\n}\n.chan-chip[_ngcontent-%COMP%] .live-dot[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-success);\n}\n.chan-chip[_ngcontent-%COMP%] .muted[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n@keyframes _ngcontent-%COMP%_chip-pulse { 0%, 100% { opacity: .55 } 50% { opacity: 1 } }"] });
61
+ }
62
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeChannelStripComponent, [{
63
+ type: Component,
64
+ args: [{ standalone: true, selector: 'mj-realtime-channel-strip', imports: [CommonModule], template: "<div class=\"channel-strip\">\n <span class=\"channel-strip__label\">Channels</span>\n @for (channel of Channels; track TrackChannel($index, channel)) {\n <span class=\"chan-chip\"\n [class.chan-chip--live]=\"channel.Status === 'live'\"\n [class.chan-chip--opening]=\"channel.Status === 'opening'\"\n [class.chan-chip--off]=\"channel.Status === 'off'\">\n <i class=\"fa-solid\" [ngClass]=\"channel.Icon\" aria-hidden=\"true\"></i>\n {{ channel.Label }}\n @if (channel.Status === 'live') {\n <span class=\"live-dot\" aria-hidden=\"true\"></span>\n } @else if (channel.Status === 'opening') {\n <span class=\"muted\">opening\u2026</span>\n }\n </span>\n }\n</div>\n", styles: [":host {\n display: block;\n}\n\n.channel-strip {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n padding: 12px 22px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.channel-strip__label {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n font-weight: 700;\n margin-right: 4px;\n}\n\n.chan-chip {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 6px 12px;\n font-size: 12.5px;\n font-weight: 600;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n.chan-chip i {\n font-size: 12px;\n}\n.chan-chip--live {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.chan-chip--opening {\n border-style: dashed;\n color: var(--mj-text-muted);\n animation: chip-pulse 1.4s ease-in-out infinite;\n}\n.chan-chip--off {\n opacity: 0.55;\n}\n.chan-chip .live-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-success);\n}\n.chan-chip .muted {\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n@keyframes chip-pulse { 0%, 100% { opacity: .55 } 50% { opacity: 1 } }\n"] }]
65
+ }], null, { Channels: [{
66
+ type: Input
67
+ }] }); })();
68
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeChannelStripComponent, { className: "RealtimeChannelStripComponent", filePath: "src/lib/components/realtime/realtime-channel-strip.component.ts", lineNumber: 29 }); })();
69
+ //# sourceMappingURL=realtime-channel-strip.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-channel-strip.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-channel-strip.component.ts","../../../../src/lib/components/realtime/realtime-channel-strip.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;;;;ICSvC,0BAAiD;;;IAEjD,+BAAoB;IAAA,6BAAQ;IAAA,iBAAO;;;IATvC,+BAGwD;IACtD,uBAAoE;IACpE,YACA;IAEE,AAFF,sGAAiC,gFAEU;IAG7C,iBAAO;;;IARD,AADA,AADA,+DAAmD,uDACM,+CACR;IACjC,cAAwB;IAAxB,yCAAwB;IAC5C,cACA;IADA,iDACA;IAAA,cAIC;IAJD,6FAIC;;ADEP;;;;;GAKG;AAQH,MAAM,OAAO,6BAA6B;IAChC,SAAS,GAAsB;QACrC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE;KAC7E,CAAC;IAEF,uEAAuE;IACvE,IACI,QAAQ,CAAC,KAA+B;QAC1C,IAAI,CAAC,SAAS,GAAG,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;IACtE,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,qCAAqC;IAC9B,YAAY,CAAC,MAAc,EAAE,OAAwB;QAC1D,OAAO,OAAO,CAAC,EAAE,CAAC;IACpB,CAAC;uHAjBU,6BAA6B;6DAA7B,6BAA6B;YC3BxC,AADF,8BAA2B,cACU;YAAA,wBAAQ;YAAA,iBAAO;YAClD,6GAaC;YACH,iBAAM;;YAdJ,eAaC;YAbD,2BAaC;4BDSS,YAAY;;iFAIX,6BAA6B;cAPzC,SAAS;6BACI,IAAI,YACN,2BAA2B,WAC5B,CAAC,YAAY,CAAC;;kBAUtB,KAAK;;kFANK,6BAA6B","sourcesContent":["import { Component, Input } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n/** A single channel chip in the session's channel strip. */\nexport interface RealtimeChannel {\n /** Stable id for tracking. */\n Id: string;\n /** Display label (e.g. \"Voice\", \"Text\"). */\n Label: string;\n /** Font Awesome icon class (e.g. \"fa-microphone-lines\"). */\n Icon: string;\n /** Channel status — drives the chip styling + live dot. */\n Status: 'live' | 'opening' | 'off';\n}\n\n/**\n * The channel strip (mirrors `.channel-bar` in live-session.html + the `.chan-strip` in\n * session-channels.html). Renders a LIST of channel chips so additional channels (whiteboard,\n * screen-share, …) slot in later without markup changes. Defaults to the always-present\n * \"🎙 Voice live now\" channel; hosts can override via {@link Channels}.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-channel-strip',\n imports: [CommonModule],\n templateUrl: './realtime-channel-strip.component.html',\n styleUrl: './realtime-channel-strip.component.css'\n})\nexport class RealtimeChannelStripComponent {\n private _channels: RealtimeChannel[] = [\n { Id: 'voice', Label: 'Voice', Icon: 'fa-microphone-lines', Status: 'live' }\n ];\n\n /** The channels to render. Defaults to a single live Voice channel. */\n @Input()\n set Channels(value: RealtimeChannel[] | null) {\n this._channels = value && value.length > 0 ? value : this._channels;\n }\n get Channels(): RealtimeChannel[] {\n return this._channels;\n }\n\n /** track fn for the channel @for. */\n public TrackChannel(_index: number, channel: RealtimeChannel): string {\n return channel.Id;\n }\n}\n","<div class=\"channel-strip\">\n <span class=\"channel-strip__label\">Channels</span>\n @for (channel of Channels; track TrackChannel($index, channel)) {\n <span class=\"chan-chip\"\n [class.chan-chip--live]=\"channel.Status === 'live'\"\n [class.chan-chip--opening]=\"channel.Status === 'opening'\"\n [class.chan-chip--off]=\"channel.Status === 'off'\">\n <i class=\"fa-solid\" [ngClass]=\"channel.Icon\" aria-hidden=\"true\"></i>\n {{ channel.Label }}\n @if (channel.Status === 'live') {\n <span class=\"live-dot\" aria-hidden=\"true\"></span>\n } @else if (channel.Status === 'opening') {\n <span class=\"muted\">opening…</span>\n }\n </span>\n }\n</div>\n"]}
@@ -0,0 +1,65 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * The call overlay's BOTTOM DOCK — the progressive-disclosure composer
5
+ * (`plans/realtime/mockups/redesign-a-progressive.html`). One component, two shapes,
6
+ * keyed off the overlay's disclosure {@link Level}:
7
+ *
8
+ * - **Levels 0–1 (phone-call strip)** — big round call controls, centered: Mute, the
9
+ * Captions toggle (level 1+, arriving WITH the text it controls), the Details peek
10
+ * (level 0 paths where the surface panel isn't earned yet — lets the user look at the
11
+ * Activity/Whiteboard panels on demand), and End call. Level 1 adds the whispered
12
+ * "press T to type" hint — typing exists, but there's no visible composer yet.
13
+ * - **Level 2+ (the dock)** — mute/captions shrink to compact minis and the in-call text
14
+ * input docks beside them (one bottom bar, per Redesign A's fused composer+controls).
15
+ * Submit calls {@link RealtimeSessionService.SendText}, which injects the text as a user
16
+ * turn into the SAME live voice call.
17
+ *
18
+ * Mute talks to the session service directly (pure local toggle); captions / Details /
19
+ * End are emitted up so the overlay shell owns that state and lifecycle.
20
+ */
21
+ export declare class RealtimeComposerComponent {
22
+ /**
23
+ * Whether the typed-input dock is OPEN. A two-way door owned by the user: the strip's
24
+ * Type control (or the T hotkey) opens it; the dock's hide control closes it — typing
25
+ * never becomes permanent chrome. Default closed (voice-first), reset per session.
26
+ */
27
+ Open: boolean;
28
+ /** Emitted when the user opens (Type control / typing) or closes (hide control) the dock. */
29
+ OpenChanged: EventEmitter<boolean>;
30
+ /** Whether captions are currently shown (drives the captions control's active state). */
31
+ CaptionsOn: boolean;
32
+ /** Whether the Details peek control renders (true until the surface panel is earned). */
33
+ ShowDetails: boolean;
34
+ /** Whether the Details peek is currently open (active state on the control). */
35
+ DetailsOn: boolean;
36
+ /** Emitted when the user toggles captions; the overlay flips its caption state. */
37
+ CaptionsToggled: EventEmitter<boolean>;
38
+ /** Emitted when the user toggles the Details peek (the on-demand surface panel). */
39
+ DetailsToggled: EventEmitter<void>;
40
+ /** Emitted when the user ends the call from the strip's End control. */
41
+ EndRequested: EventEmitter<void>;
42
+ /** Current draft text in the dock's composer input. */
43
+ Draft: string;
44
+ /** Local mic mute state, reflected from the service. */
45
+ IsMuted: boolean;
46
+ private dockInput?;
47
+ private voice;
48
+ /** True when there's non-whitespace text to send. */
49
+ get CanSend(): boolean;
50
+ /** True while the big-controls phone-call strip renders (instead of the dock). */
51
+ get StripMode(): boolean;
52
+ /** Toggle the local microphone mute. */
53
+ ToggleMute(): void;
54
+ /** Toggle captions visibility and notify the overlay. */
55
+ ToggleCaptions(): void;
56
+ /** Focuses the dock's text input (the overlay's T-to-type hotkey lands here). */
57
+ FocusInput(): void;
58
+ /** Send the typed text into the live session, then clear the input. */
59
+ Send(): void;
60
+ /** Enter sends (Shift+Enter is free for future multiline if the input becomes a textarea). */
61
+ OnKeydown(event: KeyboardEvent): void;
62
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeComposerComponent, never>;
63
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeComposerComponent, "mj-realtime-composer", never, { "Open": { "alias": "Open"; "required": false; }; "CaptionsOn": { "alias": "CaptionsOn"; "required": false; }; "ShowDetails": { "alias": "ShowDetails"; "required": false; }; "DetailsOn": { "alias": "DetailsOn"; "required": false; }; }, { "OpenChanged": "OpenChanged"; "CaptionsToggled": "CaptionsToggled"; "DetailsToggled": "DetailsToggled"; "EndRequested": "EndRequested"; }, never, never, true, never>;
64
+ }
65
+ //# sourceMappingURL=realtime-composer.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-composer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAoC,MAAM,eAAe,CAAC;;AAKtG;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAOa,yBAAyB;IACpC;;;;OAIG;IACM,IAAI,UAAS;IAEtB,6FAA6F;IACnF,WAAW,wBAA+B;IAEpD,yFAAyF;IAChF,UAAU,UAAQ;IAE3B,yFAAyF;IAChF,WAAW,UAAS;IAE7B,gFAAgF;IACvE,SAAS,UAAS;IAE3B,mFAAmF;IACzE,eAAe,wBAA+B;IAExD,oFAAoF;IAC1E,cAAc,qBAA4B;IAEpD,wEAAwE;IAC9D,YAAY,qBAA4B;IAElD,uDAAuD;IAChD,KAAK,SAAM;IAElB,wDAAwD;IACjD,OAAO,UAAS;IAEC,OAAO,CAAC,SAAS,CAAC,CAA+B;IAEzE,OAAO,CAAC,KAAK,CAAkC;IAE/C,qDAAqD;IACrD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,kFAAkF;IAClF,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,wCAAwC;IACjC,UAAU,IAAI,IAAI;IAIzB,yDAAyD;IAClD,cAAc,IAAI,IAAI;IAK7B,iFAAiF;IAC1E,UAAU,IAAI,IAAI;IAIzB,uEAAuE;IAChE,IAAI,IAAI,IAAI;IAQnB,8FAA8F;IACvF,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;yCA3EjC,yBAAyB;2CAAzB,yBAAyB;CAiFrC"}