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

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 (164) hide show
  1. package/dist/lib/components/attachment/image-viewer.component.d.ts +3 -1
  2. package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
  3. package/dist/lib/components/attachment/image-viewer.component.js +5 -1
  4. package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
  5. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  6. package/dist/lib/components/collection/collection-view.component.js +1 -0
  7. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  8. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +188 -9
  9. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  10. package/dist/lib/components/conversation/conversation-chat-area.component.js +1333 -464
  11. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  12. package/dist/lib/components/conversation/conversation-mode-picker.component.js +2 -2
  13. package/dist/lib/components/conversation/conversation-mode-picker.component.js.map +1 -1
  14. package/dist/lib/components/conversation/conversation-remote-browser-controller.d.ts +109 -0
  15. package/dist/lib/components/conversation/conversation-remote-browser-controller.d.ts.map +1 -0
  16. package/dist/lib/components/conversation/conversation-remote-browser-controller.js +298 -0
  17. package/dist/lib/components/conversation/conversation-remote-browser-controller.js.map +1 -0
  18. package/dist/lib/components/message/agent-handoff-card.component.d.ts +102 -0
  19. package/dist/lib/components/message/agent-handoff-card.component.d.ts.map +1 -0
  20. package/dist/lib/components/message/agent-handoff-card.component.js +439 -0
  21. package/dist/lib/components/message/agent-handoff-card.component.js.map +1 -0
  22. package/dist/lib/components/message/message-input.component.d.ts +126 -59
  23. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  24. package/dist/lib/components/message/message-input.component.js +559 -554
  25. package/dist/lib/components/message/message-input.component.js.map +1 -1
  26. package/dist/lib/components/message/message-item.component.d.ts +34 -2
  27. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  28. package/dist/lib/components/message/message-item.component.js +678 -520
  29. package/dist/lib/components/message/message-item.component.js.map +1 -1
  30. package/dist/lib/components/message/message-list.component.d.ts +13 -1
  31. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  32. package/dist/lib/components/message/message-list.component.js +92 -39
  33. package/dist/lib/components/message/message-list.component.js.map +1 -1
  34. package/dist/lib/components/overlay/chat-overlay.component.d.ts +19 -0
  35. package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
  36. package/dist/lib/components/overlay/chat-overlay.component.js +125 -13
  37. package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
  38. package/dist/lib/components/project/project-form-modal.component.js +2 -2
  39. package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
  40. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +1 -1
  41. package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -1
  42. package/dist/lib/components/realtime/media/media-channel-state.d.ts +5 -0
  43. package/dist/lib/components/realtime/media/media-channel-state.d.ts.map +1 -1
  44. package/dist/lib/components/realtime/media/media-channel-state.js +27 -1
  45. package/dist/lib/components/realtime/media/media-channel-state.js.map +1 -1
  46. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  47. package/dist/lib/components/realtime/media/media-channel.js +7 -2
  48. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  49. package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts +19 -2
  50. package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts.map +1 -1
  51. package/dist/lib/components/realtime/media/realtime-media-surface.component.js +59 -10
  52. package/dist/lib/components/realtime/media/realtime-media-surface.component.js.map +1 -1
  53. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +22 -6
  54. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  55. package/dist/lib/components/realtime/realtime-agent-banner.component.js +160 -98
  56. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  57. package/dist/lib/components/realtime/realtime-call-failure-notice.d.ts +13 -0
  58. package/dist/lib/components/realtime/realtime-call-failure-notice.d.ts.map +1 -0
  59. package/dist/lib/components/realtime/realtime-call-failure-notice.js +21 -0
  60. package/dist/lib/components/realtime/realtime-call-failure-notice.js.map +1 -0
  61. package/dist/lib/components/realtime/realtime-composer.component.d.ts +26 -3
  62. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  63. package/dist/lib/components/realtime/realtime-composer.component.js +226 -120
  64. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  65. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +73 -16
  66. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  67. package/dist/lib/components/realtime/realtime-session-overlay.component.js +219 -108
  68. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  69. package/dist/lib/components/realtime/realtime-ui-config.d.ts +9 -12
  70. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  71. package/dist/lib/components/realtime/realtime-ui-config.js +38 -18
  72. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  73. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  74. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +34 -5
  75. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  76. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts +8 -2
  77. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts.map +1 -1
  78. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js +51 -10
  79. package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js.map +1 -1
  80. package/dist/lib/components/realtime/whiteboard/whiteboard-channel-config.d.ts +46 -0
  81. package/dist/lib/components/realtime/whiteboard/whiteboard-channel-config.d.ts.map +1 -0
  82. package/dist/lib/components/realtime/whiteboard/whiteboard-channel-config.js +64 -0
  83. package/dist/lib/components/realtime/whiteboard/whiteboard-channel-config.js.map +1 -0
  84. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +131 -9
  85. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  86. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +347 -38
  87. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  88. package/dist/lib/conversations.module.d.ts +2 -1
  89. package/dist/lib/conversations.module.d.ts.map +1 -1
  90. package/dist/lib/conversations.module.js +9 -4
  91. package/dist/lib/conversations.module.js.map +1 -1
  92. package/dist/lib/events/chat-events.d.ts +5 -4
  93. package/dist/lib/events/chat-events.d.ts.map +1 -1
  94. package/dist/lib/events/chat-events.js +2 -2
  95. package/dist/lib/events/chat-events.js.map +1 -1
  96. package/dist/lib/models/agent-turn.model.d.ts +11 -7
  97. package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
  98. package/dist/lib/models/agent-turn.model.js.map +1 -1
  99. package/dist/lib/services/active-tasks.service.d.ts +5 -0
  100. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  101. package/dist/lib/services/active-tasks.service.js +16 -0
  102. package/dist/lib/services/active-tasks.service.js.map +1 -1
  103. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  104. package/dist/lib/services/agent-state.service.js +7 -1
  105. package/dist/lib/services/agent-state.service.js.map +1 -1
  106. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  107. package/dist/lib/services/artifact-permission.service.js +2 -0
  108. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  109. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  110. package/dist/lib/services/artifact-state.service.js +1 -0
  111. package/dist/lib/services/artifact-state.service.js.map +1 -1
  112. package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
  113. package/dist/lib/services/collection-permission.service.js +1 -0
  114. package/dist/lib/services/collection-permission.service.js.map +1 -1
  115. package/dist/lib/services/conversation-agent.service.d.ts +38 -16
  116. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  117. package/dist/lib/services/conversation-agent.service.js +57 -71
  118. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  119. package/dist/lib/services/conversation-detail-window.store.d.ts +5 -0
  120. package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
  121. package/dist/lib/services/conversation-detail-window.store.js +52 -5
  122. package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
  123. package/dist/lib/services/realtime-session-review.service.d.ts +2 -1
  124. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  125. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  126. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  127. package/dist/lib/services/realtime-session.service.js +2 -1
  128. package/dist/lib/services/realtime-session.service.js.map +1 -1
  129. package/dist/lib/services/search.service.d.ts.map +1 -1
  130. package/dist/lib/services/search.service.js +1 -0
  131. package/dist/lib/services/search.service.js.map +1 -1
  132. package/dist/lib/utils/agent-failure-display.d.ts +14 -0
  133. package/dist/lib/utils/agent-failure-display.d.ts.map +1 -0
  134. package/dist/lib/utils/agent-failure-display.js +26 -0
  135. package/dist/lib/utils/agent-failure-display.js.map +1 -0
  136. package/dist/lib/utils/agent-handoff-map.d.ts +52 -0
  137. package/dist/lib/utils/agent-handoff-map.d.ts.map +1 -0
  138. package/dist/lib/utils/agent-handoff-map.js +270 -0
  139. package/dist/lib/utils/agent-handoff-map.js.map +1 -0
  140. package/dist/lib/utils/agent-turn-routing.d.ts +62 -7
  141. package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -1
  142. package/dist/lib/utils/agent-turn-routing.js +147 -6
  143. package/dist/lib/utils/agent-turn-routing.js.map +1 -1
  144. package/dist/lib/utils/decision-routing.d.ts +17 -9
  145. package/dist/lib/utils/decision-routing.d.ts.map +1 -1
  146. package/dist/lib/utils/decision-routing.js +23 -14
  147. package/dist/lib/utils/decision-routing.js.map +1 -1
  148. package/dist/lib/utils/message-list-order.d.ts +13 -0
  149. package/dist/lib/utils/message-list-order.d.ts.map +1 -0
  150. package/dist/lib/utils/message-list-order.js +31 -0
  151. package/dist/lib/utils/message-list-order.js.map +1 -0
  152. package/dist/lib/utils/pin-state.d.ts +11 -0
  153. package/dist/lib/utils/pin-state.d.ts.map +1 -0
  154. package/dist/lib/utils/pin-state.js +9 -0
  155. package/dist/lib/utils/pin-state.js.map +1 -0
  156. package/dist/lib/utils/thread-replies.d.ts +34 -0
  157. package/dist/lib/utils/thread-replies.d.ts.map +1 -0
  158. package/dist/lib/utils/thread-replies.js +49 -0
  159. package/dist/lib/utils/thread-replies.js.map +1 -0
  160. package/dist/public-api.d.ts +6 -0
  161. package/dist/public-api.d.ts.map +1 -1
  162. package/dist/public-api.js +6 -0
  163. package/dist/public-api.js.map +1 -1
  164. package/package.json +36 -36
@@ -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 * - 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"]}
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 /** IDs of persisted rows that the loader returned with `Sequence === 0` (legacy rows). */\n private serverAssignedZeroSequenceIds = new Set<string>();\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 this.serverAssignedZeroSequenceIds.clear();\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.recordServerZeroSequences(page.Page);\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.recordServerZeroSequences(page.Page);\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: oldestAssignedSequence(this.loadedDetails, this.serverAssignedZeroSequenceIds) ?? 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 this.recordServerZeroSequences(fetched);\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: oldestAssignedSequence(this.loadedDetails, this.serverAssignedZeroSequenceIds),\n NewestSequence: newestAssignedSequence(this.loadedDetails, this.serverAssignedZeroSequenceIds),\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 = newestAssignedSequence(this.loadedDetails, this.serverAssignedZeroSequenceIds) ?? this.cursor.NewestSequence;\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 private recordServerZeroSequences(rows: readonly MJConversationDetailEntity[]): void {\n for (const row of rows) {\n if (row.Sequence === 0) {\n this.serverAssignedZeroSequenceIds.add(NormalizeUUID(row.ID));\n }\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 * Unsaved local placeholders (`Sequence === 0`) have no sequence yet and stay at the tail\n * in insertion order instead of sorting ahead of `Sequence >= 1` rows.\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) => {\n const aAssigned = hasAssignedSequence(a, this.serverAssignedZeroSequenceIds);\n const bAssigned = hasAssignedSequence(b, this.serverAssignedZeroSequenceIds);\n if (aAssigned && bAssigned) {\n return a.Sequence - b.Sequence;\n }\n if (aAssigned !== bAssigned) {\n return aAssigned ? -1 : 1;\n }\n return 0;\n });\n }\n}\n\n/** True when a row has a persisted `Sequence` (unsaved local placeholders have `Sequence === 0` and are not in `serverZeroIds`). */\nfunction hasAssignedSequence(detail: MJConversationDetailEntity, serverZeroIds: ReadonlySet<string>): boolean {\n return typeof detail.Sequence === 'number' && (\n detail.Sequence > 0 || (detail.Sequence === 0 && serverZeroIds.has(NormalizeUUID(detail.ID)))\n );\n}\n\n/** The smallest assigned `Sequence` in a sorted loaded-details slice, or `null` when none is assigned. */\nfunction oldestAssignedSequence(details: readonly MJConversationDetailEntity[], serverZeroIds: ReadonlySet<string>): number | null {\n for (let i = 0; i < details.length; i++) {\n if (hasAssignedSequence(details[i], serverZeroIds)) {\n return details[i].Sequence;\n }\n }\n return null;\n}\n\n/** The largest assigned `Sequence` in a sorted loaded-details slice, or `null` when none is assigned. */\nfunction newestAssignedSequence(details: readonly MJConversationDetailEntity[], serverZeroIds: ReadonlySet<string>): number | null {\n for (let i = details.length - 1; i >= 0; i--) {\n if (hasAssignedSequence(details[i], serverZeroIds)) {\n return details[i].Sequence;\n }\n }\n return null;\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,4 +1,5 @@
1
1
  import { IMetadataProvider } from '@memberjunction/core';
2
+ import type { MJAIAgentSessionEntity } from '@memberjunction/core-entities';
2
3
  import { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';
3
4
  import { ParsedDelegationArtifact } from '@memberjunction/realtime-runtime';
4
5
  import * as i0 from "@angular/core";
@@ -7,7 +8,7 @@ import * as i0 from "@angular/core";
7
8
  * (mirrors `MJAIAgentSessionEntity.CloseReason`). `null` means the session is still open OR a
8
9
  * legacy row was closed before the column existed.
9
10
  */
10
- export type RealtimeReviewCloseReason = 'Error' | 'Explicit' | 'Janitor' | 'Shutdown';
11
+ export type RealtimeReviewCloseReason = NonNullable<MJAIAgentSessionEntity['CloseReason']>;
11
12
  /**
12
13
  * One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).
13
14
  *
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime-session-review.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session-review.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { IMetadataProvider, Metadata, RunView, RunViewParams } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';\nimport { ParsedDelegationArtifact, FormatToolName } from '@memberjunction/realtime-runtime';\n\n/**\n * Why a reviewed session was closed, as stamped server-side by `SessionManager.CloseSession`\n * (mirrors `MJAIAgentSessionEntity.CloseReason`). `null` means the session is still open OR a\n * legacy row was closed before the column existed.\n */\nexport type RealtimeReviewCloseReason = 'Error' | 'Explicit' | 'Janitor' | 'Shutdown';\n\n/**\n * One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).\n *\n * Carries BOTH the thread-rendering fields (`Role`/`Text`/`At`) AND the raw fields the time-aligned\n * evidence player reads (`ID`, `Message`, `__mj_CreatedAt`, `UtteranceStartMs`, `UtteranceEndMs`) so\n * a review's turns can be handed straight to {@link RealtimeEvidencePlaybackComponent} for the\n * Recording tab — this shape structurally satisfies that player's `EvidencePlaybackTurn` input.\n */\nexport interface RealtimeSessionReviewTurn {\n /** `MJ: Conversation Details.ID` — the player's `@for` track key. */\n ID: string;\n /** Who spoke the turn. Persisted `AI` rows map to `Assistant`. */\n Role: 'User' | 'Assistant';\n /** The transcript text. */\n Text: string;\n /** The raw transcript text (mirrors {@link Text}) — the player reads `Message`. */\n Message: string | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. Aliases {@link At}. */\n __mj_CreatedAt: Date | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. */\n At: Date | null;\n /** Precise media-relative start (ms from recording t0), or null when the driver supplied no timing. */\n UtteranceStartMs: number | null;\n /** Precise media-relative end (ms from recording t0), or null. */\n UtteranceEndMs: number | null;\n}\n\n/**\n * A compact preview of one DELEGATED agent run the reviewed session spawned (an\n * `MJ: AI Agent Runs` row linked via `AgentSessionID`, EXCLUDING the co-agent's own\n * observability run). Carries just enough to render a done delegation card.\n */\nexport interface RealtimeSessionReviewRun {\n /** `MJ: AI Agent Runs.ID`. */\n RunID: string;\n /** The delegated agent's id. */\n AgentID: string;\n /** Denormalized agent display name from the run view, when available. */\n AgentName: string | null;\n /** Terminal (or last-known) run status (`Completed` | `Failed` | `Running` | …). */\n Status: string;\n /** Whether the run reported success. */\n Success: boolean;\n /** The run's user-facing result message, when one was recorded. */\n Message: string | null;\n /** The run's error message, when it failed. */\n ErrorMessage: string | null;\n /** The final step the run reported (`Success` | `Failed` | `Retry` | …), when known. */\n FinalStep: string | null;\n StartedAt: Date | null;\n CompletedAt: Date | null;\n}\n\n/** The persisted state of one interactive channel of the reviewed session. */\nexport interface RealtimeSessionReviewChannelState {\n /** Channel display name (e.g. `Whiteboard`), denormalized on the session-channel row. */\n ChannelName: string;\n /** The channel's serialized state of record (`AIAgentSessionChannel.Config`), or null when none was saved. */\n StateJson: string | null;\n}\n\n/**\n * MULTI-LEG channel-state merge: folds every leg's channel rows into one state set,\n * NEWEST leg wins per channel name — but only a leg that actually SAVED state counts.\n * A resumed session whose final leg never touched the whiteboard therefore still\n * reviews with the board an EARLIER leg drew (previously only the primary/newest leg's\n * rows were consulted, so that board silently vanished from review).\n *\n * @param legChannelStates Per-leg channel states, ordered OLDEST → NEWEST (the chain order).\n * @returns One entry per channel name (case-insensitive), each from the newest leg that\n * saved a non-empty state; channels no leg ever saved keep a null-state entry so the\n * review still knows the channel existed.\n */\nexport function MergeChainChannelStates(\n legChannelStates: ReadonlyArray<ReadonlyArray<RealtimeSessionReviewChannelState>>\n): RealtimeSessionReviewChannelState[] {\n const byName = new Map<string, RealtimeSessionReviewChannelState>();\n for (const leg of legChannelStates) {\n for (const state of leg) {\n const key = state.ChannelName.trim().toLowerCase();\n if (key.length === 0) {\n continue;\n }\n const existing = byName.get(key);\n const hasState = typeof state.StateJson === 'string' && state.StateJson.trim().length > 0;\n // Later legs are newer: a saved state always supersedes; a null/empty state only\n // registers the channel's existence and never clobbers an earlier saved board.\n if (!existing || hasState) {\n byName.set(key, hasState ? state : (existing ?? state));\n }\n }\n }\n return [...byName.values()];\n}\n\n/**\n * A direct action or channel tool execution performed during the reviewed session\n * (stored as a hidden `MJ: Conversation Details` turn with `type: 'realtime_tool_execution'`).\n */\nexport interface RealtimeSessionReviewAction {\n /** `MJ: Conversation Details.ID`. */\n ID: string;\n /** Correlated tool call id (`MJ: Conversation Details.ExternalID`), falling back to ID. */\n CallID: string;\n /** The tool/action name (e.g. `File_Storage_List_Objects` or `Whiteboard_draw_shape`). */\n ToolName: string;\n /** Serialized argument payload, when recorded. */\n ArgsJson: string | null;\n /** Serialized result payload, when recorded. */\n ResultJson: string | null;\n /** Whether the execution reported success. */\n Success: boolean;\n /** Execution duration in ms (`MJ: Conversation Details.CompletionTime`). */\n DurationMs: number;\n /** When the tool execution was recorded (`MJ: Conversation Details.__mj_CreatedAt`). */\n At: Date | null;\n}\n\n/**\n * One LEG of a reviewed session chain: a single `MJ: AI Agent Sessions` row plus its own\n * caption turns and delegated-run previews. A session resumed via `lastSessionId` chains\n * legs together (newest leg's `LastSessionID` → prior leg); the review loader walks that\n * chain BACKWARDS (capped — see the loader docs) so review mode can render the FULL\n * conversation arc chronologically, with a divider between legs.\n */\nexport interface RealtimeSessionReviewLeg {\n /** `MJ: AI Agent Sessions.ID` of this leg. */\n SessionID: string;\n /** When this leg started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n /** When this leg closed (null while still open). */\n ClosedAt: Date | null;\n /** Why this leg closed (null while open / legacy rows). */\n CloseReason: RealtimeReviewCloseReason | null;\n /** This leg's chronological caption turns (oldest first). */\n Turns: RealtimeSessionReviewTurn[];\n /** This leg's delegated-run previews (oldest first, minus its co-agent observability run). */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** This leg's direct action and channel tool executions. */\n DirectActions?: RealtimeSessionReviewAction[];\n}\n\n/**\n * Everything the call overlay's SESSION REVIEW mode renders for one past realtime session:\n * the session identity/lifecycle row, the chronological caption turns, previews of the\n * delegated runs, and the saved per-channel states (e.g. the whiteboard board).\n */\nexport interface RealtimeSessionReview {\n /** `MJ: AI Agent Sessions.ID` of the reviewed session. */\n SessionID: string;\n /** The session's fronting agent id (`AIAgentSession.AgentID` — usually the Realtime Co-Agent). */\n AgentID: string;\n /** Display name shown in the review banner (target agent when resolvable, else the session agent). */\n AgentName: string;\n /**\n * The agent a RESUMED live session should front: the session Config's `targetAgentID`,\n * falling back to the session's own `AgentID` when the config doesn't carry one.\n */\n TargetAgentID: string;\n /** Conversation the session was bound to, when any. */\n ConversationID: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n CloseReason: RealtimeReviewCloseReason | null;\n /** When the session started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n LastActiveAt: Date | null;\n ClosedAt: Date | null;\n /**\n * The `MJ: Files` id of the reviewed session's recorded audio, or null when nothing was recorded.\n * When set, review mode resolves a signed download URL and shows a Recording tab with the\n * time-aligned evidence player. From the PRIMARY (reviewed) leg only.\n */\n RecordingFileID: string | null;\n /** Recording alignment origin (t0), used by the playback transcript sync. From the primary leg. */\n RecordingStartedAt: Date | null;\n /** What was captured (`Audio` / `AudioVideo`), or null. From the primary leg. */\n RecordingMedia: string | null;\n /** Chronological caption turns (oldest first) — ALL legs of the chain, flattened. */\n Turns: RealtimeSessionReviewTurn[];\n /** Delegated run previews (oldest first, all legs), minus each leg's co-agent observability run. */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** Direct action and channel tool executions (oldest first, all legs). */\n DirectActions?: RealtimeSessionReviewAction[];\n /**\n * Saved channel states, one per session-channel row that carried a name. Channel state\n * (e.g. the whiteboard board) is the LATEST leg's only — earlier legs' states were\n * superseded when the chain resumed.\n */\n ChannelStates: RealtimeSessionReviewChannelState[];\n /**\n * The session-chain LEGS, chronological (oldest first; the LAST leg is the reviewed\n * session itself). Single-session reviews carry exactly one leg. Drives the per-leg\n * dividers `BuildReviewThreadItems` renders.\n */\n Legs: RealtimeSessionReviewLeg[];\n /**\n * ARTIFACTS attached to the chain's conversation history: every `MJ: Conversation\n * Detail Artifacts` junction (Direction `Output`) hanging off the chain's\n * session-stamped `Conversation Details`, resolved to `{ArtifactID, ArtifactVersionID,\n * Name}`. Review mode registers each as an (unfocused) artifact tab on the surface\n * panel, and they carry into a resumed live session. Empty when none / on any\n * tolerated load failure.\n */\n Artifacts: ParsedDelegationArtifact[];\n}\n\n// ── Raw row shapes (ResultType: 'simple', narrowed Fields) ──────────────────\n\ninterface SessionRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n ConversationID: string | null;\n Config: string | null;\n LastSessionID: string | null;\n LastActiveAt: string | null;\n ClosedAt: string | null;\n CloseReason: RealtimeReviewCloseReason | null;\n RecordingFileID: string | null;\n RecordingStartedAt: string | null;\n RecordingMedia: string | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface DetailRow {\n ID: string;\n Role: 'AI' | 'Error' | 'User';\n Message: string | null;\n HiddenToUser: boolean;\n UserID: string | null;\n Status: string | null;\n ExternalID?: string | null;\n CompletionTime?: number | null;\n UtteranceStartMs: number | null;\n UtteranceEndMs: number | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface RunRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: string;\n Success: boolean | null;\n Message: string | null;\n ErrorMessage: string | null;\n FinalStep: string | null;\n StartedAt: string | null;\n CompletedAt: string | null;\n}\n\ninterface ChannelRow {\n ID: string;\n Channel: string | null;\n Config: string | null;\n}\n\ninterface DetailArtifactJunctionRow {\n ID: string;\n ConversationDetailID: string;\n ArtifactVersionID: string | null;\n}\n\ninterface ArtifactVersionRow {\n ID: string;\n ArtifactID: string;\n /** Version display name (nullable on the row). */\n Name: string | null;\n /** Denormalized parent-artifact name from the version view. */\n Artifact: string | null;\n}\n\n/** The raw rows of ONE chain leg, before mapping to the public review shapes. */\ninterface LegRows {\n session: SessionRow;\n details: DetailRow[];\n runs: RunRow[];\n channels: ChannelRow[];\n}\n\n/** The Config-JSON keys the realtime voice stack persists on `AIAgentSession.Config`. */\ninterface SessionConfigJson {\n targetAgentID?: string;\n coAgentRunID?: string;\n}\n\nconst SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', 'RecordingFileID', 'RecordingStartedAt', 'RecordingMedia', '__mj_CreatedAt'];\nconst DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', 'UserID', 'Status', 'ExternalID', 'CompletionTime', 'UtteranceStartMs', 'UtteranceEndMs', '__mj_CreatedAt'];\nconst RUN_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'Success', 'Message', 'ErrorMessage', 'FinalStep', 'StartedAt', 'CompletedAt'];\nconst CHANNEL_FIELDS = ['ID', 'Channel', 'Config'];\nconst JUNCTION_FIELDS = ['ID', 'ConversationDetailID', 'ArtifactVersionID'];\nconst VERSION_FIELDS = ['ID', 'ArtifactID', 'Name', 'Artifact'];\n\n/** Maximum number of chain legs the review loader walks (the reviewed session included). */\nexport const MAX_REVIEW_LEGS = 5;\n/** Maximum total caption-detail rows loaded across the whole chain (oldest legs trimmed first). */\nexport const MAX_REVIEW_DETAILS = 500;\n\n// ── Review → thread-item mapping (pure, unit-testable) ──────────────────────\n\n/** Maps one delegated-run preview to the done delegation-card VM the thread/rail render. */\nexport function BuildReviewDelegationCard(run: RealtimeSessionReviewRun, fallbackAgentName: string): RealtimeDelegationCardVM {\n const startedAt = run.StartedAt?.getTime() ?? 0;\n return {\n Kind: 'agent',\n CallID: run.RunID,\n AgentName: run.AgentName || fallbackAgentName,\n LatestMessage: run.Message ?? run.ErrorMessage ?? run.Status,\n LatestStep: run.FinalStep ?? '',\n Done: true,\n Success: run.Success,\n RunRef: shortRunRef(run.RunID),\n RunID: run.RunID,\n Result: run.Message ?? run.ErrorMessage ?? null,\n StartedAt: startedAt,\n FinishedAt: run.CompletedAt?.getTime() ?? startedAt\n };\n}\n\n/** Maps one direct-action execution to the done action-card VM the thread/rail render. */\nexport function BuildReviewActionCard(action: RealtimeSessionReviewAction): RealtimeDelegationCardVM {\n const at = action.At?.getTime() ?? 0;\n const toolTitle = FormatToolName(action.ToolName);\n return {\n Kind: 'action',\n CallID: action.CallID,\n ToolName: action.ToolName,\n AgentName: toolTitle,\n LatestMessage: `Executed ${toolTitle}`,\n LatestStep: 'direct_action',\n Done: true,\n Success: action.Success,\n RunRef: shortRunRef(action.CallID),\n Result: action.ResultJson,\n StartedAt: at,\n FinishedAt: at + action.DurationMs\n };\n}\n\n/**\n * Builds the chronological thread (caption turns + done delegation cards + done action cards, oldest first)\n * for a reviewed session — the items `RealtimeSessionState.LoadHistoricalItems` takes.\n *\n * CHAIN-AWARE: when the review carries multiple {@link RealtimeSessionReview.Legs}, each\n * leg's items render in leg order with a `divider` item between legs (\"Session leg\n * started · <time>\", carrying the PREVIOUS leg's CloseReason as a chip). A single-leg\n * review (or a legless legacy shape) renders the flat thread with no divider —\n * byte-identical to the pre-chain behavior.\n */\nexport function BuildReviewThreadItems(review: RealtimeSessionReview): RealtimeThreadItem[] {\n const legs = review.Legs ?? [];\n if (legs.length <= 1) {\n const only = legs[0];\n return buildLegThreadItems(\n only?.Turns ?? review.Turns,\n only?.DelegatedRuns ?? review.DelegatedRuns,\n only?.DirectActions ?? review.DirectActions ?? [],\n review.AgentName\n );\n }\n const items: RealtimeThreadItem[] = [];\n legs.forEach((leg, i) => {\n if (i > 0) {\n items.push({\n Kind: 'divider',\n Label: 'Session leg started',\n At: leg.StartedAt,\n Icon: 'fa-solid fa-arrows-rotate',\n CloseReason: legs[i - 1].CloseReason ?? null\n });\n }\n items.push(...buildLegThreadItems(leg.Turns, leg.DelegatedRuns, leg.DirectActions ?? [], review.AgentName));\n });\n return items;\n}\n\n/**\n * Builds ONE leg's chronological items (caption turns + done delegation cards + done action cards,\n * oldest first). Entries without a timestamp sort to the front, preserving their relative order.\n */\nfunction buildLegThreadItems(\n turns: RealtimeSessionReviewTurn[],\n runs: RealtimeSessionReviewRun[],\n actions: RealtimeSessionReviewAction[],\n fallbackAgentName: string\n): RealtimeThreadItem[] {\n const stamped: Array<{ At: number; Item: RealtimeThreadItem }> = [];\n for (const turn of turns) {\n stamped.push({ At: turn.At?.getTime() ?? 0, Item: { Kind: 'caption', Role: turn.Role, Text: turn.Text } });\n }\n for (const run of runs) {\n stamped.push({ At: run.StartedAt?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewDelegationCard(run, fallbackAgentName) } });\n }\n for (const action of actions) {\n stamped.push({ At: action.At?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewActionCard(action) } });\n }\n // Array.prototype.sort is stable — equal timestamps keep their build order.\n stamped.sort((a, b) => a.At - b.At);\n return stamped.map(s => s.Item);\n}\n\n/** Derives a short run reference (e.g. \"#a3f1\") from the run id — mirrors the live cards. */\nfunction shortRunRef(runId: string): string {\n const compact = runId.replace(/[^a-z0-9]/gi, '');\n return compact.length >= 4 ? `#${compact.slice(-4).toLowerCase()}` : `#${compact.toLowerCase()}`;\n}\n\n/**\n * STATELESS loader for the call overlay's SESSION REVIEW mode: given a past\n * `MJ: AI Agent Sessions` id, batch-loads the session row, its persisted caption turns\n * (`MJ: Conversation Details` linked by `AgentSessionID`), its delegated agent runs\n * (minus the co-agent observability run named in the session Config's `coAgentRunID`),\n * and its saved channel states — and folds them into one {@link RealtimeSessionReview}.\n *\n * CHAIN-AWARE: when the reviewed session carries a `LastSessionID` (it RESUMED an earlier\n * session), the loader walks the chain BACKWARDS — capped at {@link MAX_REVIEW_LEGS} legs\n * and {@link MAX_REVIEW_DETAILS} caption rows total (oldest legs trimmed first), with a\n * cycle guard so a corrupt A→B→A chain can never loop — and surfaces ALL legs\n * chronologically on {@link RealtimeSessionReview.Legs}. Channel state stays the\n * reviewed (latest) leg's only. The chain's conversation-history ARTIFACTS (junction\n * rows on the session-stamped details) are collected onto\n * {@link RealtimeSessionReview.Artifacts}.\n *\n * TOLERANT by design: any missing piece degrades to an empty collection; the loader\n * returns `null` only when the reviewed session row itself can't be found.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionReviewService {\n /**\n * Loads everything review mode renders for one past session (and its prior-leg chain).\n *\n * @param agentSessionId The `MJ: AI Agent Sessions.ID` to review.\n * @param provider Optional metadata provider (multi-server apps); falls back to the global default.\n * @returns The assembled review, or `null` when the session doesn't exist / can't be read.\n */\n public async LoadSessionReview(agentSessionId: string, provider?: IMetadataProvider): Promise<RealtimeSessionReview | null> {\n const trimmed = agentSessionId?.trim() ?? '';\n if (trimmed.length === 0) {\n return null;\n }\n try {\n const md = provider ?? Metadata.Provider;\n const primary = await this.loadLegRows(trimmed, md, true);\n if (!primary) {\n return null;\n }\n const chain = await this.collectChainLegs(primary, md);\n const artifacts = await this.loadChainArtifacts(chain, md);\n return this.assembleReview(chain, artifacts);\n } catch (error) {\n console.error('[RealtimeSessionReview] Failed to load session review:', error);\n return null;\n }\n }\n\n /**\n * One batched RunViews pass for one chain leg: session row + caption turns + linked\n * runs (+ channel rows for the PRIMARY leg only — channel state is latest-leg-only).\n * Returns `null` when the session row can't be found.\n */\n private async loadLegRows(\n agentSessionId: string,\n provider: IMetadataProvider,\n includeChannels: boolean\n ): Promise<LegRows | null> {\n const safeID = agentSessionId.replace(/'/g, \"''\");\n const rv = RunView.FromMetadataProvider(provider);\n const queries: RunViewParams[] = [\n { EntityName: 'MJ: AI Agent Sessions', ExtraFilter: `ID='${safeID}'`, Fields: SESSION_FIELDS, ResultType: 'simple' as const },\n {\n EntityName: 'MJ: Conversation Details', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: DETAIL_FIELDS,\n OrderBy: '__mj_CreatedAt ASC', MaxRows: MAX_REVIEW_DETAILS, ResultType: 'simple' as const\n },\n { EntityName: 'MJ: AI Agent Runs', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: RUN_FIELDS, OrderBy: 'StartedAt ASC', ResultType: 'simple' as const }\n ];\n if (includeChannels) {\n queries.push({ EntityName: 'MJ: AI Agent Session Channels', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: CHANNEL_FIELDS, ResultType: 'simple' as const });\n }\n const [sessionResult, detailResult, runResult, channelResult] = await rv.RunViews(queries);\n const sessions = (sessionResult?.Success ? sessionResult.Results : []) as SessionRow[];\n const session = sessions[0] ?? null;\n if (!session) {\n return null;\n }\n return {\n session,\n details: (detailResult?.Success ? detailResult.Results : []) as DetailRow[],\n runs: (runResult?.Success ? runResult.Results : []) as RunRow[],\n channels: (channelResult?.Success ? channelResult.Results : []) as ChannelRow[]\n };\n }\n\n /**\n * Walks the `LastSessionID` chain BACKWARDS from the reviewed (primary) leg, collecting\n * raw leg rows OLDEST-FIRST (primary last). Safety rails:\n * - at most {@link MAX_REVIEW_LEGS} legs total;\n * - at most {@link MAX_REVIEW_DETAILS} caption rows across the chain — an older leg\n * whose details would overflow the budget is trimmed to its NEWEST rows and ends\n * the walk;\n * - a visited-set cycle guard (case-insensitive ids) so A→B→A can never loop;\n * - a leg that fails to load simply ends the walk (the collected legs still render).\n */\n private async collectChainLegs(primary: LegRows, provider: IMetadataProvider): Promise<LegRows[]> {\n const chain: LegRows[] = [primary];\n const visited = new Set<string>([this.normalizeID(primary.session.ID)]);\n let cursor = primary.session.LastSessionID ?? null;\n let detailBudget = MAX_REVIEW_DETAILS - primary.details.length;\n\n while (cursor && chain.length < MAX_REVIEW_LEGS && detailBudget > 0) {\n const key = this.normalizeID(cursor);\n if (visited.has(key)) {\n console.warn(`[RealtimeSessionReview] Session chain cycle detected at ${cursor} — stopping the walk.`);\n break;\n }\n visited.add(key);\n const leg = await this.loadLegRows(cursor, provider, false);\n if (!leg) {\n break;\n }\n if (leg.details.length > detailBudget) {\n // Keep this leg's NEWEST rows (details arrive oldest-first) and end the walk.\n leg.details = leg.details.slice(leg.details.length - detailBudget);\n detailBudget = 0;\n } else {\n detailBudget -= leg.details.length;\n }\n chain.unshift(leg);\n cursor = leg.session.LastSessionID ?? null;\n }\n return chain;\n }\n\n /**\n * Collects the chain's conversation-history ARTIFACTS: `MJ: Conversation Detail\n * Artifacts` junction rows (Direction `Output`) hanging off the chain's session-stamped\n * details, resolved through `MJ: Artifact Versions` to `{ArtifactID, ArtifactVersionID,\n * Name}` (version name, falling back to the artifact name). Order follows junction\n * creation; duplicate versions are deduped. TOLERANT: any failure returns `[]`.\n */\n private async loadChainArtifacts(chain: LegRows[], provider: IMetadataProvider): Promise<ParsedDelegationArtifact[]> {\n const detailIDs = chain.flatMap(leg => leg.details.map(d => d.ID)).filter(id => typeof id === 'string' && id.length > 0);\n if (detailIDs.length === 0) {\n return [];\n }\n try {\n const rv = RunView.FromMetadataProvider(provider);\n const detailList = detailIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [junctionResult] = await rv.RunViews([{\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${detailList}) AND Direction='Output'`,\n Fields: JUNCTION_FIELDS,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'simple'\n }]);\n const junctions = (junctionResult?.Success ? junctionResult.Results : []) as DetailArtifactJunctionRow[];\n const versionIDs = this.uniqueVersionIDs(junctions);\n if (versionIDs.length === 0) {\n return [];\n }\n\n const versionList = versionIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [versionResult] = await rv.RunViews([{\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionList})`,\n Fields: VERSION_FIELDS,\n ResultType: 'simple'\n }]);\n const versions = (versionResult?.Success ? versionResult.Results : []) as ArtifactVersionRow[];\n const byID = new Map<string, ArtifactVersionRow>(versions.map(v => [this.normalizeID(v.ID), v]));\n\n const artifacts: ParsedDelegationArtifact[] = [];\n for (const versionID of versionIDs) {\n const row = byID.get(this.normalizeID(versionID));\n if (!row?.ArtifactID) {\n continue; // junction points at an unreadable / deleted version — skip\n }\n artifacts.push({\n ArtifactID: row.ArtifactID,\n ArtifactVersionID: row.ID,\n Name: row.Name?.trim() || row.Artifact?.trim() || 'Artifact'\n });\n }\n return artifacts;\n } catch (error) {\n console.warn('[RealtimeSessionReview] Artifact collection failed — review renders without artifact tabs.', error);\n return [];\n }\n }\n\n /** Unique, non-empty `ArtifactVersionID`s from junction rows, in arrival order (case-insensitive dedupe). */\n private uniqueVersionIDs(junctions: DetailArtifactJunctionRow[]): string[] {\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const j of junctions) {\n const id = typeof j.ArtifactVersionID === 'string' ? j.ArtifactVersionID.trim() : '';\n if (id.length === 0 || seen.has(this.normalizeID(id))) {\n continue;\n }\n seen.add(this.normalizeID(id));\n ids.push(id);\n }\n return ids;\n }\n\n /** Case-insensitive UUID key for Set/Map membership (SQL Server uppercase vs PostgreSQL lowercase). */\n private normalizeID(id: string): string {\n return (id ?? '').trim().toLowerCase();\n }\n\n /**\n * Folds the chain's raw leg rows into the typed review. The PRIMARY (reviewed) leg —\n * the chain's LAST entry — supplies identity/lifecycle/channel state; turns and runs\n * are surfaced both per-leg (`Legs`) and flattened chronologically (`Turns` /\n * `DelegatedRuns`). Each leg excludes ITS OWN config's co-agent observability run.\n */\n private assembleReview(chain: LegRows[], artifacts: ParsedDelegationArtifact[]): RealtimeSessionReview {\n const primary = chain[chain.length - 1];\n const session = primary.session;\n const config = this.parseSessionConfig(session.Config);\n const legs = chain.map(leg => this.mapLeg(leg));\n return {\n SessionID: session.ID,\n AgentID: session.AgentID,\n AgentName: session.Agent || 'the agent',\n TargetAgentID: config.targetAgentID ?? session.AgentID,\n ConversationID: session.ConversationID ?? null,\n Status: session.Status,\n CloseReason: session.CloseReason ?? null,\n StartedAt: this.toDate(session.__mj_CreatedAt),\n LastActiveAt: this.toDate(session.LastActiveAt),\n ClosedAt: this.toDate(session.ClosedAt),\n RecordingFileID: session.RecordingFileID ?? null,\n RecordingStartedAt: this.toDate(session.RecordingStartedAt),\n RecordingMedia: session.RecordingMedia ?? null,\n Turns: legs.flatMap(l => l.Turns),\n DelegatedRuns: legs.flatMap(l => l.DelegatedRuns),\n DirectActions: legs.flatMap(l => l.DirectActions ?? []),\n // Multi-leg: newest leg with a SAVED state wins per channel — a final leg that\n // never touched the board no longer hides an earlier leg's drawing from review.\n ChannelStates: MergeChainChannelStates(chain.map(leg => this.mapChannels(leg.channels))),\n Legs: legs,\n Artifacts: artifacts\n };\n }\n\n /** Maps one leg's raw rows to the public leg shape (per-leg co-agent-run exclusion). */\n private mapLeg(leg: LegRows): RealtimeSessionReviewLeg {\n const config = this.parseSessionConfig(leg.session.Config);\n return {\n SessionID: leg.session.ID,\n StartedAt: this.toDate(leg.session.__mj_CreatedAt),\n ClosedAt: this.toDate(leg.session.ClosedAt),\n CloseReason: leg.session.CloseReason ?? null,\n Turns: this.mapTurns(leg.details),\n DelegatedRuns: this.mapRuns(leg.runs, config.coAgentRunID ?? null),\n DirectActions: this.mapDirectActions(leg.details)\n };\n }\n\n /** Hidden detail rows with realtime_tool_execution payload → direct-action reviews. */\n private mapDirectActions(details: DetailRow[]): RealtimeSessionReviewAction[] {\n const actions: RealtimeSessionReviewAction[] = [];\n for (const row of details) {\n if (!row.HiddenToUser || row.Role !== 'AI' || !row.Message) {\n continue;\n }\n try {\n const parsed = JSON.parse(row.Message) as {\n type?: string;\n callId?: string | null;\n toolName?: string;\n argsJson?: string | null;\n resultJson?: string | null;\n success?: boolean;\n durationMs?: number;\n };\n if (parsed && parsed.type === 'realtime_tool_execution' && typeof parsed.toolName === 'string') {\n const createdAt = this.toDate(row.__mj_CreatedAt);\n actions.push({\n ID: row.ID,\n CallID: parsed.callId || row.ExternalID || row.ID,\n ToolName: parsed.toolName,\n ArgsJson: parsed.argsJson ?? null,\n ResultJson: parsed.resultJson ?? null,\n Success: typeof parsed.success === 'boolean' ? parsed.success : (row.Status === 'Complete'),\n DurationMs: typeof parsed.durationMs === 'number' ? parsed.durationMs : (row.CompletionTime ?? 0),\n At: createdAt\n });\n }\n } catch {\n // Not a JSON fact payload — ignore\n }\n }\n return actions;\n }\n\n /** Persisted detail rows → caption turns: visible `User`/`AI` rows with text (AI → Assistant). */\n private mapTurns(details: DetailRow[]): RealtimeSessionReviewTurn[] {\n const turns: RealtimeSessionReviewTurn[] = [];\n for (const row of details) {\n const text = row.Message?.trim() ?? '';\n if (row.HiddenToUser || text.length === 0 || (row.Role !== 'User' && row.Role !== 'AI')) {\n continue;\n }\n const createdAt = this.toDate(row.__mj_CreatedAt);\n turns.push({\n ID: row.ID,\n Role: row.Role === 'AI' ? 'Assistant' : 'User',\n Text: text,\n Message: text,\n __mj_CreatedAt: createdAt,\n At: createdAt,\n UtteranceStartMs: row.UtteranceStartMs ?? null,\n UtteranceEndMs: row.UtteranceEndMs ?? null\n });\n }\n return turns;\n }\n\n /** Linked run rows → delegated-run previews, EXCLUDING the co-agent's observability run. */\n private mapRuns(runs: RunRow[], coAgentRunId: string | null): RealtimeSessionReviewRun[] {\n return runs\n .filter(r => !coAgentRunId || !UUIDsEqual(r.ID, coAgentRunId))\n .map(r => ({\n RunID: r.ID,\n AgentID: r.AgentID,\n AgentName: r.Agent ?? null,\n Status: r.Status ?? '',\n Success: r.Success === true,\n Message: r.Message ?? null,\n ErrorMessage: r.ErrorMessage ?? null,\n FinalStep: r.FinalStep ?? null,\n StartedAt: this.toDate(r.StartedAt),\n CompletedAt: this.toDate(r.CompletedAt)\n }));\n }\n\n /** Session-channel rows → named channel states (rows without a channel name are skipped). */\n private mapChannels(channels: ChannelRow[]): RealtimeSessionReviewChannelState[] {\n return channels\n .filter(c => !!c.Channel)\n .map(c => ({ ChannelName: c.Channel as string, StateJson: c.Config ?? null }));\n }\n\n /** Tolerant Config JSON parse — malformed/missing payloads degrade to `{}`. */\n private parseSessionConfig(raw: string | null): SessionConfigJson {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw) as SessionConfigJson;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n\n /** Tolerant date conversion — view rows arrive as ISO strings (or Dates from some providers). */\n private toDate(value: string | Date | null | undefined): Date | null {\n if (value == null) {\n return null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isNaN(date.getTime()) ? null : date;\n }\n}\n"]}
1
+ {"version":3,"file":"realtime-session-review.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session-review.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { IMetadataProvider, Metadata, RunView, RunViewParams } from '@memberjunction/core';\nimport type { MJAIAgentSessionEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { RealtimeDelegationCardVM, RealtimeThreadItem } from '../components/realtime/realtime-session-state';\nimport { ParsedDelegationArtifact, FormatToolName } from '@memberjunction/realtime-runtime';\n\n/**\n * Why a reviewed session was closed, as stamped server-side by `SessionManager.CloseSession`\n * (mirrors `MJAIAgentSessionEntity.CloseReason`). `null` means the session is still open OR a\n * legacy row was closed before the column existed.\n */\nexport type RealtimeReviewCloseReason = NonNullable<MJAIAgentSessionEntity['CloseReason']>;\n\n/**\n * One historical caption turn of a reviewed session (a persisted `MJ: Conversation Details` row).\n *\n * Carries BOTH the thread-rendering fields (`Role`/`Text`/`At`) AND the raw fields the time-aligned\n * evidence player reads (`ID`, `Message`, `__mj_CreatedAt`, `UtteranceStartMs`, `UtteranceEndMs`) so\n * a review's turns can be handed straight to {@link RealtimeEvidencePlaybackComponent} for the\n * Recording tab — this shape structurally satisfies that player's `EvidencePlaybackTurn` input.\n */\nexport interface RealtimeSessionReviewTurn {\n /** `MJ: Conversation Details.ID` — the player's `@for` track key. */\n ID: string;\n /** Who spoke the turn. Persisted `AI` rows map to `Assistant`. */\n Role: 'User' | 'Assistant';\n /** The transcript text. */\n Text: string;\n /** The raw transcript text (mirrors {@link Text}) — the player reads `Message`. */\n Message: string | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. Aliases {@link At}. */\n __mj_CreatedAt: Date | null;\n /** When the turn was persisted (`__mj_CreatedAt`), or null when unknown. */\n At: Date | null;\n /** Precise media-relative start (ms from recording t0), or null when the driver supplied no timing. */\n UtteranceStartMs: number | null;\n /** Precise media-relative end (ms from recording t0), or null. */\n UtteranceEndMs: number | null;\n}\n\n/**\n * A compact preview of one DELEGATED agent run the reviewed session spawned (an\n * `MJ: AI Agent Runs` row linked via `AgentSessionID`, EXCLUDING the co-agent's own\n * observability run). Carries just enough to render a done delegation card.\n */\nexport interface RealtimeSessionReviewRun {\n /** `MJ: AI Agent Runs.ID`. */\n RunID: string;\n /** The delegated agent's id. */\n AgentID: string;\n /** Denormalized agent display name from the run view, when available. */\n AgentName: string | null;\n /** Terminal (or last-known) run status (`Completed` | `Failed` | `Running` | …). */\n Status: string;\n /** Whether the run reported success. */\n Success: boolean;\n /** The run's user-facing result message, when one was recorded. */\n Message: string | null;\n /** The run's error message, when it failed. */\n ErrorMessage: string | null;\n /** The final step the run reported (`Success` | `Failed` | `Retry` | …), when known. */\n FinalStep: string | null;\n StartedAt: Date | null;\n CompletedAt: Date | null;\n}\n\n/** The persisted state of one interactive channel of the reviewed session. */\nexport interface RealtimeSessionReviewChannelState {\n /** Channel display name (e.g. `Whiteboard`), denormalized on the session-channel row. */\n ChannelName: string;\n /** The channel's serialized state of record (`AIAgentSessionChannel.Config`), or null when none was saved. */\n StateJson: string | null;\n}\n\n/**\n * MULTI-LEG channel-state merge: folds every leg's channel rows into one state set,\n * NEWEST leg wins per channel name — but only a leg that actually SAVED state counts.\n * A resumed session whose final leg never touched the whiteboard therefore still\n * reviews with the board an EARLIER leg drew (previously only the primary/newest leg's\n * rows were consulted, so that board silently vanished from review).\n *\n * @param legChannelStates Per-leg channel states, ordered OLDEST → NEWEST (the chain order).\n * @returns One entry per channel name (case-insensitive), each from the newest leg that\n * saved a non-empty state; channels no leg ever saved keep a null-state entry so the\n * review still knows the channel existed.\n */\nexport function MergeChainChannelStates(\n legChannelStates: ReadonlyArray<ReadonlyArray<RealtimeSessionReviewChannelState>>\n): RealtimeSessionReviewChannelState[] {\n const byName = new Map<string, RealtimeSessionReviewChannelState>();\n for (const leg of legChannelStates) {\n for (const state of leg) {\n const key = state.ChannelName.trim().toLowerCase();\n if (key.length === 0) {\n continue;\n }\n const existing = byName.get(key);\n const hasState = typeof state.StateJson === 'string' && state.StateJson.trim().length > 0;\n // Later legs are newer: a saved state always supersedes; a null/empty state only\n // registers the channel's existence and never clobbers an earlier saved board.\n if (!existing || hasState) {\n byName.set(key, hasState ? state : (existing ?? state));\n }\n }\n }\n return [...byName.values()];\n}\n\n/**\n * A direct action or channel tool execution performed during the reviewed session\n * (stored as a hidden `MJ: Conversation Details` turn with `type: 'realtime_tool_execution'`).\n */\nexport interface RealtimeSessionReviewAction {\n /** `MJ: Conversation Details.ID`. */\n ID: string;\n /** Correlated tool call id (`MJ: Conversation Details.ExternalID`), falling back to ID. */\n CallID: string;\n /** The tool/action name (e.g. `File_Storage_List_Objects` or `Whiteboard_draw_shape`). */\n ToolName: string;\n /** Serialized argument payload, when recorded. */\n ArgsJson: string | null;\n /** Serialized result payload, when recorded. */\n ResultJson: string | null;\n /** Whether the execution reported success. */\n Success: boolean;\n /** Execution duration in ms (`MJ: Conversation Details.CompletionTime`). */\n DurationMs: number;\n /** When the tool execution was recorded (`MJ: Conversation Details.__mj_CreatedAt`). */\n At: Date | null;\n}\n\n/**\n * One LEG of a reviewed session chain: a single `MJ: AI Agent Sessions` row plus its own\n * caption turns and delegated-run previews. A session resumed via `lastSessionId` chains\n * legs together (newest leg's `LastSessionID` → prior leg); the review loader walks that\n * chain BACKWARDS (capped — see the loader docs) so review mode can render the FULL\n * conversation arc chronologically, with a divider between legs.\n */\nexport interface RealtimeSessionReviewLeg {\n /** `MJ: AI Agent Sessions.ID` of this leg. */\n SessionID: string;\n /** When this leg started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n /** When this leg closed (null while still open). */\n ClosedAt: Date | null;\n /** Why this leg closed (null while open / legacy rows). */\n CloseReason: RealtimeReviewCloseReason | null;\n /** This leg's chronological caption turns (oldest first). */\n Turns: RealtimeSessionReviewTurn[];\n /** This leg's delegated-run previews (oldest first, minus its co-agent observability run). */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** This leg's direct action and channel tool executions. */\n DirectActions?: RealtimeSessionReviewAction[];\n}\n\n/**\n * Everything the call overlay's SESSION REVIEW mode renders for one past realtime session:\n * the session identity/lifecycle row, the chronological caption turns, previews of the\n * delegated runs, and the saved per-channel states (e.g. the whiteboard board).\n */\nexport interface RealtimeSessionReview {\n /** `MJ: AI Agent Sessions.ID` of the reviewed session. */\n SessionID: string;\n /** The session's fronting agent id (`AIAgentSession.AgentID` — usually the Realtime Co-Agent). */\n AgentID: string;\n /** Display name shown in the review banner (target agent when resolvable, else the session agent). */\n AgentName: string;\n /**\n * The agent a RESUMED live session should front: the session Config's `targetAgentID`,\n * falling back to the session's own `AgentID` when the config doesn't carry one.\n */\n TargetAgentID: string;\n /** Conversation the session was bound to, when any. */\n ConversationID: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n CloseReason: RealtimeReviewCloseReason | null;\n /** When the session started (`__mj_CreatedAt`). */\n StartedAt: Date | null;\n LastActiveAt: Date | null;\n ClosedAt: Date | null;\n /**\n * The `MJ: Files` id of the reviewed session's recorded audio, or null when nothing was recorded.\n * When set, review mode resolves a signed download URL and shows a Recording tab with the\n * time-aligned evidence player. From the PRIMARY (reviewed) leg only.\n */\n RecordingFileID: string | null;\n /** Recording alignment origin (t0), used by the playback transcript sync. From the primary leg. */\n RecordingStartedAt: Date | null;\n /** What was captured (`Audio` / `AudioVideo`), or null. From the primary leg. */\n RecordingMedia: string | null;\n /** Chronological caption turns (oldest first) — ALL legs of the chain, flattened. */\n Turns: RealtimeSessionReviewTurn[];\n /** Delegated run previews (oldest first, all legs), minus each leg's co-agent observability run. */\n DelegatedRuns: RealtimeSessionReviewRun[];\n /** Direct action and channel tool executions (oldest first, all legs). */\n DirectActions?: RealtimeSessionReviewAction[];\n /**\n * Saved channel states, one per session-channel row that carried a name. Channel state\n * (e.g. the whiteboard board) is the LATEST leg's only — earlier legs' states were\n * superseded when the chain resumed.\n */\n ChannelStates: RealtimeSessionReviewChannelState[];\n /**\n * The session-chain LEGS, chronological (oldest first; the LAST leg is the reviewed\n * session itself). Single-session reviews carry exactly one leg. Drives the per-leg\n * dividers `BuildReviewThreadItems` renders.\n */\n Legs: RealtimeSessionReviewLeg[];\n /**\n * ARTIFACTS attached to the chain's conversation history: every `MJ: Conversation\n * Detail Artifacts` junction (Direction `Output`) hanging off the chain's\n * session-stamped `Conversation Details`, resolved to `{ArtifactID, ArtifactVersionID,\n * Name}`. Review mode registers each as an (unfocused) artifact tab on the surface\n * panel, and they carry into a resumed live session. Empty when none / on any\n * tolerated load failure.\n */\n Artifacts: ParsedDelegationArtifact[];\n}\n\n// ── Raw row shapes (ResultType: 'simple', narrowed Fields) ──────────────────\n\ninterface SessionRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: 'Active' | 'Closed' | 'Idle';\n ConversationID: string | null;\n Config: string | null;\n LastSessionID: string | null;\n LastActiveAt: string | null;\n ClosedAt: string | null;\n CloseReason: RealtimeReviewCloseReason | null;\n RecordingFileID: string | null;\n RecordingStartedAt: string | null;\n RecordingMedia: string | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface DetailRow {\n ID: string;\n Role: 'AI' | 'Error' | 'User';\n Message: string | null;\n HiddenToUser: boolean;\n UserID: string | null;\n Status: string | null;\n ExternalID?: string | null;\n CompletionTime?: number | null;\n UtteranceStartMs: number | null;\n UtteranceEndMs: number | null;\n __mj_CreatedAt: string | null;\n}\n\ninterface RunRow {\n ID: string;\n AgentID: string;\n Agent: string | null;\n Status: string;\n Success: boolean | null;\n Message: string | null;\n ErrorMessage: string | null;\n FinalStep: string | null;\n StartedAt: string | null;\n CompletedAt: string | null;\n}\n\ninterface ChannelRow {\n ID: string;\n Channel: string | null;\n Config: string | null;\n}\n\ninterface DetailArtifactJunctionRow {\n ID: string;\n ConversationDetailID: string;\n ArtifactVersionID: string | null;\n}\n\ninterface ArtifactVersionRow {\n ID: string;\n ArtifactID: string;\n /** Version display name (nullable on the row). */\n Name: string | null;\n /** Denormalized parent-artifact name from the version view. */\n Artifact: string | null;\n}\n\n/** The raw rows of ONE chain leg, before mapping to the public review shapes. */\ninterface LegRows {\n session: SessionRow;\n details: DetailRow[];\n runs: RunRow[];\n channels: ChannelRow[];\n}\n\n/** The Config-JSON keys the realtime voice stack persists on `AIAgentSession.Config`. */\ninterface SessionConfigJson {\n targetAgentID?: string;\n coAgentRunID?: string;\n}\n\nconst SESSION_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'ConversationID', 'Config', 'LastSessionID', 'LastActiveAt', 'ClosedAt', 'CloseReason', 'RecordingFileID', 'RecordingStartedAt', 'RecordingMedia', '__mj_CreatedAt'];\nconst DETAIL_FIELDS = ['ID', 'Role', 'Message', 'HiddenToUser', 'UserID', 'Status', 'ExternalID', 'CompletionTime', 'UtteranceStartMs', 'UtteranceEndMs', '__mj_CreatedAt'];\nconst RUN_FIELDS = ['ID', 'AgentID', 'Agent', 'Status', 'Success', 'Message', 'ErrorMessage', 'FinalStep', 'StartedAt', 'CompletedAt'];\nconst CHANNEL_FIELDS = ['ID', 'Channel', 'Config'];\nconst JUNCTION_FIELDS = ['ID', 'ConversationDetailID', 'ArtifactVersionID'];\nconst VERSION_FIELDS = ['ID', 'ArtifactID', 'Name', 'Artifact'];\n\n/** Maximum number of chain legs the review loader walks (the reviewed session included). */\nexport const MAX_REVIEW_LEGS = 5;\n/** Maximum total caption-detail rows loaded across the whole chain (oldest legs trimmed first). */\nexport const MAX_REVIEW_DETAILS = 500;\n\n// ── Review → thread-item mapping (pure, unit-testable) ──────────────────────\n\n/** Maps one delegated-run preview to the done delegation-card VM the thread/rail render. */\nexport function BuildReviewDelegationCard(run: RealtimeSessionReviewRun, fallbackAgentName: string): RealtimeDelegationCardVM {\n const startedAt = run.StartedAt?.getTime() ?? 0;\n return {\n Kind: 'agent',\n CallID: run.RunID,\n AgentName: run.AgentName || fallbackAgentName,\n LatestMessage: run.Message ?? run.ErrorMessage ?? run.Status,\n LatestStep: run.FinalStep ?? '',\n Done: true,\n Success: run.Success,\n RunRef: shortRunRef(run.RunID),\n RunID: run.RunID,\n Result: run.Message ?? run.ErrorMessage ?? null,\n StartedAt: startedAt,\n FinishedAt: run.CompletedAt?.getTime() ?? startedAt\n };\n}\n\n/** Maps one direct-action execution to the done action-card VM the thread/rail render. */\nexport function BuildReviewActionCard(action: RealtimeSessionReviewAction): RealtimeDelegationCardVM {\n const at = action.At?.getTime() ?? 0;\n const toolTitle = FormatToolName(action.ToolName);\n return {\n Kind: 'action',\n CallID: action.CallID,\n ToolName: action.ToolName,\n AgentName: toolTitle,\n LatestMessage: `Executed ${toolTitle}`,\n LatestStep: 'direct_action',\n Done: true,\n Success: action.Success,\n RunRef: shortRunRef(action.CallID),\n Result: action.ResultJson,\n StartedAt: at,\n FinishedAt: at + action.DurationMs\n };\n}\n\n/**\n * Builds the chronological thread (caption turns + done delegation cards + done action cards, oldest first)\n * for a reviewed session — the items `RealtimeSessionState.LoadHistoricalItems` takes.\n *\n * CHAIN-AWARE: when the review carries multiple {@link RealtimeSessionReview.Legs}, each\n * leg's items render in leg order with a `divider` item between legs (\"Session leg\n * started · <time>\", carrying the PREVIOUS leg's CloseReason as a chip). A single-leg\n * review (or a legless legacy shape) renders the flat thread with no divider —\n * byte-identical to the pre-chain behavior.\n */\nexport function BuildReviewThreadItems(review: RealtimeSessionReview): RealtimeThreadItem[] {\n const legs = review.Legs ?? [];\n if (legs.length <= 1) {\n const only = legs[0];\n return buildLegThreadItems(\n only?.Turns ?? review.Turns,\n only?.DelegatedRuns ?? review.DelegatedRuns,\n only?.DirectActions ?? review.DirectActions ?? [],\n review.AgentName\n );\n }\n const items: RealtimeThreadItem[] = [];\n legs.forEach((leg, i) => {\n if (i > 0) {\n items.push({\n Kind: 'divider',\n Label: 'Session leg started',\n At: leg.StartedAt,\n Icon: 'fa-solid fa-arrows-rotate',\n CloseReason: legs[i - 1].CloseReason ?? null\n });\n }\n items.push(...buildLegThreadItems(leg.Turns, leg.DelegatedRuns, leg.DirectActions ?? [], review.AgentName));\n });\n return items;\n}\n\n/**\n * Builds ONE leg's chronological items (caption turns + done delegation cards + done action cards,\n * oldest first). Entries without a timestamp sort to the front, preserving their relative order.\n */\nfunction buildLegThreadItems(\n turns: RealtimeSessionReviewTurn[],\n runs: RealtimeSessionReviewRun[],\n actions: RealtimeSessionReviewAction[],\n fallbackAgentName: string\n): RealtimeThreadItem[] {\n const stamped: Array<{ At: number; Item: RealtimeThreadItem }> = [];\n for (const turn of turns) {\n stamped.push({ At: turn.At?.getTime() ?? 0, Item: { Kind: 'caption', Role: turn.Role, Text: turn.Text } });\n }\n for (const run of runs) {\n stamped.push({ At: run.StartedAt?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewDelegationCard(run, fallbackAgentName) } });\n }\n for (const action of actions) {\n stamped.push({ At: action.At?.getTime() ?? 0, Item: { Kind: 'delegation', Card: BuildReviewActionCard(action) } });\n }\n // Array.prototype.sort is stable — equal timestamps keep their build order.\n stamped.sort((a, b) => a.At - b.At);\n return stamped.map(s => s.Item);\n}\n\n/** Derives a short run reference (e.g. \"#a3f1\") from the run id — mirrors the live cards. */\nfunction shortRunRef(runId: string): string {\n const compact = runId.replace(/[^a-z0-9]/gi, '');\n return compact.length >= 4 ? `#${compact.slice(-4).toLowerCase()}` : `#${compact.toLowerCase()}`;\n}\n\n/**\n * STATELESS loader for the call overlay's SESSION REVIEW mode: given a past\n * `MJ: AI Agent Sessions` id, batch-loads the session row, its persisted caption turns\n * (`MJ: Conversation Details` linked by `AgentSessionID`), its delegated agent runs\n * (minus the co-agent observability run named in the session Config's `coAgentRunID`),\n * and its saved channel states — and folds them into one {@link RealtimeSessionReview}.\n *\n * CHAIN-AWARE: when the reviewed session carries a `LastSessionID` (it RESUMED an earlier\n * session), the loader walks the chain BACKWARDS — capped at {@link MAX_REVIEW_LEGS} legs\n * and {@link MAX_REVIEW_DETAILS} caption rows total (oldest legs trimmed first), with a\n * cycle guard so a corrupt A→B→A chain can never loop — and surfaces ALL legs\n * chronologically on {@link RealtimeSessionReview.Legs}. Channel state stays the\n * reviewed (latest) leg's only. The chain's conversation-history ARTIFACTS (junction\n * rows on the session-stamped details) are collected onto\n * {@link RealtimeSessionReview.Artifacts}.\n *\n * TOLERANT by design: any missing piece degrades to an empty collection; the loader\n * returns `null` only when the reviewed session row itself can't be found.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionReviewService {\n /**\n * Loads everything review mode renders for one past session (and its prior-leg chain).\n *\n * @param agentSessionId The `MJ: AI Agent Sessions.ID` to review.\n * @param provider Optional metadata provider (multi-server apps); falls back to the global default.\n * @returns The assembled review, or `null` when the session doesn't exist / can't be read.\n */\n public async LoadSessionReview(agentSessionId: string, provider?: IMetadataProvider): Promise<RealtimeSessionReview | null> {\n const trimmed = agentSessionId?.trim() ?? '';\n if (trimmed.length === 0) {\n return null;\n }\n try {\n const md = provider ?? Metadata.Provider;\n const primary = await this.loadLegRows(trimmed, md, true);\n if (!primary) {\n return null;\n }\n const chain = await this.collectChainLegs(primary, md);\n const artifacts = await this.loadChainArtifacts(chain, md);\n return this.assembleReview(chain, artifacts);\n } catch (error) {\n console.error('[RealtimeSessionReview] Failed to load session review:', error);\n return null;\n }\n }\n\n /**\n * One batched RunViews pass for one chain leg: session row + caption turns + linked\n * runs (+ channel rows for the PRIMARY leg only — channel state is latest-leg-only).\n * Returns `null` when the session row can't be found.\n */\n private async loadLegRows(\n agentSessionId: string,\n provider: IMetadataProvider,\n includeChannels: boolean\n ): Promise<LegRows | null> {\n const safeID = agentSessionId.replace(/'/g, \"''\");\n const rv = RunView.FromMetadataProvider(provider);\n const queries: RunViewParams[] = [\n { EntityName: 'MJ: AI Agent Sessions', ExtraFilter: `ID='${safeID}'`, Fields: SESSION_FIELDS, ResultType: 'simple' as const },\n {\n EntityName: 'MJ: Conversation Details', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: DETAIL_FIELDS,\n OrderBy: '__mj_CreatedAt ASC', MaxRows: MAX_REVIEW_DETAILS, ResultType: 'simple' as const\n },\n { EntityName: 'MJ: AI Agent Runs', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: RUN_FIELDS, OrderBy: 'StartedAt ASC', ResultType: 'simple' as const }\n ];\n if (includeChannels) {\n queries.push({ EntityName: 'MJ: AI Agent Session Channels', ExtraFilter: `AgentSessionID='${safeID}'`, Fields: CHANNEL_FIELDS, ResultType: 'simple' as const });\n }\n const [sessionResult, detailResult, runResult, channelResult] = await rv.RunViews(queries);\n const sessions = (sessionResult?.Success ? sessionResult.Results : []) as SessionRow[];\n const session = sessions[0] ?? null;\n if (!session) {\n return null;\n }\n return {\n session,\n details: (detailResult?.Success ? detailResult.Results : []) as DetailRow[],\n runs: (runResult?.Success ? runResult.Results : []) as RunRow[],\n channels: (channelResult?.Success ? channelResult.Results : []) as ChannelRow[]\n };\n }\n\n /**\n * Walks the `LastSessionID` chain BACKWARDS from the reviewed (primary) leg, collecting\n * raw leg rows OLDEST-FIRST (primary last). Safety rails:\n * - at most {@link MAX_REVIEW_LEGS} legs total;\n * - at most {@link MAX_REVIEW_DETAILS} caption rows across the chain — an older leg\n * whose details would overflow the budget is trimmed to its NEWEST rows and ends\n * the walk;\n * - a visited-set cycle guard (case-insensitive ids) so A→B→A can never loop;\n * - a leg that fails to load simply ends the walk (the collected legs still render).\n */\n private async collectChainLegs(primary: LegRows, provider: IMetadataProvider): Promise<LegRows[]> {\n const chain: LegRows[] = [primary];\n const visited = new Set<string>([this.normalizeID(primary.session.ID)]);\n let cursor = primary.session.LastSessionID ?? null;\n let detailBudget = MAX_REVIEW_DETAILS - primary.details.length;\n\n while (cursor && chain.length < MAX_REVIEW_LEGS && detailBudget > 0) {\n const key = this.normalizeID(cursor);\n if (visited.has(key)) {\n console.warn(`[RealtimeSessionReview] Session chain cycle detected at ${cursor} — stopping the walk.`);\n break;\n }\n visited.add(key);\n const leg = await this.loadLegRows(cursor, provider, false);\n if (!leg) {\n break;\n }\n if (leg.details.length > detailBudget) {\n // Keep this leg's NEWEST rows (details arrive oldest-first) and end the walk.\n leg.details = leg.details.slice(leg.details.length - detailBudget);\n detailBudget = 0;\n } else {\n detailBudget -= leg.details.length;\n }\n chain.unshift(leg);\n cursor = leg.session.LastSessionID ?? null;\n }\n return chain;\n }\n\n /**\n * Collects the chain's conversation-history ARTIFACTS: `MJ: Conversation Detail\n * Artifacts` junction rows (Direction `Output`) hanging off the chain's session-stamped\n * details, resolved through `MJ: Artifact Versions` to `{ArtifactID, ArtifactVersionID,\n * Name}` (version name, falling back to the artifact name). Order follows junction\n * creation; duplicate versions are deduped. TOLERANT: any failure returns `[]`.\n */\n private async loadChainArtifacts(chain: LegRows[], provider: IMetadataProvider): Promise<ParsedDelegationArtifact[]> {\n const detailIDs = chain.flatMap(leg => leg.details.map(d => d.ID)).filter(id => typeof id === 'string' && id.length > 0);\n if (detailIDs.length === 0) {\n return [];\n }\n try {\n const rv = RunView.FromMetadataProvider(provider);\n const detailList = detailIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [junctionResult] = await rv.RunViews([{\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${detailList}) AND Direction='Output'`,\n Fields: JUNCTION_FIELDS,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'simple'\n }]);\n const junctions = (junctionResult?.Success ? junctionResult.Results : []) as DetailArtifactJunctionRow[];\n const versionIDs = this.uniqueVersionIDs(junctions);\n if (versionIDs.length === 0) {\n return [];\n }\n\n const versionList = versionIDs.map(id => `'${id.replace(/'/g, \"''\")}'`).join(',');\n const [versionResult] = await rv.RunViews([{\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionList})`,\n Fields: VERSION_FIELDS,\n ResultType: 'simple'\n }]);\n const versions = (versionResult?.Success ? versionResult.Results : []) as ArtifactVersionRow[];\n const byID = new Map<string, ArtifactVersionRow>(versions.map(v => [this.normalizeID(v.ID), v]));\n\n const artifacts: ParsedDelegationArtifact[] = [];\n for (const versionID of versionIDs) {\n const row = byID.get(this.normalizeID(versionID));\n if (!row?.ArtifactID) {\n continue; // junction points at an unreadable / deleted version — skip\n }\n artifacts.push({\n ArtifactID: row.ArtifactID,\n ArtifactVersionID: row.ID,\n Name: row.Name?.trim() || row.Artifact?.trim() || 'Artifact'\n });\n }\n return artifacts;\n } catch (error) {\n console.warn('[RealtimeSessionReview] Artifact collection failed — review renders without artifact tabs.', error);\n return [];\n }\n }\n\n /** Unique, non-empty `ArtifactVersionID`s from junction rows, in arrival order (case-insensitive dedupe). */\n private uniqueVersionIDs(junctions: DetailArtifactJunctionRow[]): string[] {\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const j of junctions) {\n const id = typeof j.ArtifactVersionID === 'string' ? j.ArtifactVersionID.trim() : '';\n if (id.length === 0 || seen.has(this.normalizeID(id))) {\n continue;\n }\n seen.add(this.normalizeID(id));\n ids.push(id);\n }\n return ids;\n }\n\n /** Case-insensitive UUID key for Set/Map membership (SQL Server uppercase vs PostgreSQL lowercase). */\n private normalizeID(id: string): string {\n return (id ?? '').trim().toLowerCase();\n }\n\n /**\n * Folds the chain's raw leg rows into the typed review. The PRIMARY (reviewed) leg —\n * the chain's LAST entry — supplies identity/lifecycle/channel state; turns and runs\n * are surfaced both per-leg (`Legs`) and flattened chronologically (`Turns` /\n * `DelegatedRuns`). Each leg excludes ITS OWN config's co-agent observability run.\n */\n private assembleReview(chain: LegRows[], artifacts: ParsedDelegationArtifact[]): RealtimeSessionReview {\n const primary = chain[chain.length - 1];\n const session = primary.session;\n const config = this.parseSessionConfig(session.Config);\n const legs = chain.map(leg => this.mapLeg(leg));\n return {\n SessionID: session.ID,\n AgentID: session.AgentID,\n AgentName: session.Agent || 'the agent',\n TargetAgentID: config.targetAgentID ?? session.AgentID,\n ConversationID: session.ConversationID ?? null,\n Status: session.Status,\n CloseReason: session.CloseReason ?? null,\n StartedAt: this.toDate(session.__mj_CreatedAt),\n LastActiveAt: this.toDate(session.LastActiveAt),\n ClosedAt: this.toDate(session.ClosedAt),\n RecordingFileID: session.RecordingFileID ?? null,\n RecordingStartedAt: this.toDate(session.RecordingStartedAt),\n RecordingMedia: session.RecordingMedia ?? null,\n Turns: legs.flatMap(l => l.Turns),\n DelegatedRuns: legs.flatMap(l => l.DelegatedRuns),\n DirectActions: legs.flatMap(l => l.DirectActions ?? []),\n // Multi-leg: newest leg with a SAVED state wins per channel — a final leg that\n // never touched the board no longer hides an earlier leg's drawing from review.\n ChannelStates: MergeChainChannelStates(chain.map(leg => this.mapChannels(leg.channels))),\n Legs: legs,\n Artifacts: artifacts\n };\n }\n\n /** Maps one leg's raw rows to the public leg shape (per-leg co-agent-run exclusion). */\n private mapLeg(leg: LegRows): RealtimeSessionReviewLeg {\n const config = this.parseSessionConfig(leg.session.Config);\n return {\n SessionID: leg.session.ID,\n StartedAt: this.toDate(leg.session.__mj_CreatedAt),\n ClosedAt: this.toDate(leg.session.ClosedAt),\n CloseReason: leg.session.CloseReason ?? null,\n Turns: this.mapTurns(leg.details),\n DelegatedRuns: this.mapRuns(leg.runs, config.coAgentRunID ?? null),\n DirectActions: this.mapDirectActions(leg.details)\n };\n }\n\n /** Hidden detail rows with realtime_tool_execution payload → direct-action reviews. */\n private mapDirectActions(details: DetailRow[]): RealtimeSessionReviewAction[] {\n const actions: RealtimeSessionReviewAction[] = [];\n for (const row of details) {\n if (!row.HiddenToUser || row.Role !== 'AI' || !row.Message) {\n continue;\n }\n try {\n const parsed = JSON.parse(row.Message) as {\n type?: string;\n callId?: string | null;\n toolName?: string;\n argsJson?: string | null;\n resultJson?: string | null;\n success?: boolean;\n durationMs?: number;\n };\n if (parsed && parsed.type === 'realtime_tool_execution' && typeof parsed.toolName === 'string') {\n const createdAt = this.toDate(row.__mj_CreatedAt);\n actions.push({\n ID: row.ID,\n CallID: parsed.callId || row.ExternalID || row.ID,\n ToolName: parsed.toolName,\n ArgsJson: parsed.argsJson ?? null,\n ResultJson: parsed.resultJson ?? null,\n Success: typeof parsed.success === 'boolean' ? parsed.success : (row.Status === 'Complete'),\n DurationMs: typeof parsed.durationMs === 'number' ? parsed.durationMs : (row.CompletionTime ?? 0),\n At: createdAt\n });\n }\n } catch {\n // Not a JSON fact payload — ignore\n }\n }\n return actions;\n }\n\n /** Persisted detail rows → caption turns: visible `User`/`AI` rows with text (AI → Assistant). */\n private mapTurns(details: DetailRow[]): RealtimeSessionReviewTurn[] {\n const turns: RealtimeSessionReviewTurn[] = [];\n for (const row of details) {\n const text = row.Message?.trim() ?? '';\n if (row.HiddenToUser || text.length === 0 || (row.Role !== 'User' && row.Role !== 'AI')) {\n continue;\n }\n const createdAt = this.toDate(row.__mj_CreatedAt);\n turns.push({\n ID: row.ID,\n Role: row.Role === 'AI' ? 'Assistant' : 'User',\n Text: text,\n Message: text,\n __mj_CreatedAt: createdAt,\n At: createdAt,\n UtteranceStartMs: row.UtteranceStartMs ?? null,\n UtteranceEndMs: row.UtteranceEndMs ?? null\n });\n }\n return turns;\n }\n\n /** Linked run rows → delegated-run previews, EXCLUDING the co-agent's observability run. */\n private mapRuns(runs: RunRow[], coAgentRunId: string | null): RealtimeSessionReviewRun[] {\n return runs\n .filter(r => !coAgentRunId || !UUIDsEqual(r.ID, coAgentRunId))\n .map(r => ({\n RunID: r.ID,\n AgentID: r.AgentID,\n AgentName: r.Agent ?? null,\n Status: r.Status ?? '',\n Success: r.Success === true,\n Message: r.Message ?? null,\n ErrorMessage: r.ErrorMessage ?? null,\n FinalStep: r.FinalStep ?? null,\n StartedAt: this.toDate(r.StartedAt),\n CompletedAt: this.toDate(r.CompletedAt)\n }));\n }\n\n /** Session-channel rows → named channel states (rows without a channel name are skipped). */\n private mapChannels(channels: ChannelRow[]): RealtimeSessionReviewChannelState[] {\n return channels\n .filter(c => !!c.Channel)\n .map(c => ({ ChannelName: c.Channel as string, StateJson: c.Config ?? null }));\n }\n\n /** Tolerant Config JSON parse — malformed/missing payloads degrade to `{}`. */\n private parseSessionConfig(raw: string | null): SessionConfigJson {\n if (!raw) {\n return {};\n }\n try {\n const parsed = JSON.parse(raw) as SessionConfigJson;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n\n /** Tolerant date conversion — view rows arrive as ISO strings (or Dates from some providers). */\n private toDate(value: string | Date | null | undefined): Date | null {\n if (value == null) {\n return null;\n }\n const date = value instanceof Date ? value : new Date(value);\n return isNaN(date.getTime()) ? null : date;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;;AA4B1E;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,sBAAuB,SAAQ,sBAAsB;;IAQ9D;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,6BAA6B,CAAC,IAAI,EAAE,mBAAmB,EAAE,UAAU,EAAE,qBAAqB,GAAG,IAAI;yCA1BlG,sBAAsB;6CAAtB,sBAAsB;CAoClC;AAED,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAEhC,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAClE;AAED,yFAAyF;AACzF,MAAM,WAAW,qBAAqB;IAElC,QAAQ,CAAC,eAAe,EAAE,uBAAuB,CAAC;IAElD,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC1E"}
1
+ {"version":3,"file":"realtime-session.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;;AA8B1E;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,sBAAuB,SAAQ,sBAAsB;;IAQ9D;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,6BAA6B,CAAC,IAAI,EAAE,mBAAmB,EAAE,UAAU,EAAE,qBAAqB,GAAG,IAAI;yCA1BlG,sBAAsB;6CAAtB,sBAAsB;CAoClC;AAED,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAEhC,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAClE;AAED,yFAAyF;AACzF,MAAM,WAAW,qBAAqB;IAElC,QAAQ,CAAC,eAAe,EAAE,uBAAuB,CAAC;IAElD,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC1E"}
@@ -1,6 +1,6 @@
1
1
  import { Injectable } from '@angular/core';
2
2
  import { RealtimeSessionRuntime } from '@memberjunction/realtime-runtime';
3
- import { LoadAssemblyAIRealtimeClient, LoadElevenLabsRealtimeClient, LoadGeminiRealtimeClient, LoadHuggingFaceRealtimeClient, LoadOpenAILiveClient, LoadOpenAIRealtimeClient, LoadxAIRealtimeClient, } from '@memberjunction/ai-realtime-client';
3
+ import { LoadAssemblyAIRealtimeClient, LoadElevenLabsRealtimeClient, LoadElevenRealtimeClient, LoadGeminiRealtimeClient, LoadHuggingFaceRealtimeClient, LoadOpenAILiveClient, LoadOpenAIRealtimeClient, LoadxAIRealtimeClient, } from '@memberjunction/ai-realtime-client';
4
4
  import { BrowserRealtimeMediaHost } from './browser-realtime-media-host';
5
5
  import * as i0 from "@angular/core";
6
6
  // Tree-shaking prevention: client drivers are resolved dynamically through the ClassFactory (by
@@ -17,6 +17,7 @@ LoadGeminiRealtimeClient();
17
17
  LoadElevenLabsRealtimeClient();
18
18
  LoadAssemblyAIRealtimeClient();
19
19
  LoadxAIRealtimeClient();
20
+ LoadElevenRealtimeClient();
20
21
  LoadHuggingFaceRealtimeClient();
21
22
  /**
22
23
  * Angular host for MemberJunction's realtime co-agent sessions.
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EACH,4BAA4B,EAC5B,4BAA4B,EAC5B,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;;AAEzE,gGAAgG;AAChG,mGAAmG;AACnG,gDAAgD;AAChD,EAAE;AACF,+FAA+F;AAC/F,0FAA0F;AAC1F,+FAA+F;AAC/F,kBAAkB;AAClB,wBAAwB,EAAE,CAAC;AAC3B,oBAAoB,EAAE,CAAC;AACvB,wBAAwB,EAAE,CAAC;AAC3B,4BAA4B,EAAE,CAAC;AAC/B,4BAA4B,EAAE,CAAC;AAC/B,qBAAqB,EAAE,CAAC;AACxB,6BAA6B,EAAE,CAAC;AAEhC;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAC9D;QACI,KAAK,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC;QACtC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACnE,IAAI,CAAC,6BAA6B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACO,6BAA6B,CAAC,IAAyB,EAAE,UAAiC;QAChG,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACrF,UAAU,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;YACjD,IAAI,UAAU,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;gBAC1C,sFAAsF;gBACtF,sFAAsF;gBACtF,IAAI,CAAC,qBAAqB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;gHAnCQ,sBAAsB;gEAAtB,sBAAsB,WAAtB,sBAAsB,mBADT,MAAM;;iFACnB,sBAAsB;cADlC,UAAU;eAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { Injectable } from '@angular/core';\nimport { RealtimeSessionRuntime } from '@memberjunction/realtime-runtime';\nimport {\n LoadAssemblyAIRealtimeClient,\n LoadElevenLabsRealtimeClient,\n LoadGeminiRealtimeClient,\n LoadHuggingFaceRealtimeClient,\n LoadOpenAILiveClient,\n LoadOpenAIRealtimeClient,\n LoadxAIRealtimeClient,\n} from '@memberjunction/ai-realtime-client';\nimport { BrowserRealtimeMediaHost } from './browser-realtime-media-host';\n\n// Tree-shaking prevention: client drivers are resolved dynamically through the ClassFactory (by\n// the server-reported Provider key), so these static calls are what keep their @RegisterClass side\n// effects from being eliminated by the bundler.\n//\n// NOTE: the interactive-channel plugins (resolved dynamically from the `MJ: AI Agent Channels`\n// registry by ClientPluginClass key) get the same treatment, but their Load calls live in\n// `conversations.module.ts` — plugins carry Angular surface COMPONENTS, and this service stays\n// component-free.\nLoadOpenAIRealtimeClient();\nLoadOpenAILiveClient();\nLoadGeminiRealtimeClient();\nLoadElevenLabsRealtimeClient();\nLoadAssemblyAIRealtimeClient();\nLoadxAIRealtimeClient();\nLoadHuggingFaceRealtimeClient();\n\n/**\n * Angular host for MemberJunction's realtime co-agent sessions.\n *\n * All orchestration — mint, driver resolution, transcripts, tool relay, delegation narration,\n * channel lifecycle, usage relay, teardown — lives in\n * {@link RealtimeSessionRuntime} (`@memberjunction/realtime-runtime`), which is framework-agnostic\n * and shared with every other host, including the React Native app. This class supplies the three\n * things that are genuinely Angular/browser: the `@Injectable` shell that lets components inject\n * it, the browser's media host, and the page-lifecycle wiring that sends the recording's terminal\n * request when the tab is hidden or unloaded (#5294).\n *\n * Consumers are unaffected by that split — the injectable token, class name, and public surface\n * are unchanged. Types that used to be declared in this file (`RealtimeCaption`,\n * `RealtimeConnectionState`, `RealtimeSessionRunOptions`, …) now come from\n * `@memberjunction/realtime-runtime`; import them from there directly, since MJ does not\n * re-export across package boundaries.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionService extends RealtimeSessionRuntime {\n constructor() {\n super(new BrowserRealtimeMediaHost());\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n this.WireRecordingTerminalTriggers(window, document);\n }\n }\n\n /**\n * Sends the recording terminal (tail shard + counts, as a keepalive request) when the page is\n * going away: on `pagehide`, and when the page becomes hidden — the last event a mobile browser\n * reliably fires before it may discard a backgrounded tab without any unload event. Both handlers\n * only call the runtime's synchronous {@link RealtimeSessionRuntime.SendRecordingTerminal}, which\n * does no IndexedDB work and no encoding: there is no time for either while a page is unloading.\n * It does nothing when no call is recording, and repeating it is safe (a sent tail is sealed, so a\n * call that continues after the tab comes back sends its later shards at new indexes).\n *\n * There is deliberately no `beforeunload` prompt any more: shards already on the server plus the\n * terminal make closing the tab safe, and a `beforeunload` listener blocks the back/forward cache.\n *\n * The service is a root singleton, so these listeners live exactly as long as the app and are\n * never removed.\n *\n * @param page the page-lifecycle event target (`window`)\n * @param visibility the visibility source (`document`)\n */\n protected WireRecordingTerminalTriggers(page: PageHideEventTarget, visibility: VisibilityEventSource): void {\n page.addEventListener('pagehide', () => this.SendRecordingTerminal({ Final: true }));\n visibility.addEventListener('visibilitychange', () => {\n if (visibility.visibilityState === 'hidden') {\n // Not final: the user may come back and the call go on, so the server only stamps the\n // counts and assembles after its grace period instead of rewriting the recording now.\n this.SendRecordingTerminal({ Final: false });\n }\n });\n }\n}\n\n/** The slice of `window` the terminal wiring needs; `window` itself satisfies it. */\nexport interface PageHideEventTarget {\n // case-violation-ok-legacy-back-compat: mirrors the DOM EventTarget API so `window` itself satisfies this interface\n addEventListener(type: 'pagehide', listener: () => void): void;\n}\n\n/** The slice of `document` the terminal wiring needs; `document` itself satisfies it. */\nexport interface VisibilityEventSource {\n // case-violation-ok-legacy-back-compat: mirrors the DOM Document API so `document` itself satisfies this interface\n readonly visibilityState: DocumentVisibilityState;\n // case-violation-ok-legacy-back-compat: mirrors the DOM EventTarget API so `document` itself satisfies this interface\n addEventListener(type: 'visibilitychange', listener: () => void): void;\n}\n"]}
1
+ {"version":3,"file":"realtime-session.service.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-session.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EACH,4BAA4B,EAC5B,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;;AAEzE,gGAAgG;AAChG,mGAAmG;AACnG,gDAAgD;AAChD,EAAE;AACF,+FAA+F;AAC/F,0FAA0F;AAC1F,+FAA+F;AAC/F,kBAAkB;AAClB,wBAAwB,EAAE,CAAC;AAC3B,oBAAoB,EAAE,CAAC;AACvB,wBAAwB,EAAE,CAAC;AAC3B,4BAA4B,EAAE,CAAC;AAC/B,4BAA4B,EAAE,CAAC;AAC/B,qBAAqB,EAAE,CAAC;AACxB,wBAAwB,EAAE,CAAC;AAC3B,6BAA6B,EAAE,CAAC;AAEhC;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAC9D;QACI,KAAK,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC;QACtC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACnE,IAAI,CAAC,6BAA6B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACO,6BAA6B,CAAC,IAAyB,EAAE,UAAiC;QAChG,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACrF,UAAU,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;YACjD,IAAI,UAAU,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;gBAC1C,sFAAsF;gBACtF,sFAAsF;gBACtF,IAAI,CAAC,qBAAqB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;gHAnCQ,sBAAsB;gEAAtB,sBAAsB,WAAtB,sBAAsB,mBADT,MAAM;;iFACnB,sBAAsB;cADlC,UAAU;eAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { Injectable } from '@angular/core';\nimport { RealtimeSessionRuntime } from '@memberjunction/realtime-runtime';\nimport {\n LoadAssemblyAIRealtimeClient,\n LoadElevenLabsRealtimeClient,\n LoadElevenRealtimeClient,\n LoadGeminiRealtimeClient,\n LoadHuggingFaceRealtimeClient,\n LoadOpenAILiveClient,\n LoadOpenAIRealtimeClient,\n LoadxAIRealtimeClient,\n} from '@memberjunction/ai-realtime-client';\nimport { BrowserRealtimeMediaHost } from './browser-realtime-media-host';\n\n// Tree-shaking prevention: client drivers are resolved dynamically through the ClassFactory (by\n// the server-reported Provider key), so these static calls are what keep their @RegisterClass side\n// effects from being eliminated by the bundler.\n//\n// NOTE: the interactive-channel plugins (resolved dynamically from the `MJ: AI Agent Channels`\n// registry by ClientPluginClass key) get the same treatment, but their Load calls live in\n// `conversations.module.ts` — plugins carry Angular surface COMPONENTS, and this service stays\n// component-free.\nLoadOpenAIRealtimeClient();\nLoadOpenAILiveClient();\nLoadGeminiRealtimeClient();\nLoadElevenLabsRealtimeClient();\nLoadAssemblyAIRealtimeClient();\nLoadxAIRealtimeClient();\nLoadElevenRealtimeClient();\nLoadHuggingFaceRealtimeClient();\n\n/**\n * Angular host for MemberJunction's realtime co-agent sessions.\n *\n * All orchestration — mint, driver resolution, transcripts, tool relay, delegation narration,\n * channel lifecycle, usage relay, teardown — lives in\n * {@link RealtimeSessionRuntime} (`@memberjunction/realtime-runtime`), which is framework-agnostic\n * and shared with every other host, including the React Native app. This class supplies the three\n * things that are genuinely Angular/browser: the `@Injectable` shell that lets components inject\n * it, the browser's media host, and the page-lifecycle wiring that sends the recording's terminal\n * request when the tab is hidden or unloaded (#5294).\n *\n * Consumers are unaffected by that split — the injectable token, class name, and public surface\n * are unchanged. Types that used to be declared in this file (`RealtimeCaption`,\n * `RealtimeConnectionState`, `RealtimeSessionRunOptions`, …) now come from\n * `@memberjunction/realtime-runtime`; import them from there directly, since MJ does not\n * re-export across package boundaries.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeSessionService extends RealtimeSessionRuntime {\n constructor() {\n super(new BrowserRealtimeMediaHost());\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n this.WireRecordingTerminalTriggers(window, document);\n }\n }\n\n /**\n * Sends the recording terminal (tail shard + counts, as a keepalive request) when the page is\n * going away: on `pagehide`, and when the page becomes hidden — the last event a mobile browser\n * reliably fires before it may discard a backgrounded tab without any unload event. Both handlers\n * only call the runtime's synchronous {@link RealtimeSessionRuntime.SendRecordingTerminal}, which\n * does no IndexedDB work and no encoding: there is no time for either while a page is unloading.\n * It does nothing when no call is recording, and repeating it is safe (a sent tail is sealed, so a\n * call that continues after the tab comes back sends its later shards at new indexes).\n *\n * There is deliberately no `beforeunload` prompt any more: shards already on the server plus the\n * terminal make closing the tab safe, and a `beforeunload` listener blocks the back/forward cache.\n *\n * The service is a root singleton, so these listeners live exactly as long as the app and are\n * never removed.\n *\n * @param page the page-lifecycle event target (`window`)\n * @param visibility the visibility source (`document`)\n */\n protected WireRecordingTerminalTriggers(page: PageHideEventTarget, visibility: VisibilityEventSource): void {\n page.addEventListener('pagehide', () => this.SendRecordingTerminal({ Final: true }));\n visibility.addEventListener('visibilitychange', () => {\n if (visibility.visibilityState === 'hidden') {\n // Not final: the user may come back and the call go on, so the server only stamps the\n // counts and assembles after its grace period instead of rewriting the recording now.\n this.SendRecordingTerminal({ Final: false });\n }\n });\n }\n}\n\n/** The slice of `window` the terminal wiring needs; `window` itself satisfies it. */\nexport interface PageHideEventTarget {\n // case-violation-ok-legacy-back-compat: mirrors the DOM EventTarget API so `window` itself satisfies this interface\n addEventListener(type: 'pagehide', listener: () => void): void;\n}\n\n/** The slice of `document` the terminal wiring needs; `document` itself satisfies it. */\nexport interface VisibilityEventSource {\n // case-violation-ok-legacy-back-compat: mirrors the DOM Document API so `document` itself satisfies this interface\n readonly visibilityState: DocumentVisibilityState;\n // case-violation-ok-legacy-back-compat: mirrors the DOM EventTarget API so `document` itself satisfies this interface\n addEventListener(type: 'visibilitychange', listener: () => void): void;\n}\n"]}