@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.5

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 (318) hide show
  1. package/README.md +33 -7
  2. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  3. package/dist/lib/components/collection/collection-view.component.js +1 -0
  4. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  5. package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
  6. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
  7. package/dist/lib/components/composer/ai-composer.component.js +35 -4
  8. package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
  9. package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +1 -1
  10. package/dist/lib/components/conversation/conversation-agent-picker.component.js +3 -3
  11. package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
  12. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +651 -53
  13. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  14. package/dist/lib/components/conversation/conversation-chat-area.component.js +3002 -661
  15. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  16. package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
  17. package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
  18. package/dist/lib/components/conversation/forks-popover.component.js +164 -0
  19. package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
  20. package/dist/lib/components/export/export-modal.component.d.ts +7 -2
  21. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  22. package/dist/lib/components/export/export-modal.component.js +16 -3
  23. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  24. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  25. package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
  26. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  27. package/dist/lib/components/message/message-input.component.d.ts +96 -11
  28. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  29. package/dist/lib/components/message/message-input.component.js +253 -112
  30. package/dist/lib/components/message/message-input.component.js.map +1 -1
  31. package/dist/lib/components/message/message-item.component.d.ts +304 -16
  32. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  33. package/dist/lib/components/message/message-item.component.js +2029 -363
  34. package/dist/lib/components/message/message-item.component.js.map +1 -1
  35. package/dist/lib/components/message/message-list.component.d.ts +101 -22
  36. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  37. package/dist/lib/components/message/message-list.component.js +326 -55
  38. package/dist/lib/components/message/message-list.component.js.map +1 -1
  39. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
  40. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
  41. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
  42. package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
  43. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
  44. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
  45. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
  46. package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
  47. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
  48. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
  49. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
  50. package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
  51. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
  52. package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
  53. package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
  54. package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
  55. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
  56. package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
  57. package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
  58. package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
  59. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
  60. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
  61. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
  62. package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
  63. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
  64. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  65. package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
  66. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  67. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
  68. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  69. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
  70. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  71. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
  72. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
  73. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
  74. package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
  75. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
  76. package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
  77. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
  78. package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
  79. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
  80. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
  81. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
  82. package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
  83. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
  84. package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
  85. package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
  86. package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
  87. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
  88. package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
  89. package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
  90. package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
  91. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
  92. package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
  93. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
  94. package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
  95. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
  96. package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
  97. package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
  98. package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
  99. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
  100. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
  101. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
  102. package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
  103. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
  104. package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
  105. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
  106. package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
  107. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
  108. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
  109. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
  110. package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
  111. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
  112. package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
  113. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
  114. package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
  115. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
  116. package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
  117. package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
  118. package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
  119. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
  120. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
  121. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
  122. package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
  123. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
  124. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
  125. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
  126. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
  127. package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
  128. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  129. package/dist/lib/components/realtime/media/media-channel.js +28 -1
  130. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  131. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
  132. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  133. package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
  134. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  135. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
  136. package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
  137. package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
  138. package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
  139. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
  140. package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
  141. package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
  142. package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
  143. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
  144. package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
  145. package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
  146. package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
  147. package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
  148. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  149. package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
  150. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  151. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
  152. package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
  153. package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
  154. package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
  155. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
  156. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  157. package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
  158. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  159. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
  160. package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
  161. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
  162. package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
  163. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
  164. package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
  165. package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
  166. package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
  167. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
  168. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  169. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
  170. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  171. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
  172. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  173. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
  174. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  175. package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
  176. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  177. package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
  178. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  179. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
  180. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  181. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
  182. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  183. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
  184. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
  185. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
  186. package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
  187. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
  188. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  189. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
  190. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  191. package/dist/lib/components/search/search-panel.component.d.ts +2 -0
  192. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  193. package/dist/lib/components/search/search-panel.component.js +25 -12
  194. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  195. package/dist/lib/components/sidebar/routines-section.component.js +1 -1
  196. package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
  197. package/dist/lib/components/task/tasks-full-view.component.d.ts +152 -31
  198. package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
  199. package/dist/lib/components/task/tasks-full-view.component.js +2227 -214
  200. package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
  201. package/dist/lib/components/tasks/tasks-dropdown.component.js +4 -4
  202. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  203. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +33 -32
  204. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  205. package/dist/lib/components/workspace/conversation-workspace.component.js +72 -88
  206. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  207. package/dist/lib/conversations.module.d.ts +30 -29
  208. package/dist/lib/conversations.module.d.ts.map +1 -1
  209. package/dist/lib/conversations.module.js +27 -5
  210. package/dist/lib/conversations.module.js.map +1 -1
  211. package/dist/lib/events/chat-events.d.ts +25 -0
  212. package/dist/lib/events/chat-events.d.ts.map +1 -1
  213. package/dist/lib/events/chat-events.js +36 -0
  214. package/dist/lib/events/chat-events.js.map +1 -1
  215. package/dist/lib/models/agent-turn.model.d.ts +5 -0
  216. package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
  217. package/dist/lib/models/agent-turn.model.js.map +1 -1
  218. package/dist/lib/services/agent-state.service.d.ts +34 -8
  219. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  220. package/dist/lib/services/agent-state.service.js +90 -37
  221. package/dist/lib/services/agent-state.service.js.map +1 -1
  222. package/dist/lib/services/artifact-state.service.d.ts +0 -9
  223. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  224. package/dist/lib/services/artifact-state.service.js +1 -32
  225. package/dist/lib/services/artifact-state.service.js.map +1 -1
  226. package/dist/lib/services/browser-realtime-media-host.d.ts +19 -7
  227. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
  228. package/dist/lib/services/browser-realtime-media-host.js +21 -72
  229. package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
  230. package/dist/lib/services/conversation-agent.service.d.ts +48 -16
  231. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  232. package/dist/lib/services/conversation-agent.service.js +110 -35
  233. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  234. package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
  235. package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
  236. package/dist/lib/services/conversation-detail-window.store.js +50 -9
  237. package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
  238. package/dist/lib/services/conversation-naming.d.ts +72 -22
  239. package/dist/lib/services/conversation-naming.d.ts.map +1 -1
  240. package/dist/lib/services/conversation-naming.js +93 -12
  241. package/dist/lib/services/conversation-naming.js.map +1 -1
  242. package/dist/lib/services/conversation-tasks-filter.d.ts +15 -0
  243. package/dist/lib/services/conversation-tasks-filter.d.ts.map +1 -0
  244. package/dist/lib/services/conversation-tasks-filter.js +69 -0
  245. package/dist/lib/services/conversation-tasks-filter.js.map +1 -0
  246. package/dist/lib/services/data-cache.service.d.ts +13 -5
  247. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  248. package/dist/lib/services/data-cache.service.js +39 -19
  249. package/dist/lib/services/data-cache.service.js.map +1 -1
  250. package/dist/lib/services/export.service.d.ts +26 -9
  251. package/dist/lib/services/export.service.d.ts.map +1 -1
  252. package/dist/lib/services/export.service.js +61 -18
  253. package/dist/lib/services/export.service.js.map +1 -1
  254. package/dist/lib/services/realtime-audio-recorder.d.ts +115 -79
  255. package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
  256. package/dist/lib/services/realtime-audio-recorder.js +273 -186
  257. package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
  258. package/dist/lib/services/realtime-pairing.d.ts +10 -5
  259. package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
  260. package/dist/lib/services/realtime-pairing.js +15 -6
  261. package/dist/lib/services/realtime-pairing.js.map +1 -1
  262. package/dist/lib/services/realtime-session.service.d.ts +31 -2
  263. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  264. package/dist/lib/services/realtime-session.service.js +34 -2
  265. package/dist/lib/services/realtime-session.service.js.map +1 -1
  266. package/dist/lib/services/recording/libopus-wasm-binary.d.ts +3 -0
  267. package/dist/lib/services/recording/libopus-wasm-binary.d.ts.map +1 -0
  268. package/dist/lib/services/recording/libopus-wasm-binary.js +489 -0
  269. package/dist/lib/services/recording/libopus-wasm-binary.js.map +1 -0
  270. package/dist/lib/services/recording/libopus-worker-source.d.ts +48 -0
  271. package/dist/lib/services/recording/libopus-worker-source.d.ts.map +1 -0
  272. package/dist/lib/services/recording/libopus-worker-source.js +170 -0
  273. package/dist/lib/services/recording/libopus-worker-source.js.map +1 -0
  274. package/dist/lib/services/recording/linear-resampler.d.ts +45 -0
  275. package/dist/lib/services/recording/linear-resampler.d.ts.map +1 -0
  276. package/dist/lib/services/recording/linear-resampler.js +85 -0
  277. package/dist/lib/services/recording/linear-resampler.js.map +1 -0
  278. package/dist/lib/services/recording/opus-packet-encoder.d.ts +50 -0
  279. package/dist/lib/services/recording/opus-packet-encoder.d.ts.map +1 -0
  280. package/dist/lib/services/recording/opus-packet-encoder.js +41 -0
  281. package/dist/lib/services/recording/opus-packet-encoder.js.map +1 -0
  282. package/dist/lib/services/recording/wasm-opus-encoder.d.ts +86 -0
  283. package/dist/lib/services/recording/wasm-opus-encoder.d.ts.map +1 -0
  284. package/dist/lib/services/recording/wasm-opus-encoder.js +232 -0
  285. package/dist/lib/services/recording/wasm-opus-encoder.js.map +1 -0
  286. package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts +39 -0
  287. package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts.map +1 -0
  288. package/dist/lib/services/recording/webcodecs-opus-encoder.js +101 -0
  289. package/dist/lib/services/recording/webcodecs-opus-encoder.js.map +1 -0
  290. package/dist/lib/services/search.service.d.ts +7 -2
  291. package/dist/lib/services/search.service.d.ts.map +1 -1
  292. package/dist/lib/services/search.service.js +16 -20
  293. package/dist/lib/services/search.service.js.map +1 -1
  294. package/dist/lib/utils/conversation-branching.d.ts +4 -0
  295. package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
  296. package/dist/lib/utils/conversation-branching.js +5 -0
  297. package/dist/lib/utils/conversation-branching.js.map +1 -0
  298. package/dist/lib/utils/conversation-forks.d.ts +315 -0
  299. package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
  300. package/dist/lib/utils/conversation-forks.js +456 -0
  301. package/dist/lib/utils/conversation-forks.js.map +1 -0
  302. package/dist/lib/utils/distinct-artifacts.d.ts +9 -3
  303. package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
  304. package/dist/lib/utils/distinct-artifacts.js +24 -5
  305. package/dist/lib/utils/distinct-artifacts.js.map +1 -1
  306. package/dist/public-api.d.ts +23 -1
  307. package/dist/public-api.d.ts.map +1 -1
  308. package/dist/public-api.js +30 -1
  309. package/dist/public-api.js.map +1 -1
  310. package/package.json +37 -33
  311. package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
  312. package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
  313. package/dist/lib/components/thread/thread-panel.component.js +0 -440
  314. package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
  315. package/dist/lib/services/realtime-pcm-wav.d.ts +0 -79
  316. package/dist/lib/services/realtime-pcm-wav.d.ts.map +0 -1
  317. package/dist/lib/services/realtime-pcm-wav.js +0 -213
  318. package/dist/lib/services/realtime-pcm-wav.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-detail-window.store.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-detail-window.store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conversation-detail-window.store.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-detail-window.store.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,8 @@ import { SelectLatestTimelinePage, DEFAULT_TRANSCRIPT_PAGE_SIZE, DEFAULT_RAW_OVE
10
10
  * - {@link Reset} bumps a generation counter; every in-flight load checks it after each
11
11
  * await and discards its result if the conversation changed underneath.
12
12
  * - {@link LoadOlder} is a no-op while a load is in flight or when nothing is above.
13
+ * - A window loaded with an `upToSequence` ({@link LoadLatest}) holds only rows at or below it;
14
+ * every later read keeps that bound.
13
15
  * - Merges dedupe by normalized ID and re-sort by `Sequence` — session expansion can
14
16
  * return rows an earlier page already had.
15
17
  * - {@link ApplyLocalDetail} never hits the network; it is the send/stream/edit path.
@@ -19,6 +21,7 @@ import { SelectLatestTimelinePage, DEFAULT_TRANSCRIPT_PAGE_SIZE, DEFAULT_RAW_OVE
19
21
  export class ConversationDetailWindowStore {
20
22
  loader;
21
23
  conversationId = null;
24
+ branchId = null;
22
25
  loadedDetails = [];
23
26
  pinnedDetails = [];
24
27
  pinnedTotalCount = 0;
@@ -28,13 +31,19 @@ export class ConversationDetailWindowStore {
28
31
  isLoadingLatest = false;
29
32
  isLoadingOlder = false;
30
33
  loadFailed = false;
34
+ /** The newest `Sequence` the window may hold; null for no bound. */
35
+ upToSequence = null;
31
36
  constructor(loader) {
32
37
  this.loader = loader;
33
38
  }
34
- /** Drops all state and invalidates in-flight loads. Call on every conversation switch. */
35
- Reset(conversationId) {
39
+ /**
40
+ * Drops all state and invalidates in-flight loads. Call on every conversation switch.
41
+ * `branchId` is the branch whose path every later load pages; null is the trunk.
42
+ */
43
+ Reset(conversationId, branchId = null) {
36
44
  this.generation++;
37
45
  this.conversationId = conversationId;
46
+ this.branchId = branchId;
38
47
  this.loadedDetails = [];
39
48
  this.pinnedDetails = [];
40
49
  this.pinnedTotalCount = 0;
@@ -43,6 +52,14 @@ export class ConversationDetailWindowStore {
43
52
  this.isLoadingLatest = false;
44
53
  this.isLoadingOlder = false;
45
54
  this.loadFailed = false;
55
+ this.upToSequence = null;
56
+ }
57
+ /**
58
+ * The exclusive `BeforeSequence` that keeps a newest-rows read at or below {@link upToSequence};
59
+ * undefined when the window has no bound. `Sequence` is an int column, so `< n + 1` is `<= n`.
60
+ */
61
+ newestReadBound() {
62
+ return this.upToSequence == null ? undefined : this.upToSequence + 1;
46
63
  }
47
64
  /**
48
65
  * Fetches a page, WIDENING the raw over-read until it yields a full page of timeline
@@ -88,18 +105,28 @@ export class ConversationDetailWindowStore {
88
105
  return result;
89
106
  }
90
107
  /**
91
- * First paint: the newest page of a conversation.
108
+ * First paint: the newest page of a conversation's path.
109
+ *
110
+ * With `upToSequence`, the window holds only rows at or below that `Sequence`: the first page
111
+ * ends there, and every later read of the window keeps the bound. Older pages load as usual.
92
112
  *
93
113
  * The loader is not expected to throw — `LoadDetailWindow` logs and returns an empty
94
114
  * window on a failed read — but a transport-layer rejection would otherwise strand
95
115
  * `isLoadingLatest` at true and wedge the store, so the flag is cleared in `finally`.
96
116
  */
97
- async LoadLatest(conversationId, contextUser) {
98
- this.Reset(conversationId);
117
+ async LoadLatest(conversationId, contextUser, branchId = null, upToSequence = null) {
118
+ this.Reset(conversationId, branchId);
119
+ this.upToSequence = upToSequence;
99
120
  const generation = this.generation;
100
121
  this.isLoadingLatest = true;
101
122
  try {
102
- const result = await this.fetchPageFillingTimeline({ ConversationID: conversationId, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE }, contextUser);
123
+ const before = this.newestReadBound();
124
+ const result = await this.fetchPageFillingTimeline({
125
+ ConversationID: conversationId,
126
+ BranchID: this.branchId,
127
+ PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE,
128
+ ...(before === undefined ? {} : { BeforeSequence: before })
129
+ }, contextUser);
103
130
  if (generation !== this.generation) {
104
131
  return; // user switched conversations mid-flight
105
132
  }
@@ -145,7 +172,12 @@ export class ConversationDetailWindowStore {
145
172
  const before = this.cursor.OldestSequence;
146
173
  this.isLoadingOlder = true;
147
174
  try {
148
- const result = await this.fetchPageFillingTimeline({ ConversationID: conversationId, BeforeSequence: before, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE }, contextUser);
175
+ const result = await this.fetchPageFillingTimeline({
176
+ ConversationID: conversationId,
177
+ BranchID: this.branchId,
178
+ BeforeSequence: before,
179
+ PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE
180
+ }, contextUser);
149
181
  if (generation !== this.generation) {
150
182
  return;
151
183
  }
@@ -236,9 +268,14 @@ export class ConversationDetailWindowStore {
236
268
  */
237
269
  async fetchRefreshedTail(conversationId, previousNewest, generation, contextUser) {
238
270
  const results = [];
239
- let before = undefined;
271
+ let before = this.newestReadBound();
240
272
  for (let page = 0; page <= MAX_REFRESH_BACKFILL_PAGES; page++) {
241
- const result = await this.loader.LoadDetailWindow({ ConversationID: conversationId, BeforeSequence: before, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE }, contextUser);
273
+ const result = await this.loader.LoadDetailWindow({
274
+ ConversationID: conversationId,
275
+ BranchID: this.branchId,
276
+ BeforeSequence: before,
277
+ PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE
278
+ }, contextUser);
242
279
  if (generation !== this.generation) {
243
280
  return { Results: results, ReachedPreviousTail: false, Failed: false }; // discarded
244
281
  }
@@ -346,6 +383,10 @@ export class ConversationDetailWindowStore {
346
383
  get LoadFailed() {
347
384
  return this.loadFailed;
348
385
  }
386
+ /** The branch whose path the window pages; null is the trunk. */
387
+ get BranchId() {
388
+ return this.branchId;
389
+ }
349
390
  /** True when a `LoadOlder` would actually do work. Drives the sentinel's observer. */
350
391
  CanLoadOlder() {
351
392
  return this.conversationId !== null
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-detail-window.store.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-detail-window.store.ts"],"names":[],"mappings":"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","sourcesContent":["import { NormalizeUUID } from '@memberjunction/global';\nimport type { UserInfo } from '@memberjunction/core';\nimport type {\n MJConversationDetailEntity,\n LoadDetailWindowParams,\n DetailWindowLoadResult\n} from '@memberjunction/core-entities';\nimport { BuildConversationTimeline } from '../utils/realtime-session-timeline';\nimport {\n ConversationDetailWindowCursor,\n SelectLatestTimelinePage,\n DEFAULT_TRANSCRIPT_PAGE_SIZE,\n DEFAULT_RAW_OVERREAD,\n MAX_OVERREAD_ATTEMPTS,\n OVERREAD_GROWTH_FACTOR,\n MAX_REFRESH_BACKFILL_PAGES\n} from '../utils/conversation-detail-window';\n\n/**\n * The engine surface this store needs. Declared structurally rather than importing\n * ConversationEngine so tests can pass a plain `{ LoadDetailWindow: vi.fn() }` with no\n * TestBed and no engine bootstrap.\n */\nexport interface DetailWindowLoader {\n LoadDetailWindow(params: LoadDetailWindowParams, contextUser: UserInfo): Promise<DetailWindowLoadResult>;\n}\n\n/**\n * Peripheral data for the loaded window, keyed the way the chat area already consumes it.\n *\n * Accumulates across pages: an older page brings its own artifacts and ratings, which merge\n * into these maps rather than replacing them.\n */\nexport type ConversationDetailWindowPeripherals = Pick<\n DetailWindowLoadResult,\n 'AgentRunsByDetailId' | 'UserAvatars' | 'RatingsByDetailId' | 'ArtifactsByDetailId'\n>;\n\n/**\n * What a tail refresh read, and whether it managed to reach back to the rows already loaded.\n *\n * `ReachedPreviousTail: false` is the \"the conversation ran away from us\" case — see\n * {@link MAX_REFRESH_BACKFILL_PAGES}. It is the only signal that the loaded set and the fresh\n * set do not join up, so it must not be dropped between the read and the merge.\n */\ninterface RefreshedTail {\n Results: DetailWindowLoadResult[];\n ReachedPreviousTail: boolean;\n /**\n * True when any read in the bridge failed.\n *\n * Kept separate from `ReachedPreviousTail: false`, which means \"the tail is genuinely\n * further away than the budget allows\" and legitimately discards the disconnected older\n * rows. A FAILED read must never trigger that — throwing away a reader's loaded history\n * because one query blipped is not a recovery, it is the bug wearing a different hat.\n */\n Failed: boolean;\n}\n\n/** What the chat area binds to after any store operation. */\nexport interface ConversationDetailWindowSnapshot extends ConversationDetailWindowPeripherals {\n ConversationID: string | null;\n /** Loaded rows, chronological by Sequence. A NEW array each call, so ngOnChanges fires. */\n Details: MJConversationDetailEntity[];\n Cursor: ConversationDetailWindowCursor;\n /** Pinned rows for the pins panel, INCLUDING pins older than the window. */\n PinnedDetails: MJConversationDetailEntity[];\n /**\n * TRUE total pins in the conversation, which is NOT `PinnedDetails.length` until the\n * panel has been opened — the open path reads only the count so the chip has a number\n * without hydrating anything.\n */\n PinnedTotalCount: number;\n IsLoadingLatest: boolean;\n IsLoadingOlder: boolean;\n /**\n * True when the most recent load FAILED, as opposed to returning nothing.\n *\n * Exists so an empty transcript can be told apart from a broken one. Without it a failed\n * first read renders as a conversation with no messages, which reads to the user as \"my\n * conversation is gone\" — the one failure mode worse than an error message.\n */\n LoadFailed: boolean;\n}\n\n/**\n * Holds ONE conversation's loaded transcript window and the cursors for paging further back.\n *\n * Owned per chat-area instance (not a singleton) so two hosts can never share window state.\n *\n * Contracts:\n * - {@link Reset} bumps a generation counter; every in-flight load checks it after each\n * await and discards its result if the conversation changed underneath.\n * - {@link LoadOlder} is a no-op while a load is in flight or when nothing is above.\n * - Merges dedupe by normalized ID and re-sort by `Sequence` — session expansion can\n * return rows an earlier page already had.\n * - {@link ApplyLocalDetail} never hits the network; it is the send/stream/edit path.\n * - Pins live in their own array. They are NOT unioned into the transcript, because a pin\n * below the window's oldest Sequence would break contiguity and the paging cursor.\n */\nexport class ConversationDetailWindowStore {\n private loader: DetailWindowLoader;\n private conversationId: string | null = null;\n private loadedDetails: MJConversationDetailEntity[] = [];\n private pinnedDetails: MJConversationDetailEntity[] = [];\n private pinnedTotalCount = 0;\n private peripherals: ConversationDetailWindowPeripherals = emptyPeripherals();\n private cursor: ConversationDetailWindowCursor = emptyCursor();\n private generation = 0;\n private isLoadingLatest = false;\n private isLoadingOlder = false;\n private loadFailed = false;\n\n constructor(loader: DetailWindowLoader) {\n this.loader = loader;\n }\n\n /** Drops all state and invalidates in-flight loads. Call on every conversation switch. */\n public Reset(conversationId: string | null): void {\n this.generation++;\n this.conversationId = conversationId;\n this.loadedDetails = [];\n this.pinnedDetails = [];\n this.pinnedTotalCount = 0;\n this.peripherals = emptyPeripherals();\n this.cursor = emptyCursor();\n this.isLoadingLatest = false;\n this.isLoadingOlder = false;\n this.loadFailed = false;\n }\n\n /**\n * Fetches a page, WIDENING the raw over-read until it yields a full page of timeline\n * items (or the conversation runs out).\n *\n * Raw rows are not display items: a realtime session folds many stamped rows into ONE\n * timeline card, so the default `3 × pageSize` over-read can come back holding two or\n * three items instead of ten. Taking that at face value gives the reader a stubby page\n * and makes the sentinel fire again immediately — which is worse than one wider read.\n *\n * Bounded by {@link MAX_OVERREAD_ATTEMPTS}: a conversation that is almost entirely one\n * long session would otherwise grow the read until it pulled the whole table.\n */\n private async fetchPageFillingTimeline(\n params: LoadDetailWindowParams,\n contextUser: UserInfo\n ): Promise<DetailWindowLoadResult> {\n let overread = DEFAULT_RAW_OVERREAD;\n let result = await this.loader.LoadDetailWindow({ ...params, RawOverread: overread }, contextUser);\n\n for (let attempt = 1; attempt < MAX_OVERREAD_ATTEMPTS; attempt++) {\n const itemCount = BuildConversationTimeline(result.Details).length;\n if (itemCount >= DEFAULT_TRANSCRIPT_PAGE_SIZE) {\n break; // already a full page of display items\n }\n if (result.Failed) {\n break; // widening a failed read just fails again\n }\n if (!result.HasMoreAbove) {\n break; // start of the conversation — short IS complete\n }\n // The decisive test: did the read actually HIT its row limit? A fetch that came\n // back under its own `MaxRows` has already returned everything available in that\n // range, so a wider read would return the identical rows. Only a fetch that filled\n // its limit can have been truncated by collapse, and only that is worth re-reading.\n if (result.Details.length < overread) {\n break;\n }\n\n overread *= OVERREAD_GROWTH_FACTOR;\n const wider = await this.loader.LoadDetailWindow({ ...params, RawOverread: overread }, contextUser);\n // A failed or non-productive retry must not discard the page we already have.\n if (!wider || wider.Details.length <= result.Details.length) {\n break;\n }\n result = wider;\n }\n return result;\n }\n\n /**\n * First paint: the newest page of a conversation.\n *\n * The loader is not expected to throw — `LoadDetailWindow` logs and returns an empty\n * window on a failed read — but a transport-layer rejection would otherwise strand\n * `isLoadingLatest` at true and wedge the store, so the flag is cleared in `finally`.\n */\n public async LoadLatest(conversationId: string, contextUser: UserInfo): Promise<void> {\n this.Reset(conversationId);\n const generation = this.generation;\n this.isLoadingLatest = true;\n\n try {\n const result = await this.fetchPageFillingTimeline(\n { ConversationID: conversationId, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE },\n contextUser\n );\n\n if (generation !== this.generation) {\n return; // user switched conversations mid-flight\n }\n // The engine OVER-READS raw rows (a page of N rows can collapse to one session\n // card), so the fetch returns more than a page's worth. Slice to the newest\n // `pageSize` TIMELINE ITEMS here — this is what actually bounds the transcript.\n const page = SelectLatestTimelinePage(result.Details, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n const droppedOlderRows = page.Page.length < result.Details.length;\n\n this.mergeDetails(page.Page);\n this.peripherals = peripheralsFrom(result);\n // A failed first read leaves the window empty. `LoadFailed` is what stops that\n // rendering as \"this conversation has no messages\" — there is no cursor to\n // protect here (an empty window cannot page), so the flag IS the whole remedy.\n this.loadFailed = result.Failed;\n this.cursor = {\n OldestSequence: page.OldestIncluded?.Sequence ?? result.OldestSequence,\n NewestSequence: result.NewestSequence,\n // Rows the slice discarded are older content that IS available — the engine's\n // probe only knows about rows below what it fetched, not below what we kept.\n HasMoreAbove: result.HasMoreAbove || droppedOlderRows\n };\n } finally {\n // Guarded: a stale load must not clear a newer load's flag.\n if (generation === this.generation) {\n this.isLoadingLatest = false;\n }\n }\n }\n\n /**\n * Prepends the next older page. No-op when nothing is above or a load is running.\n *\n * `isLoadingOlder` is cleared in `finally` for the same reason as {@link LoadLatest} —\n * and it matters more here, because a stuck flag makes {@link CanLoadOlder} false\n * forever, which silently kills the transcript's \"earlier messages\" sentinel.\n */\n public async LoadOlder(contextUser: UserInfo): Promise<void> {\n if (!this.CanLoadOlder()) {\n return;\n }\n const generation = this.generation;\n const conversationId = this.conversationId as string;\n const before = this.cursor.OldestSequence as number;\n this.isLoadingOlder = true;\n\n try {\n const result = await this.fetchPageFillingTimeline(\n { ConversationID: conversationId, BeforeSequence: before, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE },\n contextUser\n );\n\n if (generation !== this.generation) {\n return;\n }\n this.loadFailed = result.Failed;\n if (result.Failed) {\n // Leave the cursor EXACTLY as it was. Folding a failed read's `HasMoreAbove:\n // false` into it would retire the \"earlier messages\" sentinel permanently —\n // the template unmounts it, the observer disconnects, and no later call ever\n // sets the flag back, so one transport blip costs the reader the rest of the\n // conversation's history with nothing said. The next sentinel fire retries.\n return;\n }\n\n // Same over-read slice as LoadLatest: keep the newest page of timeline items\n // from what came back, not every raw row.\n const page = SelectLatestTimelinePage(result.Details, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n const droppedOlderRows = page.Page.length < result.Details.length;\n\n this.mergeDetails(page.Page);\n // Older pages bring their OWN artifacts/ratings/runs — merge, never replace,\n // or paging up would strip the peripherals off the rows already on screen.\n this.mergePeripherals(result);\n // Only the upward bound moves — the tail is whatever we already had.\n this.cursor = {\n OldestSequence: this.loadedDetails[0]?.Sequence ?? this.cursor.OldestSequence,\n NewestSequence: this.cursor.NewestSequence,\n HasMoreAbove: result.HasMoreAbove || droppedOlderRows\n };\n } finally {\n if (generation === this.generation) {\n this.isLoadingOlder = false;\n }\n }\n }\n\n /**\n * Re-fetches the tail and folds it into the existing window.\n *\n * The refresh-in-place counterpart to {@link LoadLatest}: used when something changed at\n * the tail (an agent finished, artifacts were written) and the transcript needs to pick\n * it up. Unlike `LoadLatest` it does NOT `Reset`, so a user who has paged up five times\n * keeps those pages instead of being yanked back to a 10-row tail.\n *\n * Reads via {@link fetchRefreshedTail}, which keeps paging down until it reaches rows the\n * window already holds — otherwise a conversation that grew by more than a page leaves a\n * hole in the middle of the merged set that nothing in the UI can reveal.\n */\n public async RefreshLatest(contextUser: UserInfo): Promise<void> {\n const conversationId = this.conversationId;\n if (!conversationId) {\n return;\n }\n const generation = this.generation;\n const previousOldest = this.cursor.OldestSequence;\n const previousNewest = this.cursor.NewestSequence;\n this.isLoadingLatest = true;\n\n try {\n const tail = await this.fetchRefreshedTail(\n conversationId, previousNewest, generation, contextUser\n );\n if (generation !== this.generation) {\n return;\n }\n this.loadFailed = tail.Failed;\n if (tail.Failed) {\n // Apply NOTHING. A bridge only reaches a second page because the first did not\n // join, so a failure part-way through means the fresh rows cannot be merged\n // without opening the very gap this method exists to close — and the fallback\n // for an unbridgeable tail discards loaded history, which is far too\n // destructive a response to a transient read error. Leave the window as it\n // was; the next refresh retries.\n return;\n }\n this.applyRefreshedTail(tail, previousOldest, previousNewest);\n } finally {\n if (generation === this.generation) {\n this.isLoadingLatest = false;\n }\n }\n }\n\n /**\n * Reads the newest page, then keeps paging down until the read reaches back to\n * `previousNewest` — the newest row the window already holds.\n *\n * One page is enough in the normal case: a refresh usually returns rows we already have\n * plus the handful that arrived since. The loop is for the case that is not normal, where\n * the tail has moved further than a page and a single read would land entirely above the\n * loaded set.\n *\n * @returns Every page read, plus whether the reads joined up with the loaded window.\n */\n private async fetchRefreshedTail(\n conversationId: string,\n previousNewest: number | null,\n generation: number,\n contextUser: UserInfo\n ): Promise<RefreshedTail> {\n const results: DetailWindowLoadResult[] = [];\n let before: number | undefined = undefined;\n\n for (let page = 0; page <= MAX_REFRESH_BACKFILL_PAGES; page++) {\n const result = await this.loader.LoadDetailWindow(\n { ConversationID: conversationId, BeforeSequence: before, PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE },\n contextUser\n );\n if (generation !== this.generation) {\n return { Results: results, ReachedPreviousTail: false, Failed: false }; // discarded\n }\n // Checked BEFORE tailIsJoined, which reads `HasMoreAbove` — false on a failed read,\n // which would report the bridge as joined and hand back a set with a hole in it.\n if (result.Failed) {\n return { Results: results, ReachedPreviousTail: false, Failed: true };\n }\n results.push(result);\n\n if (this.tailIsJoined(result, previousNewest)) {\n return { Results: results, ReachedPreviousTail: true, Failed: false };\n }\n before = result.OldestSequence ?? undefined;\n }\n return { Results: results, ReachedPreviousTail: false, Failed: false };\n }\n\n /** True when this page reaches back into the loaded window, so nothing sits between them. */\n private tailIsJoined(result: DetailWindowLoadResult, previousNewest: number | null): boolean {\n // Nothing loaded to join up WITH, or the read came back empty — either way, done.\n if (previousNewest === null || result.OldestSequence === null) {\n return true;\n }\n // The page overlaps or abuts what we hold.\n if (result.OldestSequence <= previousNewest) {\n return true;\n }\n // The engine's probe says no row exists below this page at all. The rows we hold are\n // below it, so they have since been deleted — there is no gap left to bridge.\n return !result.HasMoreAbove;\n }\n\n /**\n * Folds a refreshed tail into the window, choosing what to keep by whether the read\n * joined up with the rows already loaded.\n */\n private applyRefreshedTail(\n tail: RefreshedTail,\n previousOldest: number | null,\n previousNewest: number | null\n ): void {\n const fetched = tail.Results.flatMap(result => result.Details);\n const hasMoreAbove = this.mergeRefreshedRows(tail, fetched, previousOldest, previousNewest);\n\n for (const result of tail.Results) {\n this.mergePeripherals(result);\n }\n this.cursor = {\n OldestSequence: this.loadedDetails[0]?.Sequence ?? null,\n NewestSequence: this.loadedDetails[this.loadedDetails.length - 1]?.Sequence ?? null,\n HasMoreAbove: hasMoreAbove\n };\n }\n\n /** Merges the refreshed rows per the three refresh cases. @returns the new `HasMoreAbove`. */\n private mergeRefreshedRows(\n tail: RefreshedTail,\n fetched: MJConversationDetailEntity[],\n previousOldest: number | null,\n previousNewest: number | null\n ): boolean {\n if (previousNewest === null) {\n // Nothing loaded — this is a first paint wearing a refresh's name, so bound it to\n // a page the way LoadLatest does.\n const page = SelectLatestTimelinePage(fetched, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n this.mergeDetails(page.Page);\n const last = tail.Results[tail.Results.length - 1];\n return (last?.HasMoreAbove ?? false) || page.Page.length < fetched.length;\n }\n\n if (tail.ReachedPreviousTail) {\n // Keep EVERY fetched row down to the window's existing floor. Slicing to a page\n // here is what opened the hole: the read deliberately spans the distance back to\n // the loaded tail, and discarding its middle throws away the very rows that make\n // the merged set contiguous. Rows below the floor are dropped so a refresh cannot\n // quietly grow the window downward — that is LoadOlder's job.\n this.mergeDetails(previousOldest === null\n ? fetched\n : fetched.filter(detail => detail.Sequence >= previousOldest));\n // The floor did not move, so what is below it is still whatever we last learned.\n return this.cursor.HasMoreAbove;\n }\n\n // Could not bridge within the page budget. Drop the now-disconnected older rows and\n // keep the fresh tail: a visible gap the sentinel can close beats an invisible one.\n this.loadedDetails = [];\n this.mergeDetails(fetched);\n return true;\n }\n\n /**\n * Cheap single-value reads for TEMPLATE binding.\n *\n * These exist because the chat area exposes `HasMoreAbove`, `IsLoadingOlder`,\n * `PinnedTotalCount`, and `PinnedDetails` as getters bound in its template, so every\n * change-detection cycle reads all four. Routing those through {@link GetSnapshot} copied\n * the whole loaded window four times per cycle — during streaming, per token — on a\n * component whose entire purpose is to stop doing work proportional to conversation length.\n *\n * {@link PinnedDetails} deliberately returns the internal array BY REFERENCE. Every mutator\n * replaces that array rather than mutating it, so the reference is stable between real\n * changes — which is precisely what keeps the pins panel's `ngOnChanges` from firing on\n * every cycle. Callers must not mutate it.\n */\n public get HasMoreAbove(): boolean {\n return this.cursor.HasMoreAbove;\n }\n\n public get IsLoadingOlder(): boolean {\n return this.isLoadingOlder;\n }\n\n public get IsLoadingLatest(): boolean {\n return this.isLoadingLatest;\n }\n\n public get PinnedTotalCount(): number {\n return this.pinnedTotalCount;\n }\n\n public get PinnedDetails(): readonly MJConversationDetailEntity[] {\n return this.pinnedDetails;\n }\n\n /** True when the most recent load failed — an empty transcript vs. a broken one. */\n public get LoadFailed(): boolean {\n return this.loadFailed;\n }\n\n /** True when a `LoadOlder` would actually do work. Drives the sentinel's observer. */\n public CanLoadOlder(): boolean {\n return this.conversationId !== null\n && this.cursor.HasMoreAbove\n && this.cursor.OldestSequence !== null\n && !this.isLoadingOlder\n && !this.isLoadingLatest;\n }\n\n /**\n * Applies a locally-known row — sent, streamed, edited. Inserts or replaces by ID and\n * re-sorts. Never queries; the caller already has the entity.\n */\n public ApplyLocalDetail(detail: MJConversationDetailEntity): void {\n this.mergeDetails([detail]);\n const newest = this.loadedDetails[this.loadedDetails.length - 1]?.Sequence ?? null;\n this.cursor = { ...this.cursor, NewestSequence: newest };\n }\n\n /** Removes a row by ID — the delete path. */\n public RemoveDetail(detailId: string): void {\n const key = NormalizeUUID(detailId);\n this.loadedDetails = this.loadedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n const pinnedBefore = this.pinnedDetails.length;\n this.pinnedDetails = this.pinnedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n if (this.pinnedDetails.length < pinnedBefore) {\n this.pinnedTotalCount = Math.max(0, this.pinnedTotalCount - 1);\n }\n }\n\n /**\n * Records how many pins exist WITHOUT loading them.\n *\n * The conversation-open path calls only this: the chip needs a number, the panel needs\n * nothing until it is opened, and hydrating every pin on open re-imports the cost this\n * windowing work exists to remove.\n */\n public SetPinnedCount(total: number): void {\n this.pinnedTotalCount = Math.max(0, total);\n }\n\n /** Replaces the pins panel's contents. Pins outside the window are expected here. */\n public SetPinnedDetails(pins: MJConversationDetailEntity[]): void {\n this.pinnedDetails = [...pins];\n // Hydration is unbounded, so once it lands the loaded set IS the whole set — any\n // drift the local pin/unpin bookkeeping accumulated is reconciled here on purpose.\n this.pinnedTotalCount = pins.length;\n }\n\n /**\n * Reflects a pin/unpin the user just performed, without re-querying.\n *\n * Newly pinned rows go to the FRONT to match the panel's newest-pin-first order, which\n * the initial `Sequence DESC` fetch also produces.\n */\n public ApplyLocalPin(detail: MJConversationDetailEntity): void {\n const key = NormalizeUUID(detail.ID);\n const wasPinned = this.pinnedDetails.some(d => NormalizeUUID(d.ID) === key);\n const without = this.pinnedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n this.pinnedDetails = detail.IsPinned ? [detail, ...without] : without;\n\n // Counted independently of the set: before the panel is opened `pinnedDetails` is\n // deliberately EMPTY, so deriving a count from its length would report zero pins on\n // a conversation that has many. `wasPinned` keeps the two in step — without it an\n // unpin of a row that was never in the set decrements a count it never entered.\n if (detail.IsPinned && !wasPinned) {\n this.pinnedTotalCount++;\n } else if (!detail.IsPinned && wasPinned) {\n this.pinnedTotalCount = Math.max(0, this.pinnedTotalCount - 1);\n }\n }\n\n /**\n * Everything the chat area needs to render, copied. Arrays are fresh so ngOnChanges fires.\n *\n * Call this from imperative paths (a load completing, a jump loop) — NOT from a template\n * getter. It copies the loaded set on every call, so binding it into change detection\n * pays that copy once per checked cycle for state that mostly has not moved. The cheap\n * single-value accessors above exist for exactly that case.\n */\n public GetSnapshot(): ConversationDetailWindowSnapshot {\n const details = [...this.loadedDetails];\n return {\n ConversationID: this.conversationId,\n Details: details,\n Cursor: { ...this.cursor },\n PinnedDetails: [...this.pinnedDetails],\n PinnedTotalCount: this.pinnedTotalCount,\n // Peripheral maps are handed out by reference — the chat area copies them into\n // its own UI-shaped maps (LazyArtifactInfo etc.) rather than mutating these.\n AgentRunsByDetailId: this.peripherals.AgentRunsByDetailId,\n UserAvatars: this.peripherals.UserAvatars,\n RatingsByDetailId: this.peripherals.RatingsByDetailId,\n ArtifactsByDetailId: this.peripherals.ArtifactsByDetailId,\n IsLoadingLatest: this.isLoadingLatest,\n IsLoadingOlder: this.isLoadingOlder,\n LoadFailed: this.loadFailed\n };\n }\n\n /**\n * Folds a newly-loaded page's peripherals into the accumulated maps.\n *\n * Later entries win on a key collision, which matters for a window refresh: a re-fetched\n * newest page should replace a row's stale agent run rather than keep the old one.\n */\n private mergePeripherals(incoming: ConversationDetailWindowPeripherals): void {\n for (const [id, run] of incoming.AgentRunsByDetailId) {\n this.peripherals.AgentRunsByDetailId.set(id, run);\n }\n for (const [id, avatar] of incoming.UserAvatars) {\n this.peripherals.UserAvatars.set(id, avatar);\n }\n for (const [id, ratings] of incoming.RatingsByDetailId) {\n this.peripherals.RatingsByDetailId.set(id, ratings);\n }\n for (const [id, artifacts] of incoming.ArtifactsByDetailId) {\n this.peripherals.ArtifactsByDetailId.set(id, artifacts);\n }\n }\n\n /**\n * Union-merges rows into the loaded set: replace-by-ID, then sort by `Sequence`.\n * Dedupe is required because session expansion can re-return rows a prior page held.\n */\n private mergeDetails(incoming: MJConversationDetailEntity[]): void {\n const byId = new Map<string, MJConversationDetailEntity>();\n for (const detail of this.loadedDetails) {\n byId.set(NormalizeUUID(detail.ID), detail);\n }\n for (const detail of incoming) {\n byId.set(NormalizeUUID(detail.ID), detail);\n }\n this.loadedDetails = [...byId.values()].sort((a, b) => a.Sequence - b.Sequence);\n }\n}\n\n/** Empty peripheral maps — the reset / no-window state. */\nfunction emptyPeripherals(): ConversationDetailWindowPeripherals {\n return {\n AgentRunsByDetailId: new Map(),\n UserAvatars: new Map(),\n RatingsByDetailId: new Map(),\n ArtifactsByDetailId: new Map()\n };\n}\n\n/** Copies a load result's peripheral maps into fresh maps the store then owns and merges into. */\nfunction peripheralsFrom(result: DetailWindowLoadResult): ConversationDetailWindowPeripherals {\n return {\n AgentRunsByDetailId: new Map(result.AgentRunsByDetailId),\n UserAvatars: new Map(result.UserAvatars),\n RatingsByDetailId: new Map(result.RatingsByDetailId),\n ArtifactsByDetailId: new Map(result.ArtifactsByDetailId)\n };\n}\n\n/** The empty-window cursor. */\nfunction emptyCursor(): ConversationDetailWindowCursor {\n return { OldestSequence: null, NewestSequence: null, HasMoreAbove: false };\n}\n\n// NOTE: there is deliberately no `cursorFrom(result)` helper. A cursor can never be copied\n// straight off a load result, because the store slices the over-read page down to `pageSize`\n// timeline items — so both the oldest bound and `HasMoreAbove` depend on what survived the\n// slice, not on what the engine fetched.\n"]}
1
+ {"version":3,"file":"conversation-detail-window.store.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-detail-window.store.ts"],"names":[],"mappings":"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","sourcesContent":["import { NormalizeUUID } from '@memberjunction/global';\nimport type { UserInfo } from '@memberjunction/core';\nimport type {\n MJConversationDetailEntity,\n LoadDetailWindowParams,\n DetailWindowLoadResult\n} from '@memberjunction/core-entities';\nimport { BuildConversationTimeline } from '../utils/realtime-session-timeline';\nimport {\n ConversationDetailWindowCursor,\n SelectLatestTimelinePage,\n DEFAULT_TRANSCRIPT_PAGE_SIZE,\n DEFAULT_RAW_OVERREAD,\n MAX_OVERREAD_ATTEMPTS,\n OVERREAD_GROWTH_FACTOR,\n MAX_REFRESH_BACKFILL_PAGES\n} from '../utils/conversation-detail-window';\n\n/**\n * The engine surface this store needs. Declared structurally rather than importing\n * ConversationEngine so tests can pass a plain `{ LoadDetailWindow: vi.fn() }` with no\n * TestBed and no engine bootstrap.\n */\nexport interface DetailWindowLoader {\n LoadDetailWindow(params: LoadDetailWindowParams, contextUser: UserInfo): Promise<DetailWindowLoadResult>;\n}\n\n/**\n * Peripheral data for the loaded window, keyed the way the chat area already consumes it.\n *\n * Accumulates across pages: an older page brings its own artifacts and ratings, which merge\n * into these maps rather than replacing them.\n */\nexport type ConversationDetailWindowPeripherals = Pick<\n DetailWindowLoadResult,\n 'AgentRunsByDetailId' | 'UserAvatars' | 'RatingsByDetailId' | 'ArtifactsByDetailId'\n>;\n\n/**\n * What a tail refresh read, and whether it managed to reach back to the rows already loaded.\n *\n * `ReachedPreviousTail: false` is the \"the conversation ran away from us\" case — see\n * {@link MAX_REFRESH_BACKFILL_PAGES}. It is the only signal that the loaded set and the fresh\n * set do not join up, so it must not be dropped between the read and the merge.\n */\ninterface RefreshedTail {\n Results: DetailWindowLoadResult[];\n ReachedPreviousTail: boolean;\n /**\n * True when any read in the bridge failed.\n *\n * Kept separate from `ReachedPreviousTail: false`, which means \"the tail is genuinely\n * further away than the budget allows\" and legitimately discards the disconnected older\n * rows. A FAILED read must never trigger that — throwing away a reader's loaded history\n * because one query blipped is not a recovery, it is the bug wearing a different hat.\n */\n Failed: boolean;\n}\n\n/** What the chat area binds to after any store operation. */\nexport interface ConversationDetailWindowSnapshot extends ConversationDetailWindowPeripherals {\n ConversationID: string | null;\n /** Loaded rows, chronological by Sequence. A NEW array each call, so ngOnChanges fires. */\n Details: MJConversationDetailEntity[];\n Cursor: ConversationDetailWindowCursor;\n /** Pinned rows for the pins panel, INCLUDING pins older than the window. */\n PinnedDetails: MJConversationDetailEntity[];\n /**\n * TRUE total pins in the conversation, which is NOT `PinnedDetails.length` until the\n * panel has been opened — the open path reads only the count so the chip has a number\n * without hydrating anything.\n */\n PinnedTotalCount: number;\n IsLoadingLatest: boolean;\n IsLoadingOlder: boolean;\n /**\n * True when the most recent load FAILED, as opposed to returning nothing.\n *\n * Exists so an empty transcript can be told apart from a broken one. Without it a failed\n * first read renders as a conversation with no messages, which reads to the user as \"my\n * conversation is gone\" — the one failure mode worse than an error message.\n */\n LoadFailed: boolean;\n}\n\n/**\n * Holds ONE conversation's loaded transcript window and the cursors for paging further back.\n *\n * Owned per chat-area instance (not a singleton) so two hosts can never share window state.\n *\n * Contracts:\n * - {@link Reset} bumps a generation counter; every in-flight load checks it after each\n * await and discards its result if the conversation changed underneath.\n * - {@link LoadOlder} is a no-op while a load is in flight or when nothing is above.\n * - A window loaded with an `upToSequence` ({@link LoadLatest}) holds only rows at or below it;\n * every later read keeps that bound.\n * - Merges dedupe by normalized ID and re-sort by `Sequence` — session expansion can\n * return rows an earlier page already had.\n * - {@link ApplyLocalDetail} never hits the network; it is the send/stream/edit path.\n * - Pins live in their own array. They are NOT unioned into the transcript, because a pin\n * below the window's oldest Sequence would break contiguity and the paging cursor.\n */\nexport class ConversationDetailWindowStore {\n private loader: DetailWindowLoader;\n private conversationId: string | null = null;\n private branchId: string | null = null;\n private loadedDetails: MJConversationDetailEntity[] = [];\n private pinnedDetails: MJConversationDetailEntity[] = [];\n private pinnedTotalCount = 0;\n private peripherals: ConversationDetailWindowPeripherals = emptyPeripherals();\n private cursor: ConversationDetailWindowCursor = emptyCursor();\n private generation = 0;\n private isLoadingLatest = false;\n private isLoadingOlder = false;\n private loadFailed = false;\n /** The newest `Sequence` the window may hold; null for no bound. */\n private upToSequence: number | null = null;\n\n constructor(loader: DetailWindowLoader) {\n this.loader = loader;\n }\n\n /**\n * Drops all state and invalidates in-flight loads. Call on every conversation switch.\n * `branchId` is the branch whose path every later load pages; null is the trunk.\n */\n public Reset(conversationId: string | null, branchId: string | null = null): void {\n this.generation++;\n this.conversationId = conversationId;\n this.branchId = branchId;\n this.loadedDetails = [];\n this.pinnedDetails = [];\n this.pinnedTotalCount = 0;\n this.peripherals = emptyPeripherals();\n this.cursor = emptyCursor();\n this.isLoadingLatest = false;\n this.isLoadingOlder = false;\n this.loadFailed = false;\n this.upToSequence = null;\n }\n\n /**\n * The exclusive `BeforeSequence` that keeps a newest-rows read at or below {@link upToSequence};\n * undefined when the window has no bound. `Sequence` is an int column, so `< n + 1` is `<= n`.\n */\n private newestReadBound(): number | undefined {\n return this.upToSequence == null ? undefined : this.upToSequence + 1;\n }\n\n /**\n * Fetches a page, WIDENING the raw over-read until it yields a full page of timeline\n * items (or the conversation runs out).\n *\n * Raw rows are not display items: a realtime session folds many stamped rows into ONE\n * timeline card, so the default `3 × pageSize` over-read can come back holding two or\n * three items instead of ten. Taking that at face value gives the reader a stubby page\n * and makes the sentinel fire again immediately — which is worse than one wider read.\n *\n * Bounded by {@link MAX_OVERREAD_ATTEMPTS}: a conversation that is almost entirely one\n * long session would otherwise grow the read until it pulled the whole table.\n */\n private async fetchPageFillingTimeline(\n params: LoadDetailWindowParams,\n contextUser: UserInfo\n ): Promise<DetailWindowLoadResult> {\n let overread = DEFAULT_RAW_OVERREAD;\n let result = await this.loader.LoadDetailWindow({ ...params, RawOverread: overread }, contextUser);\n\n for (let attempt = 1; attempt < MAX_OVERREAD_ATTEMPTS; attempt++) {\n const itemCount = BuildConversationTimeline(result.Details).length;\n if (itemCount >= DEFAULT_TRANSCRIPT_PAGE_SIZE) {\n break; // already a full page of display items\n }\n if (result.Failed) {\n break; // widening a failed read just fails again\n }\n if (!result.HasMoreAbove) {\n break; // start of the conversation — short IS complete\n }\n // The decisive test: did the read actually HIT its row limit? A fetch that came\n // back under its own `MaxRows` has already returned everything available in that\n // range, so a wider read would return the identical rows. Only a fetch that filled\n // its limit can have been truncated by collapse, and only that is worth re-reading.\n if (result.Details.length < overread) {\n break;\n }\n\n overread *= OVERREAD_GROWTH_FACTOR;\n const wider = await this.loader.LoadDetailWindow({ ...params, RawOverread: overread }, contextUser);\n // A failed or non-productive retry must not discard the page we already have.\n if (!wider || wider.Details.length <= result.Details.length) {\n break;\n }\n result = wider;\n }\n return result;\n }\n\n /**\n * First paint: the newest page of a conversation's path.\n *\n * With `upToSequence`, the window holds only rows at or below that `Sequence`: the first page\n * ends there, and every later read of the window keeps the bound. Older pages load as usual.\n *\n * The loader is not expected to throw — `LoadDetailWindow` logs and returns an empty\n * window on a failed read — but a transport-layer rejection would otherwise strand\n * `isLoadingLatest` at true and wedge the store, so the flag is cleared in `finally`.\n */\n public async LoadLatest(\n conversationId: string,\n contextUser: UserInfo,\n branchId: string | null = null,\n upToSequence: number | null = null\n ): Promise<void> {\n this.Reset(conversationId, branchId);\n this.upToSequence = upToSequence;\n const generation = this.generation;\n this.isLoadingLatest = true;\n\n try {\n const before = this.newestReadBound();\n const result = await this.fetchPageFillingTimeline(\n {\n ConversationID: conversationId,\n BranchID: this.branchId,\n PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE,\n ...(before === undefined ? {} : { BeforeSequence: before })\n },\n contextUser\n );\n\n if (generation !== this.generation) {\n return; // user switched conversations mid-flight\n }\n // The engine OVER-READS raw rows (a page of N rows can collapse to one session\n // card), so the fetch returns more than a page's worth. Slice to the newest\n // `pageSize` TIMELINE ITEMS here — this is what actually bounds the transcript.\n const page = SelectLatestTimelinePage(result.Details, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n const droppedOlderRows = page.Page.length < result.Details.length;\n\n this.mergeDetails(page.Page);\n this.peripherals = peripheralsFrom(result);\n // A failed first read leaves the window empty. `LoadFailed` is what stops that\n // rendering as \"this conversation has no messages\" — there is no cursor to\n // protect here (an empty window cannot page), so the flag IS the whole remedy.\n this.loadFailed = result.Failed;\n this.cursor = {\n OldestSequence: page.OldestIncluded?.Sequence ?? result.OldestSequence,\n NewestSequence: result.NewestSequence,\n // Rows the slice discarded are older content that IS available — the engine's\n // probe only knows about rows below what it fetched, not below what we kept.\n HasMoreAbove: result.HasMoreAbove || droppedOlderRows\n };\n } finally {\n // Guarded: a stale load must not clear a newer load's flag.\n if (generation === this.generation) {\n this.isLoadingLatest = false;\n }\n }\n }\n\n /**\n * Prepends the next older page. No-op when nothing is above or a load is running.\n *\n * `isLoadingOlder` is cleared in `finally` for the same reason as {@link LoadLatest} —\n * and it matters more here, because a stuck flag makes {@link CanLoadOlder} false\n * forever, which silently kills the transcript's \"earlier messages\" sentinel.\n */\n public async LoadOlder(contextUser: UserInfo): Promise<void> {\n if (!this.CanLoadOlder()) {\n return;\n }\n const generation = this.generation;\n const conversationId = this.conversationId as string;\n const before = this.cursor.OldestSequence as number;\n this.isLoadingOlder = true;\n\n try {\n const result = await this.fetchPageFillingTimeline(\n {\n ConversationID: conversationId,\n BranchID: this.branchId,\n BeforeSequence: before,\n PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE\n },\n contextUser\n );\n\n if (generation !== this.generation) {\n return;\n }\n this.loadFailed = result.Failed;\n if (result.Failed) {\n // Leave the cursor EXACTLY as it was. Folding a failed read's `HasMoreAbove:\n // false` into it would retire the \"earlier messages\" sentinel permanently —\n // the template unmounts it, the observer disconnects, and no later call ever\n // sets the flag back, so one transport blip costs the reader the rest of the\n // conversation's history with nothing said. The next sentinel fire retries.\n return;\n }\n\n // Same over-read slice as LoadLatest: keep the newest page of timeline items\n // from what came back, not every raw row.\n const page = SelectLatestTimelinePage(result.Details, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n const droppedOlderRows = page.Page.length < result.Details.length;\n\n this.mergeDetails(page.Page);\n // Older pages bring their OWN artifacts/ratings/runs — merge, never replace,\n // or paging up would strip the peripherals off the rows already on screen.\n this.mergePeripherals(result);\n // Only the upward bound moves — the tail is whatever we already had.\n this.cursor = {\n OldestSequence: this.loadedDetails[0]?.Sequence ?? this.cursor.OldestSequence,\n NewestSequence: this.cursor.NewestSequence,\n HasMoreAbove: result.HasMoreAbove || droppedOlderRows\n };\n } finally {\n if (generation === this.generation) {\n this.isLoadingOlder = false;\n }\n }\n }\n\n /**\n * Re-fetches the tail and folds it into the existing window.\n *\n * The refresh-in-place counterpart to {@link LoadLatest}: used when something changed at\n * the tail (an agent finished, artifacts were written) and the transcript needs to pick\n * it up. Unlike `LoadLatest` it does NOT `Reset`, so a user who has paged up five times\n * keeps those pages instead of being yanked back to a 10-row tail.\n *\n * Reads via {@link fetchRefreshedTail}, which keeps paging down until it reaches rows the\n * window already holds — otherwise a conversation that grew by more than a page leaves a\n * hole in the middle of the merged set that nothing in the UI can reveal.\n */\n public async RefreshLatest(contextUser: UserInfo): Promise<void> {\n const conversationId = this.conversationId;\n if (!conversationId) {\n return;\n }\n const generation = this.generation;\n const previousOldest = this.cursor.OldestSequence;\n const previousNewest = this.cursor.NewestSequence;\n this.isLoadingLatest = true;\n\n try {\n const tail = await this.fetchRefreshedTail(\n conversationId, previousNewest, generation, contextUser\n );\n if (generation !== this.generation) {\n return;\n }\n this.loadFailed = tail.Failed;\n if (tail.Failed) {\n // Apply NOTHING. A bridge only reaches a second page because the first did not\n // join, so a failure part-way through means the fresh rows cannot be merged\n // without opening the very gap this method exists to close — and the fallback\n // for an unbridgeable tail discards loaded history, which is far too\n // destructive a response to a transient read error. Leave the window as it\n // was; the next refresh retries.\n return;\n }\n this.applyRefreshedTail(tail, previousOldest, previousNewest);\n } finally {\n if (generation === this.generation) {\n this.isLoadingLatest = false;\n }\n }\n }\n\n /**\n * Reads the newest page, then keeps paging down until the read reaches back to\n * `previousNewest` — the newest row the window already holds.\n *\n * One page is enough in the normal case: a refresh usually returns rows we already have\n * plus the handful that arrived since. The loop is for the case that is not normal, where\n * the tail has moved further than a page and a single read would land entirely above the\n * loaded set.\n *\n * @returns Every page read, plus whether the reads joined up with the loaded window.\n */\n private async fetchRefreshedTail(\n conversationId: string,\n previousNewest: number | null,\n generation: number,\n contextUser: UserInfo\n ): Promise<RefreshedTail> {\n const results: DetailWindowLoadResult[] = [];\n let before: number | undefined = this.newestReadBound();\n\n for (let page = 0; page <= MAX_REFRESH_BACKFILL_PAGES; page++) {\n const result = await this.loader.LoadDetailWindow(\n {\n ConversationID: conversationId,\n BranchID: this.branchId,\n BeforeSequence: before,\n PageSize: DEFAULT_TRANSCRIPT_PAGE_SIZE\n },\n contextUser\n );\n if (generation !== this.generation) {\n return { Results: results, ReachedPreviousTail: false, Failed: false }; // discarded\n }\n // Checked BEFORE tailIsJoined, which reads `HasMoreAbove` — false on a failed read,\n // which would report the bridge as joined and hand back a set with a hole in it.\n if (result.Failed) {\n return { Results: results, ReachedPreviousTail: false, Failed: true };\n }\n results.push(result);\n\n if (this.tailIsJoined(result, previousNewest)) {\n return { Results: results, ReachedPreviousTail: true, Failed: false };\n }\n before = result.OldestSequence ?? undefined;\n }\n return { Results: results, ReachedPreviousTail: false, Failed: false };\n }\n\n /** True when this page reaches back into the loaded window, so nothing sits between them. */\n private tailIsJoined(result: DetailWindowLoadResult, previousNewest: number | null): boolean {\n // Nothing loaded to join up WITH, or the read came back empty — either way, done.\n if (previousNewest === null || result.OldestSequence === null) {\n return true;\n }\n // The page overlaps or abuts what we hold.\n if (result.OldestSequence <= previousNewest) {\n return true;\n }\n // The engine's probe says no row exists below this page at all. The rows we hold are\n // below it, so they have since been deleted — there is no gap left to bridge.\n return !result.HasMoreAbove;\n }\n\n /**\n * Folds a refreshed tail into the window, choosing what to keep by whether the read\n * joined up with the rows already loaded.\n */\n private applyRefreshedTail(\n tail: RefreshedTail,\n previousOldest: number | null,\n previousNewest: number | null\n ): void {\n const fetched = tail.Results.flatMap(result => result.Details);\n const hasMoreAbove = this.mergeRefreshedRows(tail, fetched, previousOldest, previousNewest);\n\n for (const result of tail.Results) {\n this.mergePeripherals(result);\n }\n this.cursor = {\n OldestSequence: this.loadedDetails[0]?.Sequence ?? null,\n NewestSequence: this.loadedDetails[this.loadedDetails.length - 1]?.Sequence ?? null,\n HasMoreAbove: hasMoreAbove\n };\n }\n\n /** Merges the refreshed rows per the three refresh cases. @returns the new `HasMoreAbove`. */\n private mergeRefreshedRows(\n tail: RefreshedTail,\n fetched: MJConversationDetailEntity[],\n previousOldest: number | null,\n previousNewest: number | null\n ): boolean {\n if (previousNewest === null) {\n // Nothing loaded — this is a first paint wearing a refresh's name, so bound it to\n // a page the way LoadLatest does.\n const page = SelectLatestTimelinePage(fetched, DEFAULT_TRANSCRIPT_PAGE_SIZE);\n this.mergeDetails(page.Page);\n const last = tail.Results[tail.Results.length - 1];\n return (last?.HasMoreAbove ?? false) || page.Page.length < fetched.length;\n }\n\n if (tail.ReachedPreviousTail) {\n // Keep EVERY fetched row down to the window's existing floor. Slicing to a page\n // here is what opened the hole: the read deliberately spans the distance back to\n // the loaded tail, and discarding its middle throws away the very rows that make\n // the merged set contiguous. Rows below the floor are dropped so a refresh cannot\n // quietly grow the window downward — that is LoadOlder's job.\n this.mergeDetails(previousOldest === null\n ? fetched\n : fetched.filter(detail => detail.Sequence >= previousOldest));\n // The floor did not move, so what is below it is still whatever we last learned.\n return this.cursor.HasMoreAbove;\n }\n\n // Could not bridge within the page budget. Drop the now-disconnected older rows and\n // keep the fresh tail: a visible gap the sentinel can close beats an invisible one.\n this.loadedDetails = [];\n this.mergeDetails(fetched);\n return true;\n }\n\n /**\n * Cheap single-value reads for TEMPLATE binding.\n *\n * These exist because the chat area exposes `HasMoreAbove`, `IsLoadingOlder`,\n * `PinnedTotalCount`, and `PinnedDetails` as getters bound in its template, so every\n * change-detection cycle reads all four. Routing those through {@link GetSnapshot} copied\n * the whole loaded window four times per cycle — during streaming, per token — on a\n * component whose entire purpose is to stop doing work proportional to conversation length.\n *\n * {@link PinnedDetails} deliberately returns the internal array BY REFERENCE. Every mutator\n * replaces that array rather than mutating it, so the reference is stable between real\n * changes — which is precisely what keeps the pins panel's `ngOnChanges` from firing on\n * every cycle. Callers must not mutate it.\n */\n public get HasMoreAbove(): boolean {\n return this.cursor.HasMoreAbove;\n }\n\n public get IsLoadingOlder(): boolean {\n return this.isLoadingOlder;\n }\n\n public get IsLoadingLatest(): boolean {\n return this.isLoadingLatest;\n }\n\n public get PinnedTotalCount(): number {\n return this.pinnedTotalCount;\n }\n\n public get PinnedDetails(): readonly MJConversationDetailEntity[] {\n return this.pinnedDetails;\n }\n\n /** True when the most recent load failed — an empty transcript vs. a broken one. */\n public get LoadFailed(): boolean {\n return this.loadFailed;\n }\n\n /** The branch whose path the window pages; null is the trunk. */\n public get BranchId(): string | null {\n return this.branchId;\n }\n\n /** True when a `LoadOlder` would actually do work. Drives the sentinel's observer. */\n public CanLoadOlder(): boolean {\n return this.conversationId !== null\n && this.cursor.HasMoreAbove\n && this.cursor.OldestSequence !== null\n && !this.isLoadingOlder\n && !this.isLoadingLatest;\n }\n\n /**\n * Applies a locally-known row — sent, streamed, edited. Inserts or replaces by ID and\n * re-sorts. Never queries; the caller already has the entity.\n */\n public ApplyLocalDetail(detail: MJConversationDetailEntity): void {\n this.mergeDetails([detail]);\n const newest = this.loadedDetails[this.loadedDetails.length - 1]?.Sequence ?? null;\n this.cursor = { ...this.cursor, NewestSequence: newest };\n }\n\n /** Removes a row by ID — the delete path. */\n public RemoveDetail(detailId: string): void {\n const key = NormalizeUUID(detailId);\n this.loadedDetails = this.loadedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n const pinnedBefore = this.pinnedDetails.length;\n this.pinnedDetails = this.pinnedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n if (this.pinnedDetails.length < pinnedBefore) {\n this.pinnedTotalCount = Math.max(0, this.pinnedTotalCount - 1);\n }\n }\n\n /**\n * Records how many pins exist WITHOUT loading them.\n *\n * The conversation-open path calls only this: the chip needs a number, the panel needs\n * nothing until it is opened, and hydrating every pin on open re-imports the cost this\n * windowing work exists to remove.\n */\n public SetPinnedCount(total: number): void {\n this.pinnedTotalCount = Math.max(0, total);\n }\n\n /** Replaces the pins panel's contents. Pins outside the window are expected here. */\n public SetPinnedDetails(pins: MJConversationDetailEntity[]): void {\n this.pinnedDetails = [...pins];\n // Hydration is unbounded, so once it lands the loaded set IS the whole set — any\n // drift the local pin/unpin bookkeeping accumulated is reconciled here on purpose.\n this.pinnedTotalCount = pins.length;\n }\n\n /**\n * Reflects a pin/unpin the user just performed, without re-querying.\n *\n * Newly pinned rows go to the FRONT to match the panel's newest-pin-first order, which\n * the initial `Sequence DESC` fetch also produces.\n */\n public ApplyLocalPin(detail: MJConversationDetailEntity): void {\n const key = NormalizeUUID(detail.ID);\n const wasPinned = this.pinnedDetails.some(d => NormalizeUUID(d.ID) === key);\n const without = this.pinnedDetails.filter(d => NormalizeUUID(d.ID) !== key);\n this.pinnedDetails = detail.IsPinned ? [detail, ...without] : without;\n\n // Counted independently of the set: before the panel is opened `pinnedDetails` is\n // deliberately EMPTY, so deriving a count from its length would report zero pins on\n // a conversation that has many. `wasPinned` keeps the two in step — without it an\n // unpin of a row that was never in the set decrements a count it never entered.\n if (detail.IsPinned && !wasPinned) {\n this.pinnedTotalCount++;\n } else if (!detail.IsPinned && wasPinned) {\n this.pinnedTotalCount = Math.max(0, this.pinnedTotalCount - 1);\n }\n }\n\n /**\n * Everything the chat area needs to render, copied. Arrays are fresh so ngOnChanges fires.\n *\n * Call this from imperative paths (a load completing, a jump loop) — NOT from a template\n * getter. It copies the loaded set on every call, so binding it into change detection\n * pays that copy once per checked cycle for state that mostly has not moved. The cheap\n * single-value accessors above exist for exactly that case.\n */\n public GetSnapshot(): ConversationDetailWindowSnapshot {\n const details = [...this.loadedDetails];\n return {\n ConversationID: this.conversationId,\n Details: details,\n Cursor: { ...this.cursor },\n PinnedDetails: [...this.pinnedDetails],\n PinnedTotalCount: this.pinnedTotalCount,\n // Peripheral maps are handed out by reference — the chat area copies them into\n // its own UI-shaped maps (LazyArtifactInfo etc.) rather than mutating these.\n AgentRunsByDetailId: this.peripherals.AgentRunsByDetailId,\n UserAvatars: this.peripherals.UserAvatars,\n RatingsByDetailId: this.peripherals.RatingsByDetailId,\n ArtifactsByDetailId: this.peripherals.ArtifactsByDetailId,\n IsLoadingLatest: this.isLoadingLatest,\n IsLoadingOlder: this.isLoadingOlder,\n LoadFailed: this.loadFailed\n };\n }\n\n /**\n * Folds a newly-loaded page's peripherals into the accumulated maps.\n *\n * Later entries win on a key collision, which matters for a window refresh: a re-fetched\n * newest page should replace a row's stale agent run rather than keep the old one.\n */\n private mergePeripherals(incoming: ConversationDetailWindowPeripherals): void {\n for (const [id, run] of incoming.AgentRunsByDetailId) {\n this.peripherals.AgentRunsByDetailId.set(id, run);\n }\n for (const [id, avatar] of incoming.UserAvatars) {\n this.peripherals.UserAvatars.set(id, avatar);\n }\n for (const [id, ratings] of incoming.RatingsByDetailId) {\n this.peripherals.RatingsByDetailId.set(id, ratings);\n }\n for (const [id, artifacts] of incoming.ArtifactsByDetailId) {\n this.peripherals.ArtifactsByDetailId.set(id, artifacts);\n }\n }\n\n /**\n * Union-merges rows into the loaded set: replace-by-ID, then sort by `Sequence`.\n * Dedupe is required because session expansion can re-return rows a prior page held.\n */\n private mergeDetails(incoming: MJConversationDetailEntity[]): void {\n const byId = new Map<string, MJConversationDetailEntity>();\n for (const detail of this.loadedDetails) {\n byId.set(NormalizeUUID(detail.ID), detail);\n }\n for (const detail of incoming) {\n byId.set(NormalizeUUID(detail.ID), detail);\n }\n this.loadedDetails = [...byId.values()].sort((a, b) => a.Sequence - b.Sequence);\n }\n}\n\n/** Empty peripheral maps — the reset / no-window state. */\nfunction emptyPeripherals(): ConversationDetailWindowPeripherals {\n return {\n AgentRunsByDetailId: new Map(),\n UserAvatars: new Map(),\n RatingsByDetailId: new Map(),\n ArtifactsByDetailId: new Map()\n };\n}\n\n/** Copies a load result's peripheral maps into fresh maps the store then owns and merges into. */\nfunction peripheralsFrom(result: DetailWindowLoadResult): ConversationDetailWindowPeripherals {\n return {\n AgentRunsByDetailId: new Map(result.AgentRunsByDetailId),\n UserAvatars: new Map(result.UserAvatars),\n RatingsByDetailId: new Map(result.RatingsByDetailId),\n ArtifactsByDetailId: new Map(result.ArtifactsByDetailId)\n };\n}\n\n/** The empty-window cursor. */\nfunction emptyCursor(): ConversationDetailWindowCursor {\n return { OldestSequence: null, NewestSequence: null, HasMoreAbove: false };\n}\n\n// NOTE: there is deliberately no `cursorFrom(result)` helper. A cursor can never be copied\n// straight off a load result, because the store slices the over-read page down to `pageSize`\n// timeline items — so both the oldest bound and `HasMoreAbove` depend on what survived the\n// slice, not on what the engine fetched.\n"]}
@@ -6,50 +6,70 @@
6
6
  * user message (the original behavior, now delegated here).
7
7
  * - **Realtime sessions**: a voice call that created a fresh conversation names it
8
8
  * from the first user utterance when the call ends.
9
+ * - **Forks**: a Fork or Edit fork is named from the first message sent into it, when it
10
+ * still has no name ({@link GenerateAndApplyForkName}).
9
11
  *
10
12
  * The naming itself is DB-driven: the `Name Conversation` AI prompt runs through the
11
- * GraphQL AI client (same path agents use) with a timeout guard; the parsed
12
- * `{ name, description }` is saved through {@link ConversationEngine.SaveConversation},
13
- * which updates the engine's cached conversation list in place (the sidebar reacts
14
- * through the engine's observables). Failures are logged and return `null` — naming is
13
+ * GraphQL AI client (same path agents use) with a timeout guard ({@link GenerateConversationName}).
14
+ * A conversation's parsed `{ name, description }` is saved through
15
+ * {@link ConversationEngine.SaveConversation}, which updates the engine's cached conversation
16
+ * list in place (the sidebar reacts through the engine's observables); a fork's name is saved
17
+ * on its `MJ: Conversation Branches` row. Failures are logged and return `null` — naming is
15
18
  * always best-effort background work that must never affect the user experience.
16
19
  */
17
- import { UserInfo } from '@memberjunction/core';
18
- import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
19
- /** The applied result of a successful auto-naming run. */
20
+ import { IMetadataProvider, UserInfo } from '@memberjunction/core';
21
+ import { GraphQLDataProvider, type RunAIPromptResult } from '@memberjunction/graphql-dataprovider';
22
+ /** The result of a successful naming run. */
20
23
  export interface ConversationNameResult {
21
- /** The generated conversation name (already saved). */
24
+ /** The generated name, trimmed. */
22
25
  Name: string;
23
- /** The generated description (already saved; empty string when the prompt omitted it). */
26
+ /** The generated description; empty string when the prompt omitted it. */
24
27
  Description: string;
25
28
  }
26
- /** Options for {@link GenerateAndApplyConversationName}. */
27
- export interface GenerateConversationNameOptions {
28
- /** The conversation to name (must exist; the caller owns membership checks). */
29
- ConversationId: string;
29
+ /** The prompt runner {@link GenerateConversationName} calls; a test seam for the GraphQL AI client. */
30
+ export type NamePromptRunner = (promptId: string, messageText: string) => Promise<Pick<RunAIPromptResult, 'success' | 'parsedResult' | 'output'> | null>;
31
+ /** Options for {@link GenerateConversationName}. */
32
+ export interface GenerateNameOptions {
30
33
  /**
31
- * The text the name is derived from — the first user message (regular chat) or the
34
+ * The text the name is derived from — the first user message (regular chat and forks) or the
32
35
  * first spoken user utterance (realtime). Callers strip mentions/markup first.
33
36
  */
34
37
  MessageText: string;
35
38
  /** The GraphQL provider the AI client runs over. */
36
39
  Provider: GraphQLDataProvider;
37
- /** The acting user (threaded into the conversation save). */
38
- CurrentUser: UserInfo;
39
- /** Abort guard for the prompt run. Default 30s — the conversation keeps its default name on timeout. */
40
+ /** Abort guard for the prompt run. Default 30s — the target keeps its current name on timeout. */
40
41
  TimeoutMs?: number;
41
42
  /**
42
43
  * Test seam: overrides the prompt execution. Production leaves this undefined and the
43
44
  * helper runs the `Name Conversation` prompt via {@link GraphQLAIClient.RunAIPrompt}.
44
45
  */
45
- RunPrompt?: (promptId: string, messageText: string) => Promise<{
46
- success: boolean;
47
- parsedResult?: unknown;
48
- output?: string;
49
- } | null>;
46
+ RunPrompt?: NamePromptRunner;
47
+ }
48
+ /** Options for {@link GenerateAndApplyConversationName}. */
49
+ export interface GenerateConversationNameOptions extends GenerateNameOptions {
50
+ /** The conversation to name (must exist; the caller owns membership checks). */
51
+ ConversationId: string;
52
+ /** The acting user (threaded into the conversation save). */
53
+ CurrentUser: UserInfo;
54
+ }
55
+ /** Options for {@link GenerateAndApplyForkName}. */
56
+ export interface GenerateForkNameOptions extends GenerateNameOptions {
57
+ /** The fork (`MJ: Conversation Branches` row) to name. */
58
+ ForkId: string;
59
+ /** The acting user; the branch entity's write rule applies to the save. */
60
+ CurrentUser: UserInfo;
50
61
  }
51
62
  /** The seeded name of the AI prompt that generates conversation names. */
52
63
  export declare const NAME_CONVERSATION_PROMPT = "Name Conversation";
64
+ /** Longest fork name the `MJ: Conversation Branches` Name field holds. */
65
+ export declare const MAX_FORK_NAME_LENGTH = 255;
66
+ /**
67
+ * Runs the `Name Conversation` prompt on a message and parses its `{ name, description }`. Saves nothing.
68
+ *
69
+ * @returns The generated `{ Name, Description }`, or `null` when the prompt is missing, the provider is
70
+ * unavailable, the run fails or times out, or the output has no name. Failures are logged.
71
+ */
72
+ export declare function GenerateConversationName(options: GenerateNameOptions): Promise<ConversationNameResult | null>;
53
73
  /**
54
74
  * Generates a name + description for a conversation from its first message and SAVES it
55
75
  * (DB + engine cache) — the single naming implementation shared by the regular composer
@@ -60,4 +80,34 @@ export declare const NAME_CONVERSATION_PROMPT = "Name Conversation";
60
80
  * the conversation keeps its current name in every null case.
61
81
  */
62
82
  export declare function GenerateAndApplyConversationName(options: GenerateConversationNameOptions): Promise<ConversationNameResult | null>;
83
+ /** Options for {@link SaveForkName}. */
84
+ export interface SaveForkNameOptions {
85
+ /** The fork (`MJ: Conversation Branches` row) to name. */
86
+ ForkId: string;
87
+ /** The new name; null or blank clears it, so the default label shows. Cut to {@link MAX_FORK_NAME_LENGTH}. */
88
+ Name: string | null;
89
+ /** The provider the branch entity is read and saved through. */
90
+ Provider: IMetadataProvider;
91
+ /** The acting user; the branch entity's write rule applies. */
92
+ CurrentUser: UserInfo;
93
+ /** When true, saves nothing if the row read fresh already has a name. */
94
+ OnlyIfUnnamed?: boolean;
95
+ }
96
+ /**
97
+ * Saves a fork's Name through the `MJ: Conversation Branches` entity, after reading the row fresh.
98
+ *
99
+ * @returns true when the name was saved; false when the row cannot be read, when `OnlyIfUnnamed` is
100
+ * set and the row has a name, or when the save fails (logged).
101
+ * @throws when the entity read or save throws
102
+ */
103
+ export declare function SaveForkName(options: SaveForkNameOptions): Promise<boolean>;
104
+ /**
105
+ * Names a fork from its first message: runs the `Name Conversation` prompt ({@link GenerateConversationName})
106
+ * and saves the name as the fork's Name only when the fork, read fresh right before the save, still has
107
+ * no name, so a person's rename wins.
108
+ *
109
+ * @returns The saved name, or `null` when naming failed, the fork already has a name, or the save failed.
110
+ * Failures are logged.
111
+ */
112
+ export declare function GenerateAndApplyForkName(options: GenerateForkNameOptions): Promise<string | null>;
63
113
  //# sourceMappingURL=conversation-naming.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-naming.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,OAAO,EAAE,mBAAmB,EAAmB,MAAM,sCAAsC,CAAC;AAG5F,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAA+B;IAC9C,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,6DAA6D;IAC7D,WAAW,EAAE,QAAQ,CAAC;IACtB,wGAAwG;IACxG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACtI;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAoDxC"}
1
+ {"version":3,"file":"conversation-naming.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,EAAE,mBAAmB,EAAmB,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAGpH,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,uGAAuG;AACvG,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;AAEpF,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAAgC,SAAQ,mBAAmB;IAC1E,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAiDnH;AAED;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAoBxC;AAED,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,8GAA8G;IAC9G,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,+DAA+D;IAC/D,WAAW,EAAE,QAAQ,CAAC;IACtB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBjF;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBvG"}