@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
@@ -0,0 +1,232 @@
1
+ import { LIBOPUS_WORKER_SOURCE } from './libopus-worker-source';
2
+ /**
3
+ * How long {@link WasmOpusEncoder.Flush} waits for the worker's `flushed` reply. The runtime bounds
4
+ * the whole recorder Stop at 2 s, so this stays below that and leaves room for closing up.
5
+ */
6
+ export const WASM_OPUS_FLUSH_TIMEOUT_MS = 1500;
7
+ /**
8
+ * How long {@link WasmOpusEncoder.Start} waits for the worker to instantiate libopus. Instantiating
9
+ * the ~330 KB module takes milliseconds; a worker that says nothing for this long is not running
10
+ * (a Content-Security-Policy without `worker-src blob:` or `'wasm-unsafe-eval'`, for instance).
11
+ */
12
+ export const WASM_OPUS_READY_TIMEOUT_MS = 5000;
13
+ /** Memoized load of the embedded wasm module, so a page only parses the 440 KB string once. */
14
+ let wasmBase64Load = null;
15
+ function loadLibopusWasmBase64() {
16
+ if (!wasmBase64Load) {
17
+ // Dynamic import, category 3 (genuine bundle-size deferral, .claude/rules/typescript-style.md):
18
+ // the embedded libopus build is ~440 KB of base64 and is needed only by browsers whose WebCodecs
19
+ // cannot encode Opus. A static import would put it in every Explorer bundle that loads this
20
+ // library. The module is local to this package, so no dependency is hidden from package.json.
21
+ wasmBase64Load = import('./libopus-wasm-binary').then((module) => module.LIBOPUS_WASM_BASE64);
22
+ wasmBase64Load.catch(() => {
23
+ // Let a later call retry (e.g. a chunk load that failed on a flaky network); the caller logs.
24
+ wasmBase64Load = null;
25
+ });
26
+ }
27
+ return wasmBase64Load;
28
+ }
29
+ /** Decodes base64 into a fresh ArrayBuffer (one the worker can take ownership of). */
30
+ export function DecodeBase64ToArrayBuffer(base64) {
31
+ const binary = atob(base64);
32
+ const bytes = new Uint8Array(binary.length);
33
+ for (let i = 0; i < binary.length; i++) {
34
+ bytes[i] = binary.charCodeAt(i);
35
+ }
36
+ return bytes.buffer;
37
+ }
38
+ /**
39
+ * Opus encoding through libopus compiled to WebAssembly, running in a dedicated Worker so encoding
40
+ * never competes with the call's UI or audio on the main thread. The fallback for browsers whose
41
+ * WebCodecs cannot encode Opus.
42
+ *
43
+ * The worker does the 960-sample framing itself (see {@link LIBOPUS_WORKER_SOURCE}); this class only
44
+ * forwards audio, collects the packets the worker posts back, and turns `flush` into a promise.
45
+ */
46
+ export class WasmOpusEncoder {
47
+ port;
48
+ onClose;
49
+ Kind = 'wasm';
50
+ packets = [];
51
+ flushWaiters = new Map();
52
+ nextFlushId = 1;
53
+ closed = false;
54
+ /** Whether the worker has reported `ready`, or the error it reported instead. */
55
+ startState = 'starting';
56
+ /** Notified once when {@link startState} leaves `starting` (null = ready, else the error). */
57
+ startWaiter = null;
58
+ /**
59
+ * @param port channel to a worker running {@link LIBOPUS_WORKER_SOURCE}
60
+ * @param wasmBytes the libopus module; ownership moves to the worker
61
+ * @param onClose extra cleanup after the worker stops (the Blob URL revoke)
62
+ */
63
+ constructor(port, wasmBytes, onClose = () => undefined) {
64
+ this.port = port;
65
+ this.onClose = onClose;
66
+ port.OnReply = (reply) => this.onReply(reply);
67
+ port.Post({ Type: 'init', Wasm: wasmBytes }, [wasmBytes]);
68
+ }
69
+ /**
70
+ * Loads the embedded wasm and starts the worker from a Blob URL. Rejects if either fails, or if the
71
+ * worker never gets libopus running (see {@link Start}).
72
+ */
73
+ static async Create() {
74
+ const wasmBytes = DecodeBase64ToArrayBuffer(await loadLibopusWasmBase64());
75
+ const url = URL.createObjectURL(new Blob([LIBOPUS_WORKER_SOURCE], { type: 'application/javascript' }));
76
+ let worker;
77
+ try {
78
+ worker = new Worker(url);
79
+ }
80
+ catch (error) {
81
+ URL.revokeObjectURL(url);
82
+ throw error;
83
+ }
84
+ return WasmOpusEncoder.Start(new BrowserWorkerPort(worker), wasmBytes, () => URL.revokeObjectURL(url));
85
+ }
86
+ /**
87
+ * Creates the encoder on `port` and resolves once the worker reports libopus ready. Rejects — after
88
+ * closing the encoder — when the worker reports an init error or says nothing for
89
+ * {@link WASM_OPUS_READY_TIMEOUT_MS}: an encoder that can never produce a packet must fail selection,
90
+ * so the recorder turns recording off visibly instead of "recording" while producing nothing.
91
+ */
92
+ static async Start(port, wasmBytes, onClose = () => undefined) {
93
+ const encoder = new WasmOpusEncoder(port, wasmBytes, onClose);
94
+ try {
95
+ await encoder.waitUntilStarted();
96
+ return encoder;
97
+ }
98
+ catch (error) {
99
+ encoder.Close();
100
+ throw error;
101
+ }
102
+ }
103
+ Encode(pcm48k) {
104
+ if (this.closed || pcm48k.length === 0) {
105
+ return;
106
+ }
107
+ const copy = pcm48k.slice();
108
+ this.port.Post({ Type: 'encode', Pcm: copy }, [copy.buffer]);
109
+ }
110
+ Flush() {
111
+ if (this.closed) {
112
+ return Promise.resolve();
113
+ }
114
+ const id = this.nextFlushId++;
115
+ return new Promise((resolve) => {
116
+ const timer = setTimeout(() => {
117
+ this.flushWaiters.delete(id);
118
+ console.warn(`[WasmOpusEncoder] Worker did not confirm flush within ${WASM_OPUS_FLUSH_TIMEOUT_MS} ms — the final packets may be missing.`);
119
+ resolve();
120
+ }, WASM_OPUS_FLUSH_TIMEOUT_MS);
121
+ this.flushWaiters.set(id, () => {
122
+ clearTimeout(timer);
123
+ resolve();
124
+ });
125
+ this.port.Post({ Type: 'flush', ID: id }, []);
126
+ });
127
+ }
128
+ TakePackets() {
129
+ const packets = this.packets;
130
+ this.packets = [];
131
+ return packets;
132
+ }
133
+ Close() {
134
+ if (this.closed) {
135
+ return;
136
+ }
137
+ this.closed = true;
138
+ this.port.OnReply = null;
139
+ this.port.Terminate();
140
+ this.onClose();
141
+ // A flush still waiting can never be answered now; release it instead of leaving it to the timeout.
142
+ for (const release of this.flushWaiters.values()) {
143
+ release();
144
+ }
145
+ this.flushWaiters.clear();
146
+ }
147
+ /** Records the worker's start outcome (only the first one counts) and wakes {@link waitUntilStarted}. */
148
+ settleStart(error) {
149
+ if (this.startState !== 'starting') {
150
+ return;
151
+ }
152
+ this.startState = error === null ? 'ready' : { Error: error };
153
+ const waiter = this.startWaiter;
154
+ this.startWaiter = null;
155
+ waiter?.(error);
156
+ }
157
+ /** Resolves once the worker is ready; rejects with its init error or after the start timeout. */
158
+ waitUntilStarted() {
159
+ return new Promise((resolve, reject) => {
160
+ const state = this.startState;
161
+ if (state === 'ready') {
162
+ resolve();
163
+ return;
164
+ }
165
+ if (state !== 'starting') {
166
+ reject(new Error(state.Error));
167
+ return;
168
+ }
169
+ const timer = setTimeout(() => {
170
+ this.startWaiter = null;
171
+ reject(new Error(`libopus worker did not start within ${WASM_OPUS_READY_TIMEOUT_MS} ms`));
172
+ }, WASM_OPUS_READY_TIMEOUT_MS);
173
+ this.startWaiter = (error) => {
174
+ clearTimeout(timer);
175
+ if (error === null) {
176
+ resolve();
177
+ }
178
+ else {
179
+ reject(new Error(error));
180
+ }
181
+ };
182
+ });
183
+ }
184
+ onReply(reply) {
185
+ switch (reply.Type) {
186
+ case 'packets':
187
+ for (const buffer of reply.Packets) {
188
+ this.packets.push(new Uint8Array(buffer));
189
+ }
190
+ break;
191
+ case 'flushed': {
192
+ const release = this.flushWaiters.get(reply.ID);
193
+ this.flushWaiters.delete(reply.ID);
194
+ release?.();
195
+ break;
196
+ }
197
+ case 'error':
198
+ console.warn(`[WasmOpusEncoder] ${reply.Message} — the rest of this call is not recorded.`);
199
+ this.settleStart(reply.Message);
200
+ break;
201
+ case 'ready':
202
+ this.settleStart(null);
203
+ break;
204
+ }
205
+ }
206
+ }
207
+ /** Adapts a DOM `Worker` to {@link OpusWorkerPort}. */
208
+ export class BrowserWorkerPort {
209
+ worker;
210
+ OnReply = null;
211
+ constructor(worker) {
212
+ this.worker = worker;
213
+ worker.onmessage = (event) => this.OnReply?.(event.data);
214
+ // A worker that fails to load or throws (a Content-Security-Policy without `worker-src blob:`, for
215
+ // instance) reports it here, not through a message. Surface it as an error reply, so a starting
216
+ // encoder fails at once instead of after its start timeout.
217
+ worker.onerror = (event) => {
218
+ const message = `Encoder worker error: ${event.message}`;
219
+ console.warn(`[WasmOpusEncoder] ${message}`);
220
+ this.OnReply?.({ Type: 'error', Message: message });
221
+ };
222
+ }
223
+ Post(message, transfer) {
224
+ this.worker.postMessage(message, transfer);
225
+ }
226
+ Terminate() {
227
+ this.worker.onmessage = null;
228
+ this.worker.onerror = null;
229
+ this.worker.terminate();
230
+ }
231
+ }
232
+ //# sourceMappingURL=wasm-opus-encoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-opus-encoder.js","sourceRoot":"","sources":["../../../../src/lib/services/recording/wasm-opus-encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import { LIBOPUS_WORKER_SOURCE, OpusWorkerReply, OpusWorkerRequest } from './libopus-worker-source';\nimport type { IOpusPacketEncoder } from './opus-packet-encoder';\n\n/**\n * How long {@link WasmOpusEncoder.Flush} waits for the worker's `flushed` reply. The runtime bounds\n * the whole recorder Stop at 2 s, so this stays below that and leaves room for closing up.\n */\nexport const WASM_OPUS_FLUSH_TIMEOUT_MS = 1500;\n\n/**\n * How long {@link WasmOpusEncoder.Start} waits for the worker to instantiate libopus. Instantiating\n * the ~330 KB module takes milliseconds; a worker that says nothing for this long is not running\n * (a Content-Security-Policy without `worker-src blob:` or `'wasm-unsafe-eval'`, for instance).\n */\nexport const WASM_OPUS_READY_TIMEOUT_MS = 5000;\n\n/** The two-way channel to the encoder worker. A real `Worker` is adapted to it; tests run the worker source in-process. */\nexport interface OpusWorkerPort {\n /** Posts a request, transferring the listed buffers. */\n Post(message: OpusWorkerRequest, transfer: Transferable[]): void;\n /** Receives every reply the worker posts. */\n OnReply: ((reply: OpusWorkerReply) => void) | null;\n /** Stops the worker. */\n Terminate(): void;\n}\n\n/** Memoized load of the embedded wasm module, so a page only parses the 440 KB string once. */\nlet wasmBase64Load: Promise<string> | null = null;\n\nfunction loadLibopusWasmBase64(): Promise<string> {\n if (!wasmBase64Load) {\n // Dynamic import, category 3 (genuine bundle-size deferral, .claude/rules/typescript-style.md):\n // the embedded libopus build is ~440 KB of base64 and is needed only by browsers whose WebCodecs\n // cannot encode Opus. A static import would put it in every Explorer bundle that loads this\n // library. The module is local to this package, so no dependency is hidden from package.json.\n wasmBase64Load = import('./libopus-wasm-binary').then((module) => module.LIBOPUS_WASM_BASE64);\n wasmBase64Load.catch(() => {\n // Let a later call retry (e.g. a chunk load that failed on a flaky network); the caller logs.\n wasmBase64Load = null;\n });\n }\n return wasmBase64Load;\n}\n\n/** Decodes base64 into a fresh ArrayBuffer (one the worker can take ownership of). */\nexport function DecodeBase64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * Opus encoding through libopus compiled to WebAssembly, running in a dedicated Worker so encoding\n * never competes with the call's UI or audio on the main thread. The fallback for browsers whose\n * WebCodecs cannot encode Opus.\n *\n * The worker does the 960-sample framing itself (see {@link LIBOPUS_WORKER_SOURCE}); this class only\n * forwards audio, collects the packets the worker posts back, and turns `flush` into a promise.\n */\nexport class WasmOpusEncoder implements IOpusPacketEncoder {\n public readonly Kind = 'wasm';\n private packets: Uint8Array[] = [];\n private readonly flushWaiters = new Map<number, () => void>();\n private nextFlushId = 1;\n private closed = false;\n /** Whether the worker has reported `ready`, or the error it reported instead. */\n private startState: 'starting' | 'ready' | { Error: string } = 'starting';\n /** Notified once when {@link startState} leaves `starting` (null = ready, else the error). */\n private startWaiter: ((error: string | null) => void) | null = null;\n\n /**\n * @param port channel to a worker running {@link LIBOPUS_WORKER_SOURCE}\n * @param wasmBytes the libopus module; ownership moves to the worker\n * @param onClose extra cleanup after the worker stops (the Blob URL revoke)\n */\n constructor(private readonly port: OpusWorkerPort, wasmBytes: ArrayBuffer, private readonly onClose: () => void = () => undefined) {\n port.OnReply = (reply) => this.onReply(reply);\n port.Post({ Type: 'init', Wasm: wasmBytes }, [wasmBytes]);\n }\n\n /**\n * Loads the embedded wasm and starts the worker from a Blob URL. Rejects if either fails, or if the\n * worker never gets libopus running (see {@link Start}).\n */\n public static async Create(): Promise<WasmOpusEncoder> {\n const wasmBytes = DecodeBase64ToArrayBuffer(await loadLibopusWasmBase64());\n const url = URL.createObjectURL(new Blob([LIBOPUS_WORKER_SOURCE], { type: 'application/javascript' }));\n let worker: Worker;\n try {\n worker = new Worker(url);\n } catch (error) {\n URL.revokeObjectURL(url);\n throw error;\n }\n return WasmOpusEncoder.Start(new BrowserWorkerPort(worker), wasmBytes, () => URL.revokeObjectURL(url));\n }\n\n /**\n * Creates the encoder on `port` and resolves once the worker reports libopus ready. Rejects — after\n * closing the encoder — when the worker reports an init error or says nothing for\n * {@link WASM_OPUS_READY_TIMEOUT_MS}: an encoder that can never produce a packet must fail selection,\n * so the recorder turns recording off visibly instead of \"recording\" while producing nothing.\n */\n public static async Start(port: OpusWorkerPort, wasmBytes: ArrayBuffer, onClose: () => void = () => undefined): Promise<WasmOpusEncoder> {\n const encoder = new WasmOpusEncoder(port, wasmBytes, onClose);\n try {\n await encoder.waitUntilStarted();\n return encoder;\n } catch (error) {\n encoder.Close();\n throw error;\n }\n }\n\n public Encode(pcm48k: Float32Array): void {\n if (this.closed || pcm48k.length === 0) {\n return;\n }\n const copy = pcm48k.slice();\n this.port.Post({ Type: 'encode', Pcm: copy }, [copy.buffer]);\n }\n\n public Flush(): Promise<void> {\n if (this.closed) {\n return Promise.resolve();\n }\n const id = this.nextFlushId++;\n return new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n this.flushWaiters.delete(id);\n console.warn(`[WasmOpusEncoder] Worker did not confirm flush within ${WASM_OPUS_FLUSH_TIMEOUT_MS} ms — the final packets may be missing.`);\n resolve();\n }, WASM_OPUS_FLUSH_TIMEOUT_MS);\n this.flushWaiters.set(id, () => {\n clearTimeout(timer);\n resolve();\n });\n this.port.Post({ Type: 'flush', ID: id }, []);\n });\n }\n\n public TakePackets(): Uint8Array[] {\n const packets = this.packets;\n this.packets = [];\n return packets;\n }\n\n public Close(): void {\n if (this.closed) {\n return;\n }\n this.closed = true;\n this.port.OnReply = null;\n this.port.Terminate();\n this.onClose();\n // A flush still waiting can never be answered now; release it instead of leaving it to the timeout.\n for (const release of this.flushWaiters.values()) {\n release();\n }\n this.flushWaiters.clear();\n }\n\n /** Records the worker's start outcome (only the first one counts) and wakes {@link waitUntilStarted}. */\n private settleStart(error: string | null): void {\n if (this.startState !== 'starting') {\n return;\n }\n this.startState = error === null ? 'ready' : { Error: error };\n const waiter = this.startWaiter;\n this.startWaiter = null;\n waiter?.(error);\n }\n\n /** Resolves once the worker is ready; rejects with its init error or after the start timeout. */\n private waitUntilStarted(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const state = this.startState;\n if (state === 'ready') {\n resolve();\n return;\n }\n if (state !== 'starting') {\n reject(new Error(state.Error));\n return;\n }\n const timer = setTimeout(() => {\n this.startWaiter = null;\n reject(new Error(`libopus worker did not start within ${WASM_OPUS_READY_TIMEOUT_MS} ms`));\n }, WASM_OPUS_READY_TIMEOUT_MS);\n this.startWaiter = (error) => {\n clearTimeout(timer);\n if (error === null) {\n resolve();\n } else {\n reject(new Error(error));\n }\n };\n });\n }\n\n private onReply(reply: OpusWorkerReply): void {\n switch (reply.Type) {\n case 'packets':\n for (const buffer of reply.Packets) {\n this.packets.push(new Uint8Array(buffer));\n }\n break;\n case 'flushed': {\n const release = this.flushWaiters.get(reply.ID);\n this.flushWaiters.delete(reply.ID);\n release?.();\n break;\n }\n case 'error':\n console.warn(`[WasmOpusEncoder] ${reply.Message} — the rest of this call is not recorded.`);\n this.settleStart(reply.Message);\n break;\n case 'ready':\n this.settleStart(null);\n break;\n }\n }\n}\n\n/** The slice of a DOM `Worker` {@link BrowserWorkerPort} drives (the real `Worker` satisfies it). */\nexport type WorkerLike = Pick<Worker, 'postMessage' | 'terminate'> & {\n // case-violation-ok-legacy-back-compat: mirrors the DOM Worker handler properties so a real Worker satisfies this type\n onmessage: ((event: MessageEvent<OpusWorkerReply>) => void) | null;\n // case-violation-ok-legacy-back-compat: mirrors the DOM Worker handler properties so a real Worker satisfies this type\n onerror: ((event: ErrorEvent) => void) | null;\n};\n\n/** Adapts a DOM `Worker` to {@link OpusWorkerPort}. */\nexport class BrowserWorkerPort implements OpusWorkerPort {\n public OnReply: ((reply: OpusWorkerReply) => void) | null = null;\n\n constructor(private readonly worker: WorkerLike) {\n worker.onmessage = (event: MessageEvent<OpusWorkerReply>) => this.OnReply?.(event.data);\n // A worker that fails to load or throws (a Content-Security-Policy without `worker-src blob:`, for\n // instance) reports it here, not through a message. Surface it as an error reply, so a starting\n // encoder fails at once instead of after its start timeout.\n worker.onerror = (event: ErrorEvent) => {\n const message = `Encoder worker error: ${event.message}`;\n console.warn(`[WasmOpusEncoder] ${message}`);\n this.OnReply?.({ Type: 'error', Message: message });\n };\n }\n\n public Post(message: OpusWorkerRequest, transfer: Transferable[]): void {\n this.worker.postMessage(message, transfer);\n }\n\n public Terminate(): void {\n this.worker.onmessage = null;\n this.worker.onerror = null;\n this.worker.terminate();\n }\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import type { IOpusPacketEncoder } from './opus-packet-encoder';
2
+ /** The recording's Opus configuration for WebCodecs: mono 48 kHz, 32 kbps, 20 ms frames. */
3
+ export declare const WEBCODECS_OPUS_CONFIG: AudioEncoderConfig;
4
+ /** The slice of a WebCodecs `AudioEncoder` instance this wrapper drives. */
5
+ export type AudioEncoderLike = Pick<AudioEncoder, 'configure' | 'encode' | 'flush' | 'close' | 'state'>;
6
+ /** The WebCodecs `AudioEncoder` constructor shape (the real global satisfies it). */
7
+ export interface AudioEncoderConstructor {
8
+ new (init: AudioEncoderInit): AudioEncoderLike;
9
+ isConfigSupported(config: AudioEncoderConfig): Promise<AudioEncoderSupport>;
10
+ }
11
+ /** The WebCodecs `AudioData` constructor shape (the real global satisfies it). */
12
+ export interface AudioDataConstructor {
13
+ new (init: AudioDataInit): AudioData;
14
+ }
15
+ /**
16
+ * Opus encoding through the browser's native WebCodecs `AudioEncoder`.
17
+ *
18
+ * Each 48 kHz block becomes one `AudioData` whose timestamp comes from the running sample count
19
+ * (never the wall clock), so the encoder sees one gap-free stream. The encoder emits one
20
+ * `EncodedAudioChunk` per 20 ms packet; each is copied out immediately because a chunk's bytes are
21
+ * only guaranteed while the callback runs.
22
+ */
23
+ export declare class WebCodecsOpusEncoder implements IOpusPacketEncoder {
24
+ private readonly audioData;
25
+ readonly Kind = "webcodecs";
26
+ private readonly encoder;
27
+ private packets;
28
+ private samplesFed;
29
+ /** Set by the encoder's error callback or a throwing encode: later input is dropped, packets kept. */
30
+ private failed;
31
+ private closed;
32
+ /** Creates and configures the encoder. Throws if `configure` does (the selector falls back to WASM). */
33
+ constructor(audioEncoder: AudioEncoderConstructor, audioData: AudioDataConstructor);
34
+ Encode(pcm48k: Float32Array): void;
35
+ Flush(): Promise<void>;
36
+ TakePackets(): Uint8Array[];
37
+ Close(): void;
38
+ }
39
+ //# sourceMappingURL=webcodecs-opus-encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webcodecs-opus-encoder.d.ts","sourceRoot":"","sources":["../../../../src/lib/services/recording/webcodecs-opus-encoder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,4FAA4F;AAC5F,eAAO,MAAM,qBAAqB,EAAE,kBAMnC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;AAExG,qFAAqF;AACrF,MAAM,WAAW,uBAAuB;IACpC,KAAK,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CAAC;IAE/C,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC/E;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACjC,KAAK,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;IAUR,OAAO,CAAC,QAAQ,CAAC,SAAS;IAT7E,SAAgB,IAAI,eAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,UAAU,CAAK;IACvB,sGAAsG;IACtG,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IAEvB,wGAAwG;gBAC5F,YAAY,EAAE,uBAAuB,EAAmB,SAAS,EAAE,oBAAoB;IAgB5F,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAwB5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,WAAW,IAAI,UAAU,EAAE;IAM3B,KAAK,IAAI,IAAI;CAcvB"}
@@ -0,0 +1,101 @@
1
+ import { RECORDING_SAMPLE_RATE } from '@memberjunction/ai-core-plus';
2
+ /** The recording's Opus configuration for WebCodecs: mono 48 kHz, 32 kbps, 20 ms frames. */
3
+ export const WEBCODECS_OPUS_CONFIG = {
4
+ codec: 'opus',
5
+ sampleRate: RECORDING_SAMPLE_RATE,
6
+ numberOfChannels: 1,
7
+ bitrate: 32000,
8
+ opus: { frameDuration: 20000 },
9
+ };
10
+ /**
11
+ * Opus encoding through the browser's native WebCodecs `AudioEncoder`.
12
+ *
13
+ * Each 48 kHz block becomes one `AudioData` whose timestamp comes from the running sample count
14
+ * (never the wall clock), so the encoder sees one gap-free stream. The encoder emits one
15
+ * `EncodedAudioChunk` per 20 ms packet; each is copied out immediately because a chunk's bytes are
16
+ * only guaranteed while the callback runs.
17
+ */
18
+ export class WebCodecsOpusEncoder {
19
+ audioData;
20
+ Kind = 'webcodecs';
21
+ encoder;
22
+ packets = [];
23
+ samplesFed = 0;
24
+ /** Set by the encoder's error callback or a throwing encode: later input is dropped, packets kept. */
25
+ failed = false;
26
+ closed = false;
27
+ /** Creates and configures the encoder. Throws if `configure` does (the selector falls back to WASM). */
28
+ constructor(audioEncoder, audioData) {
29
+ this.audioData = audioData;
30
+ this.encoder = new audioEncoder({
31
+ output: (chunk) => {
32
+ const bytes = new Uint8Array(chunk.byteLength);
33
+ chunk.copyTo(bytes);
34
+ this.packets.push(bytes);
35
+ },
36
+ error: (error) => {
37
+ // The recorder keeps the packets it already has; a broken encoder must never end the call.
38
+ console.warn(`[WebCodecsOpusEncoder] Encoder failed after ${this.samplesFed} samples — the rest of this call is not recorded:`, error);
39
+ this.failed = true;
40
+ },
41
+ });
42
+ this.encoder.configure(WEBCODECS_OPUS_CONFIG);
43
+ }
44
+ Encode(pcm48k) {
45
+ if (this.failed || this.closed || pcm48k.length === 0) {
46
+ return;
47
+ }
48
+ const data = new this.audioData({
49
+ format: 'f32',
50
+ sampleRate: RECORDING_SAMPLE_RATE,
51
+ numberOfFrames: pcm48k.length,
52
+ numberOfChannels: 1,
53
+ timestamp: Math.round((this.samplesFed * 1_000_000) / RECORDING_SAMPLE_RATE),
54
+ // AudioData needs an ArrayBuffer-backed view (not a SharedArrayBuffer one); it copies anyway.
55
+ data: pcm48k.buffer instanceof ArrayBuffer ? pcm48k : new Float32Array(pcm48k),
56
+ });
57
+ this.samplesFed += pcm48k.length;
58
+ try {
59
+ this.encoder.encode(data);
60
+ }
61
+ catch (error) {
62
+ console.warn(`[WebCodecsOpusEncoder] encode() threw at sample ${this.samplesFed} — the rest of this call is not recorded:`, error);
63
+ this.failed = true;
64
+ }
65
+ finally {
66
+ data.close();
67
+ }
68
+ }
69
+ async Flush() {
70
+ if (this.failed || this.closed) {
71
+ return;
72
+ }
73
+ try {
74
+ await this.encoder.flush();
75
+ }
76
+ catch (error) {
77
+ console.warn(`[WebCodecsOpusEncoder] flush() failed after ${this.samplesFed} samples — the final packets may be missing:`, error);
78
+ }
79
+ }
80
+ TakePackets() {
81
+ const packets = this.packets;
82
+ this.packets = [];
83
+ return packets;
84
+ }
85
+ Close() {
86
+ if (this.closed) {
87
+ return;
88
+ }
89
+ this.closed = true;
90
+ if (this.encoder.state === 'closed') {
91
+ return;
92
+ }
93
+ try {
94
+ this.encoder.close();
95
+ }
96
+ catch (error) {
97
+ console.warn('[WebCodecsOpusEncoder] close() failed:', error);
98
+ }
99
+ }
100
+ }
101
+ //# sourceMappingURL=webcodecs-opus-encoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webcodecs-opus-encoder.js","sourceRoot":"","sources":["../../../../src/lib/services/recording/webcodecs-opus-encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import { RECORDING_SAMPLE_RATE } from '@memberjunction/ai-core-plus';\nimport type { IOpusPacketEncoder } from './opus-packet-encoder';\n\n/** The recording's Opus configuration for WebCodecs: mono 48 kHz, 32 kbps, 20 ms frames. */\nexport const WEBCODECS_OPUS_CONFIG: AudioEncoderConfig = {\n codec: 'opus',\n sampleRate: RECORDING_SAMPLE_RATE,\n numberOfChannels: 1,\n bitrate: 32000,\n opus: { frameDuration: 20000 },\n};\n\n/** The slice of a WebCodecs `AudioEncoder` instance this wrapper drives. */\nexport type AudioEncoderLike = Pick<AudioEncoder, 'configure' | 'encode' | 'flush' | 'close' | 'state'>;\n\n/** The WebCodecs `AudioEncoder` constructor shape (the real global satisfies it). */\nexport interface AudioEncoderConstructor {\n new (init: AudioEncoderInit): AudioEncoderLike;\n // case-violation-ok-legacy-back-compat: mirrors the WebCodecs static so the real `AudioEncoder` global satisfies this interface\n isConfigSupported(config: AudioEncoderConfig): Promise<AudioEncoderSupport>;\n}\n\n/** The WebCodecs `AudioData` constructor shape (the real global satisfies it). */\nexport interface AudioDataConstructor {\n new (init: AudioDataInit): AudioData;\n}\n\n/**\n * Opus encoding through the browser's native WebCodecs `AudioEncoder`.\n *\n * Each 48 kHz block becomes one `AudioData` whose timestamp comes from the running sample count\n * (never the wall clock), so the encoder sees one gap-free stream. The encoder emits one\n * `EncodedAudioChunk` per 20 ms packet; each is copied out immediately because a chunk's bytes are\n * only guaranteed while the callback runs.\n */\nexport class WebCodecsOpusEncoder implements IOpusPacketEncoder {\n public readonly Kind = 'webcodecs';\n private readonly encoder: AudioEncoderLike;\n private packets: Uint8Array[] = [];\n private samplesFed = 0;\n /** Set by the encoder's error callback or a throwing encode: later input is dropped, packets kept. */\n private failed = false;\n private closed = false;\n\n /** Creates and configures the encoder. Throws if `configure` does (the selector falls back to WASM). */\n constructor(audioEncoder: AudioEncoderConstructor, private readonly audioData: AudioDataConstructor) {\n this.encoder = new audioEncoder({\n output: (chunk: EncodedAudioChunk) => {\n const bytes = new Uint8Array(chunk.byteLength);\n chunk.copyTo(bytes);\n this.packets.push(bytes);\n },\n error: (error: DOMException) => {\n // The recorder keeps the packets it already has; a broken encoder must never end the call.\n console.warn(`[WebCodecsOpusEncoder] Encoder failed after ${this.samplesFed} samples — the rest of this call is not recorded:`, error);\n this.failed = true;\n },\n });\n this.encoder.configure(WEBCODECS_OPUS_CONFIG);\n }\n\n public Encode(pcm48k: Float32Array): void {\n if (this.failed || this.closed || pcm48k.length === 0) {\n return;\n }\n const data = new this.audioData({\n format: 'f32',\n sampleRate: RECORDING_SAMPLE_RATE,\n numberOfFrames: pcm48k.length,\n numberOfChannels: 1,\n timestamp: Math.round((this.samplesFed * 1_000_000) / RECORDING_SAMPLE_RATE),\n // AudioData needs an ArrayBuffer-backed view (not a SharedArrayBuffer one); it copies anyway.\n data: pcm48k.buffer instanceof ArrayBuffer ? (pcm48k as Float32Array<ArrayBuffer>) : new Float32Array(pcm48k),\n });\n this.samplesFed += pcm48k.length;\n try {\n this.encoder.encode(data);\n } catch (error) {\n console.warn(`[WebCodecsOpusEncoder] encode() threw at sample ${this.samplesFed} — the rest of this call is not recorded:`, error);\n this.failed = true;\n } finally {\n data.close();\n }\n }\n\n public async Flush(): Promise<void> {\n if (this.failed || this.closed) {\n return;\n }\n try {\n await this.encoder.flush();\n } catch (error) {\n console.warn(`[WebCodecsOpusEncoder] flush() failed after ${this.samplesFed} samples — the final packets may be missing:`, error);\n }\n }\n\n public TakePackets(): Uint8Array[] {\n const packets = this.packets;\n this.packets = [];\n return packets;\n }\n\n public Close(): void {\n if (this.closed) {\n return;\n }\n this.closed = true;\n if (this.encoder.state === 'closed') {\n return;\n }\n try {\n this.encoder.close();\n } catch (error) {\n console.warn('[WebCodecsOpusEncoder] close() failed:', error);\n }\n }\n}\n"]}
@@ -26,6 +26,10 @@ export interface SearchResult {
26
26
  collectionName?: string;
27
27
  createdAt: Date;
28
28
  relevanceScore: number;
29
+ /** A message hit's branch; null is the trunk. */
30
+ branchId?: string | null;
31
+ /** A message hit's position in its conversation. */
32
+ sequence?: number;
29
33
  }
30
34
  /**
31
35
  * Search results grouped by type
@@ -107,7 +111,8 @@ export declare class SearchService {
107
111
  */
108
112
  private searchConversations;
109
113
  /**
110
- * Search message content inside the conversations the conversation list shows the user
114
+ * Search message content inside the conversations the conversation list shows the user,
115
+ * on every branch of each conversation
111
116
  */
112
117
  private searchMessages;
113
118
  /**
@@ -135,7 +140,7 @@ export declare class SearchService {
135
140
  */
136
141
  private mapConversationToSearchResult;
137
142
  /**
138
- * Map message entity to search result
143
+ * Map a message row to a search result, with the branch and sequence that locate it
139
144
  */
140
145
  private mapMessageToSearchResult;
141
146
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"search.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/search.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/search.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,UAAU,EAAe,MAAM,MAAM,CAAC;AAYhE,OAAO,EAAW,QAAQ,EAAY,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;;AAG1E;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,OAAO,CAAC;AAExG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAaD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH;;;;;;;;;GASG;AACH,qBAGa,aAAa;IAoDZ,OAAO,CAAC,mBAAmB;IAnDvC,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,WAAW,CAA8D;IACjF,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,eAAe,CAOpB;IAGH,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAM;IAG1C,SAAgB,YAAY,qBAAqC;IAEjE,4CAA4C;IAC5C,IAAW,YAAY,uBAEtB;IACD,SAAgB,aAAa,2BAAsC;IAEnE,6CAA6C;IAC7C,IAAW,aAAa,6BAEvB;IACD,SAAgB,UAAU,wBAAmC;IAE7D,0CAA0C;IAC1C,IAAW,UAAU,0BAEpB;IACD,SAAgB,YAAY,sBAAqC;IAEjE,4CAA4C;IAC5C,IAAW,YAAY,wBAEtB;IACD,SAAgB,cAAc,mCAAuC;IAErE,8CAA8C;IAC9C,IAAW,cAAc,qCAExB;IAED,OAAO,CAAC,SAAS,CAAkC;gBAE/B,mBAAmB,EAAE,yBAAyB;IAKlE;;;OAGG;IACH,IAAW,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAKlD;IAED,IAAW,QAAQ,IAAI,iBAAiB,CAEvC;IAED;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACU,MAAM,CACjB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,QAAQ,GACpB,OAAO,CAAC,oBAAoB,CAAC;IAwDhC,sCAAsC;IACzB,MAAM,CACjB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,QAAQ,GACpB,OAAO,CAAC,oBAAoB,CAAC;IAIhC;;;OAGG;YACW,mBAAmB;IAsCjC;;;OAGG;YACW,cAAc;IAgD5B;;;OAGG;YACW,yBAAyB;IAmBvC;;;OAGG;YACW,eAAe;IAwE7B;;;OAGG;YACW,iBAAiB;IA8C/B;;;OAGG;YACW,WAAW;IAwCzB;;OAEG;IACH,OAAO,CAAC,6BAA6B;IA6BrC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmBhC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IA2BnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyB7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACI,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIlD,+CAA+C;IACxC,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIlD;;OAEG;IACI,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAI3C,4CAA4C;IACrC,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAI3C;;OAEG;IACI,YAAY,IAAI,IAAI;IAK3B,4CAA4C;IACrC,YAAY,IAAI,IAAI;IAI3B;;OAEG;IACI,YAAY,IAAI,IAAI;IAW3B,4CAA4C;IACrC,YAAY,IAAI,IAAI;IAI3B;;OAEG;IACI,iBAAiB,IAAI,MAAM,EAAE;IAIpC,iDAAiD;IAC1C,iBAAiB,IAAI,MAAM,EAAE;IAIpC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;IACI,mBAAmB,IAAI,IAAI;IAKlC,mDAAmD;IAC5C,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;yCAruBf,aAAa;6CAAb,aAAa;CA4uBzB"}
@@ -4,8 +4,13 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
4
4
  import { ConversationEngine } from '@memberjunction/core-entities';
5
5
  import { RunView, Metadata } from '@memberjunction/core';
6
6
  import { EscapeSQLString } from '@memberjunction/global';
7
+ import { BuildConversationTasksFilter } from './conversation-tasks-filter';
7
8
  import * as i0 from "@angular/core";
8
9
  import * as i1 from "./artifact-permission.service";
10
+ /** Columns of {@link MessageSearchRow}, as the message query's `Fields`. */
11
+ const MESSAGE_SEARCH_FIELDS = [
12
+ 'ID', 'ConversationID', 'Conversation', 'Message', 'BranchID', 'Sequence', '__mj_CreatedAt'
13
+ ];
9
14
  /**
10
15
  * Service for searching across conversations, messages, and artifacts
11
16
  * Provides debounced search with result ranking and filtering
@@ -179,7 +184,8 @@ export class SearchService {
179
184
  return result.Results.map(conv => this.mapConversationToSearchResult(conv, query));
180
185
  }
181
186
  /**
182
- * Search message content inside the conversations the conversation list shows the user
187
+ * Search message content inside the conversations the conversation list shows the user,
188
+ * on every branch of each conversation
183
189
  */
184
190
  async searchMessages(query, environmentId, currentUser, dateRange) {
185
191
  const conversationIds = await this.getVisibleConversationIds(environmentId, currentUser);
@@ -199,12 +205,14 @@ export class SearchService {
199
205
  if (dateRange.end) {
200
206
  filter += ` AND __mj_CreatedAt <= '${dateRange.end.toISOString()}'`;
201
207
  }
208
+ // conversation-scope: search spans every path on purpose; opening a hit switches to its branch
202
209
  const result = await rv.RunView({
203
210
  EntityName: 'MJ: Conversation Details',
204
211
  ExtraFilter: filter,
205
212
  OrderBy: '__mj_CreatedAt DESC',
206
213
  MaxRows: 100,
207
- ResultType: 'entity_object'
214
+ Fields: [...MESSAGE_SEARCH_FIELDS],
215
+ ResultType: 'simple'
208
216
  }, currentUser);
209
217
  if (!result.Success || !result.Results) {
210
218
  console.error('Failed to search messages:', result.ErrorMessage);
@@ -322,22 +330,8 @@ export class SearchService {
322
330
  async searchTasks(query, environmentId, currentUser, dateRange) {
323
331
  const rv = RunView.FromMetadataProvider(this.Provider);
324
332
  const lowerQuery = query.toLowerCase();
325
- // Build filter using same logic as TasksFullViewComponent
326
- const md = this.Provider;
327
- const cd = md.EntityByName('MJ: Conversation Details');
328
- const c = md.EntityByName('MJ: Conversations');
329
- if (!cd || !c) {
330
- console.warn('⚠️ Missing metadata for Conversations or Conversation Details');
331
- return [];
332
- }
333
- let filter = `ParentID IS NULL AND (UserID = '${currentUser.ID}' OR ConversationDetailID IN (
334
- SELECT ID FROM [${cd.SchemaName}].[${cd.BaseView}]
335
- WHERE
336
- UserID ='${currentUser.ID}' OR
337
- ConversationID IN (
338
- SELECT ID FROM [${c.SchemaName}].[${c.BaseView}] WHERE UserID='${currentUser.ID}'
339
- )
340
- ))`;
333
+ // The same tasks the conversation workspace's tasks view shows.
334
+ let filter = await BuildConversationTasksFilter(this.Provider, currentUser);
341
335
  filter += ` AND (LOWER(Name) LIKE '%${EscapeSQLString(lowerQuery)}%' OR LOWER(Description) LIKE '%${EscapeSQLString(lowerQuery)}%')`;
342
336
  if (dateRange.start) {
343
337
  filter += ` AND __mj_CreatedAt >= '${dateRange.start.toISOString()}'`;
@@ -386,7 +380,7 @@ export class SearchService {
386
380
  };
387
381
  }
388
382
  /**
389
- * Map message entity to search result
383
+ * Map a message row to a search result, with the branch and sequence that locate it
390
384
  */
391
385
  mapMessageToSearchResult(message, query) {
392
386
  const messageText = message.Message || '';
@@ -400,7 +394,9 @@ export class SearchService {
400
394
  conversationId: message.ConversationID,
401
395
  conversationName: message.Conversation || undefined,
402
396
  createdAt: message.__mj_CreatedAt,
403
- relevanceScore: 5
397
+ relevanceScore: 5,
398
+ branchId: message.BranchID ?? null,
399
+ sequence: message.Sequence
404
400
  };
405
401
  }
406
402
  /**