@memberjunction/ng-conversations 6.1.4 → 6.2.0-edge.1

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 (424) hide show
  1. package/README.md +36 -3
  2. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +19 -3
  3. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
  4. package/dist/lib/components/active-tasks/active-tasks-panel.component.js +39 -7
  5. package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
  6. package/dist/lib/components/agent/active-agent-indicator.component.d.ts +74 -6
  7. package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -1
  8. package/dist/lib/components/agent/active-agent-indicator.component.js +111 -21
  9. package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -1
  10. package/dist/lib/components/agent/agent-process-panel.component.d.ts +31 -5
  11. package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
  12. package/dist/lib/components/agent/agent-process-panel.component.js +71 -15
  13. package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
  14. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +65 -9
  15. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
  16. package/dist/lib/components/artifact/artifact-share-modal.component.js +169 -57
  17. package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
  18. package/dist/lib/components/attachment/image-viewer.component.d.ts +77 -11
  19. package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
  20. package/dist/lib/components/attachment/image-viewer.component.js +181 -47
  21. package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
  22. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +129 -19
  23. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  24. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +350 -116
  25. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  26. package/dist/lib/components/collection/artifact-create-modal.component.d.ts +60 -8
  27. package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
  28. package/dist/lib/components/collection/artifact-create-modal.component.js +130 -46
  29. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  30. package/dist/lib/components/collection/collection-artifact-card.component.d.ts +63 -3
  31. package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
  32. package/dist/lib/components/collection/collection-artifact-card.component.js +113 -19
  33. package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
  34. package/dist/lib/components/collection/collection-form-modal.component.d.ts +54 -8
  35. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  36. package/dist/lib/components/collection/collection-form-modal.component.js +130 -46
  37. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  38. package/dist/lib/components/collection/collection-share-modal.component.d.ts +70 -10
  39. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  40. package/dist/lib/components/collection/collection-share-modal.component.js +175 -53
  41. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  42. package/dist/lib/components/collection/collection-tree.component.d.ts +89 -9
  43. package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
  44. package/dist/lib/components/collection/collection-tree.component.js +220 -70
  45. package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
  46. package/dist/lib/components/collection/collection-view.component.d.ts +89 -11
  47. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  48. package/dist/lib/components/collection/collection-view.component.js +154 -40
  49. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  50. package/dist/lib/components/collection/collections-full-view.component.d.ts +390 -38
  51. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  52. package/dist/lib/components/collection/collections-full-view.component.js +951 -367
  53. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  54. package/dist/lib/components/composer/ai-composer.component.d.ts +213 -18
  55. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
  56. package/dist/lib/components/composer/ai-composer.component.js +388 -44
  57. package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
  58. package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +12 -1
  59. package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts.map +1 -1
  60. package/dist/lib/components/conversation/conversation-agent-picker.component.js +26 -4
  61. package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
  62. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +1090 -123
  63. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  64. package/dist/lib/components/conversation/conversation-chat-area.component.js +2407 -731
  65. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  66. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +139 -19
  67. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
  68. package/dist/lib/components/conversation/conversation-empty-state.component.js +296 -59
  69. package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
  70. package/dist/lib/components/conversation/conversation-list.component.d.ts +579 -78
  71. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  72. package/dist/lib/components/conversation/conversation-list.component.js +2322 -823
  73. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  74. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +40 -4
  75. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
  76. package/dist/lib/components/conversation/pinned-messages-panel.component.js +72 -14
  77. package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
  78. package/dist/lib/components/dialogs/input-dialog.component.d.ts +57 -11
  79. package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -1
  80. package/dist/lib/components/dialogs/input-dialog.component.js +128 -16
  81. package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -1
  82. package/dist/lib/components/dialogs/rating-dialog.component.d.ts +68 -10
  83. package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -1
  84. package/dist/lib/components/dialogs/rating-dialog.component.js +151 -27
  85. package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -1
  86. package/dist/lib/components/export/export-modal.component.d.ts +84 -10
  87. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  88. package/dist/lib/components/export/export-modal.component.js +173 -49
  89. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  90. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +29 -3
  91. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -1
  92. package/dist/lib/components/global-tasks/global-tasks-panel.component.js +58 -12
  93. package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -1
  94. package/dist/lib/components/library/library-full-view.component.d.ts +57 -8
  95. package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
  96. package/dist/lib/components/library/library-full-view.component.js +119 -35
  97. package/dist/lib/components/library/library-full-view.component.js.map +1 -1
  98. package/dist/lib/components/members/members-modal.component.d.ts +76 -10
  99. package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
  100. package/dist/lib/components/members/members-modal.component.js +164 -50
  101. package/dist/lib/components/members/members-modal.component.js.map +1 -1
  102. package/dist/lib/components/message/actionable-commands.component.d.ts +37 -5
  103. package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
  104. package/dist/lib/components/message/actionable-commands.component.js +82 -16
  105. package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
  106. package/dist/lib/components/message/conversation-message-rating.component.d.ts +46 -10
  107. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  108. package/dist/lib/components/message/conversation-message-rating.component.js +120 -36
  109. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  110. package/dist/lib/components/message/message-input.component.d.ts +549 -74
  111. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  112. package/dist/lib/components/message/message-input.component.js +1250 -421
  113. package/dist/lib/components/message/message-input.component.js.map +1 -1
  114. package/dist/lib/components/message/message-item.component.d.ts +411 -29
  115. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  116. package/dist/lib/components/message/message-item.component.js +896 -222
  117. package/dist/lib/components/message/message-item.component.js.map +1 -1
  118. package/dist/lib/components/message/message-list.component.d.ts +288 -29
  119. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  120. package/dist/lib/components/message/message-list.component.js +561 -123
  121. package/dist/lib/components/message/message-list.component.js.map +1 -1
  122. package/dist/lib/components/navigation/conversation-navigation.component.d.ts +64 -5
  123. package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
  124. package/dist/lib/components/navigation/conversation-navigation.component.js +101 -11
  125. package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
  126. package/dist/lib/components/notification/activity-indicator.component.d.ts +6 -2
  127. package/dist/lib/components/notification/activity-indicator.component.d.ts.map +1 -1
  128. package/dist/lib/components/notification/activity-indicator.component.js +13 -3
  129. package/dist/lib/components/notification/activity-indicator.component.js.map +1 -1
  130. package/dist/lib/components/notification/notification-badge.component.d.ts +15 -3
  131. package/dist/lib/components/notification/notification-badge.component.d.ts.map +1 -1
  132. package/dist/lib/components/notification/notification-badge.component.js +36 -8
  133. package/dist/lib/components/notification/notification-badge.component.js.map +1 -1
  134. package/dist/lib/components/overlay/chat-overlay.component.d.ts +1 -1
  135. package/dist/lib/components/overlay/chat-overlay.component.js +4 -4
  136. package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
  137. package/dist/lib/components/project/project-form-modal.component.d.ts +93 -11
  138. package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
  139. package/dist/lib/components/project/project-form-modal.component.js +348 -87
  140. package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
  141. package/dist/lib/components/project/project-selector.component.d.ts +78 -8
  142. package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
  143. package/dist/lib/components/project/project-selector.component.js +177 -46
  144. package/dist/lib/components/project/project-selector.component.js.map +1 -1
  145. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +1 -1
  146. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -1
  147. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -1
  148. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +1 -1
  149. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  150. package/dist/lib/components/realtime/channels/client-context-channel.js +1 -1
  151. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  152. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +1 -1
  153. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  154. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +3 -0
  155. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  156. package/dist/lib/components/realtime/media/media-channel.d.ts +2 -1
  157. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  158. package/dist/lib/components/realtime/media/media-channel.js +1 -1
  159. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  160. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +2 -2
  161. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
  162. package/dist/lib/components/realtime/realtime-activity-rail.component.js +2 -2
  163. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
  164. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +1 -1
  165. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  166. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  167. package/dist/lib/components/realtime/realtime-composer.component.d.ts +3 -1
  168. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  169. package/dist/lib/components/realtime/realtime-composer.component.js +26 -8
  170. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  171. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +2 -2
  172. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
  173. package/dist/lib/components/realtime/realtime-delegation-card.component.js +2 -2
  174. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
  175. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +4 -4
  176. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  177. package/dist/lib/components/realtime/realtime-session-overlay.component.js +19 -19
  178. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  179. package/dist/lib/components/realtime/realtime-session-state.d.ts +2 -3
  180. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
  181. package/dist/lib/components/realtime/realtime-session-state.js +3 -2
  182. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
  183. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +17 -1
  184. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -1
  185. package/dist/lib/components/realtime/realtime-session-thread.component.js +122 -45
  186. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -1
  187. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +47 -31
  188. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
  189. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +138 -124
  190. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
  191. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +4 -4
  192. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  193. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +4 -4
  194. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  195. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +2 -2
  196. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  197. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +3 -3
  198. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  199. package/dist/lib/components/realtime/realtime-ui-config.d.ts +13 -11
  200. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  201. package/dist/lib/components/realtime/realtime-ui-config.js +29 -25
  202. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  203. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +1 -1
  204. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  205. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +1 -1
  206. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  207. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +4 -2
  208. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  209. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +7 -3
  210. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  211. package/dist/lib/components/search/search-panel.component.d.ts +133 -22
  212. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  213. package/dist/lib/components/search/search-panel.component.js +312 -83
  214. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  215. package/dist/lib/components/share/share-modal.component.d.ts +69 -9
  216. package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
  217. package/dist/lib/components/share/share-modal.component.js +139 -31
  218. package/dist/lib/components/share/share-modal.component.js.map +1 -1
  219. package/dist/lib/components/shared/user-picker.component.d.ts +48 -8
  220. package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
  221. package/dist/lib/components/shared/user-picker.component.js +110 -30
  222. package/dist/lib/components/shared/user-picker.component.js.map +1 -1
  223. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +114 -11
  224. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
  225. package/dist/lib/components/sidebar/conversation-sidebar.component.js +199 -21
  226. package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
  227. package/dist/lib/components/sidebar/routines-section.component.d.ts +20 -1
  228. package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -1
  229. package/dist/lib/components/sidebar/routines-section.component.js +25 -5
  230. package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
  231. package/dist/lib/components/slots/slot-interfaces.d.ts +19 -0
  232. package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -1
  233. package/dist/lib/components/slots/slot-interfaces.js.map +1 -1
  234. package/dist/lib/components/task/tasks-full-view.component.d.ts +95 -13
  235. package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
  236. package/dist/lib/components/task/tasks-full-view.component.js +223 -75
  237. package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
  238. package/dist/lib/components/tasks/task-widget.component.d.ts +46 -6
  239. package/dist/lib/components/tasks/task-widget.component.d.ts.map +1 -1
  240. package/dist/lib/components/tasks/task-widget.component.js +100 -16
  241. package/dist/lib/components/tasks/task-widget.component.js.map +1 -1
  242. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +64 -7
  243. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
  244. package/dist/lib/components/tasks/tasks-dropdown.component.js +127 -27
  245. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  246. package/dist/lib/components/thread/thread-panel.component.d.ts +66 -8
  247. package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -1
  248. package/dist/lib/components/thread/thread-panel.component.js +146 -36
  249. package/dist/lib/components/thread/thread-panel.component.js.map +1 -1
  250. package/dist/lib/components/toast/toast.component.d.ts +11 -1
  251. package/dist/lib/components/toast/toast.component.d.ts.map +1 -1
  252. package/dist/lib/components/toast/toast.component.js +25 -5
  253. package/dist/lib/components/toast/toast.component.js.map +1 -1
  254. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +385 -42
  255. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  256. package/dist/lib/components/workspace/conversation-workspace.component.js +887 -291
  257. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  258. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +8 -0
  259. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -1
  260. package/dist/lib/composer-plugins/base-conversation-mention.provider.js +8 -1
  261. package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -1
  262. package/dist/lib/conversations.module.d.ts.map +1 -1
  263. package/dist/lib/conversations.module.js.map +1 -1
  264. package/dist/lib/directives/chat-slot.directive.d.ts +5 -1
  265. package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -1
  266. package/dist/lib/directives/chat-slot.directive.js.map +1 -1
  267. package/dist/lib/directives/search-shortcut.directive.d.ts +9 -1
  268. package/dist/lib/directives/search-shortcut.directive.d.ts.map +1 -1
  269. package/dist/lib/directives/search-shortcut.directive.js +14 -4
  270. package/dist/lib/directives/search-shortcut.directive.js.map +1 -1
  271. package/dist/lib/events/chat-events.d.ts +34 -7
  272. package/dist/lib/events/chat-events.d.ts.map +1 -1
  273. package/dist/lib/events/chat-events.js +37 -7
  274. package/dist/lib/events/chat-events.js.map +1 -1
  275. package/dist/lib/models/agent-turn.model.d.ts +103 -0
  276. package/dist/lib/models/agent-turn.model.d.ts.map +1 -0
  277. package/dist/lib/models/agent-turn.model.js +12 -0
  278. package/dist/lib/models/agent-turn.model.js.map +1 -0
  279. package/dist/lib/models/collection-view.model.js.map +1 -1
  280. package/dist/lib/models/conversation-state.model.d.ts +8 -0
  281. package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
  282. package/dist/lib/models/conversation-state.model.js.map +1 -1
  283. package/dist/lib/models/lazy-artifact-info.d.ts +44 -12
  284. package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
  285. package/dist/lib/models/lazy-artifact-info.js +98 -34
  286. package/dist/lib/models/lazy-artifact-info.js.map +1 -1
  287. package/dist/lib/services/active-tasks.service.d.ts +30 -4
  288. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  289. package/dist/lib/services/active-tasks.service.js +71 -19
  290. package/dist/lib/services/active-tasks.service.js.map +1 -1
  291. package/dist/lib/services/agent-state.service.d.ts +17 -1
  292. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  293. package/dist/lib/services/agent-state.service.js +48 -16
  294. package/dist/lib/services/agent-state.service.js.map +1 -1
  295. package/dist/lib/services/artifact-permission.service.d.ts +39 -0
  296. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  297. package/dist/lib/services/artifact-permission.service.js +152 -17
  298. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  299. package/dist/lib/services/artifact-state.service.d.ts +58 -5
  300. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  301. package/dist/lib/services/artifact-state.service.js +135 -35
  302. package/dist/lib/services/artifact-state.service.js.map +1 -1
  303. package/dist/lib/services/browser-realtime-media-host.d.ts +24 -0
  304. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -0
  305. package/dist/lib/services/browser-realtime-media-host.js +95 -0
  306. package/dist/lib/services/browser-realtime-media-host.js.map +1 -0
  307. package/dist/lib/services/collection-permission.service.d.ts +28 -0
  308. package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
  309. package/dist/lib/services/collection-permission.service.js +88 -32
  310. package/dist/lib/services/collection-permission.service.js.map +1 -1
  311. package/dist/lib/services/collection-state.service.d.ts +11 -1
  312. package/dist/lib/services/collection-state.service.d.ts.map +1 -1
  313. package/dist/lib/services/collection-state.service.js +25 -5
  314. package/dist/lib/services/collection-state.service.js.map +1 -1
  315. package/dist/lib/services/conversation-agent.service.d.ts +26 -4
  316. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  317. package/dist/lib/services/conversation-agent.service.js +57 -18
  318. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  319. package/dist/lib/services/conversation-attachment.service.d.ts +41 -2
  320. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  321. package/dist/lib/services/conversation-attachment.service.js +80 -13
  322. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  323. package/dist/lib/services/conversation-streaming.service.d.ts +22 -0
  324. package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
  325. package/dist/lib/services/conversation-streaming.service.js +50 -10
  326. package/dist/lib/services/conversation-streaming.service.js.map +1 -1
  327. package/dist/lib/services/data-cache.service.d.ts +31 -0
  328. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  329. package/dist/lib/services/data-cache.service.js +71 -15
  330. package/dist/lib/services/data-cache.service.js.map +1 -1
  331. package/dist/lib/services/dialog.service.d.ts +13 -0
  332. package/dist/lib/services/dialog.service.d.ts.map +1 -1
  333. package/dist/lib/services/dialog.service.js +25 -5
  334. package/dist/lib/services/dialog.service.js.map +1 -1
  335. package/dist/lib/services/export.service.d.ts +2 -0
  336. package/dist/lib/services/export.service.d.ts.map +1 -1
  337. package/dist/lib/services/export.service.js +5 -1
  338. package/dist/lib/services/export.service.js.map +1 -1
  339. package/dist/lib/services/graphql-attachment-blob-store.d.ts +44 -0
  340. package/dist/lib/services/graphql-attachment-blob-store.d.ts.map +1 -0
  341. package/dist/lib/services/graphql-attachment-blob-store.js +113 -0
  342. package/dist/lib/services/graphql-attachment-blob-store.js.map +1 -0
  343. package/dist/lib/services/mention-autocomplete.service.d.ts +17 -141
  344. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  345. package/dist/lib/services/mention-autocomplete.service.js +15 -460
  346. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  347. package/dist/lib/services/mention-parser.service.d.ts +10 -0
  348. package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
  349. package/dist/lib/services/mention-parser.service.js +25 -5
  350. package/dist/lib/services/mention-parser.service.js.map +1 -1
  351. package/dist/lib/services/notification.service.d.ts +54 -6
  352. package/dist/lib/services/notification.service.d.ts.map +1 -1
  353. package/dist/lib/services/notification.service.js +123 -27
  354. package/dist/lib/services/notification.service.js.map +1 -1
  355. package/dist/lib/services/realtime-audio-recorder.d.ts +4 -4
  356. package/dist/lib/services/realtime-audio-recorder.js +12 -12
  357. package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
  358. package/dist/lib/services/realtime-pcm-wav.d.ts +4 -0
  359. package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -1
  360. package/dist/lib/services/realtime-pcm-wav.js +10 -2
  361. package/dist/lib/services/realtime-pcm-wav.js.map +1 -1
  362. package/dist/lib/services/realtime-session-review.service.d.ts +1 -1
  363. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  364. package/dist/lib/services/realtime-session-review.service.js +1 -1
  365. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  366. package/dist/lib/services/realtime-session.service.d.ts +16 -1150
  367. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  368. package/dist/lib/services/realtime-session.service.js +28 -2430
  369. package/dist/lib/services/realtime-session.service.js.map +1 -1
  370. package/dist/lib/services/search.service.d.ts +42 -9
  371. package/dist/lib/services/search.service.d.ts.map +1 -1
  372. package/dist/lib/services/search.service.js +103 -23
  373. package/dist/lib/services/search.service.js.map +1 -1
  374. package/dist/lib/services/toast.service.d.ts +19 -1
  375. package/dist/lib/services/toast.service.d.ts.map +1 -1
  376. package/dist/lib/services/toast.service.js +45 -9
  377. package/dist/lib/services/toast.service.js.map +1 -1
  378. package/dist/lib/services/ui-command-handler.service.d.ts +16 -2
  379. package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
  380. package/dist/lib/services/ui-command-handler.service.js +36 -8
  381. package/dist/lib/services/ui-command-handler.service.js.map +1 -1
  382. package/dist/lib/utils/agent-artifact-summary.d.ts +2 -2
  383. package/dist/lib/utils/agent-artifact-summary.js +3 -3
  384. package/dist/lib/utils/agent-artifact-summary.js.map +1 -1
  385. package/dist/lib/utils/agent-turn-routing.d.ts +69 -0
  386. package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -0
  387. package/dist/lib/utils/agent-turn-routing.js +96 -0
  388. package/dist/lib/utils/agent-turn-routing.js.map +1 -0
  389. package/dist/lib/utils/artifact-panel-action.d.ts +15 -4
  390. package/dist/lib/utils/artifact-panel-action.d.ts.map +1 -1
  391. package/dist/lib/utils/artifact-panel-action.js +10 -2
  392. package/dist/lib/utils/artifact-panel-action.js.map +1 -1
  393. package/dist/lib/utils/distinct-artifacts.d.ts +2 -0
  394. package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
  395. package/dist/lib/utils/distinct-artifacts.js +5 -1
  396. package/dist/lib/utils/distinct-artifacts.js.map +1 -1
  397. package/dist/lib/utils/plan-mode-preference.d.ts +2 -2
  398. package/dist/lib/utils/plan-mode-preference.js +6 -6
  399. package/dist/lib/utils/plan-mode-preference.js.map +1 -1
  400. package/dist/lib/utils/realtime-session-timeline.d.ts +8 -79
  401. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -1
  402. package/dist/lib/utils/realtime-session-timeline.js +8 -89
  403. package/dist/lib/utils/realtime-session-timeline.js.map +1 -1
  404. package/dist/public-api.d.ts +5 -2
  405. package/dist/public-api.d.ts.map +1 -1
  406. package/dist/public-api.js +9 -2
  407. package/dist/public-api.js.map +1 -1
  408. package/package.json +33 -32
  409. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +0 -384
  410. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +0 -1
  411. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +0 -231
  412. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +0 -1
  413. package/dist/lib/services/delegation-result-parser.d.ts +0 -50
  414. package/dist/lib/services/delegation-result-parser.d.ts.map +0 -1
  415. package/dist/lib/services/delegation-result-parser.js +0 -60
  416. package/dist/lib/services/delegation-result-parser.js.map +0 -1
  417. package/dist/lib/services/narration-template.d.ts +0 -42
  418. package/dist/lib/services/narration-template.d.ts.map +0 -1
  419. package/dist/lib/services/narration-template.js +0 -73
  420. package/dist/lib/services/narration-template.js.map +0 -1
  421. package/dist/lib/services/skill-picker-narrowing.d.ts +0 -13
  422. package/dist/lib/services/skill-picker-narrowing.d.ts.map +0 -1
  423. package/dist/lib/services/skill-picker-narrowing.js +0 -13
  424. package/dist/lib/services/skill-picker-narrowing.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-audio-recorder.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-audio-recorder.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodePcm16Wav, PeakAccumulator } from './realtime-pcm-wav';\n\n/**\n * Browser-side audio recorder for a CLIENT-DIRECT realtime voice session.\n *\n * Mixes the user's microphone stream with the agent's remote-audio stream (when the driver\n * exposes one — `OpenAIRealtimeClient.GetRemoteMediaStream()`) into a single mono **WAV** (16-bit\n * PCM) blob via the Web Audio API. Rather than a `MediaRecorder` (which only emits webm/opus —\n * header-less, no duration/cues, so HTTP-range seeking is unreliable), the mix is routed into an\n * {@link AudioWorkletNode} (preferred) or a {@link ScriptProcessorNode} (fallback) that captures\n * Float32 PCM frames. PCM is accumulated in memory and encoded as a seekable RIFF/WAVE file at\n * {@link Stop}. WAV's header carries the exact duration and maps byte-offset → time linearly, so\n * range seeking is exact and waveform peaks are computed cheaply during capture. The tradeoff is\n * size (PCM WAV is larger than opus) — acceptable for these short session recordings.\n *\n * Robust + MVP by design — every step degrades gracefully:\n * - No `AudioContext` (server-side render / unsupported env) → the recorder disables itself\n * ({@link IsRecording} stays `false`, {@link Stop} resolves `null`); the voice call proceeds.\n * - No `AudioWorkletNode` AND no `ScriptProcessorNode` → disables itself rather than throwing.\n * - No remote stream (non-WebRTC drivers, or the track hasn't landed yet) → records mic only.\n * - Any construction/start error is logged and disables the recorder rather than throwing into\n * the session-start path.\n *\n * Not an Angular service: it owns transient per-session media plumbing the\n * {@link RealtimeSessionService} creates and discards per call, so a plain class is the right\n * shape (no DI, no singleton).\n */\nexport class RealtimeAudioRecorder {\n /** The container/codec we now produce — a seekable mono 16-bit PCM WAV. */\n private static readonly WavMimeType = 'audio/wav';\n /** Target waveform-peak resolution (buckets) across the whole recording. */\n private static readonly PeakBuckets = 600;\n /** PCM frame size for the ScriptProcessor fallback (worklet uses its native 128-frame quantum). */\n private static readonly ScriptProcessorBufferSize = 4096;\n /** Inline AudioWorklet processor: forwards each 128-frame mono input block to the main thread. */\n private static readonly WorkletProcessorSource = `\n class MJPcmCaptureProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0] && input[0].length > 0) {\n // Copy out of the reused worklet buffer before posting.\n this.port.postMessage(input[0].slice(0));\n }\n return true;\n }\n }\n registerProcessor('mj-pcm-capture', MJPcmCaptureProcessor);\n `;\n\n private audioContext: AudioContext | null = null;\n private destination: MediaStreamAudioDestinationNode | null = null;\n private workletNode: AudioWorkletNode | null = null;\n private scriptNode: ScriptProcessorNode | null = null;\n /** Captured mono Float32 PCM frames (in capture order); concatenated + encoded to WAV at Stop. */\n private pcmFrames: Float32Array[] = [];\n /** Total captured sample count across {@link pcmFrames} (kept in step to avoid re-summing). */\n private totalSamples = 0;\n /** Streaming waveform-peak accumulator — bounded regardless of recording length. */\n private peaks = new PeakAccumulator(RealtimeAudioRecorder.PeakBuckets);\n /** Final normalized peaks, snapshotted at {@link Stop} so {@link GetPeaks} survives cleanup. */\n private finalPeaks: number[] = [];\n private recording = false;\n\n /** True once the agent's remote stream has been wired into the mix (prevents double-attach). */\n private remoteAttached = false;\n /** A remote stream handed to AttachRemoteStream before the audio graph was ready; wired at setup. */\n private pendingRemoteStream: MediaStream | null = null;\n\n /** Sample index up to which crash-recovery shards have already been emitted (the segment cursor). */\n private flushedSampleCount = 0;\n\n /** Wall-clock ms at recording start; anchors {@link NowOffsetMs}. 0 before {@link Start}. */\n private startedAtMs = 0;\n\n /** Sample rate of the capturing {@link AudioContext}; 0 before {@link Start}. Needed to wrap shards. */\n private sampleRate = 0;\n\n /** True while a recorder is actively capturing. */\n public get IsRecording(): boolean {\n return this.recording;\n }\n\n /** Wall-clock ms when recording started (0 before {@link Start}). */\n public get StartedAtMs(): number {\n return this.startedAtMs;\n }\n\n /**\n * The container/codec the active recording uses. Always `'audio/wav'` once recording (empty\n * string before {@link Start} / when disabled) — the consolidated upload and the WAV-wrapped\n * crash-recovery shards are all 16-bit PCM WAV.\n */\n public get MimeType(): string {\n return this.recording ? RealtimeAudioRecorder.WavMimeType : '';\n }\n\n /**\n * The captured AudioContext sample rate (0 before {@link Start} / when disabled). Exposed so a\n * recovery path can WAV-wrap the raw-PCM shards with the correct rate.\n */\n public get SampleRate(): number {\n return this.sampleRate;\n }\n\n /**\n * Begins recording a mix of `micStream` and (when present) `remoteStream`. Best-effort:\n * a missing `AudioContext` / no worklet+scriptprocessor support / any setup failure disables\n * the recorder silently (logged) so the live call is never blocked.\n *\n * @param micStream The user's microphone capture stream (required).\n * @param remoteStream The agent's remote-audio stream, or `null` for mic-only capture.\n */\n public Start(micStream: MediaStream, remoteStream: MediaStream | null): void {\n if (this.recording) {\n return;\n }\n if (typeof AudioContext === 'undefined') {\n console.warn('[RealtimeAudioRecorder] AudioContext unavailable — recording disabled for this session.');\n return;\n }\n // Mark recording + stamp t0 SYNCHRONOUSLY so a caller that checks IsRecording immediately after\n // Start() (the session service does) sees `true`, even though the audio-graph setup\n // (AudioContext.resume + worklet module load) completes asynchronously below. Without this the\n // caller discards the recorder before it finishes starting and nothing is ever uploaded.\n this.startedAtMs = Date.now();\n this.finalPeaks = [];\n this.recording = true;\n // Fire-and-forget the async setup (it must `await audioContext.resume()` + worklet load); any\n // failure disables the recorder rather than throwing into the session-start path.\n void this.startMixedRecording(micStream, remoteStream).catch((error) => {\n console.warn('[RealtimeAudioRecorder] Failed to start recording — disabling for this session:', error);\n this.cleanup();\n });\n }\n\n /**\n * Wires the agent's remote-audio stream into the live mix once it arrives. The WebRTC\n * `ontrack` that delivers the agent voice usually lands AFTER recording has already begun\n * (mic-only), so the session attaches it here when it lands. Idempotent, and safe to call\n * before the audio graph finishes its async setup (the stream is connected once ready).\n */\n public AttachRemoteStream(stream: MediaStream): void {\n if (this.remoteAttached || stream.getAudioTracks().length === 0) {\n return;\n }\n if (this.audioContext && this.captureNode()) {\n this.connectStream(this.audioContext, stream);\n this.remoteAttached = true;\n } else {\n // Audio-graph setup still in flight (awaiting resume / worklet load) — connect at setup.\n this.pendingRemoteStream = stream;\n }\n }\n\n /**\n * Returns a Blob of the raw PCM captured since the last call (a window of header-less,\n * little-endian PCM16 bytes), advancing the segment cursor. `null` when nothing new. Used to\n * upload crash-recovery shards mid-call. NOTE: shards are header-less raw PCM (NOT individually\n * playable WAV) — recovery is concatenation in order, then WAV-wrapping with {@link SampleRate}.\n * The canonical consolidated file is still authored as a single WAV from full memory at {@link Stop}.\n */\n public SnapshotNewSegment(): Blob | null {\n if (!this.recording || this.flushedSampleCount >= this.totalSamples) {\n return null;\n }\n const fresh = this.collectSamples(this.flushedSampleCount, this.totalSamples);\n this.flushedSampleCount = this.totalSamples;\n if (fresh.length === 0) {\n return null;\n }\n const pcm16 = this.floatToPcm16Bytes(fresh);\n return new Blob([pcm16], { type: 'application/octet-stream' });\n }\n\n /** Ms elapsed since recording started (>= 0); 0 when not recording. */\n public NowOffsetMs(): number {\n if (this.startedAtMs === 0) {\n return 0;\n }\n return Math.max(0, Date.now() - this.startedAtMs);\n }\n\n /**\n * The downsampled waveform peaks (each 0..1, max-abs per bucket, ~{@link RealtimeAudioRecorder.PeakBuckets}\n * buckets across the whole recording). Computed incrementally during capture so it's cheap and\n * bounded regardless of length. Returns `[]` before any audio / for a silent recording. Safe to\n * call after {@link Stop} — the peaks are snapshotted there before {@link cleanup} clears state.\n */\n public GetPeaks(): number[] {\n return this.recording ? this.peaks.Normalize() : this.finalPeaks;\n }\n\n /**\n * Stops recording and resolves the captured audio as a single mono 16-bit PCM **WAV**\n * {@link Blob}, then releases the audio graph. Resolves `null` when nothing was recorded\n * (recorder disabled, or no samples captured). Safe to call when not recording.\n */\n public async Stop(): Promise<Blob | null> {\n if (!this.recording) {\n this.cleanup();\n return null;\n }\n // Detach the capture node so no further frames arrive while we assemble the file. Snapshot the\n // peaks BEFORE cleanup so GetPeaks() still returns them for the post-Stop upload.\n this.recording = false;\n this.finalPeaks = this.peaks.Normalize();\n const blob = this.encodeWavBlob();\n this.cleanup();\n return blob;\n }\n\n /** Wires up the Web Audio mix graph + PCM capture node (worklet preferred) and starts capture. */\n private async startMixedRecording(micStream: MediaStream, remoteStream: MediaStream | null): Promise<void> {\n const audioContext = new AudioContext();\n // CRITICAL: browsers create an AudioContext in the `suspended` state under the autoplay policy.\n // Without resuming it, the mix graph never processes audio and we capture only silence. Starting\n // a voice call is a user gesture, so resume() succeeds here.\n if (audioContext.state === 'suspended') {\n await audioContext.resume();\n }\n const destination = audioContext.createMediaStreamDestination();\n // Publish the context + sample rate BEFORE wiring the remote so a concurrent AttachRemoteStream()\n // (the agent track can land during the awaits above) sees a ready graph to connect to.\n this.audioContext = audioContext;\n this.destination = destination;\n this.sampleRate = audioContext.sampleRate;\n\n // Build the PCM capture node: AudioWorklet preferred, ScriptProcessor fallback. Either way the\n // node both pulls audio from the mix AND drives the destination so the graph keeps processing.\n await this.createCaptureNode(audioContext, destination);\n\n this.connectStream(audioContext, micStream);\n // Connect the agent's stream if it was passed now, or if AttachRemoteStream() stashed one while\n // we were setting up. Either way, capture the agent voice — not just the mic.\n const remote = remoteStream ?? this.pendingRemoteStream;\n this.pendingRemoteStream = null;\n if (remote && remote.getAudioTracks().length > 0) {\n this.connectStream(audioContext, remote);\n this.remoteAttached = true;\n }\n }\n\n /**\n * Creates the PCM capture node and inserts it into the graph: sources → captureNode → destination.\n * Prefers an {@link AudioWorkletNode} (off-main-thread, no deprecation); falls back to a\n * {@link ScriptProcessorNode} where worklets are unavailable. Throws when neither is supported\n * (caught by {@link Start}, which then disables the recorder).\n */\n private async createCaptureNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): Promise<void> {\n if (await this.tryCreateWorkletNode(audioContext, destination)) {\n return;\n }\n this.createScriptProcessorNode(audioContext, destination);\n }\n\n /** Attempts to build the AudioWorklet capture node; returns `false` (no throw) when unsupported. */\n private async tryCreateWorkletNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): Promise<boolean> {\n if (!audioContext.audioWorklet || typeof AudioWorkletNode === 'undefined' || typeof Blob === 'undefined') {\n return false;\n }\n try {\n const moduleUrl = URL.createObjectURL(\n new Blob([RealtimeAudioRecorder.WorkletProcessorSource], { type: 'application/javascript' }),\n );\n try {\n await audioContext.audioWorklet.addModule(moduleUrl);\n } finally {\n URL.revokeObjectURL(moduleUrl);\n }\n const node = new AudioWorkletNode(audioContext, 'mj-pcm-capture', { numberOfInputs: 1, numberOfOutputs: 1 });\n node.port.onmessage = (event: MessageEvent<Float32Array>) => this.captureFrame(event.data);\n node.connect(destination);\n this.workletNode = node;\n return true;\n } catch (error) {\n console.warn('[RealtimeAudioRecorder] AudioWorklet unavailable — falling back to ScriptProcessor:', error);\n return false;\n }\n }\n\n /** Builds the ScriptProcessor fallback capture node and inserts it into the graph. */\n private createScriptProcessorNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): void {\n if (typeof audioContext.createScriptProcessor !== 'function') {\n throw new Error('Neither AudioWorklet nor ScriptProcessor is supported');\n }\n const node = audioContext.createScriptProcessor(RealtimeAudioRecorder.ScriptProcessorBufferSize, 1, 1);\n node.onaudioprocess = (event: AudioProcessingEvent) => {\n // Copy out of the reused input buffer before retaining.\n this.captureFrame(event.inputBuffer.getChannelData(0).slice(0));\n };\n // ScriptProcessor only fires onaudioprocess while connected to the destination.\n node.connect(destination);\n this.scriptNode = node;\n }\n\n /** The active capture node (worklet or script processor), or `null` before setup. */\n private captureNode(): AudioNode | null {\n return this.workletNode ?? this.scriptNode;\n }\n\n /** Absorbs one captured PCM frame: accumulate samples + update the bounded peak array. */\n private captureFrame(frame: Float32Array): void {\n if (!this.recording || frame.length === 0) {\n return;\n }\n // Defensive copy — worklet/script buffers are reused by the engine.\n const copy = frame.slice(0);\n this.pcmFrames.push(copy);\n this.totalSamples += copy.length;\n this.peaks.Push(copy);\n }\n\n /** Routes one stream's audio tracks into the capture node (no-op when track-less / no node). */\n private connectStream(audioContext: AudioContext, stream: MediaStream): void {\n const node = this.captureNode();\n if (!node || stream.getAudioTracks().length === 0) {\n return;\n }\n const source = audioContext.createMediaStreamSource(stream);\n source.connect(node);\n }\n\n /** Concatenates a half-open sample range [from, to) across the captured frames into one Float32Array. */\n private collectSamples(from: number, to: number): Float32Array {\n const out = new Float32Array(Math.max(0, to - from));\n if (out.length === 0) {\n return out;\n }\n let cursor = 0; // absolute sample index at the start of the current frame\n let written = 0;\n for (const frame of this.pcmFrames) {\n const frameStart = cursor;\n const frameEnd = cursor + frame.length;\n cursor = frameEnd;\n if (frameEnd <= from) {\n continue; // entirely before the window\n }\n if (frameStart >= to) {\n break; // entirely after the window\n }\n const sliceStart = Math.max(0, from - frameStart);\n const sliceEnd = Math.min(frame.length, to - frameStart);\n for (let i = sliceStart; i < sliceEnd; i++) {\n out[written++] = frame[i];\n }\n }\n return written === out.length ? out : out.subarray(0, written);\n }\n\n /**\n * Converts a mono Float32 buffer to a little-endian PCM16 `ArrayBuffer` (for raw crash-recovery\n * shards). Returns the backing `ArrayBuffer` directly so it's a valid `BlobPart`.\n */\n private floatToPcm16Bytes(samples: Float32Array): ArrayBuffer {\n const buffer = new ArrayBuffer(samples.length * 2);\n const view = new DataView(buffer);\n for (let i = 0; i < samples.length; i++) {\n const s = samples[i] < -1 ? -1 : samples[i] > 1 ? 1 : samples[i];\n view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true);\n }\n return buffer;\n }\n\n /** Encodes all accumulated PCM into a single seekable WAV blob, or `null` when nothing captured. */\n private encodeWavBlob(): Blob | null {\n if (this.totalSamples === 0 || this.sampleRate === 0) {\n return null;\n }\n const all = this.collectSamples(0, this.totalSamples);\n const wav = encodePcm16Wav(all, this.sampleRate);\n return new Blob([wav], { type: RealtimeAudioRecorder.WavMimeType });\n }\n\n /** Releases the audio graph + capture node and resets state. Idempotent. */\n private cleanup(): void {\n this.recording = false;\n this.pcmFrames = [];\n this.totalSamples = 0;\n this.flushedSampleCount = 0;\n this.sampleRate = 0;\n this.peaks = new PeakAccumulator(RealtimeAudioRecorder.PeakBuckets);\n this.remoteAttached = false;\n this.pendingRemoteStream = null;\n if (this.workletNode) {\n this.workletNode.port.onmessage = null;\n try { this.workletNode.disconnect(); } catch { /* already disconnected */ }\n this.workletNode = null;\n }\n if (this.scriptNode) {\n this.scriptNode.onaudioprocess = null;\n try { this.scriptNode.disconnect(); } catch { /* already disconnected */ }\n this.scriptNode = null;\n }\n this.destination = null;\n if (this.audioContext) {\n void this.audioContext.close().catch(() => { /* already closed */ });\n this.audioContext = null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"realtime-audio-recorder.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-audio-recorder.ts"],"names":[],"mappings":"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","sourcesContent":["import { EncodePcm16Wav, PeakAccumulator } from './realtime-pcm-wav';\n\n/**\n * Browser-side audio recorder for a CLIENT-DIRECT realtime voice session.\n *\n * Mixes the user's microphone stream with the agent's remote-audio stream (when the driver\n * exposes one — `OpenAIRealtimeClient.GetRemoteMediaStream()`) into a single mono **WAV** (16-bit\n * PCM) blob via the Web Audio API. Rather than a `MediaRecorder` (which only emits webm/opus —\n * header-less, no duration/cues, so HTTP-range seeking is unreliable), the mix is routed into an\n * {@link AudioWorkletNode} (preferred) or a {@link ScriptProcessorNode} (fallback) that captures\n * Float32 PCM frames. PCM is accumulated in memory and encoded as a seekable RIFF/WAVE file at\n * {@link Stop}. WAV's header carries the exact duration and maps byte-offset → time linearly, so\n * range seeking is exact and waveform peaks are computed cheaply during capture. The tradeoff is\n * size (PCM WAV is larger than opus) — acceptable for these short session recordings.\n *\n * Robust + MVP by design — every step degrades gracefully:\n * - No `AudioContext` (server-side render / unsupported env) → the recorder disables itself\n * ({@link IsRecording} stays `false`, {@link Stop} resolves `null`); the voice call proceeds.\n * - No `AudioWorkletNode` AND no `ScriptProcessorNode` → disables itself rather than throwing.\n * - No remote stream (non-WebRTC drivers, or the track hasn't landed yet) → records mic only.\n * - Any construction/start error is logged and disables the recorder rather than throwing into\n * the session-start path.\n *\n * Not an Angular service: it owns transient per-session media plumbing the\n * {@link RealtimeSessionService} creates and discards per call, so a plain class is the right\n * shape (no DI, no singleton).\n */\nexport class RealtimeAudioRecorder {\n /** The container/codec we now produce — a seekable mono 16-bit PCM WAV. */\n private static readonly wavMimeType = 'audio/wav';\n /** Target waveform-peak resolution (buckets) across the whole recording. */\n private static readonly peakBuckets = 600;\n /** PCM frame size for the ScriptProcessor fallback (worklet uses its native 128-frame quantum). */\n private static readonly scriptProcessorBufferSize = 4096;\n /** Inline AudioWorklet processor: forwards each 128-frame mono input block to the main thread. */\n private static readonly workletProcessorSource = `\n class MJPcmCaptureProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0] && input[0].length > 0) {\n // Copy out of the reused worklet buffer before posting.\n this.port.postMessage(input[0].slice(0));\n }\n return true;\n }\n }\n registerProcessor('mj-pcm-capture', MJPcmCaptureProcessor);\n `;\n\n private audioContext: AudioContext | null = null;\n private destination: MediaStreamAudioDestinationNode | null = null;\n private workletNode: AudioWorkletNode | null = null;\n private scriptNode: ScriptProcessorNode | null = null;\n /** Captured mono Float32 PCM frames (in capture order); concatenated + encoded to WAV at Stop. */\n private pcmFrames: Float32Array[] = [];\n /** Total captured sample count across {@link pcmFrames} (kept in step to avoid re-summing). */\n private totalSamples = 0;\n /** Streaming waveform-peak accumulator — bounded regardless of recording length. */\n private peaks = new PeakAccumulator(RealtimeAudioRecorder.peakBuckets);\n /** Final normalized peaks, snapshotted at {@link Stop} so {@link GetPeaks} survives cleanup. */\n private finalPeaks: number[] = [];\n private recording = false;\n\n /** True once the agent's remote stream has been wired into the mix (prevents double-attach). */\n private remoteAttached = false;\n /** A remote stream handed to AttachRemoteStream before the audio graph was ready; wired at setup. */\n private pendingRemoteStream: MediaStream | null = null;\n\n /** Sample index up to which crash-recovery shards have already been emitted (the segment cursor). */\n private flushedSampleCount = 0;\n\n /** Wall-clock ms at recording start; anchors {@link NowOffsetMs}. 0 before {@link Start}. */\n private startedAtMs = 0;\n\n /** Sample rate of the capturing {@link AudioContext}; 0 before {@link Start}. Needed to wrap shards. */\n private sampleRate = 0;\n\n /** True while a recorder is actively capturing. */\n public get IsRecording(): boolean {\n return this.recording;\n }\n\n /** Wall-clock ms when recording started (0 before {@link Start}). */\n public get StartedAtMs(): number {\n return this.startedAtMs;\n }\n\n /**\n * The container/codec the active recording uses. Always `'audio/wav'` once recording (empty\n * string before {@link Start} / when disabled) — the consolidated upload and the WAV-wrapped\n * crash-recovery shards are all 16-bit PCM WAV.\n */\n public get MimeType(): string {\n return this.recording ? RealtimeAudioRecorder.wavMimeType : '';\n }\n\n /**\n * The captured AudioContext sample rate (0 before {@link Start} / when disabled). Exposed so a\n * recovery path can WAV-wrap the raw-PCM shards with the correct rate.\n */\n public get SampleRate(): number {\n return this.sampleRate;\n }\n\n /**\n * Begins recording a mix of `micStream` and (when present) `remoteStream`. Best-effort:\n * a missing `AudioContext` / no worklet+scriptprocessor support / any setup failure disables\n * the recorder silently (logged) so the live call is never blocked.\n *\n * @param micStream The user's microphone capture stream (required).\n * @param remoteStream The agent's remote-audio stream, or `null` for mic-only capture.\n */\n public Start(micStream: MediaStream, remoteStream: MediaStream | null): void {\n if (this.recording) {\n return;\n }\n if (typeof AudioContext === 'undefined') {\n console.warn('[RealtimeAudioRecorder] AudioContext unavailable — recording disabled for this session.');\n return;\n }\n // Mark recording + stamp t0 SYNCHRONOUSLY so a caller that checks IsRecording immediately after\n // Start() (the session service does) sees `true`, even though the audio-graph setup\n // (AudioContext.resume + worklet module load) completes asynchronously below. Without this the\n // caller discards the recorder before it finishes starting and nothing is ever uploaded.\n this.startedAtMs = Date.now();\n this.finalPeaks = [];\n this.recording = true;\n // Fire-and-forget the async setup (it must `await audioContext.resume()` + worklet load); any\n // failure disables the recorder rather than throwing into the session-start path.\n void this.startMixedRecording(micStream, remoteStream).catch((error) => {\n console.warn('[RealtimeAudioRecorder] Failed to start recording — disabling for this session:', error);\n this.cleanup();\n });\n }\n\n /**\n * Wires the agent's remote-audio stream into the live mix once it arrives. The WebRTC\n * `ontrack` that delivers the agent voice usually lands AFTER recording has already begun\n * (mic-only), so the session attaches it here when it lands. Idempotent, and safe to call\n * before the audio graph finishes its async setup (the stream is connected once ready).\n */\n public AttachRemoteStream(stream: MediaStream): void {\n if (this.remoteAttached || stream.getAudioTracks().length === 0) {\n return;\n }\n if (this.audioContext && this.captureNode()) {\n this.connectStream(this.audioContext, stream);\n this.remoteAttached = true;\n } else {\n // Audio-graph setup still in flight (awaiting resume / worklet load) — connect at setup.\n this.pendingRemoteStream = stream;\n }\n }\n\n /**\n * Returns a Blob of the raw PCM captured since the last call (a window of header-less,\n * little-endian PCM16 bytes), advancing the segment cursor. `null` when nothing new. Used to\n * upload crash-recovery shards mid-call. NOTE: shards are header-less raw PCM (NOT individually\n * playable WAV) — recovery is concatenation in order, then WAV-wrapping with {@link SampleRate}.\n * The canonical consolidated file is still authored as a single WAV from full memory at {@link Stop}.\n */\n public SnapshotNewSegment(): Blob | null {\n if (!this.recording || this.flushedSampleCount >= this.totalSamples) {\n return null;\n }\n const fresh = this.collectSamples(this.flushedSampleCount, this.totalSamples);\n this.flushedSampleCount = this.totalSamples;\n if (fresh.length === 0) {\n return null;\n }\n const pcm16 = this.floatToPcm16Bytes(fresh);\n return new Blob([pcm16], { type: 'application/octet-stream' });\n }\n\n /** Ms elapsed since recording started (>= 0); 0 when not recording. */\n public NowOffsetMs(): number {\n if (this.startedAtMs === 0) {\n return 0;\n }\n return Math.max(0, Date.now() - this.startedAtMs);\n }\n\n /**\n * The downsampled waveform peaks (each 0..1, max-abs per bucket, ~{@link RealtimeAudioRecorder.PeakBuckets}\n * buckets across the whole recording). Computed incrementally during capture so it's cheap and\n * bounded regardless of length. Returns `[]` before any audio / for a silent recording. Safe to\n * call after {@link Stop} — the peaks are snapshotted there before {@link cleanup} clears state.\n */\n public GetPeaks(): number[] {\n return this.recording ? this.peaks.Normalize() : this.finalPeaks;\n }\n\n /**\n * Stops recording and resolves the captured audio as a single mono 16-bit PCM **WAV**\n * {@link Blob}, then releases the audio graph. Resolves `null` when nothing was recorded\n * (recorder disabled, or no samples captured). Safe to call when not recording.\n */\n public async Stop(): Promise<Blob | null> {\n if (!this.recording) {\n this.cleanup();\n return null;\n }\n // Detach the capture node so no further frames arrive while we assemble the file. Snapshot the\n // peaks BEFORE cleanup so GetPeaks() still returns them for the post-Stop upload.\n this.recording = false;\n this.finalPeaks = this.peaks.Normalize();\n const blob = this.encodeWavBlob();\n this.cleanup();\n return blob;\n }\n\n /** Wires up the Web Audio mix graph + PCM capture node (worklet preferred) and starts capture. */\n private async startMixedRecording(micStream: MediaStream, remoteStream: MediaStream | null): Promise<void> {\n const audioContext = new AudioContext();\n // CRITICAL: browsers create an AudioContext in the `suspended` state under the autoplay policy.\n // Without resuming it, the mix graph never processes audio and we capture only silence. Starting\n // a voice call is a user gesture, so resume() succeeds here.\n if (audioContext.state === 'suspended') {\n await audioContext.resume();\n }\n const destination = audioContext.createMediaStreamDestination();\n // Publish the context + sample rate BEFORE wiring the remote so a concurrent AttachRemoteStream()\n // (the agent track can land during the awaits above) sees a ready graph to connect to.\n this.audioContext = audioContext;\n this.destination = destination;\n this.sampleRate = audioContext.sampleRate;\n\n // Build the PCM capture node: AudioWorklet preferred, ScriptProcessor fallback. Either way the\n // node both pulls audio from the mix AND drives the destination so the graph keeps processing.\n await this.createCaptureNode(audioContext, destination);\n\n this.connectStream(audioContext, micStream);\n // Connect the agent's stream if it was passed now, or if AttachRemoteStream() stashed one while\n // we were setting up. Either way, capture the agent voice — not just the mic.\n const remote = remoteStream ?? this.pendingRemoteStream;\n this.pendingRemoteStream = null;\n if (remote && remote.getAudioTracks().length > 0) {\n this.connectStream(audioContext, remote);\n this.remoteAttached = true;\n }\n }\n\n /**\n * Creates the PCM capture node and inserts it into the graph: sources → captureNode → destination.\n * Prefers an {@link AudioWorkletNode} (off-main-thread, no deprecation); falls back to a\n * {@link ScriptProcessorNode} where worklets are unavailable. Throws when neither is supported\n * (caught by {@link Start}, which then disables the recorder).\n */\n private async createCaptureNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): Promise<void> {\n if (await this.tryCreateWorkletNode(audioContext, destination)) {\n return;\n }\n this.createScriptProcessorNode(audioContext, destination);\n }\n\n /** Attempts to build the AudioWorklet capture node; returns `false` (no throw) when unsupported. */\n private async tryCreateWorkletNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): Promise<boolean> {\n if (!audioContext.audioWorklet || typeof AudioWorkletNode === 'undefined' || typeof Blob === 'undefined') {\n return false;\n }\n try {\n const moduleUrl = URL.createObjectURL(\n new Blob([RealtimeAudioRecorder.workletProcessorSource], { type: 'application/javascript' }),\n );\n try {\n await audioContext.audioWorklet.addModule(moduleUrl);\n } finally {\n URL.revokeObjectURL(moduleUrl);\n }\n const node = new AudioWorkletNode(audioContext, 'mj-pcm-capture', { numberOfInputs: 1, numberOfOutputs: 1 });\n node.port.onmessage = (event: MessageEvent<Float32Array>) => this.captureFrame(event.data);\n node.connect(destination);\n this.workletNode = node;\n return true;\n } catch (error) {\n console.warn('[RealtimeAudioRecorder] AudioWorklet unavailable — falling back to ScriptProcessor:', error);\n return false;\n }\n }\n\n /** Builds the ScriptProcessor fallback capture node and inserts it into the graph. */\n private createScriptProcessorNode(audioContext: AudioContext, destination: MediaStreamAudioDestinationNode): void {\n if (typeof audioContext.createScriptProcessor !== 'function') {\n throw new Error('Neither AudioWorklet nor ScriptProcessor is supported');\n }\n const node = audioContext.createScriptProcessor(RealtimeAudioRecorder.scriptProcessorBufferSize, 1, 1);\n node.onaudioprocess = (event: AudioProcessingEvent) => {\n // Copy out of the reused input buffer before retaining.\n this.captureFrame(event.inputBuffer.getChannelData(0).slice(0));\n };\n // ScriptProcessor only fires onaudioprocess while connected to the destination.\n node.connect(destination);\n this.scriptNode = node;\n }\n\n /** The active capture node (worklet or script processor), or `null` before setup. */\n private captureNode(): AudioNode | null {\n return this.workletNode ?? this.scriptNode;\n }\n\n /** Absorbs one captured PCM frame: accumulate samples + update the bounded peak array. */\n private captureFrame(frame: Float32Array): void {\n if (!this.recording || frame.length === 0) {\n return;\n }\n // Defensive copy — worklet/script buffers are reused by the engine.\n const copy = frame.slice(0);\n this.pcmFrames.push(copy);\n this.totalSamples += copy.length;\n this.peaks.Push(copy);\n }\n\n /** Routes one stream's audio tracks into the capture node (no-op when track-less / no node). */\n private connectStream(audioContext: AudioContext, stream: MediaStream): void {\n const node = this.captureNode();\n if (!node || stream.getAudioTracks().length === 0) {\n return;\n }\n const source = audioContext.createMediaStreamSource(stream);\n source.connect(node);\n }\n\n /** Concatenates a half-open sample range [from, to) across the captured frames into one Float32Array. */\n private collectSamples(from: number, to: number): Float32Array {\n const out = new Float32Array(Math.max(0, to - from));\n if (out.length === 0) {\n return out;\n }\n let cursor = 0; // absolute sample index at the start of the current frame\n let written = 0;\n for (const frame of this.pcmFrames) {\n const frameStart = cursor;\n const frameEnd = cursor + frame.length;\n cursor = frameEnd;\n if (frameEnd <= from) {\n continue; // entirely before the window\n }\n if (frameStart >= to) {\n break; // entirely after the window\n }\n const sliceStart = Math.max(0, from - frameStart);\n const sliceEnd = Math.min(frame.length, to - frameStart);\n for (let i = sliceStart; i < sliceEnd; i++) {\n out[written++] = frame[i];\n }\n }\n return written === out.length ? out : out.subarray(0, written);\n }\n\n /**\n * Converts a mono Float32 buffer to a little-endian PCM16 `ArrayBuffer` (for raw crash-recovery\n * shards). Returns the backing `ArrayBuffer` directly so it's a valid `BlobPart`.\n */\n private floatToPcm16Bytes(samples: Float32Array): ArrayBuffer {\n const buffer = new ArrayBuffer(samples.length * 2);\n const view = new DataView(buffer);\n for (let i = 0; i < samples.length; i++) {\n const s = samples[i] < -1 ? -1 : samples[i] > 1 ? 1 : samples[i];\n view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7fff, true);\n }\n return buffer;\n }\n\n /** Encodes all accumulated PCM into a single seekable WAV blob, or `null` when nothing captured. */\n private encodeWavBlob(): Blob | null {\n if (this.totalSamples === 0 || this.sampleRate === 0) {\n return null;\n }\n const all = this.collectSamples(0, this.totalSamples);\n const wav = EncodePcm16Wav(all, this.sampleRate);\n return new Blob([wav], { type: RealtimeAudioRecorder.wavMimeType });\n }\n\n /** Releases the audio graph + capture node and resets state. Idempotent. */\n private cleanup(): void {\n this.recording = false;\n this.pcmFrames = [];\n this.totalSamples = 0;\n this.flushedSampleCount = 0;\n this.sampleRate = 0;\n this.peaks = new PeakAccumulator(RealtimeAudioRecorder.peakBuckets);\n this.remoteAttached = false;\n this.pendingRemoteStream = null;\n if (this.workletNode) {\n this.workletNode.port.onmessage = null;\n try { this.workletNode.disconnect(); } catch { /* already disconnected */ }\n this.workletNode = null;\n }\n if (this.scriptNode) {\n this.scriptNode.onaudioprocess = null;\n try { this.scriptNode.disconnect(); } catch { /* already disconnected */ }\n this.scriptNode = null;\n }\n this.destination = null;\n if (this.audioContext) {\n void this.audioContext.close().catch(() => { /* already closed */ });\n this.audioContext = null;\n }\n }\n}\n"]}
@@ -25,6 +25,8 @@ export declare const WAV_HEADER_BYTES = 44;
25
25
  * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).
26
26
  * @returns A standalone `ArrayBuffer` containing the full WAV file.
27
27
  */
28
+ export declare function EncodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer;
29
+ /** @deprecated Use {@link EncodePcm16Wav}. */
28
30
  export declare function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer;
29
31
  /**
30
32
  * A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets
@@ -71,5 +73,7 @@ export declare class PeakAccumulator {
71
73
  * not produced — a short buffer yields at most `samples.length` peaks.
72
74
  * @returns Normalized peaks; `[]` for an empty or all-silent buffer.
73
75
  */
76
+ export declare function DownsamplePeaks(samples: Float32Array, targetBuckets?: number): number[];
77
+ /** @deprecated Use {@link DownsamplePeaks}. */
74
78
  export declare function downsamplePeaks(samples: Float32Array, targetBuckets?: number): number[];
75
79
  //# sourceMappingURL=realtime-pcm-wav.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-pcm-wav.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAcnC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAkCrF;AASD;;;;;;GAMG;AACH,qBAAa,eAAe;IACxB,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAgB;IAC/B,gFAAgF;IAChF,OAAO,CAAC,gBAAgB,CAAK;IAC7B,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;OAGG;gBACS,aAAa,SAAM;IAI/B,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,uFAAuF;IAChF,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAMxC,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAsBlB,gGAAgG;IAChG,OAAO,CAAC,IAAI;IAYZ;;;OAGG;IACI,SAAS,IAAI,MAAM,EAAE;CAgB/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CA4BpF"}
1
+ {"version":3,"file":"realtime-pcm-wav.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAcnC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAkCrF;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAErF;AASD;;;;;;GAMG;AACH,qBAAa,eAAe;IACxB,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAgB;IAC/B,gFAAgF;IAChF,OAAO,CAAC,gBAAgB,CAAK;IAC7B,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;OAGG;gBACS,aAAa,SAAM;IAI/B,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,uFAAuF;IAChF,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAMxC,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAsBlB,gGAAgG;IAChG,OAAO,CAAC,IAAI;IAYZ;;;OAGG;IACI,SAAS,IAAI,MAAM,EAAE;CAgB/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CA4BpF;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CAEpF"}
@@ -40,7 +40,7 @@ function floatToPcm16(sample) {
40
40
  * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).
41
41
  * @returns A standalone `ArrayBuffer` containing the full WAV file.
42
42
  */
43
- export function encodePcm16Wav(samples, sampleRate) {
43
+ export function EncodePcm16Wav(samples, sampleRate) {
44
44
  const numChannels = 1;
45
45
  const bitsPerSample = 16;
46
46
  const bytesPerSample = bitsPerSample / 8;
@@ -69,6 +69,10 @@ export function encodePcm16Wav(samples, sampleRate) {
69
69
  }
70
70
  return buffer;
71
71
  }
72
+ /** @deprecated Use {@link EncodePcm16Wav}. */
73
+ export function encodePcm16Wav(samples, sampleRate) {
74
+ return EncodePcm16Wav(samples, sampleRate);
75
+ }
72
76
  /** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */
73
77
  function writeAscii(view, offset, text) {
74
78
  for (let i = 0; i < text.length; i++) {
@@ -173,7 +177,7 @@ export class PeakAccumulator {
173
177
  * not produced — a short buffer yields at most `samples.length` peaks.
174
178
  * @returns Normalized peaks; `[]` for an empty or all-silent buffer.
175
179
  */
176
- export function downsamplePeaks(samples, targetBuckets = 600) {
180
+ export function DownsamplePeaks(samples, targetBuckets = 600) {
177
181
  const target = Math.max(1, Math.floor(targetBuckets));
178
182
  if (samples.length === 0) {
179
183
  return [];
@@ -202,4 +206,8 @@ export function downsamplePeaks(samples, targetBuckets = 600) {
202
206
  }
203
207
  return peaks.map(v => v / globalMax);
204
208
  }
209
+ /** @deprecated Use {@link DownsamplePeaks}. */
210
+ export function downsamplePeaks(samples, targetBuckets = 600) {
211
+ return DownsamplePeaks(samples, targetBuckets);
212
+ }
205
213
  //# sourceMappingURL=realtime-pcm-wav.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-pcm-wav.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:\n * encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a\n * bounded, downsampled waveform **peak** array at capture time.\n *\n * These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can\n * be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio\n * graph and feeds the captured samples here.\n *\n * Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte\n * offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),\n * and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is\n * acceptable for these short session recordings.\n *\n * @module @memberjunction/ng-conversations/realtime-pcm-wav\n */\n\n/** Lowest value representable by signed 16-bit PCM. */\nconst PCM16_MIN = -32768;\n/** Highest value representable by signed 16-bit PCM. */\nconst PCM16_MAX = 32767;\n/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */\nexport const WAV_HEADER_BYTES = 44;\n\n/**\n * Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.\n * Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.\n */\nfunction floatToPcm16(sample: number): number {\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: negative full-scale is -32768, positive is +32767.\n const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;\n const rounded = Math.round(scaled);\n return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;\n}\n\n/**\n * Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).\n * The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper\n * 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.\n *\n * @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).\n * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).\n * @returns A standalone `ArrayBuffer` containing the full WAV file.\n */\nexport function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n const numChannels = 1;\n const bitsPerSample = 16;\n const bytesPerSample = bitsPerSample / 8;\n const blockAlign = numChannels * bytesPerSample;\n const byteRate = sampleRate * blockAlign;\n const dataSize = samples.length * bytesPerSample;\n\n const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);\n const view = new DataView(buffer);\n\n writeAscii(view, 0, 'RIFF');\n view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size\n writeAscii(view, 8, 'WAVE');\n\n writeAscii(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n writeAscii(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n let offset = WAV_HEADER_BYTES;\n for (let i = 0; i < samples.length; i++) {\n view.setInt16(offset, floatToPcm16(samples[i]), true);\n offset += bytesPerSample;\n }\n\n return buffer;\n}\n\n/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */\nfunction writeAscii(view: DataView, offset: number, text: string): void {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n}\n\n/**\n * A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets\n * (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:\n * once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise\n * max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an\n * arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.\n */\nexport class PeakAccumulator {\n /** Target (max) number of buckets in the produced peak array. */\n private readonly targetBuckets: number;\n /** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */\n private buckets: number[] = [];\n /** How many samples each bucket currently absorbs before a new bucket opens. */\n private samplesPerBucket = 1;\n /** Samples absorbed into the current (last) bucket so far. */\n private samplesInCurrent = 0;\n\n /**\n * @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.\n * ~600 gives a smooth overview waveform at trivial cost.\n */\n constructor(targetBuckets = 600) {\n this.targetBuckets = Math.max(1, Math.floor(targetBuckets));\n }\n\n /** Number of buckets currently held (for tests/inspection). */\n public get BucketCount(): number {\n return this.buckets.length;\n }\n\n /** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */\n public Push(samples: Float32Array): void {\n for (let i = 0; i < samples.length; i++) {\n this.pushSample(samples[i]);\n }\n }\n\n /** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */\n private pushSample(sample: number): void {\n if (this.buckets.length === 0) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n }\n const abs = sample < 0 ? -sample : sample;\n const last = this.buckets.length - 1;\n if (abs > this.buckets[last]) {\n this.buckets[last] = abs;\n }\n this.samplesInCurrent++;\n if (this.samplesInCurrent >= this.samplesPerBucket) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n // Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the\n // resolution stays under the cap while the per-bucket sample capacity doubles.\n if (this.buckets.length >= this.targetBuckets * 2) {\n this.fold();\n }\n }\n }\n\n /** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */\n private fold(): void {\n const folded: number[] = [];\n for (let i = 0; i < this.buckets.length; i += 2) {\n const a = this.buckets[i];\n const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;\n folded.push(a > b ? a : b);\n }\n this.buckets = folded;\n this.samplesPerBucket *= 2;\n this.samplesInCurrent = 0;\n }\n\n /**\n * Produces the final normalized peak array (each value 0..1, divided by the global max).\n * Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.\n */\n public Normalize(): number[] {\n // Drop a trailing freshly-opened empty bucket that absorbed nothing.\n const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1\n ? this.buckets.slice(0, -1)\n : this.buckets.slice();\n let max = 0;\n for (const v of raw) {\n if (v > max) {\n max = v;\n }\n }\n if (max <= 0) {\n return [];\n }\n return raw.map(v => v / max);\n }\n}\n\n/**\n * One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized\n * max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the\n * direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).\n *\n * @param samples The full mono Float32 PCM buffer.\n * @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are\n * not produced — a short buffer yields at most `samples.length` peaks.\n * @returns Normalized peaks; `[]` for an empty or all-silent buffer.\n */\nexport function downsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n const target = Math.max(1, Math.floor(targetBuckets));\n if (samples.length === 0) {\n return [];\n }\n const buckets = Math.min(target, samples.length);\n const samplesPerBucket = samples.length / buckets;\n const peaks = new Array<number>(buckets).fill(0);\n let globalMax = 0;\n for (let b = 0; b < buckets; b++) {\n const start = Math.floor(b * samplesPerBucket);\n const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);\n let localMax = 0;\n for (let i = start; i < end; i++) {\n const abs = samples[i] < 0 ? -samples[i] : samples[i];\n if (abs > localMax) {\n localMax = abs;\n }\n }\n peaks[b] = localMax;\n if (localMax > globalMax) {\n globalMax = localMax;\n }\n }\n if (globalMax <= 0) {\n return [];\n }\n return peaks.map(v => v / globalMax);\n}\n"]}
1
+ {"version":3,"file":"realtime-pcm-wav.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:\n * encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a\n * bounded, downsampled waveform **peak** array at capture time.\n *\n * These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can\n * be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio\n * graph and feeds the captured samples here.\n *\n * Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte\n * offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),\n * and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is\n * acceptable for these short session recordings.\n *\n * @module @memberjunction/ng-conversations/realtime-pcm-wav\n */\n\n/** Lowest value representable by signed 16-bit PCM. */\nconst PCM16_MIN = -32768;\n/** Highest value representable by signed 16-bit PCM. */\nconst PCM16_MAX = 32767;\n/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */\nexport const WAV_HEADER_BYTES = 44;\n\n/**\n * Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.\n * Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.\n */\nfunction floatToPcm16(sample: number): number {\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: negative full-scale is -32768, positive is +32767.\n const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;\n const rounded = Math.round(scaled);\n return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;\n}\n\n/**\n * Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).\n * The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper\n * 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.\n *\n * @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).\n * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).\n * @returns A standalone `ArrayBuffer` containing the full WAV file.\n */\nexport function EncodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n const numChannels = 1;\n const bitsPerSample = 16;\n const bytesPerSample = bitsPerSample / 8;\n const blockAlign = numChannels * bytesPerSample;\n const byteRate = sampleRate * blockAlign;\n const dataSize = samples.length * bytesPerSample;\n\n const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);\n const view = new DataView(buffer);\n\n writeAscii(view, 0, 'RIFF');\n view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size\n writeAscii(view, 8, 'WAVE');\n\n writeAscii(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n writeAscii(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n let offset = WAV_HEADER_BYTES;\n for (let i = 0; i < samples.length; i++) {\n view.setInt16(offset, floatToPcm16(samples[i]), true);\n offset += bytesPerSample;\n }\n\n return buffer;\n}\n\n/** @deprecated Use {@link EncodePcm16Wav}. */\nexport function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n return EncodePcm16Wav(samples, sampleRate);\n}\n\n/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */\nfunction writeAscii(view: DataView, offset: number, text: string): void {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n}\n\n/**\n * A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets\n * (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:\n * once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise\n * max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an\n * arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.\n */\nexport class PeakAccumulator {\n /** Target (max) number of buckets in the produced peak array. */\n private readonly targetBuckets: number;\n /** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */\n private buckets: number[] = [];\n /** How many samples each bucket currently absorbs before a new bucket opens. */\n private samplesPerBucket = 1;\n /** Samples absorbed into the current (last) bucket so far. */\n private samplesInCurrent = 0;\n\n /**\n * @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.\n * ~600 gives a smooth overview waveform at trivial cost.\n */\n constructor(targetBuckets = 600) {\n this.targetBuckets = Math.max(1, Math.floor(targetBuckets));\n }\n\n /** Number of buckets currently held (for tests/inspection). */\n public get BucketCount(): number {\n return this.buckets.length;\n }\n\n /** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */\n public Push(samples: Float32Array): void {\n for (let i = 0; i < samples.length; i++) {\n this.pushSample(samples[i]);\n }\n }\n\n /** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */\n private pushSample(sample: number): void {\n if (this.buckets.length === 0) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n }\n const abs = sample < 0 ? -sample : sample;\n const last = this.buckets.length - 1;\n if (abs > this.buckets[last]) {\n this.buckets[last] = abs;\n }\n this.samplesInCurrent++;\n if (this.samplesInCurrent >= this.samplesPerBucket) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n // Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the\n // resolution stays under the cap while the per-bucket sample capacity doubles.\n if (this.buckets.length >= this.targetBuckets * 2) {\n this.fold();\n }\n }\n }\n\n /** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */\n private fold(): void {\n const folded: number[] = [];\n for (let i = 0; i < this.buckets.length; i += 2) {\n const a = this.buckets[i];\n const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;\n folded.push(a > b ? a : b);\n }\n this.buckets = folded;\n this.samplesPerBucket *= 2;\n this.samplesInCurrent = 0;\n }\n\n /**\n * Produces the final normalized peak array (each value 0..1, divided by the global max).\n * Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.\n */\n public Normalize(): number[] {\n // Drop a trailing freshly-opened empty bucket that absorbed nothing.\n const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1\n ? this.buckets.slice(0, -1)\n : this.buckets.slice();\n let max = 0;\n for (const v of raw) {\n if (v > max) {\n max = v;\n }\n }\n if (max <= 0) {\n return [];\n }\n return raw.map(v => v / max);\n }\n}\n\n/**\n * One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized\n * max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the\n * direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).\n *\n * @param samples The full mono Float32 PCM buffer.\n * @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are\n * not produced — a short buffer yields at most `samples.length` peaks.\n * @returns Normalized peaks; `[]` for an empty or all-silent buffer.\n */\nexport function DownsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n const target = Math.max(1, Math.floor(targetBuckets));\n if (samples.length === 0) {\n return [];\n }\n const buckets = Math.min(target, samples.length);\n const samplesPerBucket = samples.length / buckets;\n const peaks = new Array<number>(buckets).fill(0);\n let globalMax = 0;\n for (let b = 0; b < buckets; b++) {\n const start = Math.floor(b * samplesPerBucket);\n const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);\n let localMax = 0;\n for (let i = start; i < end; i++) {\n const abs = samples[i] < 0 ? -samples[i] : samples[i];\n if (abs > localMax) {\n localMax = abs;\n }\n }\n peaks[b] = localMax;\n if (localMax > globalMax) {\n globalMax = localMax;\n }\n }\n if (globalMax <= 0) {\n return [];\n }\n return peaks.map(v => v / globalMax);\n}\n\n/** @deprecated Use {@link DownsamplePeaks}. */\nexport function downsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n return DownsamplePeaks(samples, targetBuckets);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { IMetadataProvider } from '@memberjunction/core';
2
2
  import { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';
3
- import { ParsedDelegationArtifact } from './delegation-result-parser';
3
+ import { ParsedDelegationArtifact } from '@memberjunction/realtime-runtime';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
6
  * Why a reviewed session was closed, as stamped server-side by `SessionManager.CloseSession`
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAoC,MAAM,sBAAsB,CAAC;AAE3F,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AAC7G,OAAO,EAAE,wBAAwB,EAAkB,MAAM,kCAAkC,CAAC;;AAE5F;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtF;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gGAAgG;IAChG,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,4EAA4E;IAC5E,EAAE,EAAE,IAAI,GAAG,IAAI,CAAC;IAChB,uGAAuG;IACvG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kEAAkE;IAClE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wFAAwF;IACxF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B;AAED,8EAA8E;AAC9E,MAAM,WAAW,iCAAiC;IAChD,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAC;IACpB,8GAA8G;IAC9G,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,aAAa,CAAC,aAAa,CAAC,iCAAiC,CAAC,CAAC,GAChF,iCAAiC,EAAE,CAkBrC;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gDAAgD;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,EAAE,EAAE,IAAI,GAAG,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,oDAAoD;IACpD,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,2DAA2D;IAC3D,WAAW,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC9C,6DAA6D;IAC7D,KAAK,EAAE,yBAAyB,EAAE,CAAC;IACnC,8FAA8F;IAC9F,aAAa,EAAE,wBAAwB,EAAE,CAAC;IAC1C,4DAA4D;IAC5D,aAAa,CAAC,EAAE,2BAA2B,EAAE,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,OAAO,EAAE,MAAM,CAAC;IAChB,sGAAsG;IACtG,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,WAAW,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC9C,mDAAmD;IACnD,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB;;;;OAIG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,mGAAmG;IACnG,kBAAkB,EAAE,IAAI,GAAG,IAAI,CAAC;IAChC,iFAAiF;IACjF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qFAAqF;IACrF,KAAK,EAAE,yBAAyB,EAAE,CAAC;IACnC,oGAAoG;IACpG,aAAa,EAAE,wBAAwB,EAAE,CAAC;IAC1C,0EAA0E;IAC1E,aAAa,CAAC,EAAE,2BAA2B,EAAE,CAAC;IAC9C;;;;OAIG;IACH,aAAa,EAAE,iCAAiC,EAAE,CAAC;IACnD;;;;OAIG;IACH,IAAI,EAAE,wBAAwB,EAAE,CAAC;IACjC;;;;;;;OAOG;IACH,SAAS,EAAE,wBAAwB,EAAE,CAAC;CACvC;AA0FD,4FAA4F;AAC5F,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,mGAAmG;AACnG,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAItC,4FAA4F;AAC5F,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,GAAG,wBAAwB,CAgB5H;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,wBAAwB,CAiBnG;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,GAAG,kBAAkB,EAAE,CAyB1F;AAiCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,4BAA4B;IACvC;;;;;;OAMG;IACU,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAoB3H;;;;OAIG;YACW,WAAW;IAgCzB;;;;;;;;;OASG;YACW,gBAAgB;IA8B9B;;;;;;OAMG;YACW,kBAAkB;IAkDhC,6GAA6G;IAC7G,OAAO,CAAC,gBAAgB;IAcxB,uGAAuG;IACvG,OAAO,CAAC,WAAW;IAInB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IA8BtB,wFAAwF;IACxF,OAAO,CAAC,MAAM;IAad,uFAAuF;IACvF,OAAO,CAAC,gBAAgB;IAoCxB,kGAAkG;IAClG,OAAO,CAAC,QAAQ;IAsBhB,4FAA4F;IAC5F,OAAO,CAAC,OAAO;IAiBf,6FAA6F;IAC7F,OAAO,CAAC,WAAW;IAMnB,+EAA+E;IAC/E,OAAO,CAAC,kBAAkB;IAY1B,iGAAiG;IACjG,OAAO,CAAC,MAAM;yCA3UH,4BAA4B;6CAA5B,4BAA4B;CAkVxC"}
@@ -1,7 +1,7 @@
1
1
  import { Injectable } from '@angular/core';
2
2
  import { Metadata, RunView } from '@memberjunction/core';
3
3
  import { UUIDsEqual } from '@memberjunction/global';
4
- import { FormatToolName } from './delegation-result-parser';
4
+ import { FormatToolName } from '@memberjunction/realtime-runtime';
5
5
  import * as i0 from "@angular/core";
6
6
  /**
7
7
  * MULTI-LEG channel-state merge: folds every leg's channel rows into one state set,
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session-review.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAqB,QAAQ,EAAE,OAAO,EAAiB,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAA4B,cAAc,EAAE,MAAM,4BAA4B,CAAC;;AAsEtF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,gBAAiF;IAEjF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6C,CAAC;IACpE,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACnD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YAC1F,iFAAiF;YACjF,+EAA+E;YAC/E,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;gBAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAkMD,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;AACjO,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;AAC5K,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACvI,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACnD,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;AAC5E,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AAEhE,4FAA4F;AAC5F,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,mGAAmG;AACnG,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC,+EAA+E;AAE/E,4FAA4F;AAC5F,MAAM,UAAU,yBAAyB,CAAC,GAA6B,EAAE,iBAAyB;IAChG,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,GAAG,CAAC,KAAK;QACjB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,iBAAiB;QAC7C,aAAa,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,MAAM;QAC5D,UAAU,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;QAC/B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,YAAY,IAAI,IAAI;QAC/C,SAAS,EAAE,SAAS;QACpB,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,SAAS;KACpD,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,qBAAqB,CAAC,MAAmC;IACvE,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,YAAY,SAAS,EAAE;QACtC,UAAU,EAAE,eAAe;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;QAClC,MAAM,EAAE,MAAM,CAAC,UAAU;QACzB,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,EAAE,GAAG,MAAM,CAAC,UAAU;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAA6B;IAClE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,OAAO,mBAAmB,CACxB,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK,EAC3B,IAAI,EAAE,aAAa,IAAI,MAAM,CAAC,aAAa,EAC3C,IAAI,EAAE,aAAa,IAAI,MAAM,CAAC,aAAa,IAAI,EAAE,EACjD,MAAM,CAAC,SAAS,CACjB,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACtB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,qBAAqB;gBAC5B,EAAE,EAAE,GAAG,CAAC,SAAS;gBACjB,IAAI,EAAE,2BAA2B;gBACjC,WAAW,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,IAAI;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9G,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,KAAkC,EAClC,IAAgC,EAChC,OAAsC,EACtC,iBAAyB;IAEzB,MAAM,OAAO,GAAoD,EAAE,CAAC;IACpE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7G,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,yBAAyB,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7I,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACrH,CAAC;IACD,4EAA4E;IAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,6FAA6F;AAC7F,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACjD,OAAO,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AACnG,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,OAAO,4BAA4B;IACvC;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAAC,cAAsB,EAAE,QAA4B;QACjF,MAAM,OAAO,GAAG,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACzC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wDAAwD,EAAE,KAAK,CAAC,CAAC;YAC/E,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,WAAW,CACvB,cAAsB,EACtB,QAA2B,EAC3B,eAAwB;QAExB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClD,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,OAAO,GAAoB;YAC/B,EAAE,UAAU,EAAE,uBAAuB,EAAE,WAAW,EAAE,OAAO,MAAM,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,QAAiB,EAAE;YAC7H;gBACE,UAAU,EAAE,0BAA0B,EAAE,WAAW,EAAE,mBAAmB,MAAM,GAAG,EAAE,MAAM,EAAE,aAAa;gBACxG,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,QAAiB;aAC1F;YACD,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,MAAM,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAiB,EAAE;SAC5J,CAAC;QACF,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,+BAA+B,EAAE,WAAW,EAAE,mBAAmB,MAAM,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,QAAiB,EAAE,CAAC,CAAC;QAClK,CAAC;QACD,MAAM,CAAC,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAiB,CAAC;QACvF,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,OAAO;YACP,OAAO,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAgB;YAC3E,IAAI,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAa;YAC/D,QAAQ,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAiB;SAChF,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACK,KAAK,CAAC,gBAAgB,CAAC,OAAgB,EAAE,QAA2B;QAC1E,MAAM,KAAK,GAAc,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;QACnD,IAAI,YAAY,GAAG,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;QAE/D,OAAO,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACpE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,2DAA2D,MAAM,uBAAuB,CAAC,CAAC;gBACvG,MAAM;YACR,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM;YACR,CAAC;YACD,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBACtC,8EAA8E;gBAC9E,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;gBACnE,YAAY,GAAG,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YACrC,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACnB,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;QAC7C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,kBAAkB,CAAC,KAAgB,EAAE,QAA2B;QAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChF,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;oBAC1C,UAAU,EAAE,mCAAmC;oBAC/C,WAAW,EAAE,4BAA4B,UAAU,0BAA0B;oBAC7E,MAAM,EAAE,eAAe;oBACvB,OAAO,EAAE,oBAAoB;oBAC7B,UAAU,EAAE,QAAQ;iBACrB,CAAC,CAAC,CAAC;YACJ,MAAM,SAAS,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAgC,CAAC;YACzG,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YACpD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClF,MAAM,CAAC,aAAa,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;oBACzC,UAAU,EAAE,uBAAuB;oBACnC,WAAW,EAAE,UAAU,WAAW,GAAG;oBACrC,MAAM,EAAE,cAAc;oBACtB,UAAU,EAAE,QAAQ;iBACrB,CAAC,CAAC,CAAC;YACJ,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAyB,CAAC;YAC/F,MAAM,IAAI,GAAG,IAAI,GAAG,CAA6B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAEjG,MAAM,SAAS,GAA+B,EAAE,CAAC;YACjD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC;oBACrB,SAAS,CAAC,4DAA4D;gBACxE,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC;oBACb,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,iBAAiB,EAAE,GAAG,CAAC,EAAE;oBACzB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,UAAU;iBAC7D,CAAC,CAAC;YACL,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,4FAA4F,EAAE,KAAK,CAAC,CAAC;YAClH,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,6GAA6G;IACrG,gBAAgB,CAAC,SAAsC;QAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrF,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,uGAAuG;IAC/F,WAAW,CAAC,EAAU;QAC5B,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACK,cAAc,CAAC,KAAgB,EAAE,SAAqC;QAC5E,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChD,OAAO;YACL,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS,EAAE,OAAO,CAAC,KAAK,IAAI,WAAW;YACvC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,OAAO,CAAC,OAAO;YACtD,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;YAC9C,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;YACxC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;YAC9C,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;YAC/C,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACvC,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI;YAChD,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;YAC3D,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;YAC9C,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YACjC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YACjD,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC;YACvD,+EAA+E;YAC/E,gFAAgF;YAChF,aAAa,EAAE,uBAAuB,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxF,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,SAAS;SACrB,CAAC;IACJ,CAAC;IAED,wFAAwF;IAChF,MAAM,CAAC,GAAY;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE;YACzB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC;YAClD,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC3C,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI;YAC5C,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;YACjC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;YAClE,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC;SAClD,CAAC;IACJ,CAAC;IAED,uFAAuF;IAC/E,gBAAgB,CAAC,OAAoB;QAC3C,MAAM,OAAO,GAAkC,EAAE,CAAC;QAClD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAQpC,CAAC;gBACF,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,yBAAyB,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBAC/F,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;oBAClD,OAAO,CAAC,IAAI,CAAC;wBACX,EAAE,EAAE,GAAG,CAAC,EAAE;wBACV,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE;wBACjD,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;wBACjC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;wBACrC,OAAO,EAAE,OAAO,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC;wBAC3F,UAAU,EAAE,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,CAAC;wBACjG,EAAE,EAAE,SAAS;qBACd,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,kGAAkG;IAC1F,QAAQ,CAAC,OAAoB;QACnC,MAAM,KAAK,GAAgC,EAAE,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACvC,IAAI,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACxF,SAAS;YACX,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;gBAC9C,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE,SAAS;gBACzB,EAAE,EAAE,SAAS;gBACb,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,IAAI,IAAI;gBAC9C,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;aAC3C,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4FAA4F;IACpF,OAAO,CAAC,IAAc,EAAE,YAA2B;QACzD,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;aAC7D,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACT,KAAK,EAAE,CAAC,CAAC,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;YAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;YACtB,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,IAAI;YAC3B,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI;YAC1B,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;YACpC,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,IAAI;YAC9B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;YACnC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;SACxC,CAAC,CAAC,CAAC;IACR,CAAC;IAED,6FAA6F;IACrF,WAAW,CAAC,QAAsB;QACxC,OAAO,QAAQ;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;aACxB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,OAAiB,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,+EAA+E;IACvE,kBAAkB,CAAC,GAAkB;QAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;YACpD,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,iGAAiG;IACzF,MAAM,CAAC,KAAuC;QACpD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;sHAjVU,4BAA4B;gEAA5B,4BAA4B,WAA5B,4BAA4B,mBADf,MAAM;;iFACnB,4BAA4B;cADxC,UAAU;eAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { Injectable } from '@angular/core';\nimport { IMetadataProvider, Metadata, RunView, RunViewParams } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';\nimport { ParsedDelegationArtifact, FormatToolName } from './delegation-result-parser';\n\n/**\n * Why a reviewed session was closed, as stamped server-side by `SessionManager.CloseSession`\n * (mirrors `MJAIAgentSessionEntity.CloseReason`). `null` means the session is still open OR a\n * legacy row was closed before the column existed.\n */\nexport type RealtimeReviewCloseReason = 'Error' | 'Explicit' | 'Janitor' | 'Shutdown';\n\n/**\n * One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).\n *\n * Carries BOTH the thread-rendering fields (`Role`/`Text`/`At`) AND the raw fields the time-aligned\n * evidence player reads (`ID`, `Message`, `__mj_CreatedAt`, `UtteranceStartMs`, `UtteranceEndMs`) so\n * a review's turns can be handed straight to {@link RealtimeEvidencePlaybackComponent} for the\n * Recording tab — this shape structurally satisfies that player's `EvidencePlaybackTurn` input.\n */\nexport interface RealtimeSessionReviewTurn {\n /** `MJ: Conversation Details.ID` — the player's `@for` track key. */\n ID: string;\n /** Who spoke the turn. Persisted `AI` rows map to `Assistant`. */\n Role: 'User' | 'Assistant';\n /** The transcript text. */\n Text: string;\n /** The raw transcript text (mirrors {@link Text}) — the player reads `Message`. */\n Message: string | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. Aliases {@link At}. */\n __mj_CreatedAt: Date | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. */\n At: Date | null;\n /** Precise media-relative start (ms from recording t0), or null when the driver supplied no timing. */\n UtteranceStartMs: number | null;\n /** Precise media-relative end (ms from recording t0), or null. */\n UtteranceEndMs: number | null;\n}\n\n/**\n * A compact preview of one DELEGATED agent run the reviewed session spawned (an\n * `MJ: AI Agent Runs` row linked via `AgentSessionID`, EXCLUDING the co-agent's own\n * observability run). Carries just enough to render a done delegation card.\n */\nexport interface RealtimeSessionReviewRun {\n /** `MJ: AI Agent Runs.ID`. */\n RunID: string;\n /** The delegated agent's id. */\n AgentID: string;\n /** Denormalized agent display name from the run view, when available. */\n AgentName: string | null;\n /** Terminal (or last-known) run status (`Completed` | `Failed` | `Running` | …). */\n Status: string;\n /** Whether the run reported success. */\n Success: boolean;\n /** The run's user-facing result message, when one was recorded. */\n Message: string | null;\n /** The run's error message, when it failed. */\n ErrorMessage: string | null;\n /** The final step the run reported (`Success` | `Failed` | `Retry` | …), when known. */\n FinalStep: string | null;\n StartedAt: Date | null;\n CompletedAt: Date | null;\n}\n\n/** The persisted state of one interactive channel of the reviewed session. */\nexport interface RealtimeSessionReviewChannelState {\n /** Channel display name (e.g. `Whiteboard`), denormalized on the session-channel row. */\n ChannelName: string;\n /** The channel's serialized state of record (`AIAgentSessionChannel.Config`), or null when none was saved. */\n StateJson: string | null;\n}\n\n/**\n * MULTI-LEG channel-state merge: folds every leg's channel rows into one state set,\n * NEWEST leg wins per channel name — but only a leg that actually SAVED state counts.\n * A resumed session whose final leg never touched the whiteboard therefore still\n * reviews with the board an EARLIER leg drew (previously only the primary/newest leg's\n * rows were consulted, so that board silently vanished from review).\n *\n * @param legChannelStates Per-leg channel states, ordered OLDEST → NEWEST (the chain order).\n * @returns One entry per channel name (case-insensitive), each from the newest leg that\n * saved a non-empty state; channels no leg ever saved keep a null-state entry so the\n * review still knows the channel existed.\n */\nexport function MergeChainChannelStates(\n legChannelStates: ReadonlyArray<ReadonlyArray<RealtimeSessionReviewChannelState>>\n): RealtimeSessionReviewChannelState[] {\n const byName = new Map<string, RealtimeSessionReviewChannelState>();\n for (const leg of legChannelStates) {\n for (const state of leg) {\n const key = state.ChannelName.trim().toLowerCase();\n if (key.length === 0) {\n continue;\n }\n const existing = byName.get(key);\n const hasState = typeof state.StateJson === 'string' && state.StateJson.trim().length > 0;\n // Later legs are newer: a saved state always supersedes; a null/empty state only\n // registers the channel's existence and never clobbers an earlier saved board.\n if (!existing || hasState) {\n byName.set(key, hasState ? state : (existing ?? state));\n }\n }\n }\n return [...byName.values()];\n}\n\n/**\n * A direct action or channel tool execution performed during the reviewed session\n * (stored as a hidden `MJ: Conversation Details` turn with `type: 'realtime_tool_execution'`).\n */\nexport interface RealtimeSessionReviewAction {\n /** `MJ: Conversation Details.ID`. */\n ID: string;\n /** Correlated tool call id (`MJ: Conversation Details.ExternalID`), falling back to ID. */\n CallID: string;\n /** The tool/action name (e.g. `File_Storage_List_Objects` or `Whiteboard_draw_shape`). */\n ToolName: string;\n /** Serialized argument payload, when recorded. */\n ArgsJson: string | null;\n /** Serialized result payload, when recorded. */\n ResultJson: string | null;\n /** Whether the execution reported success. */\n Success: boolean;\n /** Execution duration in ms (`MJ: Conversation Details.CompletionTime`). */\n DurationMs: number;\n /** When the tool execution was recorded (`MJ: Conversation Details.__mj_CreatedAt`). */\n At: Date | null;\n}\n\n/**\n * One LEG of a reviewed session chain: a single `MJ: AI Agent Sessions` row plus its own\n * caption turns and delegated-run previews. A session resumed via `lastSessionId` chains\n * legs together (newest leg's `LastSessionID` → prior leg); the review loader walks that\n * chain BACKWARDS (capped — see the loader docs) so review mode can render the FULL\n * conversation arc chronologically, with a divider between legs.\n */\nexport interface RealtimeSessionReviewLeg {\n /** `MJ: AI Agent Sessions.ID` of this leg. */\n SessionID: string;\n /** When this leg started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n /** When this leg closed (null while still open). */\n ClosedAt: Date | null;\n /** Why this leg closed (null while open / legacy rows). */\n CloseReason: RealtimeReviewCloseReason | null;\n /** This leg's chronological caption turns (oldest first). */\n Turns: RealtimeSessionReviewTurn[];\n /** This leg's delegated-run previews (oldest first, minus its co-agent observability run). */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** This leg's direct action and channel tool executions. */\n DirectActions?: RealtimeSessionReviewAction[];\n}\n\n/**\n * Everything the call overlay's SESSION REVIEW mode renders for one past realtime session:\n * the session identity/lifecycle row, the chronological caption turns, previews of the\n * delegated runs, and the saved per-channel states (e.g. the whiteboard board).\n */\nexport interface RealtimeSessionReview {\n /** `MJ: AI Agent Sessions.ID` of the reviewed session. */\n SessionID: string;\n /** The session's fronting agent id (`AIAgentSession.AgentID` — usually the Realtime Co-Agent). */\n AgentID: string;\n /** Display name shown in the review banner (target agent when resolvable, else the session agent). */\n AgentName: string;\n /**\n * The agent a RESUMED live session should front: the session Config's `targetAgentID`,\n * falling back to the session's own `AgentID` when the config doesn't carry one.\n */\n TargetAgentID: string;\n /** Conversation the session was bound to, when any. */\n ConversationID: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n CloseReason: RealtimeReviewCloseReason | null;\n /** When the session started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n LastActiveAt: Date | null;\n ClosedAt: Date | null;\n /**\n * The `MJ: Files` id of the reviewed session's recorded audio, or null when nothing was recorded.\n * When set, review mode resolves a signed download URL and shows a Recording tab with the\n * time-aligned evidence player. From the PRIMARY (reviewed) leg only.\n */\n RecordingFileID: string | null;\n /** Recording alignment origin (t0), used by the playback transcript sync. From the primary leg. */\n RecordingStartedAt: Date | null;\n /** What was captured (`Audio` / `AudioVideo`), or null. From the primary leg. */\n RecordingMedia: string | null;\n /** Chronological caption turns (oldest first) — ALL legs of the chain, flattened. */\n Turns: RealtimeSessionReviewTurn[];\n /** Delegated run previews (oldest first, all legs), minus each leg's co-agent observability run. */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** Direct action and channel tool executions (oldest first, all legs). */\n DirectActions?: RealtimeSessionReviewAction[];\n /**\n * Saved channel states, one per session-channel row that carried a name. Channel state\n * (e.g. the whiteboard board) is the LATEST leg's only — earlier legs' states were\n * superseded when the chain resumed.\n */\n ChannelStates: RealtimeSessionReviewChannelState[];\n /**\n * The session-chain LEGS, chronological (oldest first; the LAST leg is the reviewed\n * session itself). Single-session reviews carry exactly one leg. Drives the per-leg\n * dividers `BuildReviewThreadItems` renders.\n */\n Legs: RealtimeSessionReviewLeg[];\n /**\n * ARTIFACTS attached to the chain's conversation history: every `MJ: Conversation\n * Detail Artifacts` junction (Direction `Output`) hanging off the chain's\n * session-stamped `Conversation Details`, resolved to `{ArtifactID, ArtifactVersionID,\n * Name}`. Review mode registers each as an (unfocused) artifact tab on the surface\n * panel, and they carry into a resumed live session. Empty when none / on any\n * tolerated load failure.\n */\n Artifacts: ParsedDelegationArtifact[];\n}\n\n// ── Raw row shapes (ResultType: 'simple', narrowed Fields) ──────────────────\n\ninterface SessionRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n ConversationID: string | null;\n Config: string | null;\n LastSessionID: string | null;\n LastActiveAt: string | null;\n ClosedAt: string | null;\n CloseReason: RealtimeReviewCloseReason | null;\n RecordingFileID: string | null;\n RecordingStartedAt: string | null;\n RecordingMedia: string | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface DetailRow {\n ID: string;\n Role: 'AI' | 'Error' | 'User';\n Message: string | null;\n HiddenToUser: boolean;\n UserID: string | null;\n Status: string | null;\n ExternalID?: string | null;\n CompletionTime?: number | null;\n UtteranceStartMs: number | null;\n UtteranceEndMs: number | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface RunRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: string;\n Success: boolean | null;\n Message: string | null;\n ErrorMessage: string | null;\n FinalStep: string | null;\n StartedAt: string | null;\n CompletedAt: string | null;\n}\n\ninterface ChannelRow {\n ID: string;\n Channel: string | null;\n Config: string | null;\n}\n\ninterface DetailArtifactJunctionRow {\n ID: string;\n ConversationDetailID: string;\n ArtifactVersionID: string | null;\n}\n\ninterface ArtifactVersionRow {\n ID: string;\n ArtifactID: string;\n /** Version display name (nullable on the row). */\n Name: string | null;\n /** Denormalized parent-artifact name from the version view. */\n Artifact: string | null;\n}\n\n/** The raw rows of ONE chain leg, before mapping to the public review shapes. */\ninterface LegRows {\n session: SessionRow;\n details: DetailRow[];\n runs: RunRow[];\n channels: ChannelRow[];\n}\n\n/** The Config-JSON keys the realtime voice stack persists on `AIAgentSession.Config`. */\ninterface SessionConfigJson {\n targetAgentID?: string;\n coAgentRunID?: string;\n}\n\nconst SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', 'RecordingFileID', 'RecordingStartedAt', 'RecordingMedia', '__mj_CreatedAt'];\nconst DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', 'UserID', 'Status', 'ExternalID', 'CompletionTime', 'UtteranceStartMs', 'UtteranceEndMs', '__mj_CreatedAt'];\nconst RUN_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'Success', 'Message', 'ErrorMessage', 'FinalStep', 'StartedAt', 'CompletedAt'];\nconst CHANNEL_FIELDS = ['ID', 'Channel', 'Config'];\nconst JUNCTION_FIELDS = ['ID', 'ConversationDetailID', 'ArtifactVersionID'];\nconst VERSION_FIELDS = ['ID', 'ArtifactID', 'Name', 'Artifact'];\n\n/** Maximum number of chain legs the review loader walks (the reviewed session included). */\nexport const MAX_REVIEW_LEGS = 5;\n/** Maximum total caption-detail rows loaded across the whole chain (oldest legs trimmed first). */\nexport const MAX_REVIEW_DETAILS = 500;\n\n// ── Review → thread-item mapping (pure, unit-testable) ──────────────────────\n\n/** Maps one delegated-run preview to the done delegation-card VM the thread/rail render. */\nexport function BuildReviewDelegationCard(run: RealtimeSessionReviewRun, fallbackAgentName: string): RealtimeDelegationCardVM {\n const startedAt = run.StartedAt?.getTime() ?? 0;\n return {\n Kind: 'agent',\n CallID: run.RunID,\n AgentName: run.AgentName || fallbackAgentName,\n LatestMessage: run.Message ?? run.ErrorMessage ?? run.Status,\n LatestStep: run.FinalStep ?? '',\n Done: true,\n Success: run.Success,\n RunRef: shortRunRef(run.RunID),\n RunID: run.RunID,\n Result: run.Message ?? run.ErrorMessage ?? null,\n StartedAt: startedAt,\n FinishedAt: run.CompletedAt?.getTime() ?? startedAt\n };\n}\n\n/** Maps one direct-action execution to the done action-card VM the thread/rail render. */\nexport function BuildReviewActionCard(action: RealtimeSessionReviewAction): RealtimeDelegationCardVM {\n const at = action.At?.getTime() ?? 0;\n const toolTitle = FormatToolName(action.ToolName);\n return {\n Kind: 'action',\n CallID: action.CallID,\n ToolName: action.ToolName,\n AgentName: toolTitle,\n LatestMessage: `Executed ${toolTitle}`,\n LatestStep: 'direct_action',\n Done: true,\n Success: action.Success,\n RunRef: shortRunRef(action.CallID),\n Result: action.ResultJson,\n StartedAt: at,\n FinishedAt: at + action.DurationMs\n };\n}\n\n/**\n * Builds the chronological thread (caption turns + done delegation cards + done action cards, oldest first)\n * for a reviewed session — the items `RealtimeSessionState.LoadHistoricalItems` takes.\n *\n * CHAIN-AWARE: when the review carries multiple {@link RealtimeSessionReview.Legs}, each\n * leg's items render in leg order with a `divider` item between legs (\"Session leg\n * started · <time>\", carrying the PREVIOUS leg's CloseReason as a chip). A single-leg\n * review (or a legless legacy shape) renders the flat thread with no divider —\n * byte-identical to the pre-chain behavior.\n */\nexport function BuildReviewThreadItems(review: RealtimeSessionReview): RealtimeThreadItem[] {\n const legs = review.Legs ?? [];\n if (legs.length <= 1) {\n const only = legs[0];\n return buildLegThreadItems(\n only?.Turns ?? review.Turns,\n only?.DelegatedRuns ?? review.DelegatedRuns,\n only?.DirectActions ?? review.DirectActions ?? [],\n review.AgentName\n );\n }\n const items: RealtimeThreadItem[] = [];\n legs.forEach((leg, i) => {\n if (i > 0) {\n items.push({\n Kind: 'divider',\n Label: 'Session leg started',\n At: leg.StartedAt,\n Icon: 'fa-solid fa-arrows-rotate',\n CloseReason: legs[i - 1].CloseReason ?? null\n });\n }\n items.push(...buildLegThreadItems(leg.Turns, leg.DelegatedRuns, leg.DirectActions ?? [], review.AgentName));\n });\n return items;\n}\n\n/**\n * Builds ONE leg's chronological items (caption turns + done delegation cards + done action cards,\n * oldest first). Entries without a timestamp sort to the front, preserving their relative order.\n */\nfunction buildLegThreadItems(\n turns: RealtimeSessionReviewTurn[],\n runs: RealtimeSessionReviewRun[],\n actions: RealtimeSessionReviewAction[],\n fallbackAgentName: string\n): RealtimeThreadItem[] {\n const stamped: Array<{ At: number; Item: RealtimeThreadItem }> = [];\n for (const turn of turns) {\n stamped.push({ At: turn.At?.getTime() ?? 0, Item: { Kind: 'caption', Role: turn.Role, Text: turn.Text } });\n }\n for (const run of runs) {\n stamped.push({ At: run.StartedAt?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewDelegationCard(run, fallbackAgentName) } });\n }\n for (const action of actions) {\n stamped.push({ At: action.At?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewActionCard(action) } });\n }\n // Array.prototype.sort is stable — equal timestamps keep their build order.\n stamped.sort((a, b) => a.At - b.At);\n return stamped.map(s => s.Item);\n}\n\n/** Derives a short run reference (e.g. \"#a3f1\") from the run id — mirrors the live cards. */\nfunction shortRunRef(runId: string): string {\n const compact = runId.replace(/[^a-z0-9]/gi, '');\n return compact.length >= 4 ? `#${compact.slice(-4).toLowerCase()}` : `#${compact.toLowerCase()}`;\n}\n\n/**\n * STATELESS loader for the call overlay's SESSION REVIEW mode: given a past\n * `MJ: AI Agent Sessions` id, batch-loads the session row, its persisted caption turns\n * (`MJ: Conversation Details` linked by `AgentSessionID`), its delegated agent runs\n * (minus the co-agent observability run named in the session Config's `coAgentRunID`),\n * and its saved channel states — and folds them into one {@link RealtimeSessionReview}.\n *\n * CHAIN-AWARE: when the reviewed session carries a `LastSessionID` (it RESUMED an earlier\n * session), the loader walks the chain BACKWARDS — capped at {@link MAX_REVIEW_LEGS} legs\n * and {@link MAX_REVIEW_DETAILS} caption rows total (oldest legs trimmed first), with a\n * cycle guard so a corrupt A→B→A chain can never loop — and surfaces ALL legs\n * chronologically on {@link RealtimeSessionReview.Legs}. Channel state stays the\n * reviewed (latest) leg's only. The chain's conversation-history ARTIFACTS (junction\n * rows on the session-stamped details) are collected onto\n * {@link RealtimeSessionReview.Artifacts}.\n *\n * TOLERANT by design: any missing piece degrades to an empty collection; the loader\n * returns `null` only when the reviewed session row itself can't be found.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionReviewService {\n /**\n * Loads everything review mode renders for one past session (and its prior-leg chain).\n *\n * @param agentSessionId The `MJ: AI Agent Sessions.ID` to review.\n * @param provider Optional metadata provider (multi-server apps); falls back to the global default.\n * @returns The assembled review, or `null` when the session doesn't exist / can't be read.\n */\n public async LoadSessionReview(agentSessionId: string, provider?: IMetadataProvider): Promise<RealtimeSessionReview | null> {\n const trimmed = agentSessionId?.trim() ?? '';\n if (trimmed.length === 0) {\n return null;\n }\n try {\n const md = provider ?? Metadata.Provider;\n const primary = await this.loadLegRows(trimmed, md, true);\n if (!primary) {\n return null;\n }\n const chain = await this.collectChainLegs(primary, md);\n const artifacts = await this.loadChainArtifacts(chain, md);\n return this.assembleReview(chain, artifacts);\n } catch (error) {\n console.error('[RealtimeSessionReview] Failed to load session review:', error);\n return null;\n }\n }\n\n /**\n * One batched RunViews pass for one chain leg: session row + caption turns + linked\n * runs (+ channel rows for the PRIMARY leg only — channel state is latest-leg-only).\n * Returns `null` when the session row can't be found.\n */\n private async loadLegRows(\n agentSessionId: string,\n provider: IMetadataProvider,\n includeChannels: boolean\n ): Promise<LegRows | null> {\n const safeID = agentSessionId.replace(/'/g, \"''\");\n const rv = RunView.FromMetadataProvider(provider);\n const queries: RunViewParams[] = [\n { EntityName: 'MJ: AI Agent Sessions', ExtraFilter: `ID='${safeID}'`, Fields: SESSION_FIELDS, ResultType: 'simple' as const },\n {\n EntityName: 'MJ: Conversation Details', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: DETAIL_FIELDS,\n OrderBy: '__mj_CreatedAt ASC', MaxRows: MAX_REVIEW_DETAILS, ResultType: 'simple' as const\n },\n { EntityName: 'MJ: AI Agent Runs', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: RUN_FIELDS, OrderBy: 'StartedAt ASC', ResultType: 'simple' as const }\n ];\n if (includeChannels) {\n queries.push({ EntityName: 'MJ: AI Agent Session Channels', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: CHANNEL_FIELDS, ResultType: 'simple' as const });\n }\n const [sessionResult, detailResult, runResult, channelResult] = await rv.RunViews(queries);\n const sessions = (sessionResult?.Success ? sessionResult.Results : []) as SessionRow[];\n const session = sessions[0] ?? null;\n if (!session) {\n return null;\n }\n return {\n session,\n details: (detailResult?.Success ? detailResult.Results : []) as DetailRow[],\n runs: (runResult?.Success ? runResult.Results : []) as RunRow[],\n channels: (channelResult?.Success ? channelResult.Results : []) as ChannelRow[]\n };\n }\n\n /**\n * Walks the `LastSessionID` chain BACKWARDS from the reviewed (primary) leg, collecting\n * raw leg rows OLDEST-FIRST (primary last). Safety rails:\n * - at most {@link MAX_REVIEW_LEGS} legs total;\n * - at most {@link MAX_REVIEW_DETAILS} caption rows across the chain — an older leg\n * whose details would overflow the budget is trimmed to its NEWEST rows and ends\n * the walk;\n * - a visited-set cycle guard (case-insensitive ids) so A→B→A can never loop;\n * - a leg that fails to load simply ends the walk (the collected legs still render).\n */\n private async collectChainLegs(primary: LegRows, provider: IMetadataProvider): Promise<LegRows[]> {\n const chain: LegRows[] = [primary];\n const visited = new Set<string>([this.normalizeID(primary.session.ID)]);\n let cursor = primary.session.LastSessionID ?? null;\n let detailBudget = MAX_REVIEW_DETAILS - primary.details.length;\n\n while (cursor && chain.length < MAX_REVIEW_LEGS && detailBudget > 0) {\n const key = this.normalizeID(cursor);\n if (visited.has(key)) {\n console.warn(`[RealtimeSessionReview] Session chain cycle detected at ${cursor} — stopping the walk.`);\n break;\n }\n visited.add(key);\n const leg = await this.loadLegRows(cursor, provider, false);\n if (!leg) {\n break;\n }\n if (leg.details.length > detailBudget) {\n // Keep this leg's NEWEST rows (details arrive oldest-first) and end the walk.\n leg.details = leg.details.slice(leg.details.length - detailBudget);\n detailBudget = 0;\n } else {\n detailBudget -= leg.details.length;\n }\n chain.unshift(leg);\n cursor = leg.session.LastSessionID ?? null;\n }\n return chain;\n }\n\n /**\n * Collects the chain's conversation-history ARTIFACTS: `MJ: Conversation Detail\n * Artifacts` junction rows (Direction `Output`) hanging off the chain's session-stamped\n * details, resolved through `MJ: Artifact Versions` to `{ArtifactID, ArtifactVersionID,\n * Name}` (version name, falling back to the artifact name). Order follows junction\n * creation; duplicate versions are deduped. TOLERANT: any failure returns `[]`.\n */\n private async loadChainArtifacts(chain: LegRows[], provider: IMetadataProvider): Promise<ParsedDelegationArtifact[]> {\n const detailIDs = chain.flatMap(leg => leg.details.map(d => d.ID)).filter(id => typeof id === 'string' && id.length > 0);\n if (detailIDs.length === 0) {\n return [];\n }\n try {\n const rv = RunView.FromMetadataProvider(provider);\n const detailList = detailIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [junctionResult] = await rv.RunViews([{\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${detailList}) AND Direction='Output'`,\n Fields: JUNCTION_FIELDS,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'simple'\n }]);\n const junctions = (junctionResult?.Success ? junctionResult.Results : []) as DetailArtifactJunctionRow[];\n const versionIDs = this.uniqueVersionIDs(junctions);\n if (versionIDs.length === 0) {\n return [];\n }\n\n const versionList = versionIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [versionResult] = await rv.RunViews([{\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionList})`,\n Fields: VERSION_FIELDS,\n ResultType: 'simple'\n }]);\n const versions = (versionResult?.Success ? versionResult.Results : []) as ArtifactVersionRow[];\n const byID = new Map<string, ArtifactVersionRow>(versions.map(v => [this.normalizeID(v.ID), v]));\n\n const artifacts: ParsedDelegationArtifact[] = [];\n for (const versionID of versionIDs) {\n const row = byID.get(this.normalizeID(versionID));\n if (!row?.ArtifactID) {\n continue; // junction points at an unreadable / deleted version — skip\n }\n artifacts.push({\n ArtifactID: row.ArtifactID,\n ArtifactVersionID: row.ID,\n Name: row.Name?.trim() || row.Artifact?.trim() || 'Artifact'\n });\n }\n return artifacts;\n } catch (error) {\n console.warn('[RealtimeSessionReview] Artifact collection failed — review renders without artifact tabs.', error);\n return [];\n }\n }\n\n /** Unique, non-empty `ArtifactVersionID`s from junction rows, in arrival order (case-insensitive dedupe). */\n private uniqueVersionIDs(junctions: DetailArtifactJunctionRow[]): string[] {\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const j of junctions) {\n const id = typeof j.ArtifactVersionID === 'string' ? j.ArtifactVersionID.trim() : '';\n if (id.length === 0 || seen.has(this.normalizeID(id))) {\n continue;\n }\n seen.add(this.normalizeID(id));\n ids.push(id);\n }\n return ids;\n }\n\n /** Case-insensitive UUID key for Set/Map membership (SQL Server uppercase vs PostgreSQL lowercase). */\n private normalizeID(id: string): string {\n return (id ?? '').trim().toLowerCase();\n }\n\n /**\n * Folds the chain's raw leg rows into the typed review. The PRIMARY (reviewed) leg —\n * the chain's LAST entry — supplies identity/lifecycle/channel state; turns and runs\n * are surfaced both per-leg (`Legs`) and flattened chronologically (`Turns` /\n * `DelegatedRuns`). Each leg excludes ITS OWN config's co-agent observability run.\n */\n private assembleReview(chain: LegRows[], artifacts: ParsedDelegationArtifact[]): RealtimeSessionReview {\n const primary = chain[chain.length - 1];\n const session = primary.session;\n const config = this.parseSessionConfig(session.Config);\n const legs = chain.map(leg => this.mapLeg(leg));\n return {\n SessionID: session.ID,\n AgentID: session.AgentID,\n AgentName: session.Agent || 'the agent',\n TargetAgentID: config.targetAgentID ?? session.AgentID,\n ConversationID: session.ConversationID ?? null,\n Status: session.Status,\n CloseReason: session.CloseReason ?? null,\n StartedAt: this.toDate(session.__mj_CreatedAt),\n LastActiveAt: this.toDate(session.LastActiveAt),\n ClosedAt: this.toDate(session.ClosedAt),\n RecordingFileID: session.RecordingFileID ?? null,\n RecordingStartedAt: this.toDate(session.RecordingStartedAt),\n RecordingMedia: session.RecordingMedia ?? null,\n Turns: legs.flatMap(l => l.Turns),\n DelegatedRuns: legs.flatMap(l => l.DelegatedRuns),\n DirectActions: legs.flatMap(l => l.DirectActions ?? []),\n // Multi-leg: newest leg with a SAVED state wins per channel — a final leg that\n // never touched the board no longer hides an earlier leg's drawing from review.\n ChannelStates: MergeChainChannelStates(chain.map(leg => this.mapChannels(leg.channels))),\n Legs: legs,\n Artifacts: artifacts\n };\n }\n\n /** Maps one leg's raw rows to the public leg shape (per-leg co-agent-run exclusion). */\n private mapLeg(leg: LegRows): RealtimeSessionReviewLeg {\n const config = this.parseSessionConfig(leg.session.Config);\n return {\n SessionID: leg.session.ID,\n StartedAt: this.toDate(leg.session.__mj_CreatedAt),\n ClosedAt: this.toDate(leg.session.ClosedAt),\n CloseReason: leg.session.CloseReason ?? null,\n Turns: this.mapTurns(leg.details),\n DelegatedRuns: this.mapRuns(leg.runs, config.coAgentRunID ?? null),\n DirectActions: this.mapDirectActions(leg.details)\n };\n }\n\n /** Hidden detail rows with realtime_tool_execution payload → direct-action reviews. */\n private mapDirectActions(details: DetailRow[]): RealtimeSessionReviewAction[] {\n const actions: RealtimeSessionReviewAction[] = [];\n for (const row of details) {\n if (!row.HiddenToUser || row.Role !== 'AI' || !row.Message) {\n continue;\n }\n try {\n const parsed = JSON.parse(row.Message) as {\n type?: string;\n callId?: string | null;\n toolName?: string;\n argsJson?: string | null;\n resultJson?: string | null;\n success?: boolean;\n durationMs?: number;\n };\n if (parsed && parsed.type === 'realtime_tool_execution' && typeof parsed.toolName === 'string') {\n const createdAt = this.toDate(row.__mj_CreatedAt);\n actions.push({\n ID: row.ID,\n CallID: parsed.callId || row.ExternalID || row.ID,\n ToolName: parsed.toolName,\n ArgsJson: parsed.argsJson ?? null,\n ResultJson: parsed.resultJson ?? null,\n Success: typeof parsed.success === 'boolean' ? parsed.success : (row.Status === 'Complete'),\n DurationMs: typeof parsed.durationMs === 'number' ? parsed.durationMs : (row.CompletionTime ?? 0),\n At: createdAt\n });\n }\n } catch {\n // Not a JSON fact payload — ignore\n }\n }\n return actions;\n }\n\n /** Persisted detail rows → caption turns: visible `User`/`AI` rows with text (AI → Assistant). */\n private mapTurns(details: DetailRow[]): RealtimeSessionReviewTurn[] {\n const turns: RealtimeSessionReviewTurn[] = [];\n for (const row of details) {\n const text = row.Message?.trim() ?? '';\n if (row.HiddenToUser || text.length === 0 || (row.Role !== 'User' && row.Role !== 'AI')) {\n continue;\n }\n const createdAt = this.toDate(row.__mj_CreatedAt);\n turns.push({\n ID: row.ID,\n Role: row.Role === 'AI' ? 'Assistant' : 'User',\n Text: text,\n Message: text,\n __mj_CreatedAt: createdAt,\n At: createdAt,\n UtteranceStartMs: row.UtteranceStartMs ?? null,\n UtteranceEndMs: row.UtteranceEndMs ?? null\n });\n }\n return turns;\n }\n\n /** Linked run rows → delegated-run previews, EXCLUDING the co-agent's observability run. */\n private mapRuns(runs: RunRow[], coAgentRunId: string | null): RealtimeSessionReviewRun[] {\n return runs\n .filter(r => !coAgentRunId || !UUIDsEqual(r.ID, coAgentRunId))\n .map(r => ({\n RunID: r.ID,\n AgentID: r.AgentID,\n AgentName: r.Agent ?? null,\n Status: r.Status ?? '',\n Success: r.Success === true,\n Message: r.Message ?? null,\n ErrorMessage: r.ErrorMessage ?? null,\n FinalStep: r.FinalStep ?? null,\n StartedAt: this.toDate(r.StartedAt),\n CompletedAt: this.toDate(r.CompletedAt)\n }));\n }\n\n /** Session-channel rows → named channel states (rows without a channel name are skipped). */\n private mapChannels(channels: ChannelRow[]): RealtimeSessionReviewChannelState[] {\n return channels\n .filter(c => !!c.Channel)\n .map(c => ({ ChannelName: c.Channel as string, StateJson: c.Config ?? null }));\n }\n\n /** Tolerant Config JSON parse — malformed/missing payloads degrade to `{}`. */\n private parseSessionConfig(raw: string | null): SessionConfigJson {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw) as SessionConfigJson;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n\n /** Tolerant date conversion — view rows arrive as ISO strings (or Dates from some providers). */\n private toDate(value: string | Date | null | undefined): Date | null {\n if (value == null) {\n return null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isNaN(date.getTime()) ? null : date;\n }\n}\n"]}
1
+ {"version":3,"file":"realtime-session-review.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { IMetadataProvider, Metadata, RunView, RunViewParams } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';\nimport { ParsedDelegationArtifact, FormatToolName } from '@memberjunction/realtime-runtime';\n\n/**\n * Why a reviewed session was closed, as stamped server-side by `SessionManager.CloseSession`\n * (mirrors `MJAIAgentSessionEntity.CloseReason`). `null` means the session is still open OR a\n * legacy row was closed before the column existed.\n */\nexport type RealtimeReviewCloseReason = 'Error' | 'Explicit' | 'Janitor' | 'Shutdown';\n\n/**\n * One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).\n *\n * Carries BOTH the thread-rendering fields (`Role`/`Text`/`At`) AND the raw fields the time-aligned\n * evidence player reads (`ID`, `Message`, `__mj_CreatedAt`, `UtteranceStartMs`, `UtteranceEndMs`) so\n * a review's turns can be handed straight to {@link RealtimeEvidencePlaybackComponent} for the\n * Recording tab — this shape structurally satisfies that player's `EvidencePlaybackTurn` input.\n */\nexport interface RealtimeSessionReviewTurn {\n /** `MJ: Conversation Details.ID` — the player's `@for` track key. */\n ID: string;\n /** Who spoke the turn. Persisted `AI` rows map to `Assistant`. */\n Role: 'User' | 'Assistant';\n /** The transcript text. */\n Text: string;\n /** The raw transcript text (mirrors {@link Text}) — the player reads `Message`. */\n Message: string | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. Aliases {@link At}. */\n __mj_CreatedAt: Date | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. */\n At: Date | null;\n /** Precise media-relative start (ms from recording t0), or null when the driver supplied no timing. */\n UtteranceStartMs: number | null;\n /** Precise media-relative end (ms from recording t0), or null. */\n UtteranceEndMs: number | null;\n}\n\n/**\n * A compact preview of one DELEGATED agent run the reviewed session spawned (an\n * `MJ: AI Agent Runs` row linked via `AgentSessionID`, EXCLUDING the co-agent's own\n * observability run). Carries just enough to render a done delegation card.\n */\nexport interface RealtimeSessionReviewRun {\n /** `MJ: AI Agent Runs.ID`. */\n RunID: string;\n /** The delegated agent's id. */\n AgentID: string;\n /** Denormalized agent display name from the run view, when available. */\n AgentName: string | null;\n /** Terminal (or last-known) run status (`Completed` | `Failed` | `Running` | …). */\n Status: string;\n /** Whether the run reported success. */\n Success: boolean;\n /** The run's user-facing result message, when one was recorded. */\n Message: string | null;\n /** The run's error message, when it failed. */\n ErrorMessage: string | null;\n /** The final step the run reported (`Success` | `Failed` | `Retry` | …), when known. */\n FinalStep: string | null;\n StartedAt: Date | null;\n CompletedAt: Date | null;\n}\n\n/** The persisted state of one interactive channel of the reviewed session. */\nexport interface RealtimeSessionReviewChannelState {\n /** Channel display name (e.g. `Whiteboard`), denormalized on the session-channel row. */\n ChannelName: string;\n /** The channel's serialized state of record (`AIAgentSessionChannel.Config`), or null when none was saved. */\n StateJson: string | null;\n}\n\n/**\n * MULTI-LEG channel-state merge: folds every leg's channel rows into one state set,\n * NEWEST leg wins per channel name — but only a leg that actually SAVED state counts.\n * A resumed session whose final leg never touched the whiteboard therefore still\n * reviews with the board an EARLIER leg drew (previously only the primary/newest leg's\n * rows were consulted, so that board silently vanished from review).\n *\n * @param legChannelStates Per-leg channel states, ordered OLDEST → NEWEST (the chain order).\n * @returns One entry per channel name (case-insensitive), each from the newest leg that\n * saved a non-empty state; channels no leg ever saved keep a null-state entry so the\n * review still knows the channel existed.\n */\nexport function MergeChainChannelStates(\n legChannelStates: ReadonlyArray<ReadonlyArray<RealtimeSessionReviewChannelState>>\n): RealtimeSessionReviewChannelState[] {\n const byName = new Map<string, RealtimeSessionReviewChannelState>();\n for (const leg of legChannelStates) {\n for (const state of leg) {\n const key = state.ChannelName.trim().toLowerCase();\n if (key.length === 0) {\n continue;\n }\n const existing = byName.get(key);\n const hasState = typeof state.StateJson === 'string' && state.StateJson.trim().length > 0;\n // Later legs are newer: a saved state always supersedes; a null/empty state only\n // registers the channel's existence and never clobbers an earlier saved board.\n if (!existing || hasState) {\n byName.set(key, hasState ? state : (existing ?? state));\n }\n }\n }\n return [...byName.values()];\n}\n\n/**\n * A direct action or channel tool execution performed during the reviewed session\n * (stored as a hidden `MJ: Conversation Details` turn with `type: 'realtime_tool_execution'`).\n */\nexport interface RealtimeSessionReviewAction {\n /** `MJ: Conversation Details.ID`. */\n ID: string;\n /** Correlated tool call id (`MJ: Conversation Details.ExternalID`), falling back to ID. */\n CallID: string;\n /** The tool/action name (e.g. `File_Storage_List_Objects` or `Whiteboard_draw_shape`). */\n ToolName: string;\n /** Serialized argument payload, when recorded. */\n ArgsJson: string | null;\n /** Serialized result payload, when recorded. */\n ResultJson: string | null;\n /** Whether the execution reported success. */\n Success: boolean;\n /** Execution duration in ms (`MJ: Conversation Details.CompletionTime`). */\n DurationMs: number;\n /** When the tool execution was recorded (`MJ: Conversation Details.__mj_CreatedAt`). */\n At: Date | null;\n}\n\n/**\n * One LEG of a reviewed session chain: a single `MJ: AI Agent Sessions` row plus its own\n * caption turns and delegated-run previews. A session resumed via `lastSessionId` chains\n * legs together (newest leg's `LastSessionID` → prior leg); the review loader walks that\n * chain BACKWARDS (capped — see the loader docs) so review mode can render the FULL\n * conversation arc chronologically, with a divider between legs.\n */\nexport interface RealtimeSessionReviewLeg {\n /** `MJ: AI Agent Sessions.ID` of this leg. */\n SessionID: string;\n /** When this leg started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n /** When this leg closed (null while still open). */\n ClosedAt: Date | null;\n /** Why this leg closed (null while open / legacy rows). */\n CloseReason: RealtimeReviewCloseReason | null;\n /** This leg's chronological caption turns (oldest first). */\n Turns: RealtimeSessionReviewTurn[];\n /** This leg's delegated-run previews (oldest first, minus its co-agent observability run). */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** This leg's direct action and channel tool executions. */\n DirectActions?: RealtimeSessionReviewAction[];\n}\n\n/**\n * Everything the call overlay's SESSION REVIEW mode renders for one past realtime session:\n * the session identity/lifecycle row, the chronological caption turns, previews of the\n * delegated runs, and the saved per-channel states (e.g. the whiteboard board).\n */\nexport interface RealtimeSessionReview {\n /** `MJ: AI Agent Sessions.ID` of the reviewed session. */\n SessionID: string;\n /** The session's fronting agent id (`AIAgentSession.AgentID` — usually the Realtime Co-Agent). */\n AgentID: string;\n /** Display name shown in the review banner (target agent when resolvable, else the session agent). */\n AgentName: string;\n /**\n * The agent a RESUMED live session should front: the session Config's `targetAgentID`,\n * falling back to the session's own `AgentID` when the config doesn't carry one.\n */\n TargetAgentID: string;\n /** Conversation the session was bound to, when any. */\n ConversationID: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n CloseReason: RealtimeReviewCloseReason | null;\n /** When the session started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n LastActiveAt: Date | null;\n ClosedAt: Date | null;\n /**\n * The `MJ: Files` id of the reviewed session's recorded audio, or null when nothing was recorded.\n * When set, review mode resolves a signed download URL and shows a Recording tab with the\n * time-aligned evidence player. From the PRIMARY (reviewed) leg only.\n */\n RecordingFileID: string | null;\n /** Recording alignment origin (t0), used by the playback transcript sync. From the primary leg. */\n RecordingStartedAt: Date | null;\n /** What was captured (`Audio` / `AudioVideo`), or null. From the primary leg. */\n RecordingMedia: string | null;\n /** Chronological caption turns (oldest first) — ALL legs of the chain, flattened. */\n Turns: RealtimeSessionReviewTurn[];\n /** Delegated run previews (oldest first, all legs), minus each leg's co-agent observability run. */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** Direct action and channel tool executions (oldest first, all legs). */\n DirectActions?: RealtimeSessionReviewAction[];\n /**\n * Saved channel states, one per session-channel row that carried a name. Channel state\n * (e.g. the whiteboard board) is the LATEST leg's only — earlier legs' states were\n * superseded when the chain resumed.\n */\n ChannelStates: RealtimeSessionReviewChannelState[];\n /**\n * The session-chain LEGS, chronological (oldest first; the LAST leg is the reviewed\n * session itself). Single-session reviews carry exactly one leg. Drives the per-leg\n * dividers `BuildReviewThreadItems` renders.\n */\n Legs: RealtimeSessionReviewLeg[];\n /**\n * ARTIFACTS attached to the chain's conversation history: every `MJ: Conversation\n * Detail Artifacts` junction (Direction `Output`) hanging off the chain's\n * session-stamped `Conversation Details`, resolved to `{ArtifactID, ArtifactVersionID,\n * Name}`. Review mode registers each as an (unfocused) artifact tab on the surface\n * panel, and they carry into a resumed live session. Empty when none / on any\n * tolerated load failure.\n */\n Artifacts: ParsedDelegationArtifact[];\n}\n\n// ── Raw row shapes (ResultType: 'simple', narrowed Fields) ──────────────────\n\ninterface SessionRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n ConversationID: string | null;\n Config: string | null;\n LastSessionID: string | null;\n LastActiveAt: string | null;\n ClosedAt: string | null;\n CloseReason: RealtimeReviewCloseReason | null;\n RecordingFileID: string | null;\n RecordingStartedAt: string | null;\n RecordingMedia: string | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface DetailRow {\n ID: string;\n Role: 'AI' | 'Error' | 'User';\n Message: string | null;\n HiddenToUser: boolean;\n UserID: string | null;\n Status: string | null;\n ExternalID?: string | null;\n CompletionTime?: number | null;\n UtteranceStartMs: number | null;\n UtteranceEndMs: number | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface RunRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: string;\n Success: boolean | null;\n Message: string | null;\n ErrorMessage: string | null;\n FinalStep: string | null;\n StartedAt: string | null;\n CompletedAt: string | null;\n}\n\ninterface ChannelRow {\n ID: string;\n Channel: string | null;\n Config: string | null;\n}\n\ninterface DetailArtifactJunctionRow {\n ID: string;\n ConversationDetailID: string;\n ArtifactVersionID: string | null;\n}\n\ninterface ArtifactVersionRow {\n ID: string;\n ArtifactID: string;\n /** Version display name (nullable on the row). */\n Name: string | null;\n /** Denormalized parent-artifact name from the version view. */\n Artifact: string | null;\n}\n\n/** The raw rows of ONE chain leg, before mapping to the public review shapes. */\ninterface LegRows {\n session: SessionRow;\n details: DetailRow[];\n runs: RunRow[];\n channels: ChannelRow[];\n}\n\n/** The Config-JSON keys the realtime voice stack persists on `AIAgentSession.Config`. */\ninterface SessionConfigJson {\n targetAgentID?: string;\n coAgentRunID?: string;\n}\n\nconst SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', 'RecordingFileID', 'RecordingStartedAt', 'RecordingMedia', '__mj_CreatedAt'];\nconst DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', 'UserID', 'Status', 'ExternalID', 'CompletionTime', 'UtteranceStartMs', 'UtteranceEndMs', '__mj_CreatedAt'];\nconst RUN_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'Success', 'Message', 'ErrorMessage', 'FinalStep', 'StartedAt', 'CompletedAt'];\nconst CHANNEL_FIELDS = ['ID', 'Channel', 'Config'];\nconst JUNCTION_FIELDS = ['ID', 'ConversationDetailID', 'ArtifactVersionID'];\nconst VERSION_FIELDS = ['ID', 'ArtifactID', 'Name', 'Artifact'];\n\n/** Maximum number of chain legs the review loader walks (the reviewed session included). */\nexport const MAX_REVIEW_LEGS = 5;\n/** Maximum total caption-detail rows loaded across the whole chain (oldest legs trimmed first). */\nexport const MAX_REVIEW_DETAILS = 500;\n\n// ── Review → thread-item mapping (pure, unit-testable) ──────────────────────\n\n/** Maps one delegated-run preview to the done delegation-card VM the thread/rail render. */\nexport function BuildReviewDelegationCard(run: RealtimeSessionReviewRun, fallbackAgentName: string): RealtimeDelegationCardVM {\n const startedAt = run.StartedAt?.getTime() ?? 0;\n return {\n Kind: 'agent',\n CallID: run.RunID,\n AgentName: run.AgentName || fallbackAgentName,\n LatestMessage: run.Message ?? run.ErrorMessage ?? run.Status,\n LatestStep: run.FinalStep ?? '',\n Done: true,\n Success: run.Success,\n RunRef: shortRunRef(run.RunID),\n RunID: run.RunID,\n Result: run.Message ?? run.ErrorMessage ?? null,\n StartedAt: startedAt,\n FinishedAt: run.CompletedAt?.getTime() ?? startedAt\n };\n}\n\n/** Maps one direct-action execution to the done action-card VM the thread/rail render. */\nexport function BuildReviewActionCard(action: RealtimeSessionReviewAction): RealtimeDelegationCardVM {\n const at = action.At?.getTime() ?? 0;\n const toolTitle = FormatToolName(action.ToolName);\n return {\n Kind: 'action',\n CallID: action.CallID,\n ToolName: action.ToolName,\n AgentName: toolTitle,\n LatestMessage: `Executed ${toolTitle}`,\n LatestStep: 'direct_action',\n Done: true,\n Success: action.Success,\n RunRef: shortRunRef(action.CallID),\n Result: action.ResultJson,\n StartedAt: at,\n FinishedAt: at + action.DurationMs\n };\n}\n\n/**\n * Builds the chronological thread (caption turns + done delegation cards + done action cards, oldest first)\n * for a reviewed session — the items `RealtimeSessionState.LoadHistoricalItems` takes.\n *\n * CHAIN-AWARE: when the review carries multiple {@link RealtimeSessionReview.Legs}, each\n * leg's items render in leg order with a `divider` item between legs (\"Session leg\n * started · <time>\", carrying the PREVIOUS leg's CloseReason as a chip). A single-leg\n * review (or a legless legacy shape) renders the flat thread with no divider —\n * byte-identical to the pre-chain behavior.\n */\nexport function BuildReviewThreadItems(review: RealtimeSessionReview): RealtimeThreadItem[] {\n const legs = review.Legs ?? [];\n if (legs.length <= 1) {\n const only = legs[0];\n return buildLegThreadItems(\n only?.Turns ?? review.Turns,\n only?.DelegatedRuns ?? review.DelegatedRuns,\n only?.DirectActions ?? review.DirectActions ?? [],\n review.AgentName\n );\n }\n const items: RealtimeThreadItem[] = [];\n legs.forEach((leg, i) => {\n if (i > 0) {\n items.push({\n Kind: 'divider',\n Label: 'Session leg started',\n At: leg.StartedAt,\n Icon: 'fa-solid fa-arrows-rotate',\n CloseReason: legs[i - 1].CloseReason ?? null\n });\n }\n items.push(...buildLegThreadItems(leg.Turns, leg.DelegatedRuns, leg.DirectActions ?? [], review.AgentName));\n });\n return items;\n}\n\n/**\n * Builds ONE leg's chronological items (caption turns + done delegation cards + done action cards,\n * oldest first). Entries without a timestamp sort to the front, preserving their relative order.\n */\nfunction buildLegThreadItems(\n turns: RealtimeSessionReviewTurn[],\n runs: RealtimeSessionReviewRun[],\n actions: RealtimeSessionReviewAction[],\n fallbackAgentName: string\n): RealtimeThreadItem[] {\n const stamped: Array<{ At: number; Item: RealtimeThreadItem }> = [];\n for (const turn of turns) {\n stamped.push({ At: turn.At?.getTime() ?? 0, Item: { Kind: 'caption', Role: turn.Role, Text: turn.Text } });\n }\n for (const run of runs) {\n stamped.push({ At: run.StartedAt?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewDelegationCard(run, fallbackAgentName) } });\n }\n for (const action of actions) {\n stamped.push({ At: action.At?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewActionCard(action) } });\n }\n // Array.prototype.sort is stable — equal timestamps keep their build order.\n stamped.sort((a, b) => a.At - b.At);\n return stamped.map(s => s.Item);\n}\n\n/** Derives a short run reference (e.g. \"#a3f1\") from the run id — mirrors the live cards. */\nfunction shortRunRef(runId: string): string {\n const compact = runId.replace(/[^a-z0-9]/gi, '');\n return compact.length >= 4 ? `#${compact.slice(-4).toLowerCase()}` : `#${compact.toLowerCase()}`;\n}\n\n/**\n * STATELESS loader for the call overlay's SESSION REVIEW mode: given a past\n * `MJ: AI Agent Sessions` id, batch-loads the session row, its persisted caption turns\n * (`MJ: Conversation Details` linked by `AgentSessionID`), its delegated agent runs\n * (minus the co-agent observability run named in the session Config's `coAgentRunID`),\n * and its saved channel states — and folds them into one {@link RealtimeSessionReview}.\n *\n * CHAIN-AWARE: when the reviewed session carries a `LastSessionID` (it RESUMED an earlier\n * session), the loader walks the chain BACKWARDS — capped at {@link MAX_REVIEW_LEGS} legs\n * and {@link MAX_REVIEW_DETAILS} caption rows total (oldest legs trimmed first), with a\n * cycle guard so a corrupt A→B→A chain can never loop — and surfaces ALL legs\n * chronologically on {@link RealtimeSessionReview.Legs}. Channel state stays the\n * reviewed (latest) leg's only. The chain's conversation-history ARTIFACTS (junction\n * rows on the session-stamped details) are collected onto\n * {@link RealtimeSessionReview.Artifacts}.\n *\n * TOLERANT by design: any missing piece degrades to an empty collection; the loader\n * returns `null` only when the reviewed session row itself can't be found.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionReviewService {\n /**\n * Loads everything review mode renders for one past session (and its prior-leg chain).\n *\n * @param agentSessionId The `MJ: AI Agent Sessions.ID` to review.\n * @param provider Optional metadata provider (multi-server apps); falls back to the global default.\n * @returns The assembled review, or `null` when the session doesn't exist / can't be read.\n */\n public async LoadSessionReview(agentSessionId: string, provider?: IMetadataProvider): Promise<RealtimeSessionReview | null> {\n const trimmed = agentSessionId?.trim() ?? '';\n if (trimmed.length === 0) {\n return null;\n }\n try {\n const md = provider ?? Metadata.Provider;\n const primary = await this.loadLegRows(trimmed, md, true);\n if (!primary) {\n return null;\n }\n const chain = await this.collectChainLegs(primary, md);\n const artifacts = await this.loadChainArtifacts(chain, md);\n return this.assembleReview(chain, artifacts);\n } catch (error) {\n console.error('[RealtimeSessionReview] Failed to load session review:', error);\n return null;\n }\n }\n\n /**\n * One batched RunViews pass for one chain leg: session row + caption turns + linked\n * runs (+ channel rows for the PRIMARY leg only — channel state is latest-leg-only).\n * Returns `null` when the session row can't be found.\n */\n private async loadLegRows(\n agentSessionId: string,\n provider: IMetadataProvider,\n includeChannels: boolean\n ): Promise<LegRows | null> {\n const safeID = agentSessionId.replace(/'/g, \"''\");\n const rv = RunView.FromMetadataProvider(provider);\n const queries: RunViewParams[] = [\n { EntityName: 'MJ: AI Agent Sessions', ExtraFilter: `ID='${safeID}'`, Fields: SESSION_FIELDS, ResultType: 'simple' as const },\n {\n EntityName: 'MJ: Conversation Details', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: DETAIL_FIELDS,\n OrderBy: '__mj_CreatedAt ASC', MaxRows: MAX_REVIEW_DETAILS, ResultType: 'simple' as const\n },\n { EntityName: 'MJ: AI Agent Runs', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: RUN_FIELDS, OrderBy: 'StartedAt ASC', ResultType: 'simple' as const }\n ];\n if (includeChannels) {\n queries.push({ EntityName: 'MJ: AI Agent Session Channels', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: CHANNEL_FIELDS, ResultType: 'simple' as const });\n }\n const [sessionResult, detailResult, runResult, channelResult] = await rv.RunViews(queries);\n const sessions = (sessionResult?.Success ? sessionResult.Results : []) as SessionRow[];\n const session = sessions[0] ?? null;\n if (!session) {\n return null;\n }\n return {\n session,\n details: (detailResult?.Success ? detailResult.Results : []) as DetailRow[],\n runs: (runResult?.Success ? runResult.Results : []) as RunRow[],\n channels: (channelResult?.Success ? channelResult.Results : []) as ChannelRow[]\n };\n }\n\n /**\n * Walks the `LastSessionID` chain BACKWARDS from the reviewed (primary) leg, collecting\n * raw leg rows OLDEST-FIRST (primary last). Safety rails:\n * - at most {@link MAX_REVIEW_LEGS} legs total;\n * - at most {@link MAX_REVIEW_DETAILS} caption rows across the chain — an older leg\n * whose details would overflow the budget is trimmed to its NEWEST rows and ends\n * the walk;\n * - a visited-set cycle guard (case-insensitive ids) so A→B→A can never loop;\n * - a leg that fails to load simply ends the walk (the collected legs still render).\n */\n private async collectChainLegs(primary: LegRows, provider: IMetadataProvider): Promise<LegRows[]> {\n const chain: LegRows[] = [primary];\n const visited = new Set<string>([this.normalizeID(primary.session.ID)]);\n let cursor = primary.session.LastSessionID ?? null;\n let detailBudget = MAX_REVIEW_DETAILS - primary.details.length;\n\n while (cursor && chain.length < MAX_REVIEW_LEGS && detailBudget > 0) {\n const key = this.normalizeID(cursor);\n if (visited.has(key)) {\n console.warn(`[RealtimeSessionReview] Session chain cycle detected at ${cursor} — stopping the walk.`);\n break;\n }\n visited.add(key);\n const leg = await this.loadLegRows(cursor, provider, false);\n if (!leg) {\n break;\n }\n if (leg.details.length > detailBudget) {\n // Keep this leg's NEWEST rows (details arrive oldest-first) and end the walk.\n leg.details = leg.details.slice(leg.details.length - detailBudget);\n detailBudget = 0;\n } else {\n detailBudget -= leg.details.length;\n }\n chain.unshift(leg);\n cursor = leg.session.LastSessionID ?? null;\n }\n return chain;\n }\n\n /**\n * Collects the chain's conversation-history ARTIFACTS: `MJ: Conversation Detail\n * Artifacts` junction rows (Direction `Output`) hanging off the chain's session-stamped\n * details, resolved through `MJ: Artifact Versions` to `{ArtifactID, ArtifactVersionID,\n * Name}` (version name, falling back to the artifact name). Order follows junction\n * creation; duplicate versions are deduped. TOLERANT: any failure returns `[]`.\n */\n private async loadChainArtifacts(chain: LegRows[], provider: IMetadataProvider): Promise<ParsedDelegationArtifact[]> {\n const detailIDs = chain.flatMap(leg => leg.details.map(d => d.ID)).filter(id => typeof id === 'string' && id.length > 0);\n if (detailIDs.length === 0) {\n return [];\n }\n try {\n const rv = RunView.FromMetadataProvider(provider);\n const detailList = detailIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [junctionResult] = await rv.RunViews([{\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${detailList}) AND Direction='Output'`,\n Fields: JUNCTION_FIELDS,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'simple'\n }]);\n const junctions = (junctionResult?.Success ? junctionResult.Results : []) as DetailArtifactJunctionRow[];\n const versionIDs = this.uniqueVersionIDs(junctions);\n if (versionIDs.length === 0) {\n return [];\n }\n\n const versionList = versionIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [versionResult] = await rv.RunViews([{\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionList})`,\n Fields: VERSION_FIELDS,\n ResultType: 'simple'\n }]);\n const versions = (versionResult?.Success ? versionResult.Results : []) as ArtifactVersionRow[];\n const byID = new Map<string, ArtifactVersionRow>(versions.map(v => [this.normalizeID(v.ID), v]));\n\n const artifacts: ParsedDelegationArtifact[] = [];\n for (const versionID of versionIDs) {\n const row = byID.get(this.normalizeID(versionID));\n if (!row?.ArtifactID) {\n continue; // junction points at an unreadable / deleted version — skip\n }\n artifacts.push({\n ArtifactID: row.ArtifactID,\n ArtifactVersionID: row.ID,\n Name: row.Name?.trim() || row.Artifact?.trim() || 'Artifact'\n });\n }\n return artifacts;\n } catch (error) {\n console.warn('[RealtimeSessionReview] Artifact collection failed — review renders without artifact tabs.', error);\n return [];\n }\n }\n\n /** Unique, non-empty `ArtifactVersionID`s from junction rows, in arrival order (case-insensitive dedupe). */\n private uniqueVersionIDs(junctions: DetailArtifactJunctionRow[]): string[] {\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const j of junctions) {\n const id = typeof j.ArtifactVersionID === 'string' ? j.ArtifactVersionID.trim() : '';\n if (id.length === 0 || seen.has(this.normalizeID(id))) {\n continue;\n }\n seen.add(this.normalizeID(id));\n ids.push(id);\n }\n return ids;\n }\n\n /** Case-insensitive UUID key for Set/Map membership (SQL Server uppercase vs PostgreSQL lowercase). */\n private normalizeID(id: string): string {\n return (id ?? '').trim().toLowerCase();\n }\n\n /**\n * Folds the chain's raw leg rows into the typed review. The PRIMARY (reviewed) leg —\n * the chain's LAST entry — supplies identity/lifecycle/channel state; turns and runs\n * are surfaced both per-leg (`Legs`) and flattened chronologically (`Turns` /\n * `DelegatedRuns`). Each leg excludes ITS OWN config's co-agent observability run.\n */\n private assembleReview(chain: LegRows[], artifacts: ParsedDelegationArtifact[]): RealtimeSessionReview {\n const primary = chain[chain.length - 1];\n const session = primary.session;\n const config = this.parseSessionConfig(session.Config);\n const legs = chain.map(leg => this.mapLeg(leg));\n return {\n SessionID: session.ID,\n AgentID: session.AgentID,\n AgentName: session.Agent || 'the agent',\n TargetAgentID: config.targetAgentID ?? session.AgentID,\n ConversationID: session.ConversationID ?? null,\n Status: session.Status,\n CloseReason: session.CloseReason ?? null,\n StartedAt: this.toDate(session.__mj_CreatedAt),\n LastActiveAt: this.toDate(session.LastActiveAt),\n ClosedAt: this.toDate(session.ClosedAt),\n RecordingFileID: session.RecordingFileID ?? null,\n RecordingStartedAt: this.toDate(session.RecordingStartedAt),\n RecordingMedia: session.RecordingMedia ?? null,\n Turns: legs.flatMap(l => l.Turns),\n DelegatedRuns: legs.flatMap(l => l.DelegatedRuns),\n DirectActions: legs.flatMap(l => l.DirectActions ?? []),\n // Multi-leg: newest leg with a SAVED state wins per channel — a final leg that\n // never touched the board no longer hides an earlier leg's drawing from review.\n ChannelStates: MergeChainChannelStates(chain.map(leg => this.mapChannels(leg.channels))),\n Legs: legs,\n Artifacts: artifacts\n };\n }\n\n /** Maps one leg's raw rows to the public leg shape (per-leg co-agent-run exclusion). */\n private mapLeg(leg: LegRows): RealtimeSessionReviewLeg {\n const config = this.parseSessionConfig(leg.session.Config);\n return {\n SessionID: leg.session.ID,\n StartedAt: this.toDate(leg.session.__mj_CreatedAt),\n ClosedAt: this.toDate(leg.session.ClosedAt),\n CloseReason: leg.session.CloseReason ?? null,\n Turns: this.mapTurns(leg.details),\n DelegatedRuns: this.mapRuns(leg.runs, config.coAgentRunID ?? null),\n DirectActions: this.mapDirectActions(leg.details)\n };\n }\n\n /** Hidden detail rows with realtime_tool_execution payload → direct-action reviews. */\n private mapDirectActions(details: DetailRow[]): RealtimeSessionReviewAction[] {\n const actions: RealtimeSessionReviewAction[] = [];\n for (const row of details) {\n if (!row.HiddenToUser || row.Role !== 'AI' || !row.Message) {\n continue;\n }\n try {\n const parsed = JSON.parse(row.Message) as {\n type?: string;\n callId?: string | null;\n toolName?: string;\n argsJson?: string | null;\n resultJson?: string | null;\n success?: boolean;\n durationMs?: number;\n };\n if (parsed && parsed.type === 'realtime_tool_execution' && typeof parsed.toolName === 'string') {\n const createdAt = this.toDate(row.__mj_CreatedAt);\n actions.push({\n ID: row.ID,\n CallID: parsed.callId || row.ExternalID || row.ID,\n ToolName: parsed.toolName,\n ArgsJson: parsed.argsJson ?? null,\n ResultJson: parsed.resultJson ?? null,\n Success: typeof parsed.success === 'boolean' ? parsed.success : (row.Status === 'Complete'),\n DurationMs: typeof parsed.durationMs === 'number' ? parsed.durationMs : (row.CompletionTime ?? 0),\n At: createdAt\n });\n }\n } catch {\n // Not a JSON fact payload — ignore\n }\n }\n return actions;\n }\n\n /** Persisted detail rows → caption turns: visible `User`/`AI` rows with text (AI → Assistant). */\n private mapTurns(details: DetailRow[]): RealtimeSessionReviewTurn[] {\n const turns: RealtimeSessionReviewTurn[] = [];\n for (const row of details) {\n const text = row.Message?.trim() ?? '';\n if (row.HiddenToUser || text.length === 0 || (row.Role !== 'User' && row.Role !== 'AI')) {\n continue;\n }\n const createdAt = this.toDate(row.__mj_CreatedAt);\n turns.push({\n ID: row.ID,\n Role: row.Role === 'AI' ? 'Assistant' : 'User',\n Text: text,\n Message: text,\n __mj_CreatedAt: createdAt,\n At: createdAt,\n UtteranceStartMs: row.UtteranceStartMs ?? null,\n UtteranceEndMs: row.UtteranceEndMs ?? null\n });\n }\n return turns;\n }\n\n /** Linked run rows → delegated-run previews, EXCLUDING the co-agent's observability run. */\n private mapRuns(runs: RunRow[], coAgentRunId: string | null): RealtimeSessionReviewRun[] {\n return runs\n .filter(r => !coAgentRunId || !UUIDsEqual(r.ID, coAgentRunId))\n .map(r => ({\n RunID: r.ID,\n AgentID: r.AgentID,\n AgentName: r.Agent ?? null,\n Status: r.Status ?? '',\n Success: r.Success === true,\n Message: r.Message ?? null,\n ErrorMessage: r.ErrorMessage ?? null,\n FinalStep: r.FinalStep ?? null,\n StartedAt: this.toDate(r.StartedAt),\n CompletedAt: this.toDate(r.CompletedAt)\n }));\n }\n\n /** Session-channel rows → named channel states (rows without a channel name are skipped). */\n private mapChannels(channels: ChannelRow[]): RealtimeSessionReviewChannelState[] {\n return channels\n .filter(c => !!c.Channel)\n .map(c => ({ ChannelName: c.Channel as string, StateJson: c.Config ?? null }));\n }\n\n /** Tolerant Config JSON parse — malformed/missing payloads degrade to `{}`. */\n private parseSessionConfig(raw: string | null): SessionConfigJson {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw) as SessionConfigJson;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n\n /** Tolerant date conversion — view rows arrive as ISO strings (or Dates from some providers). */\n private toDate(value: string | Date | null | undefined): Date | null {\n if (value == null) {\n return null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isNaN(date.getTime()) ? null : date;\n }\n}\n"]}