@memberjunction/ng-conversations 6.1.0-edge.2 → 6.1.0-edge.3
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.
- package/LICENSE +180 -4
- package/README.md +32 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +159 -9
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +497 -106
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +14 -2
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +37 -19
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +7 -3
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +78 -159
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +287 -7
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +850 -56
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +98 -16
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +218 -69
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +206 -0
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -0
- package/dist/lib/services/conversation-detail-window.store.js +503 -0
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -0
- package/dist/lib/utils/agent-artifact-summary.d.ts +54 -0
- package/dist/lib/utils/agent-artifact-summary.d.ts.map +1 -0
- package/dist/lib/utils/agent-artifact-summary.js +49 -0
- package/dist/lib/utils/agent-artifact-summary.js.map +1 -0
- package/dist/lib/utils/conversation-detail-window.d.ts +49 -0
- package/dist/lib/utils/conversation-detail-window.d.ts.map +1 -0
- package/dist/lib/utils/conversation-detail-window.js +86 -0
- package/dist/lib/utils/conversation-detail-window.js.map +1 -0
- package/dist/lib/utils/date-jump.d.ts +65 -0
- package/dist/lib/utils/date-jump.d.ts.map +1 -0
- package/dist/lib/utils/date-jump.js +106 -0
- package/dist/lib/utils/date-jump.js.map +1 -0
- package/package.json +32 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-list.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/message-list.component.ts","../../../../src/lib/components/message/message-list.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ViewChild,\n ViewContainerRef,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ElementRef,\n AfterViewInit,\n AfterViewChecked,\n ComponentRef,\n EmbeddedViewRef,\n TemplateRef\n} from '@angular/core';\nimport { MJConversationDetailEntity, MJConversationEntity, RatingJSON } from '@memberjunction/core-entities';\nimport { UserInfo, CompositeKey } from '@memberjunction/core';\nimport { NormalizeUUID } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MessageItemComponent, MessageAttachment } from './message-item.component';\nimport {\n BeforeResponseFormSubmittedEventArgs,\n AfterResponseFormSubmittedEventArgs,\n} from '../../events/chat-events';\nimport { RealtimeSessionTimelineCardComponent } from '../realtime/realtime-session-timeline-card.component';\nimport { LazyArtifactInfo } from '../../models/lazy-artifact-info';\nimport { selectDistinctLatestArtifacts } from '../../utils/distinct-artifacts';\nimport {\n BuildConversationTimeline,\n ConversationTimelineItem,\n RealtimeSessionTimelineGroup,\n RealtimeSessionTimelineMeta\n} from '../../utils/realtime-session-timeline';\nimport { MJAIAgentRunEntityExtended } from '@memberjunction/ai-core-plus';\n\n/** Context handed to the `messageRenderer` slot template per message. */\ninterface MessageRendererContext {\n $implicit: MJConversationDetailEntity;\n message: MJConversationDetailEntity;\n}\n\n/**\n * One per rendered message in the list. Three paths can produce an entry:\n * - `component` — the default `MessageItemComponent` (single message).\n * - `embedded` — an `EmbeddedViewRef` from the consumer's\n * `messageRenderer` slot template (full per-message\n * replacement, PR 2c slot system).\n * - `realtime-session` — a `RealtimeSessionTimelineCardComponent` collapsing\n * an entire past realtime session into one timeline\n * card (PR #2787 co-agent timeline). The grouping pass\n * (`BuildConversationTimeline`) emits these alongside\n * normal messages — see the timeline utility for the\n * rules.\n *\n * Discriminated by the `kind` tag for ergonomic narrowing.\n */\ntype RenderedMessageEntry =\n | { kind: 'component'; ref: ComponentRef<MessageItemComponent> }\n | { kind: 'embedded'; ref: EmbeddedViewRef<MessageRendererContext> }\n | { kind: 'realtime-session'; ref: ComponentRef<RealtimeSessionTimelineCardComponent> };\n\n/**\n * Container component for displaying a list of messages\n * Uses dynamic component creation (like skip-chat) to avoid Angular binding overhead\n * This dramatically improves performance when messages are added/removed\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-list',\n templateUrl: './message-list.component.html',\n styleUrls: ['./message-list.component.css']\n})\nexport class MessageListComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, AfterViewChecked {\n @Input() public messages: MJConversationDetailEntity[] = [];\n @Input() public conversation!: MJConversationEntity | null;\n @Input() public currentUser!: UserInfo;\n @Input() public isProcessing: boolean = false;\n /** Whether the built-in \"No messages yet\" filler renders for empty conversations. Hosts with their own empty-state chrome set false. */\n @Input() public showEmptyFill: boolean = true;\n /** Whether the sticky date header + jump-to-date dropdown render. */\n @Input() public showDateNavigation: boolean = true;\n // Per-message feature gates — forwarded onto each MessageItemComponent instance\n // (see applyMessageItemFeatureFlags). All default true.\n @Input() public showAgentRunDetails: boolean = true;\n @Input() public showReactions: boolean = true;\n @Input() public showMessageRating: boolean = true;\n @Input() public allowPinning: boolean = true;\n @Input() public allowMessageEdit: boolean = true;\n @Input() public allowMessageDelete: boolean = true;\n // ── Assistant identity overrides — static host config forwarded to every message\n // item (null = engine identity). Setters (not ngOnChanges) so an imperative\n // host — `@ViewChild(MessageListComponent).assistantDisplayName = …` — restamps\n // too, and so identity changes don't pay a check on every other input's cycle.\n // Identity can land AFTER first render (branding resolves async) or change\n // mid-session (per-conversation persona), and message items are created\n // dynamically with the overrides stamped as static config — so a change has to\n // restamp the ALREADY-rendered items or existing bubbles keep the old identity\n // until the next messages-array mutation. ──\n /** Display name shown on AI messages. Null = the engine-resolved agent name. */\n @Input()\n public set assistantDisplayName(value: string | null) {\n if (value !== this._assistantDisplayName) {\n this._assistantDisplayName = value;\n this.restampAssistantIdentity();\n }\n }\n public get assistantDisplayName(): string | null {\n return this._assistantDisplayName;\n }\n private _assistantDisplayName: string | null = null;\n\n /** Image URL for the AI message avatar. Null = the agent's Font Awesome icon. */\n @Input()\n public set assistantAvatarUrl(value: string | null) {\n if (value !== this._assistantAvatarUrl) {\n this._assistantAvatarUrl = value;\n this.restampAssistantIdentity();\n }\n }\n public get assistantAvatarUrl(): string | null {\n return this._assistantAvatarUrl;\n }\n private _assistantAvatarUrl: string | null = null;\n @Input() public artifactMap: Map<string, LazyArtifactInfo[]> = new Map();\n @Input() public agentRunMap: Map<string, MJAIAgentRunEntityExtended> = new Map();\n @Input() public ratingsMap: Map<string, RatingJSON[]> = new Map();\n @Input() public userAvatarMap: Map<string, {imageUrl: string | null; iconClass: string | null}> = new Map();\n @Input() public attachmentsMap: Map<string, MessageAttachment[]> = new Map();\n /**\n * Optional session-row enrichment for realtime SESSION BLOCKS, keyed by\n * `NormalizeUUID(sessionId)` (agent name / status / close reason). Details stamped\n * with an `AgentSessionID` collapse into one timeline card per session — see\n * `BuildConversationTimeline` — and this map dresses those cards up when present.\n */\n @Input() public sessionMetaMap: Map<string, RealtimeSessionTimelineMeta> = new Map();\n\n /**\n * Optional per-iteration custom message renderer. When set, the list renders each\n * message via this template (full replacement) instead of the default\n * `MessageItemComponent`. Forwarded by chat-area when a consumer projects\n * `mjChatSlot=\"messageRenderer\"`. The template receives the message as\n * `$implicit` and as a named `message` context binding.\n *\n * Consumers opting into a custom renderer take full responsibility for displaying\n * the message — edit/delete/retry affordances, artifacts, ratings, attachments,\n * etc. The minimal `MJChatMessageBubbleDefaultComponent` ships as a ready-to-use\n * bubble renderer.\n */\n @Input() public messageRendererTemplate: TemplateRef<unknown> | null = null;\n\n /**\n * Optional per-message additive decoration template, projected INSIDE the default\n * `MessageItemComponent` (after the message text). Forwarded by chat-area when a\n * consumer projects `mjChatSlot=\"messageExtra\"`. Ignored when\n * `messageRendererTemplate` is set (custom renderers own all per-message content).\n */\n @Input() public messageExtraTemplate: TemplateRef<unknown> | null = null;\n\n @Output() public editMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public deleteMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public retryMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public testFeedbackMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public artifactClicked = new EventEmitter<{artifactId: string; versionId?: string}>();\n @Output() public replyInThread = new EventEmitter<MJConversationDetailEntity>();\n @Output() public viewThread = new EventEmitter<MJConversationDetailEntity>();\n @Output() public messageEdited = new EventEmitter<MJConversationDetailEntity>();\n @Output() public openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n @Output() public suggestedResponseSelected = new EventEmitter<{text: string; customInput?: string}>();\n @Output() public attachmentClicked = new EventEmitter<MessageAttachment>();\n @Output() public diagnosticRequested = new EventEmitter<string>(); // emits messageId\n @Output() public messagePinToggled = new EventEmitter<MJConversationDetailEntity>();\n /** Emitted with the `MJ: AI Agent Sessions.ID` when a realtime session block's Open affordance is clicked. */\n @Output() public realtimeSessionOpenRequested = new EventEmitter<string>();\n\n /** Forwarded from MessageItemComponent — see its docs. */\n @Output() public beforeResponseFormSubmitted = new EventEmitter<BeforeResponseFormSubmittedEventArgs>();\n /** Forwarded from MessageItemComponent — see its docs. */\n @Output() public afterResponseFormSubmitted = new EventEmitter<AfterResponseFormSubmittedEventArgs>();\n\n @ViewChild('messageContainer', { read: ViewContainerRef }) messageContainerRef!: ViewContainerRef;\n @ViewChild('scrollContainer') scrollContainer!: ElementRef;\n\n /**\n * Per-message rendered entries — see `RenderedMessageEntry` for the 3-way\n * union (default MessageItemComponent / consumer messageRenderer slot\n * embedded view / collapsed realtime session timeline card).\n */\n private _renderedMessages = new Map<string, RenderedMessageEntry>();\n private _shouldScrollToBottom = false;\n private _previousMessageCount = 0; // Track previous count to detect new messages\n\n public currentDateDisplay: string = 'Today';\n public showDateNav: boolean = false;\n public shouldShowDateFilter: boolean = false;\n\n constructor(private cdRef: ChangeDetectorRef) {\n super();\n }\n\n public toggleDateNav(): void {\n this.showDateNav = !this.showDateNav;\n }\n\n public jumpToDate(period: string): void {\n // TODO: Implement date jumping logic\n console.log('Jump to date:', period);\n this.showDateNav = false;\n\n // Update display based on period\n switch(period) {\n case 'today':\n this.currentDateDisplay = 'Today';\n break;\n case 'yesterday':\n this.currentDateDisplay = 'Yesterday';\n break;\n case 'last-week':\n this.currentDateDisplay = 'Last week';\n break;\n case 'last-month':\n this.currentDateDisplay = 'Last month';\n break;\n }\n }\n\n // Track whether initial render has happened\n private _initialRenderComplete = false;\n\n ngOnInit() {\n // Initial render will happen in ngAfterViewInit when ViewContainerRef is available\n }\n\n ngAfterViewInit() {\n // ViewContainerRef is now available - perform initial render if we have messages\n if (this.messages && this.messages.length > 0 && this.messageContainerRef && !this._initialRenderComplete) {\n this._initialRenderComplete = true;\n this.updateMessages(this.messages);\n this.updateDateFilterVisibility();\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n // React to messages array changes\n // Note: On initial load, messageContainerRef may not be available yet (ngOnChanges runs before ngAfterViewInit)\n // In that case, ngAfterViewInit will handle the initial render\n if (changes['messages'] && this.messages && this.messageContainerRef) {\n this._initialRenderComplete = true;\n this.updateMessages(this.messages);\n this.updateDateFilterVisibility();\n }\n\n // Watch for artifactMap changes to handle newly created artifacts\n // While artifacts are pre-loaded during initial peripheral data load,\n // new artifacts can be created mid-conversation (e.g., by agent runs)\n // This ensures artifact cards appear in messages immediately without requiring a refresh\n if (changes['artifactMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n // Watch for attachmentsMap changes to handle newly created attachments\n // This ensures media attachments (e.g., images generated by agents) appear\n // immediately without requiring a page refresh\n if (changes['attachmentsMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n // Watch for session-meta changes so realtime session blocks pick up their\n // agent name / status chip once the (async, batched) session lookup lands\n if (changes['sessionMetaMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n }\n\n /**\n * Re-stamp the assistant-identity overrides onto every already-rendered message\n * item. Called from the identity setters (see the inputs above) — items are created\n * dynamically with these values stamped as static config, so without this a change\n * that arrives after first render wouldn't reach existing bubbles.\n *\n * No-op before the first render (the map is empty), so it's safe to fire during\n * Angular's initial input binding.\n */\n private restampAssistantIdentity(): void {\n for (const entry of this._renderedMessages.values()) {\n if (entry.kind === 'component') {\n this.applyMessageItemFeatureFlags(entry.ref.instance);\n entry.ref.changeDetectorRef.markForCheck();\n }\n }\n }\n\n ngAfterViewChecked() {\n if (this._shouldScrollToBottom) {\n this.scrollToBottom();\n this._shouldScrollToBottom = false;\n }\n }\n\n ngOnDestroy() {\n // Clean up all dynamically created components AND embedded views (both have destroy()).\n this._renderedMessages.forEach((entry) => {\n if (entry) {\n entry.ref.destroy();\n }\n });\n this._renderedMessages.clear();\n\n if (this.messageContainerRef) {\n this.messageContainerRef.clear();\n }\n }\n\n /**\n * Called when messages array changes\n * Efficiently updates the DOM without re-rendering everything\n */\n @Input()\n set messagesUpdate(messages: MJConversationDetailEntity[]) {\n if (messages && this.messageContainerRef) {\n this.updateMessages(messages);\n }\n }\n\n /**\n * Updates the message list using dynamic component creation\n * Only adds/removes changed messages for optimal performance\n *\n * REALTIME SESSIONS: details stamped with an `AgentSessionID` (turns persisted during\n * a live realtime session) do NOT render as normal chat bubbles. The timeline pass\n * (`BuildConversationTimeline`) collapses each session's stamped rows into ONE session\n * block, rendered as a `RealtimeSessionTimelineCardComponent` at the session's\n * chronological position. Everything else renders exactly as before.\n */\n private updateMessages(messages: MJConversationDetailEntity[]): void {\n // Temporarily detach change detection for performance\n this.cdRef.detach();\n\n try {\n // Build the timeline first — collapses contiguous realtime-session rows\n // into ONE session block per session, leaving normal messages in place.\n // See `BuildConversationTimeline` in `utils/realtime-session-timeline`.\n const timeline = BuildConversationTimeline(messages);\n\n // Remove rendered items (messages AND session blocks) that no longer exist\n const currentKeys = new Set(timeline.map(item => this.getTimelineKey(item)));\n this._renderedMessages.forEach((entry, key) => {\n if (!currentKeys.has(key)) {\n entry.ref.destroy();\n this._renderedMessages.delete(key);\n }\n });\n\n // Add or update timeline items in chronological order. `renderMessageItem`\n // internally branches on the slot template (messageRenderer) vs the\n // default MessageItemComponent; `renderSessionBlock` always creates a\n // RealtimeSessionTimelineCardComponent.\n const lastMessageKey = this.findLastMessageKey(timeline);\n for (const item of timeline) {\n if (item.Kind === 'session') {\n this.renderSessionBlock(item.Group);\n } else {\n this.renderMessageItem(item.Detail, messages, this.getMessageKey(item.Detail) === lastMessageKey);\n }\n }\n\n // Only scroll to bottom if new messages were added (not just updates)\n // This prevents scrolling when the message list is merely refreshed (e.g., during agent run timer)\n const previousCount = this._previousMessageCount;\n this._previousMessageCount = messages.length;\n\n if (messages.length > previousCount) {\n this._shouldScrollToBottom = true;\n }\n } finally {\n // Re-attach change detection\n this.cdRef.reattach();\n this.cdRef.detectChanges();\n }\n }\n\n /** Stable render key for a timeline item — message ID, or a prefixed session key for session blocks. */\n private getTimelineKey(item: ConversationTimelineItem<MJConversationDetailEntity>): string {\n return item.Kind === 'session' ? this.getSessionKey(item.Group.SessionID) : this.getMessageKey(item.Detail);\n }\n\n /** Render key for a session block (case-insensitive on the session id; prefixed so it can't collide with message IDs). */\n private getSessionKey(sessionId: string): string {\n return `session:${NormalizeUUID(sessionId)}`;\n }\n\n /** The render key of the LAST normal message item in the timeline (drives `isLastMessage`), or null when none. */\n private findLastMessageKey(timeline: ConversationTimelineItem<MJConversationDetailEntity>[]): string | null {\n for (let i = timeline.length - 1; i >= 0; i--) {\n const item = timeline[i];\n if (item.Kind === 'message') {\n return this.getMessageKey(item.Detail);\n }\n }\n return null;\n }\n\n /**\n * Creates or updates the ONE timeline card a realtime session collapses to.\n * Click/Open on the card bubbles up via {@link realtimeSessionOpenRequested} so the\n * chat area can host the SESSION REVIEW overlay for it.\n */\n private renderSessionBlock(group: RealtimeSessionTimelineGroup): void {\n const key = this.getSessionKey(group.SessionID);\n const meta = this.sessionMetaMap.get(NormalizeUUID(group.SessionID)) ?? null;\n const existing = this._renderedMessages.get(key);\n\n if (existing && existing.kind === 'realtime-session') {\n // Update existing card in place.\n const instance = existing.ref.instance;\n instance.Group = group;\n instance.Meta = meta;\n existing.ref.changeDetectorRef.markForCheck();\n return;\n }\n\n // Different kind at this key (e.g. mode changed) — drop the old entry, fall through to create.\n if (existing) {\n existing.ref.destroy();\n this._renderedMessages.delete(key);\n }\n\n const componentRef = this.messageContainerRef.createComponent(RealtimeSessionTimelineCardComponent);\n componentRef.instance.Group = group;\n componentRef.instance.Meta = meta;\n componentRef.instance.UserName = this.currentUser?.Name || 'You';\n componentRef.instance.OpenRequested.subscribe((sessionId: string) => this.realtimeSessionOpenRequested.emit(sessionId));\n this._renderedMessages.set(key, { kind: 'realtime-session', ref: componentRef });\n }\n\n /**\n * Creates or updates one normal chat message item. Routes to the\n * consumer-projected `messageRenderer` slot template (EmbeddedViewRef path)\n * when present, otherwise falls back to the default `MessageItemComponent`\n * dynamic-component path. Both paths flow through the shared\n * `createRenderedEntry` / `updateMessageItemInstance` helpers.\n */\n private renderMessageItem(message: MJConversationDetailEntity, messages: MJConversationDetailEntity[], isLastMessage: boolean): void {\n const key = this.getMessageKey(message);\n // `index` is only used for the `isLastMessage` heuristic inside\n // updateMessageItemInstance — synthesize a value that produces the right\n // boolean (last index when `isLastMessage` is true, else 0 — any non-last\n // index works since it just affects that one comparison).\n const index = isLastMessage ? messages.length - 1 : 0;\n const useCustomRenderer = this.messageRendererTemplate !== null;\n const existing = this._renderedMessages.get(key);\n\n if (existing && existing.kind === 'embedded' && useCustomRenderer) {\n // Update existing embedded view from messageRenderer slot\n existing.ref.context.$implicit = message;\n existing.ref.context.message = message;\n existing.ref.markForCheck();\n return;\n }\n if (existing && existing.kind === 'component' && !useCustomRenderer) {\n // Update existing MessageItemComponent in place\n this.updateMessageItemInstance(existing.ref, message, messages, index);\n return;\n }\n if (existing) {\n // Rendering kind changed (e.g. component↔embedded, or a session block was\n // overwritten with a message). Destroy + recreate.\n existing.ref.destroy();\n this._renderedMessages.delete(key);\n }\n\n this.createRenderedEntry(message, messages, index, key, useCustomRenderer);\n }\n\n /**\n * Updates an existing `MessageItemComponent` in place — used on the default\n * (non-custom-renderer) path when a message's status / artifacts / agent-run /\n * etc. changes mid-stream.\n */\n private updateMessageItemInstance(\n ref: ComponentRef<MessageItemComponent>,\n message: MJConversationDetailEntity,\n messages: MJConversationDetailEntity[],\n index: number\n ): void {\n const instance = ref.instance;\n const previousMessage = instance.message;\n\n instance.message = message;\n instance.allMessages = messages;\n instance.isProcessing = this.isProcessing;\n instance.userAvatarMap = this.userAvatarMap;\n instance.isLastMessage = (index === messages.length - 1);\n instance.messageExtraTemplate = this.messageExtraTemplate;\n this.applyMessageItemFeatureFlags(instance);\n\n this.applyArtifactsToInstance(instance, message.ID, ref.changeDetectorRef);\n\n instance.agentRun = this.agentRunMap.get(message.ID) || null;\n instance.ratings = this.ratingsMap.get(message.ID);\n instance.attachments = this.attachmentsMap.get(message.ID) || [];\n\n // Status change requires explicit markForCheck on the OnPush dynamic child.\n if (previousMessage && previousMessage.Status !== message.Status) {\n ref.changeDetectorRef.markForCheck();\n }\n }\n\n /**\n * Forward the host-level per-message feature gates onto a MessageItemComponent\n * instance. These are static host config (not per-message data), so the same\n * values apply to every message; applied on both the create and in-place-update\n * paths so a mid-session rebind stays consistent.\n */\n private applyMessageItemFeatureFlags(instance: MessageItemComponent): void {\n instance.showAgentRunDetails = this.showAgentRunDetails;\n instance.showReactions = this.showReactions;\n instance.showMessageRating = this.showMessageRating;\n instance.allowPinning = this.allowPinning;\n instance.allowMessageEdit = this.allowMessageEdit;\n instance.allowMessageDelete = this.allowMessageDelete;\n instance.assistantDisplayName = this.assistantDisplayName;\n instance.assistantAvatarUrl = this.assistantAvatarUrl;\n }\n\n /**\n * Creates a new rendered entry — either a `MessageItemComponent` (default path)\n * or an `EmbeddedViewRef` from the consumer's `messageRenderer` slot template.\n * Stores the entry in `_renderedMessages` and stamps a back-reference on the\n * message entity.\n */\n private createRenderedEntry(\n message: MJConversationDetailEntity,\n messages: MJConversationDetailEntity[],\n index: number,\n key: string,\n useCustomRenderer: boolean\n ): void {\n if (useCustomRenderer && this.messageRendererTemplate) {\n // The slot directive carries TemplateRef<unknown>; assert the contract here\n // (consumers' `let-message` bindings consume the message context shape below).\n const template = this.messageRendererTemplate as TemplateRef<MessageRendererContext>;\n const viewRef = this.messageContainerRef.createEmbeddedView<MessageRendererContext>(\n template,\n { $implicit: message, message }\n );\n this._renderedMessages.set(key, { kind: 'embedded', ref: viewRef });\n // Stamp back-ref for parity with the component path.\n (message as unknown as { _viewRef?: EmbeddedViewRef<MessageRendererContext> })._viewRef = viewRef;\n return;\n }\n\n const componentRef = this.messageContainerRef.createComponent(MessageItemComponent);\n const instance = componentRef.instance;\n\n instance.message = message;\n instance.conversation = this.conversation;\n instance.currentUser = this.currentUser;\n instance.allMessages = messages;\n instance.isProcessing = this.isProcessing;\n instance.userAvatarMap = this.userAvatarMap;\n instance.isLastMessage = (index === messages.length - 1);\n instance.messageExtraTemplate = this.messageExtraTemplate;\n this.applyMessageItemFeatureFlags(instance);\n\n this.applyArtifactsToInstance(instance, message.ID, componentRef.changeDetectorRef);\n\n instance.agentRun = this.agentRunMap.get(message.ID) || null;\n instance.ratings = this.ratingsMap.get(message.ID);\n instance.attachments = this.attachmentsMap.get(message.ID) || [];\n\n instance.editClicked.subscribe((msg: MJConversationDetailEntity) => this.editMessage.emit(msg));\n instance.deleteClicked.subscribe((msg: MJConversationDetailEntity) => this.deleteMessage.emit(msg));\n instance.retryClicked.subscribe((msg: MJConversationDetailEntity) => this.retryMessage.emit(msg));\n instance.testFeedbackClicked.subscribe((msg: MJConversationDetailEntity) => this.testFeedbackMessage.emit(msg));\n instance.artifactClicked.subscribe((data: {artifactId: string; versionId?: string}) => this.artifactClicked.emit(data));\n instance.messageEdited.subscribe((msg: MJConversationDetailEntity) => this.messageEdited.emit(msg));\n instance.openEntityRecord.subscribe((data: {entityName: string; compositeKey: CompositeKey}) => this.openEntityRecord.emit(data));\n instance.suggestedResponseSelected.subscribe((data: {text: string; customInput?: string}) => this.suggestedResponseSelected.emit(data));\n instance.attachmentClicked.subscribe((attachment: MessageAttachment) => this.attachmentClicked.emit(attachment));\n instance.diagnosticRequested.subscribe((messageId: string) => this.diagnosticRequested.emit(messageId));\n instance.messagePinToggled.subscribe((msg: MJConversationDetailEntity) => this.messagePinToggled.emit(msg));\n instance.beforeResponseFormSubmitted.subscribe((e: BeforeResponseFormSubmittedEventArgs) => this.beforeResponseFormSubmitted.emit(e));\n instance.afterResponseFormSubmitted.subscribe((e: AfterResponseFormSubmittedEventArgs) => this.afterResponseFormSubmitted.emit(e));\n\n if (instance.artifactActionPerformed) {\n instance.artifactActionPerformed.subscribe((data: {action: string; artifactId: string}) => {\n // Parent can handle artifact actions (save, fork, history, share)\n console.log('Artifact action:', data);\n });\n }\n\n this._renderedMessages.set(key, { kind: 'component', ref: componentRef });\n // Preserve the existing back-ref pattern from the skip-chat performance design.\n (message as unknown as { _componentRef?: ComponentRef<MessageItemComponent> })._componentRef = componentRef;\n }\n\n /**\n * Resolves the DISTINCT artifacts for a message (one entry per artifactId at its\n * latest version), lazy-loads them all, and applies them to the rendered\n * message-item. Loads in the background so the UI never blocks.\n *\n * WHY WE SURFACE THEM ALL (design rationale — see PR discussion w/ Pranav & Ethan):\n * A single message can legitimately carry more than one DISTINCT artifact — e.g. a\n * research report PLUS a *standalone* generated infographic. This is deliberately\n * NOT in conflict with the server-side consolidation in AgentRunner\n * (Pranav, 5664b86: \"keep the report's embedded image in the report, not as a\n * duplicate artifact\"): that logic only suppresses media that is *embedded inline*\n * (base64) in another artifact's payload — a true duplicate. Genuinely standalone\n * sibling artifacts (the report uses SVG charts; the infographic is a separate JPEG)\n * are correctly kept as separate artifacts, and the UI must show every one of them.\n *\n * The earlier `artifactList[length - 1]` (\"show only the most recent\") approach\n * (EL-BC, 95492622) assumed consolidation always left exactly one artifact per\n * message; when it legitimately leaves two, that silently hid the report behind the\n * image. Grouping by artifactId (latest version each) shows all distinct artifacts\n * while still collapsing multiple *versions* of the same artifact to one card.\n */\n private applyArtifactsToInstance(\n instance: MessageItemComponent,\n messageId: string,\n childCdRef: ChangeDetectorRef\n ): void {\n const infos = this.resolveDistinctArtifacts(messageId);\n if (infos.length === 0) {\n instance.artifacts = [];\n instance.artifact = undefined;\n instance.artifactVersion = undefined;\n return;\n }\n\n Promise.all(\n infos.map(info =>\n Promise.all([info.getArtifact(), info.getVersion()]).then(([artifact, version]) => ({ artifact, version }))\n )\n )\n .then(refs => {\n instance.artifacts = refs;\n // Keep the legacy single inputs pointed at the first entry for back-compat.\n instance.artifact = refs[0]?.artifact;\n instance.artifactVersion = refs[0]?.version;\n // zone.js 0.15: parent detectChanges doesn't propagate to dynamically created children\n childCdRef.detectChanges();\n this.cdRef.detectChanges();\n })\n .catch(err => {\n console.error('Failed to lazy-load artifacts:', err);\n });\n }\n\n /**\n * Groups a message's artifact list by artifactId, keeping the highest version of\n * each. Multiple versions of the SAME artifact collapse to one card (latest wins),\n * while genuinely distinct artifacts are all retained.\n */\n private resolveDistinctArtifacts(messageId: string): LazyArtifactInfo[] {\n const list = this.artifactMap.get(messageId);\n if (!list || list.length === 0) {\n return [];\n }\n return selectDistinctLatestArtifacts(list);\n }\n\n /**\n * Generates a unique key for a message\n * Uses ID if available, otherwise uses a temporary key\n */\n private getMessageKey(message: MJConversationDetailEntity): string {\n return message.ID && message.ID.length > 0\n ? message.ID\n : `temp_${message.__mj_CreatedAt?.getTime() || Date.now()}`;\n }\n\n /**\n * Determines whether to show the date filter dropdown\n * Only show if conversation is long and spans multiple days\n */\n private updateDateFilterVisibility(): void {\n if (!this.messages || this.messages.length < 20) {\n this.shouldShowDateFilter = false;\n return;\n }\n\n // Check if messages span more than 2 days\n const dates = this.messages\n .map(m => m.__mj_CreatedAt)\n .filter(d => d != null)\n .map(d => new Date(d!).setHours(0, 0, 0, 0));\n\n if (dates.length === 0) {\n this.shouldShowDateFilter = false;\n return;\n }\n\n const uniqueDates = new Set(dates);\n const daySpan = uniqueDates.size;\n\n // Show filter if conversation has 20+ messages and spans 3+ days\n this.shouldShowDateFilter = daySpan >= 3;\n }\n\n /**\n * Scrolls the message list to the bottom\n */\n private scrollToBottom(): void {\n if (this.scrollContainer && this.scrollContainer.nativeElement) {\n Promise.resolve().then(() => {\n const element = this.scrollContainer.nativeElement;\n element.scrollTop = element.scrollHeight;\n });\n }\n }\n\n /**\n * Removes a message from the rendered list\n * Called externally when a message is deleted\n */\n public removeMessage(message: MJConversationDetailEntity): void {\n const key = this.getMessageKey(message);\n const entry = this._renderedMessages.get(key);\n if (entry) {\n entry.ref.destroy();\n this._renderedMessages.delete(key);\n }\n }\n}","<div class=\"message-list-container\" #scrollContainer>\n <!-- Sticky Date Header (only show for long conversations spanning multiple days) -->\n @if (showDateNavigation && shouldShowDateFilter && messages.length > 0) {\n <div class=\"sticky-date-header\">\n <div class=\"sticky-date-wrapper\">\n <button class=\"sticky-date-button\" (click)=\"toggleDateNav()\">\n <span>{{ currentDateDisplay }}</span>\n <i class=\"fas fa-chevron-down\"></i>\n </button>\n <div class=\"date-nav-dropdown\" [class.show]=\"showDateNav\">\n <div class=\"date-nav-option jump-to\">Jump to...</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('today')\">Today</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('yesterday')\">Yesterday</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('last-week')\">Last week</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('last-month')\">Last month</div>\n </div>\n </div>\n </div>\n }\n\n <ng-container #messageContainer></ng-container>\n\n @if (messages.length === 0 && showEmptyFill) {\n <mj-empty-state\n class=\"messages-empty-fill\"\n Icon=\"fa-solid fa-comments\"\n Title=\"No messages yet. Start a conversation!\" />\n }\n</div>"]}
|
|
1
|
+
{"version":3,"file":"message-list.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/message-list.component.ts","../../../../src/lib/components/message/message-list.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n HostBinding,\n EventEmitter,\n ViewChild,\n ViewContainerRef,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ElementRef,\n AfterViewInit,\n AfterViewChecked,\n ComponentRef,\n EmbeddedViewRef,\n TemplateRef\n} from '@angular/core';\nimport { MJConversationDetailEntity, MJConversationEntity, RatingJSON } from '@memberjunction/core-entities';\nimport { UserInfo, CompositeKey } from '@memberjunction/core';\nimport { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MessageItemComponent, MessageAttachment } from './message-item.component';\nimport {\n BeforeResponseFormSubmittedEventArgs,\n AfterResponseFormSubmittedEventArgs,\n} from '../../events/chat-events';\nimport { RealtimeSessionTimelineCardComponent } from '../realtime/realtime-session-timeline-card.component';\nimport { LazyArtifactInfo } from '../../models/lazy-artifact-info';\nimport { selectDistinctLatestArtifacts } from '../../utils/distinct-artifacts';\nimport {\n BuildConversationTimeline,\n ConversationTimelineItem,\n RealtimeSessionTimelineGroup,\n RealtimeSessionTimelineMeta\n} from '../../utils/realtime-session-timeline';\nimport { MJAIAgentRunEntityExtended } from '@memberjunction/ai-core-plus';\nimport { DEFAULT_TRANSCRIPT_PAGE_SIZE } from '../../utils/conversation-detail-window';\nimport {\n ResolveDateJumpTarget,\n type DateJumpPeriod,\n type DateJumpOutcome\n} from '../../utils/date-jump';\n\n/** Context handed to the `messageRenderer` slot template per message. */\ninterface MessageRendererContext {\n $implicit: MJConversationDetailEntity;\n message: MJConversationDetailEntity;\n}\n\n/**\n * One per rendered message in the list. Three paths can produce an entry:\n * - `component` — the default `MessageItemComponent` (single message).\n * - `embedded` — an `EmbeddedViewRef` from the consumer's\n * `messageRenderer` slot template (full per-message\n * replacement, PR 2c slot system).\n * - `realtime-session` — a `RealtimeSessionTimelineCardComponent` collapsing\n * an entire past realtime session into one timeline\n * card (PR #2787 co-agent timeline). The grouping pass\n * (`BuildConversationTimeline`) emits these alongside\n * normal messages — see the timeline utility for the\n * rules.\n *\n * Discriminated by the `kind` tag for ergonomic narrowing.\n */\ntype RenderedMessageEntry =\n | { kind: 'component'; ref: ComponentRef<MessageItemComponent> }\n | { kind: 'embedded'; ref: EmbeddedViewRef<MessageRendererContext> }\n | { kind: 'realtime-session'; ref: ComponentRef<RealtimeSessionTimelineCardComponent> }\n /**\n * A timeline item that has been UNMOUNTED to keep the DOM bounded — replaced by a\n * fixed-height div so the scroll range is unchanged. Stored under the item's own\n * timeline key so it can be swapped back for the real view on scroll-back.\n */\n | { kind: 'spacer'; ref: EmbeddedViewRef<SpacerContext> };\n\n/** Context for the spacer template — the height the unmounted item occupied. */\ninterface SpacerContext {\n height: number;\n}\n\n/**\n * Container component for displaying a list of messages\n * Uses dynamic component creation (like skip-chat) to avoid Angular binding overhead\n * This dramatically improves performance when messages are added/removed\n */\n/** Dropdown label per period. Kept beside the guard so a new period cannot render blank. */\nconst DATE_JUMP_LABELS: Record<DateJumpPeriod, string> = {\n 'today': 'Today',\n 'yesterday': 'Yesterday',\n 'last-week': 'Last week',\n 'last-month': 'Last month'\n};\n\n/** Narrows the template's string to the period union — the template cannot type its own literals. */\nfunction isDateJumpPeriod(value: string): value is DateJumpPeriod {\n return Object.prototype.hasOwnProperty.call(DATE_JUMP_LABELS, value);\n}\n\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-list',\n templateUrl: './message-list.component.html',\n styleUrls: ['./message-list.component.css']\n})\nexport class MessageListComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, AfterViewChecked {\n @Input() public messages: MJConversationDetailEntity[] = [];\n @Input() public conversation!: MJConversationEntity | null;\n @Input() public currentUser!: UserInfo;\n @Input() public isProcessing: boolean = false;\n /** Whether the built-in \"No messages yet\" filler renders for empty conversations. Hosts with their own empty-state chrome set false. */\n @Input() public showEmptyFill: boolean = true;\n /** Whether the sticky date header + jump-to-date dropdown render. */\n @Input() public showDateNavigation: boolean = true;\n // Per-message feature gates — forwarded onto each MessageItemComponent instance\n // (see applyMessageItemFeatureFlags). All default true.\n @Input() public showAgentRunDetails: boolean = true;\n @Input() public showReactions: boolean = true;\n @Input() public showMessageRating: boolean = true;\n @Input() public allowPinning: boolean = true;\n @Input() public allowMessageEdit: boolean = true;\n @Input() public allowMessageDelete: boolean = true;\n\n // ── Windowed-transcript paging state ────────────────────────────────────────\n // The list renders only the LOADED window, not the whole conversation. These two\n // describe what lies above it. Unused until the Phase 5 sentinel lands; wired now so\n // the host binding is in place and the component's contract is stable.\n\n /**\n * True when older pages remain above the loaded window.\n *\n * Setter rather than a plain input: flipping this creates or destroys the sentinel via\n * `@if`, and the observer has to be re-pointed at the new element. Relying on an ambient\n * `ngAfterViewChecked` tick to notice is fragile — once the list settles there may not be\n * another one.\n */\n @Input()\n public set HasMoreAbove(value: boolean) {\n if (value === this._hasMoreAbove) {\n return;\n }\n this._hasMoreAbove = value;\n // Gates the date navigator too — see updateDateFilterVisibility. Without this the button\n // would only re-evaluate on a `messages` change, so exhausting history would leave it up.\n this.updateDateFilterVisibility();\n // Deferred: the `@if` has not rendered the sentinel yet at set time.\n Promise.resolve().then(() => this.syncOlderObserver());\n }\n public get HasMoreAbove(): boolean {\n return this._hasMoreAbove;\n }\n private _hasMoreAbove = false;\n\n /** True while an older page is in flight. */\n @Input() public IsLoadingOlder: boolean = false;\n\n /**\n * The host's scrolling element, used as the sentinel observer's root.\n *\n * This component's own container does NOT scroll — hosts wrap it in their own scroller\n * (in the chat area, `.chat-messages-container`, which carries the `min-height: 0` a flex\n * child needs). Passing it in is deterministic; discovering it by walking the DOM depends\n * on layout having settled, which is not knowable from in here.\n *\n * Optional: when omitted the component falls back to walking its ancestors.\n */\n @Input()\n public set ScrollRoot(value: HTMLElement | null | undefined) {\n const next = value ?? null;\n if (next === this._scrollRoot) {\n return;\n }\n this._scrollRoot = next;\n this._scrollParent = next;\n // The root changed, so any live observer is pointed at the wrong element.\n Promise.resolve().then(() => this.syncOlderObserver());\n }\n public get ScrollRoot(): HTMLElement | null {\n return this._scrollRoot;\n }\n private _scrollRoot: HTMLElement | null = null;\n\n /**\n * Marks the host as \"someone else owns the scrolling\", which drops `overflow-y` on this\n * component's own container.\n *\n * `position: sticky` pins to the nearest ancestor with `overflow-y: auto|scroll`. When a\n * host supplies a scroller, this component's container still declared `overflow-y: auto`\n * but never actually scrolled (its content grows to fit), so the sticky date header bound\n * to a container whose `scrollTop` is permanently 0 — it rendered, then rode out of view\n * with the messages and could not be clicked.\n *\n * Driven off `_scrollRoot` rather than `resolveScrollParent()` on purpose: the DOM walk is\n * lazy and layout-dependent, and dropping `overflow-y` for a consumer that turned out to\n * have NO scrolling ancestor would leave the transcript unable to scroll or page at all.\n * The explicit input is the only signal that is safe here — a host that passes it has, by\n * definition, a scroller of its own.\n */\n @HostBinding('class.mj-list-host-scrolled')\n public get HostSuppliesScroller(): boolean {\n return this._scrollRoot !== null;\n }\n\n // ── Assistant identity overrides — static host config forwarded to every message\n // item (null = engine identity). Setters (not ngOnChanges) so an imperative\n // host — `@ViewChild(MessageListComponent).assistantDisplayName = …` — restamps\n // too, and so identity changes don't pay a check on every other input's cycle.\n // Identity can land AFTER first render (branding resolves async) or change\n // mid-session (per-conversation persona), and message items are created\n // dynamically with the overrides stamped as static config — so a change has to\n // restamp the ALREADY-rendered items or existing bubbles keep the old identity\n // until the next messages-array mutation. ──\n /** Display name shown on AI messages. Null = the engine-resolved agent name. */\n @Input()\n public set assistantDisplayName(value: string | null) {\n if (value !== this._assistantDisplayName) {\n this._assistantDisplayName = value;\n this.restampAssistantIdentity();\n }\n }\n public get assistantDisplayName(): string | null {\n return this._assistantDisplayName;\n }\n private _assistantDisplayName: string | null = null;\n\n /** Image URL for the AI message avatar. Null = the agent's Font Awesome icon. */\n @Input()\n public set assistantAvatarUrl(value: string | null) {\n if (value !== this._assistantAvatarUrl) {\n this._assistantAvatarUrl = value;\n this.restampAssistantIdentity();\n }\n }\n public get assistantAvatarUrl(): string | null {\n return this._assistantAvatarUrl;\n }\n private _assistantAvatarUrl: string | null = null;\n @Input() public artifactMap: Map<string, LazyArtifactInfo[]> = new Map();\n @Input() public agentRunMap: Map<string, MJAIAgentRunEntityExtended> = new Map();\n @Input() public ratingsMap: Map<string, RatingJSON[]> = new Map();\n @Input() public userAvatarMap: Map<string, {imageUrl: string | null; iconClass: string | null}> = new Map();\n @Input() public attachmentsMap: Map<string, MessageAttachment[]> = new Map();\n /**\n * Optional session-row enrichment for realtime SESSION BLOCKS, keyed by\n * `NormalizeUUID(sessionId)` (agent name / status / close reason). Details stamped\n * with an `AgentSessionID` collapse into one timeline card per session — see\n * `BuildConversationTimeline` — and this map dresses those cards up when present.\n */\n @Input() public sessionMetaMap: Map<string, RealtimeSessionTimelineMeta> = new Map();\n\n /**\n * Optional per-iteration custom message renderer. When set, the list renders each\n * message via this template (full replacement) instead of the default\n * `MessageItemComponent`. Forwarded by chat-area when a consumer projects\n * `mjChatSlot=\"messageRenderer\"`. The template receives the message as\n * `$implicit` and as a named `message` context binding.\n *\n * Consumers opting into a custom renderer take full responsibility for displaying\n * the message — edit/delete/retry affordances, artifacts, ratings, attachments,\n * etc. The minimal `MJChatMessageBubbleDefaultComponent` ships as a ready-to-use\n * bubble renderer.\n */\n @Input() public messageRendererTemplate: TemplateRef<unknown> | null = null;\n\n /**\n * Optional per-message additive decoration template, projected INSIDE the default\n * `MessageItemComponent` (after the message text). Forwarded by chat-area when a\n * consumer projects `mjChatSlot=\"messageExtra\"`. Ignored when\n * `messageRendererTemplate` is set (custom renderers own all per-message content).\n */\n @Input() public messageExtraTemplate: TemplateRef<unknown> | null = null;\n\n @Output() public editMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public deleteMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public retryMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public testFeedbackMessage = new EventEmitter<MJConversationDetailEntity>();\n @Output() public artifactClicked = new EventEmitter<{artifactId: string; versionId?: string}>();\n @Output() public replyInThread = new EventEmitter<MJConversationDetailEntity>();\n @Output() public viewThread = new EventEmitter<MJConversationDetailEntity>();\n @Output() public messageEdited = new EventEmitter<MJConversationDetailEntity>();\n @Output() public openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n @Output() public suggestedResponseSelected = new EventEmitter<{text: string; customInput?: string}>();\n @Output() public attachmentClicked = new EventEmitter<MessageAttachment>();\n @Output() public diagnosticRequested = new EventEmitter<string>(); // emits messageId\n @Output() public messagePinToggled = new EventEmitter<MJConversationDetailEntity>();\n /** Emitted with the `MJ: AI Agent Sessions.ID` when a realtime session block's Open affordance is clicked. */\n @Output() public realtimeSessionOpenRequested = new EventEmitter<string>();\n\n /** Forwarded from MessageItemComponent — see its docs. */\n @Output() public beforeResponseFormSubmitted = new EventEmitter<BeforeResponseFormSubmittedEventArgs>();\n /** Forwarded from MessageItemComponent — see its docs. */\n @Output() public afterResponseFormSubmitted = new EventEmitter<AfterResponseFormSubmittedEventArgs>();\n\n /**\n * Asks the host to load the next older page. Fired when the \"earlier messages\"\n * sentinel scrolls into view — never on a raw scroll event, so a fast scroll costs\n * one emit rather than one per pixel.\n */\n @Output() public OlderRequested = new EventEmitter<void>();\n\n /**\n * Asks the host to page older history far enough back to satisfy a date jump, then scroll.\n * Emitted instead of handled locally because paging belongs to the window store.\n */\n @Output() public DateJumpRequested = new EventEmitter<DateJumpPeriod>();\n\n @ViewChild('messageContainer', { read: ViewContainerRef }) messageContainerRef!: ViewContainerRef;\n @ViewChild('scrollContainer') scrollContainer!: ElementRef;\n /** Only present while `HasMoreAbove` is true — the `@if` creates and destroys it. */\n @ViewChild('olderSentinel') olderSentinel?: ElementRef<HTMLElement>;\n /** Template rendered in place of an unmounted timeline item. */\n @ViewChild('spacerTemplate') private spacerTemplate?: TemplateRef<SpacerContext>;\n\n /**\n * Per-message rendered entries — see `RenderedMessageEntry` for the 3-way\n * union (default MessageItemComponent / consumer messageRenderer slot\n * embedded view / collapsed realtime session timeline card).\n */\n private _renderedMessages = new Map<string, RenderedMessageEntry>();\n private _shouldScrollToBottom = false;\n private _previousMessageCount = 0; // Track previous count to detect new messages\n\n /** Watches the \"earlier messages\" sentinel. Rebuilt whenever the sentinel comes or goes. */\n private _olderObserver?: IntersectionObserver;\n /**\n * Set when the newest render PREPENDED older content, so `ngAfterViewChecked` can hold\n * the user's reading position instead of letting the browser's pixel-based `scrollTop`\n * slide them to unfamiliar content.\n */\n private _restoreScrollAfterPrepend = false;\n /** `scrollHeight` captured immediately before a prepend render. */\n private _heightBeforePrepend = 0;\n /** Memoized result of {@link resolveScrollParent} — the host's scroller, not ours. */\n private _scrollParent: HTMLElement | null = null;\n /** What the live observer is currently watching, so a stale pairing can be detected. */\n private _observedSentinel: HTMLElement | null = null;\n private _observedRoot: HTMLElement | null = null;\n /** Guards the no-scroll-parent warning so it fires once, not every checked cycle. */\n private _warnedNoScrollParent = false;\n /** Guards the missing-spacer-template warning the same way. */\n private _warnedNoSpacerTemplate = false;\n\n // ── DOM unmount (bounded transcript) ────────────────────────────────────────\n // Paging up 20 times would otherwise leave 200 live MessageItemComponents mounted.\n // Items far from the viewport are destroyed and replaced by a height-holding spacer,\n // then remounted from `messages` (already in memory — no network) on scroll-back.\n\n /** Rendered pixel height per timeline key, captured just before an item is unmounted. */\n private _measuredHeights = new Map<string, number>();\n /** Watches spacers so an item remounts as the user scrolls back toward it. */\n private _spacerObserver?: IntersectionObserver;\n /** Which spacers the live observer is watching, so it is only rebuilt when the set changes. */\n private _observedSpacerKeys = '';\n /** Scroller the window listener is attached to, and its coalescing frame handle. */\n private _scrollListenerTarget: HTMLElement | null = null;\n private _onScroll: (() => void) | null = null;\n private _scrollFrame: number | null = null;\n\n /** Items kept mounted beyond the visible page, above and below. */\n private static readonly MOUNT_BUFFER = 5;\n /**\n * Height used for an item unmounted before it was ever measured. Only a first-render\n * fallback — a real measurement replaces it and is preferred forever after.\n */\n private static readonly ESTIMATED_MESSAGE_HEIGHT = 72;\n private static readonly ESTIMATED_SESSION_HEIGHT = 88;\n /** Frames spent waiting for a scroller to appear, and the pending rAF handle. */\n private _scrollParentRetries = 0;\n private _scrollParentRetryHandle: number | null = null;\n /** ~1s at 60fps — long enough for layout to settle, short enough to report a real fault. */\n private static readonly MAX_SCROLL_PARENT_RETRIES = 60;\n /**\n * Render key of the FIRST timeline item last time we rendered. A change here means older\n * content arrived at the head — the only reliable way to tell a prepend from an append,\n * since both grow `messages.length`.\n */\n private _previousFirstKey: string | null = null;\n\n public currentDateDisplay: string = 'Today';\n public showDateNav: boolean = false;\n public shouldShowDateFilter: boolean = false;\n\n constructor(private cdRef: ChangeDetectorRef, private hostRef: ElementRef<HTMLElement>) {\n super();\n }\n\n public toggleDateNav(): void {\n this.showDateNav = !this.showDateNav;\n }\n\n /**\n * Handles a date-navigator selection.\n *\n * The list cannot page history itself — it is a Generic widget with no store — so it asks\n * the host, which owns the window and runs the older-page loop, then calls back into\n * {@link ScrollToDateTarget}. The label updates immediately so the dropdown feels responsive\n * while paging runs.\n */\n public jumpToDate(period: string): void {\n this.showDateNav = false;\n if (!isDateJumpPeriod(period)) {\n return;\n }\n this.currentDateDisplay = DATE_JUMP_LABELS[period];\n this.DateJumpRequested.emit(period);\n }\n\n /**\n * Scrolls to the start of `period` within the currently loaded messages.\n *\n * Called by the host AFTER it has paged as far back as it intends to, so whatever is loaded\n * now is the best answer available. Returns the outcome rather than failing silently — the\n * plan's explicit requirement for this path.\n */\n public ScrollToDateTarget(period: DateJumpPeriod): DateJumpOutcome {\n if (!this.messages || this.messages.length === 0) {\n return 'empty';\n }\n\n const { Detail } = ResolveDateJumpTarget(this.messages, period, new Date());\n // A miss lands the user on the oldest loaded message — where paging left them — rather\n // than leaving the viewport wherever it happened to be.\n const target = Detail ?? this.messages[0];\n const scrolled = this.scrollToDetail(target);\n if (!scrolled) {\n return 'empty';\n }\n return Detail ? 'reached' : 'oldest';\n }\n\n /**\n * Scrolls a loaded detail into view, mounted or not.\n *\n * Resolves through the TIMELINE KEY rather than querying `[data-message-id]`, because the\n * jump target is by definition far above the viewport — exactly the region this component\n * unmounts and replaces with height-holding spacers. A DOM query for the message id misses\n * every unmounted target, which made a legitimate jump report \"nothing loaded to jump to\".\n *\n * Spacers carry the same timeline key as the item they stand in for, so scrolling to the\n * key lands on the right place either way; the spacer observer then remounts the real item\n * as it enters the viewport.\n */\n private scrollToDetail(detail: MJConversationDetailEntity): boolean {\n return this.scrollToTimelineEntry(detail.ID, detail.AgentSessionID, 'start');\n }\n\n /**\n * Scrolls a LOADED message into view by id, mounted or not, and returns whether it landed.\n *\n * Public because the pins panel's \"Jump to message\" lives on the host: a pin can be far\n * above the viewport, which is exactly the region this component unmounts into spacers, so\n * the host's own `[data-message-id]` query found nothing and the button silently did\n * nothing. Resolution goes through the timeline key instead — see\n * {@link scrollToTimelineEntry}.\n *\n * Returns false when the message is not in the loaded window at all; the host decides\n * whether to page back for it or tell the user.\n */\n public ScrollToMessage(messageId: string): boolean {\n const detail = this.messages?.find(m => UUIDsEqual(m.ID, messageId));\n if (!detail) {\n return false;\n }\n return this.scrollToTimelineEntry(detail.ID, detail.AgentSessionID, 'center');\n }\n\n /**\n * Shared resolution for both jump paths: timeline key -> rendered node.\n *\n * Two things a `[data-message-id]` query cannot do, and both matter here:\n * - A session-stamped row folds into its session CARD, so the row itself never has a\n * node of its own; the card is what is on screen.\n * - An item far from the viewport is unmounted and replaced by a height-holding spacer,\n * which carries the SAME timeline key — so scrolling to the key lands in the right\n * place either way, and the spacer observer remounts the real item on arrival.\n */\n private scrollToTimelineEntry(\n detailId: string,\n agentSessionId: string | null,\n block: ScrollLogicalPosition\n ): boolean {\n const stampedSessionId = agentSessionId?.trim() || null;\n const timeline = BuildConversationTimeline(this.messages);\n const item = timeline.find(entry =>\n entry.Kind === 'session'\n ? stampedSessionId !== null && UUIDsEqual(entry.Group.SessionID, stampedSessionId)\n : UUIDsEqual(entry.Detail.ID, detailId)\n );\n if (!item) {\n return false;\n }\n\n const node = this.nodeForKey(this.getTimelineKey(item));\n if (!node) {\n return false;\n }\n node.scrollIntoView({ behavior: 'smooth', block });\n return true;\n }\n\n // Track whether initial render has happened\n private _initialRenderComplete = false;\n\n ngOnInit() {\n // Initial render will happen in ngAfterViewInit when ViewContainerRef is available\n }\n\n ngAfterViewInit() {\n // ViewContainerRef is now available - perform initial render if we have messages\n if (this.messages && this.messages.length > 0 && this.messageContainerRef && !this._initialRenderComplete) {\n this._initialRenderComplete = true;\n this.updateMessages(this.messages);\n this.updateDateFilterVisibility();\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n // React to messages array changes\n // Note: On initial load, messageContainerRef may not be available yet (ngOnChanges runs before ngAfterViewInit)\n // In that case, ngAfterViewInit will handle the initial render\n if (changes['messages'] && this.messages && this.messageContainerRef) {\n this._initialRenderComplete = true;\n // Capture the pre-render height so a prepend can be corrected for. Must happen\n // BEFORE updateMessages — afterwards the new rows are already in the layout — and\n // must read the HOST's scroller, which is the element whose height actually changes.\n this._heightBeforePrepend = this.resolveScrollParent()?.scrollHeight ?? 0;\n this.updateMessages(this.messages);\n this.updateDateFilterVisibility();\n }\n\n // Watch for artifactMap changes to handle newly created artifacts\n // While artifacts are pre-loaded during initial peripheral data load,\n // new artifacts can be created mid-conversation (e.g., by agent runs)\n // This ensures artifact cards appear in messages immediately without requiring a refresh\n if (changes['artifactMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n // Watch for attachmentsMap changes to handle newly created attachments\n // This ensures media attachments (e.g., images generated by agents) appear\n // immediately without requiring a page refresh\n if (changes['attachmentsMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n // Watch for session-meta changes so realtime session blocks pick up their\n // agent name / status chip once the (async, batched) session lookup lands\n if (changes['sessionMetaMap'] && this.messages && this.messageContainerRef) {\n this.updateMessages(this.messages);\n }\n\n }\n\n /**\n * Re-stamp the assistant-identity overrides onto every already-rendered message\n * item. Called from the identity setters (see the inputs above) — items are created\n * dynamically with these values stamped as static config, so without this a change\n * that arrives after first render wouldn't reach existing bubbles.\n *\n * No-op before the first render (the map is empty), so it's safe to fire during\n * Angular's initial input binding.\n */\n private restampAssistantIdentity(): void {\n for (const entry of this._renderedMessages.values()) {\n if (entry.kind === 'component') {\n this.applyMessageItemFeatureFlags(entry.ref.instance);\n entry.ref.changeDetectorRef.markForCheck();\n }\n }\n }\n\n ngAfterViewChecked() {\n // Mutually exclusive on purpose: scrolling to the bottom would undo a prepend restore.\n if (this._restoreScrollAfterPrepend) {\n this.restoreScrollAfterPrepend();\n this._restoreScrollAfterPrepend = false;\n } else if (this._shouldScrollToBottom) {\n this.scrollToBottom();\n this._shouldScrollToBottom = false;\n }\n // Measure while things are on screen, so an item has a real height recorded before it\n // ever needs a spacer — the plan's \"measure offsetHeight the first time an item is\n // mounted and remember it by key\".\n this.measureMountedItems();\n this.syncScrollListener();\n this.syncOlderObserver();\n this.syncSpacerObserver();\n }\n\n /** The rendered sentinel, read from the DOM so it does not depend on view-query timing. */\n private findSentinelElement(): HTMLElement | null {\n return this.hostRef.nativeElement.querySelector('.transcript-older-sentinel');\n }\n\n /**\n * Whether this instance is actually on screen.\n *\n * `offsetParent` is null for any element in a `display: none` subtree — which is how the\n * chat area parks the message lists of conversations you are not currently looking at.\n */\n private isHostVisible(): boolean {\n const host = this.hostRef.nativeElement;\n return host.offsetParent !== null || getComputedStyle(host).position === 'fixed';\n }\n\n /**\n * Retries {@link syncOlderObserver} on animation frames until a scroller appears.\n *\n * Bounded: after {@link MAX_SCROLL_PARENT_RETRIES} frames it gives up and logs the DOM\n * chain it walked, so a genuine host-layout problem names itself instead of presenting\n * as \"paging silently doesn't work\".\n */\n private scheduleScrollParentRetry(): void {\n if (this._scrollParentRetryHandle !== null) {\n return; // one retry loop at a time\n }\n // A HIDDEN instance can never resolve a scroller: the chat area keeps one message list\n // alive per visited conversation in a DOM cache, and a display:none subtree reports\n // every height as 0, so `scrollHeight > clientHeight` is false all the way up. Keep\n // waiting (it may be shown later) but never burn the retry budget or warn — that noise\n // would point at the wrong instance entirely.\n if (!this.isHostVisible()) {\n this._scrollParentRetryHandle = requestAnimationFrame(() => {\n this._scrollParentRetryHandle = null;\n this.syncOlderObserver();\n });\n return;\n }\n if (this._scrollParentRetries >= MessageListComponent.MAX_SCROLL_PARENT_RETRIES) {\n this.warnNoScrollParentOnce();\n return;\n }\n this._scrollParentRetries++;\n this._scrollParentRetryHandle = requestAnimationFrame(() => {\n this._scrollParentRetryHandle = null;\n this.syncOlderObserver();\n });\n }\n\n /** One-time diagnostic dump of the ancestor chain, so the failure is self-explaining. */\n private warnNoScrollParentOnce(): void {\n if (this._warnedNoScrollParent) {\n return;\n }\n this._warnedNoScrollParent = true;\n\n const chain: Array<Record<string, unknown>> = [];\n let el: HTMLElement | null =\n this.findSentinelElement() ?? this.scrollContainer?.nativeElement ?? null;\n while (el && chain.length < 20) {\n const style = getComputedStyle(el);\n chain.push({\n el: el.className || el.tagName,\n overflowY: style.overflowY,\n scrollHeight: el.scrollHeight,\n clientHeight: el.clientHeight\n });\n el = el.parentElement;\n }\n\n console.warn(\n '[MessageList] \"Earlier messages\" is showing but no scrolling ancestor was found, so '\n + 'older pages cannot auto-load. The host must give the transcript a scrollable container '\n + '(overflow-y: auto AND a bounded height, e.g. min-height: 0 on a flex child). '\n + 'Walked from '\n + (this.olderSentinel ? 'the sentinel' : this.scrollContainer ? 'the list container' : 'NOTHING — both view children are undefined')\n + ':',\n chain\n );\n }\n\n /**\n * The element that ACTUALLY scrolls the transcript.\n *\n * This component's own `.message-list-container` does not scroll: the chat area wraps it\n * in `.chat-messages-container`, and that outer div is the one carrying `min-height: 0`\n * alongside `overflow-y: auto` — the pair a flex child needs before it will scroll instead\n * of growing to fit its content. Targeting the inner div means writing `scrollTop` on an\n * element whose `scrollHeight === clientHeight`, which silently does nothing, and giving\n * an IntersectionObserver a root that never scrolls.\n *\n * Walking up keeps this component agnostic about the host's markup — any consumer that\n * wraps it in its own scroller works the same way.\n */\n private resolveScrollParent(): HTMLElement | null {\n // Host-supplied root wins — no discovery, no timing dependency.\n if (this._scrollRoot?.isConnected) {\n return this._scrollRoot;\n }\n if (this._scrollParent && this._scrollParent.isConnected) {\n return this._scrollParent;\n }\n // Start from the sentinel when it exists: it is the element being observed, so it is\n // guaranteed present exactly when the walk matters. `@ViewChild('scrollContainer')`\n // resolves on Angular's own schedule and can still be undefined here, which would end\n // the walk before it began.\n let el: HTMLElement | null =\n this.findSentinelElement() ?? this.scrollContainer?.nativeElement ?? null;\n while (el) {\n const overflowY = getComputedStyle(el).overflowY;\n if ((overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight) {\n this._scrollParent = el;\n return el;\n }\n el = el.parentElement;\n }\n return null; // nothing overflows yet — short conversation, nothing to scroll\n }\n\n /**\n * Holds the user's reading position after older content is spliced in above.\n *\n * `scrollTop` is a pixel offset from the top, so inserting content above silently shifts\n * everything down — the user ends up looking at messages they never scrolled to. Adding\n * the height delta puts the same message back under their eyes.\n */\n private restoreScrollAfterPrepend(): void {\n const el = this.resolveScrollParent();\n if (!el) {\n return;\n }\n const delta = el.scrollHeight - this._heightBeforePrepend;\n if (delta > 0) {\n el.scrollTop = el.scrollTop + delta;\n }\n }\n\n /**\n * True when the environment provides `IntersectionObserver`.\n *\n * False under SSR and in the unit-test projects. Both observer syncs are reached a\n * microtask late (see the `HasMoreAbove` setter), so a spec that stubs the global and\n * restores it synchronously has already restored it by the time the sync runs — the\n * constructor call then throws inside a `.then()` with no catch, which surfaces as an\n * unhandled rejection rather than a test failure and fails the run despite every\n * assertion passing.\n */\n private get canObserve(): boolean {\n return typeof IntersectionObserver !== 'undefined';\n }\n\n /**\n * Keeps the IntersectionObserver attached to the current sentinel element.\n *\n * The sentinel lives inside `@if (HasMoreAbove)`, so it is created and destroyed as the\n * user reaches the top of the loaded window and as older pages arrive. Runs every checked\n * cycle and is a no-op once attached.\n *\n * Observer-on-sentinel rather than a scroll listener: a fast scroll costs one callback,\n * not one per frame.\n */\n private syncOlderObserver(): void {\n if (!this.canObserve) {\n return;\n }\n if (!this.HasMoreAbove) {\n this._olderObserver?.disconnect();\n this._olderObserver = undefined;\n this._observedSentinel = null;\n this._observedRoot = null;\n return;\n }\n\n // Query the DOM rather than reading `@ViewChild('olderSentinel')`.\n //\n // The sentinel lives inside `@if`, so the view query resolves on Angular's own\n // schedule — and `updateMessages` detaches/reattaches this component's change detector\n // around every render, which makes that schedule hard to reason about. Reading the host\n // element directly is timing-independent: if the div is on the page, we find it.\n const el = this.findSentinelElement();\n if (!el) {\n this.scheduleScrollParentRetry(); // not rendered yet — look again next frame\n return;\n }\n\n // The scroll parent is not resolvable until something actually overflows, which is not\n // true on the first checked cycle. Bailing (rather than observing with a null root)\n // matters: a viewport-rooted observer never sees a sentinel clipped inside a scrolled\n // container, so it would silently never fire.\n const root = this.resolveScrollParent();\n if (!root) {\n // A scroller only becomes findable once its content overflows, which is not true on\n // the tick the sentinel first renders. Retry on animation frames rather than waiting\n // for another change-detection pass — once the list settles there may not be one.\n this.scheduleScrollParentRetry();\n return;\n }\n this._scrollParentRetries = 0;\n\n // Rebuild whenever EITHER end of the relationship changes — `@if` swaps the sentinel\n // element as HasMoreAbove toggles, and the root only becomes known once content\n // overflows. Observing a stale element or a stale root is silent, not loud.\n if (this._olderObserver && this._observedSentinel === el && this._observedRoot === root) {\n return;\n }\n this._olderObserver?.disconnect();\n\n this._olderObserver = new IntersectionObserver(\n entries => {\n // Re-check the flags at fire time: the observer can fire while a load is already\n // running, and LoadOlder's own guard shouldn't be the only thing standing between\n // a fast scroll and a burst of duplicate requests.\n if (entries.some(e => e.isIntersecting) && this.HasMoreAbove && !this.IsLoadingOlder) {\n this.OlderRequested.emit();\n }\n },\n // Root must be the REAL scroller, not this component's own container — an observer\n // rooted on a non-scrolling ancestor reports the sentinel as permanently visible.\n { root, threshold: 0.01 }\n );\n this._olderObserver.observe(el);\n this._observedSentinel = el;\n this._observedRoot = root;\n }\n\n ngOnDestroy() {\n this._olderObserver?.disconnect();\n this._olderObserver = undefined;\n this._spacerObserver?.disconnect();\n this._spacerObserver = undefined;\n if (this._scrollParentRetryHandle !== null) {\n cancelAnimationFrame(this._scrollParentRetryHandle);\n this._scrollParentRetryHandle = null;\n }\n\n // Clean up all dynamically created components AND embedded views (both have destroy()).\n this._renderedMessages.forEach((entry) => {\n if (entry) {\n entry.ref.destroy();\n }\n });\n this._renderedMessages.clear();\n\n if (this.messageContainerRef) {\n this.messageContainerRef.clear();\n }\n }\n\n /**\n * Called when messages array changes\n * Efficiently updates the DOM without re-rendering everything\n */\n @Input()\n set messagesUpdate(messages: MJConversationDetailEntity[]) {\n if (messages && this.messageContainerRef) {\n this.updateMessages(messages);\n }\n }\n\n /**\n * Updates the message list using dynamic component creation\n * Only adds/removes changed messages for optimal performance\n *\n * REALTIME SESSIONS: details stamped with an `AgentSessionID` (turns persisted during\n * a live realtime session) do NOT render as normal chat bubbles. The timeline pass\n * (`BuildConversationTimeline`) collapses each session's stamped rows into ONE session\n * block, rendered as a `RealtimeSessionTimelineCardComponent` at the session's\n * chronological position. Everything else renders exactly as before.\n */\n private updateMessages(messages: MJConversationDetailEntity[]): void {\n // Temporarily detach change detection for performance\n this.cdRef.detach();\n\n try {\n // Build the timeline first — collapses contiguous realtime-session rows\n // into ONE session block per session, leaving normal messages in place.\n // See `BuildConversationTimeline` in `utils/realtime-session-timeline`.\n const timeline = BuildConversationTimeline(messages);\n\n // Remove rendered items (messages AND session blocks) that no longer exist\n const currentKeys = new Set(timeline.map(item => this.getTimelineKey(item)));\n this._renderedMessages.forEach((entry, key) => {\n if (!currentKeys.has(key)) {\n entry.ref.destroy();\n this._renderedMessages.delete(key);\n }\n });\n\n // Add or update timeline items in chronological order. `renderMessageItem`\n // internally branches on the slot template (messageRenderer) vs the\n // default MessageItemComponent; `renderSessionBlock` always creates a\n // RealtimeSessionTimelineCardComponent.\n // The timeline index is passed through so newly created views land at the RIGHT\n // position. `createComponent` appends by default, which would put prepended older\n // messages at the bottom of the DOM despite being the oldest content.\n // Items far from the viewport are UNMOUNTED and replaced by a height-holding spacer,\n // so paging a long way up leaves a bounded DOM rather than hundreds of live message\n // components. The tail and any in-progress message are always kept.\n const range = this.computeMountedRange(timeline);\n const lastMessageKey = this.findLastMessageKey(timeline);\n for (let i = 0; i < timeline.length; i++) {\n const item = timeline[i];\n const mounted = (i >= range.start && i <= range.end)\n || this.mustStayMounted(item, i, timeline.length);\n\n if (!mounted) {\n this.ensureSpacer(this.getTimelineKey(item), item, i);\n } else if (item.Kind === 'session') {\n this.renderSessionBlock(item.Group, i);\n } else {\n this.renderMessageItem(item.Detail, messages, this.getMessageKey(item.Detail) === lastMessageKey, i);\n }\n }\n\n // Decide where the viewport should end up.\n //\n // A raw `length > previousCount` check cannot tell an append from a prepend — paging\n // older history also grows the array, and treating that as \"someone sent a message\"\n // would snap the user to the newest message every time they scrolled up. Compare the\n // FIRST timeline key instead: if it changed, older content arrived at the head.\n const previousCount = this._previousMessageCount;\n this._previousMessageCount = messages.length;\n\n const firstKey = timeline.length > 0 ? this.getTimelineKey(timeline[0]) : null;\n const prepended = this._previousFirstKey !== null\n && firstKey !== null\n && firstKey !== this._previousFirstKey;\n this._previousFirstKey = firstKey;\n\n if (prepended) {\n this._restoreScrollAfterPrepend = true;\n } else if (messages.length > previousCount) {\n this._shouldScrollToBottom = true;\n }\n } finally {\n // Re-attach change detection\n this.cdRef.reattach();\n this.cdRef.detectChanges();\n }\n }\n\n /**\n * The span of timeline indices that stay mounted.\n *\n * Follows the tail on first paint and whenever nothing measurable is on screen. Once items\n * are rendered, the span is centred on what the reader is actually looking at — measured\n * from scroll position, plus {@link MessageListComponent.MOUNT_BUFFER} either side — so\n * scrolling back does not collapse the window to the newest messages on the next render.\n *\n * (An earlier design pinned the top of the span with a remembered key instead. It was\n * replaced by the measurement below for the reason that comment explains, and the key no\n * longer exists.)\n */\n private computeMountedRange(\n timeline: ConversationTimelineItem<MJConversationDetailEntity>[]\n ): { start: number; end: number } {\n const lastIndex = timeline.length - 1;\n const span = DEFAULT_TRANSCRIPT_PAGE_SIZE + MessageListComponent.MOUNT_BUFFER * 2;\n const tailRange = { start: Math.max(0, timeline.length - span), end: lastIndex };\n\n const root = this.resolveScrollParent();\n if (!root || this._renderedMessages.size === 0) {\n return tailRange; // first paint — follow the tail\n }\n\n // Derived from SCROLL POSITION, which nothing in the render loop feeds back into.\n //\n // Reacting to spacer intersections instead is circular: a spacer's height is an\n // estimate, so where it sits decides what is visible, which decides which spacers fire,\n // which changes what is mounted, which changes heights. That loop is what made the\n // transcript replay the same region; constraining it to one direction only traded the\n // ping-pong for dead zones that never remounted.\n const rootTop = root.getBoundingClientRect().top;\n const viewportHeight = root.clientHeight;\n let firstVisible = -1;\n let lastVisible = -1;\n\n for (let i = 0; i < timeline.length; i++) {\n const node = this.nodeForKey(this.getTimelineKey(timeline[i]));\n if (!node) {\n continue;\n }\n const rect = node.getBoundingClientRect();\n const top = rect.top - rootTop;\n const bottom = top + rect.height;\n if (bottom > 0 && firstVisible < 0) {\n firstVisible = i;\n }\n if (top < viewportHeight) {\n lastVisible = i;\n }\n }\n if (firstVisible < 0 || lastVisible < 0) {\n return tailRange;\n }\n\n return {\n start: Math.max(0, firstVisible - MessageListComponent.MOUNT_BUFFER),\n end: Math.min(lastIndex, lastVisible + MessageListComponent.MOUNT_BUFFER)\n };\n }\n\n /** The rendered DOM node for a timeline key, whatever kind of entry backs it. */\n private nodeForKey(key: string): HTMLElement | undefined {\n const entry = this._renderedMessages.get(key);\n if (!entry) {\n return undefined;\n }\n return entry.kind === 'embedded' || entry.kind === 'spacer'\n ? (entry.ref.rootNodes[0] as HTMLElement | undefined)\n : (entry.ref.location.nativeElement as HTMLElement | undefined);\n }\n\n /**\n * Items that must never be unmounted regardless of position.\n *\n * The tail carries streaming output, `isLastMessage` affordances and suggested\n * responses; an in-progress message is mid-stream and would lose its live state.\n */\n private mustStayMounted(\n item: ConversationTimelineItem<MJConversationDetailEntity>,\n index: number,\n timelineLength: number\n ): boolean {\n if (index === timelineLength - 1) {\n return true;\n }\n return item.Kind === 'message' && item.Detail.Status === 'In-Progress';\n }\n\n /**\n * Records what an entry occupied on screen, so its spacer holds exactly that much space.\n *\n * Called immediately BEFORE destroying — afterwards the node is gone. A wrong height here\n * is the failure mode that makes scrolling jump, which is the whole thing spacers exist\n * to prevent.\n */\n private rememberHeight(key: string, entry: RenderedMessageEntry): void {\n const node = entry.kind === 'embedded' || entry.kind === 'spacer'\n ? (entry.ref.rootNodes[0] as HTMLElement | undefined)\n : (entry.ref.location.nativeElement as HTMLElement | undefined);\n const height = node?.offsetHeight ?? 0;\n if (height > 0) {\n this._measuredHeights.set(key, height);\n }\n }\n\n /** Measured height when we have one, else a kind-appropriate estimate. */\n private heightFor(key: string, item: ConversationTimelineItem<MJConversationDetailEntity>): number {\n const measured = this._measuredHeights.get(key);\n if (measured !== undefined) {\n return measured;\n }\n return item.Kind === 'session'\n ? MessageListComponent.ESTIMATED_SESSION_HEIGHT\n : MessageListComponent.ESTIMATED_MESSAGE_HEIGHT;\n }\n\n /**\n * Measures every currently-mounted item.\n *\n * Runs each checked cycle so an item has a real height recorded BEFORE it scrolls far\n * enough to be unmounted — otherwise its first spacer is always a guess.\n */\n private measureMountedItems(): void {\n this._renderedMessages.forEach((entry, key) => {\n if (entry.kind === 'spacer') {\n return;\n }\n const node = entry.kind === 'embedded'\n ? (entry.ref.rootNodes[0] as HTMLElement | undefined)\n : (entry.ref.location.nativeElement as HTMLElement | undefined);\n const height = node?.offsetHeight ?? 0;\n if (height > 0) {\n this._measuredHeights.set(key, height);\n }\n });\n }\n\n\n /**\n * Replaces a mounted item with a height-holding spacer, or leaves an existing spacer\n * alone. Stored under the item's own timeline key so {@link updateMessages}'s\n * remove-stale pass and the remount path both find it.\n */\n private ensureSpacer(\n key: string,\n item: ConversationTimelineItem<MJConversationDetailEntity>,\n timelineIndex: number\n ): void {\n const existing = this._renderedMessages.get(key);\n if (existing?.kind === 'spacer') {\n return;\n }\n if (!this.spacerTemplate) {\n // Staying mounted is the safe choice, but silently doing so means the transcript\n // grows without bound and nothing says why. Report it once.\n if (!this._warnedNoSpacerTemplate) {\n this._warnedNoSpacerTemplate = true;\n console.warn(\n '[MessageList] spacerTemplate did not resolve, so off-screen messages cannot be '\n + 'unmounted and the DOM will grow with every page loaded.'\n );\n }\n return;\n }\n if (existing) {\n this.rememberHeight(key, existing);\n existing.ref.destroy();\n this._renderedMessages.delete(key);\n }\n\n const viewRef = this.messageContainerRef.createEmbeddedView<SpacerContext>(\n this.spacerTemplate,\n { height: this.heightFor(key, item) },\n { index: timelineIndex }\n );\n this._renderedMessages.set(key, { kind: 'spacer', ref: viewRef });\n }\n\n /**\n * Re-evaluates the mounted window as the user scrolls.\n *\n * Attached once to the host's scroller. Coalesced onto an animation frame so a fast scroll\n * costs one re-render per frame rather than one per event, and skipped entirely when the\n * window has not actually moved.\n */\n private syncScrollListener(): void {\n const root = this.resolveScrollParent();\n if (!root || root === this._scrollListenerTarget) {\n return;\n }\n this.detachScrollListener();\n this._scrollListenerTarget = root;\n this._onScroll = () => {\n if (this._scrollFrame !== null) {\n return;\n }\n this._scrollFrame = requestAnimationFrame(() => {\n this._scrollFrame = null;\n if (this.messages?.length) {\n this.updateMessages(this.messages);\n }\n });\n };\n root.addEventListener('scroll', this._onScroll, { passive: true });\n }\n\n private detachScrollListener(): void {\n if (this._scrollListenerTarget && this._onScroll) {\n this._scrollListenerTarget.removeEventListener('scroll', this._onScroll);\n }\n this._scrollListenerTarget = null;\n this._onScroll = null;\n if (this._scrollFrame !== null) {\n cancelAnimationFrame(this._scrollFrame);\n this._scrollFrame = null;\n }\n }\n\n /**\n * Watches the current spacers so scrolling back toward one remounts it.\n *\n * Rebuilt on every render because spacers come and go. Remounting reads from `messages`,\n * which is already in memory — this never triggers a fetch.\n */\n private syncSpacerObserver(): void {\n if (!this.canObserve) {\n return;\n }\n const root = this.resolveScrollParent();\n if (!root) {\n this._spacerObserver?.disconnect();\n this._spacerObserver = undefined;\n this._observedSpacerKeys = '';\n return;\n }\n const spacers: Array<{ key: string; el: HTMLElement }> = [];\n this._renderedMessages.forEach((entry, key) => {\n if (entry.kind === 'spacer') {\n const el = entry.ref.rootNodes[0] as HTMLElement | undefined;\n if (el) {\n spacers.push({ key, el });\n }\n }\n });\n if (spacers.length === 0) {\n this._spacerObserver?.disconnect();\n this._spacerObserver = undefined;\n this._observedSpacerKeys = '';\n return;\n }\n\n // Rebuild ONLY when the spacer set actually changes.\n //\n // This runs every checked cycle, and a fresh IntersectionObserver delivers an initial\n // callback for everything it observes. Rebuilding unconditionally therefore re-fired\n // remountAround on every change-detection pass, which re-rendered, which triggered\n // another pass — the transcript visibly stuck, replaying the same region.\n const signature = spacers.map(s => s.key).sort().join('|');\n if (this._spacerObserver && signature === this._observedSpacerKeys) {\n return;\n }\n this._spacerObserver?.disconnect();\n this._observedSpacerKeys = signature;\n\n this._spacerObserver = new IntersectionObserver(\n entries => {\n const hit = entries.find(e => e.isIntersecting);\n if (!hit) {\n return;\n }\n // The range is computed from scroll position; a spacer coming into view just means\n // it is time to recompute. No key is threaded through, so there is no feedback loop.\n if (this.messages?.length) {\n this.updateMessages(this.messages);\n }\n },\n { root, threshold: 0.01 }\n );\n for (const s of spacers) {\n this._spacerObserver.observe(s.el);\n }\n }\n\n\n /** Stable render key for a timeline item — message ID, or a prefixed session key for session blocks. */\n private getTimelineKey(item: ConversationTimelineItem<MJConversationDetailEntity>): string {\n return item.Kind === 'session' ? this.getSessionKey(item.Group.SessionID) : this.getMessageKey(item.Detail);\n }\n\n /** Render key for a session block (case-insensitive on the session id; prefixed so it can't collide with message IDs). */\n private getSessionKey(sessionId: string): string {\n return `session:${NormalizeUUID(sessionId)}`;\n }\n\n /** The render key of the LAST normal message item in the timeline (drives `isLastMessage`), or null when none. */\n private findLastMessageKey(timeline: ConversationTimelineItem<MJConversationDetailEntity>[]): string | null {\n for (let i = timeline.length - 1; i >= 0; i--) {\n const item = timeline[i];\n if (item.Kind === 'message') {\n return this.getMessageKey(item.Detail);\n }\n }\n return null;\n }\n\n /**\n * Creates or updates the ONE timeline card a realtime session collapses to.\n * Click/Open on the card bubbles up via {@link realtimeSessionOpenRequested} so the\n * chat area can host the SESSION REVIEW overlay for it.\n */\n private renderSessionBlock(group: RealtimeSessionTimelineGroup, timelineIndex: number): void {\n const key = this.getSessionKey(group.SessionID);\n const meta = this.sessionMetaMap.get(NormalizeUUID(group.SessionID)) ?? null;\n const existing = this._renderedMessages.get(key);\n\n if (existing && existing.kind === 'realtime-session') {\n // Update existing card in place.\n const instance = existing.ref.instance;\n instance.Group = group;\n instance.Meta = meta;\n existing.ref.changeDetectorRef.markForCheck();\n return;\n }\n\n // Different kind at this key (e.g. mode changed) — drop the old entry, fall through to create.\n if (existing) {\n existing.ref.destroy();\n this._renderedMessages.delete(key);\n }\n\n const componentRef = this.messageContainerRef.createComponent(\n RealtimeSessionTimelineCardComponent,\n { index: timelineIndex }\n );\n componentRef.instance.Group = group;\n componentRef.instance.Meta = meta;\n componentRef.instance.UserName = this.currentUser?.Name || 'You';\n componentRef.instance.OpenRequested.subscribe((sessionId: string) => this.realtimeSessionOpenRequested.emit(sessionId));\n this._renderedMessages.set(key, { kind: 'realtime-session', ref: componentRef });\n }\n\n /**\n * Creates or updates one normal chat message item. Routes to the\n * consumer-projected `messageRenderer` slot template (EmbeddedViewRef path)\n * when present, otherwise falls back to the default `MessageItemComponent`\n * dynamic-component path. Both paths flow through the shared\n * `createRenderedEntry` / `updateMessageItemInstance` helpers.\n */\n private renderMessageItem(\n message: MJConversationDetailEntity,\n messages: MJConversationDetailEntity[],\n isLastMessage: boolean,\n timelineIndex: number\n ): void {\n const key = this.getMessageKey(message);\n // `index` is only used for the `isLastMessage` heuristic inside\n // updateMessageItemInstance — synthesize a value that produces the right\n // boolean (last index when `isLastMessage` is true, else 0 — any non-last\n // index works since it just affects that one comparison).\n const index = isLastMessage ? messages.length - 1 : 0;\n const useCustomRenderer = this.messageRendererTemplate !== null;\n const existing = this._renderedMessages.get(key);\n\n if (existing && existing.kind === 'embedded' && useCustomRenderer) {\n // Update existing embedded view from messageRenderer slot\n existing.ref.context.$implicit = message;\n existing.ref.context.message = message;\n existing.ref.markForCheck();\n return;\n }\n if (existing && existing.kind === 'component' && !useCustomRenderer) {\n // Update existing MessageItemComponent in place\n this.updateMessageItemInstance(existing.ref, message, messages, index);\n return;\n }\n if (existing) {\n // Rendering kind changed (e.g. component↔embedded, or a session block was\n // overwritten with a message). Destroy + recreate.\n existing.ref.destroy();\n this._renderedMessages.delete(key);\n }\n\n this.createRenderedEntry(message, messages, index, key, useCustomRenderer, timelineIndex);\n }\n\n /**\n * Updates an existing `MessageItemComponent` in place — used on the default\n * (non-custom-renderer) path when a message's status / artifacts / agent-run /\n * etc. changes mid-stream.\n */\n private updateMessageItemInstance(\n ref: ComponentRef<MessageItemComponent>,\n message: MJConversationDetailEntity,\n messages: MJConversationDetailEntity[],\n index: number\n ): void {\n const instance = ref.instance;\n const previousMessage = instance.message;\n\n instance.message = message;\n instance.allMessages = messages;\n instance.isProcessing = this.isProcessing;\n instance.userAvatarMap = this.userAvatarMap;\n instance.isLastMessage = (index === messages.length - 1);\n instance.messageExtraTemplate = this.messageExtraTemplate;\n this.applyMessageItemFeatureFlags(instance);\n\n this.applyArtifactsToInstance(instance, message.ID, ref.changeDetectorRef);\n\n instance.agentRun = this.agentRunMap.get(message.ID) || null;\n instance.ratings = this.ratingsMap.get(message.ID);\n instance.attachments = this.attachmentsMap.get(message.ID) || [];\n\n // Status change requires explicit markForCheck on the OnPush dynamic child.\n if (previousMessage && previousMessage.Status !== message.Status) {\n ref.changeDetectorRef.markForCheck();\n }\n }\n\n /**\n * Forward the host-level per-message feature gates onto a MessageItemComponent\n * instance. These are static host config (not per-message data), so the same\n * values apply to every message; applied on both the create and in-place-update\n * paths so a mid-session rebind stays consistent.\n */\n private applyMessageItemFeatureFlags(instance: MessageItemComponent): void {\n instance.showAgentRunDetails = this.showAgentRunDetails;\n instance.showReactions = this.showReactions;\n instance.showMessageRating = this.showMessageRating;\n instance.allowPinning = this.allowPinning;\n instance.allowMessageEdit = this.allowMessageEdit;\n instance.allowMessageDelete = this.allowMessageDelete;\n instance.assistantDisplayName = this.assistantDisplayName;\n instance.assistantAvatarUrl = this.assistantAvatarUrl;\n }\n\n /**\n * Creates a new rendered entry — either a `MessageItemComponent` (default path)\n * or an `EmbeddedViewRef` from the consumer's `messageRenderer` slot template.\n * Stores the entry in `_renderedMessages` and stamps a back-reference on the\n * message entity.\n */\n private createRenderedEntry(\n message: MJConversationDetailEntity,\n messages: MJConversationDetailEntity[],\n index: number,\n key: string,\n useCustomRenderer: boolean,\n timelineIndex: number\n ): void {\n if (useCustomRenderer && this.messageRendererTemplate) {\n // The slot directive carries TemplateRef<unknown>; assert the contract here\n // (consumers' `let-message` bindings consume the message context shape below).\n const template = this.messageRendererTemplate as TemplateRef<MessageRendererContext>;\n const viewRef = this.messageContainerRef.createEmbeddedView<MessageRendererContext>(\n template,\n { $implicit: message, message },\n { index: timelineIndex }\n );\n this._renderedMessages.set(key, { kind: 'embedded', ref: viewRef });\n // Stamp back-ref for parity with the component path.\n (message as unknown as { _viewRef?: EmbeddedViewRef<MessageRendererContext> })._viewRef = viewRef;\n return;\n }\n\n const componentRef = this.messageContainerRef.createComponent(MessageItemComponent, { index: timelineIndex });\n const instance = componentRef.instance;\n\n instance.message = message;\n instance.conversation = this.conversation;\n instance.currentUser = this.currentUser;\n instance.allMessages = messages;\n instance.isProcessing = this.isProcessing;\n instance.userAvatarMap = this.userAvatarMap;\n instance.isLastMessage = (index === messages.length - 1);\n instance.messageExtraTemplate = this.messageExtraTemplate;\n this.applyMessageItemFeatureFlags(instance);\n\n this.applyArtifactsToInstance(instance, message.ID, componentRef.changeDetectorRef);\n\n instance.agentRun = this.agentRunMap.get(message.ID) || null;\n instance.ratings = this.ratingsMap.get(message.ID);\n instance.attachments = this.attachmentsMap.get(message.ID) || [];\n\n instance.editClicked.subscribe((msg: MJConversationDetailEntity) => this.editMessage.emit(msg));\n instance.deleteClicked.subscribe((msg: MJConversationDetailEntity) => this.deleteMessage.emit(msg));\n instance.retryClicked.subscribe((msg: MJConversationDetailEntity) => this.retryMessage.emit(msg));\n instance.testFeedbackClicked.subscribe((msg: MJConversationDetailEntity) => this.testFeedbackMessage.emit(msg));\n instance.artifactClicked.subscribe((data: {artifactId: string; versionId?: string}) => this.artifactClicked.emit(data));\n instance.messageEdited.subscribe((msg: MJConversationDetailEntity) => this.messageEdited.emit(msg));\n instance.openEntityRecord.subscribe((data: {entityName: string; compositeKey: CompositeKey}) => this.openEntityRecord.emit(data));\n instance.suggestedResponseSelected.subscribe((data: {text: string; customInput?: string}) => this.suggestedResponseSelected.emit(data));\n instance.attachmentClicked.subscribe((attachment: MessageAttachment) => this.attachmentClicked.emit(attachment));\n instance.diagnosticRequested.subscribe((messageId: string) => this.diagnosticRequested.emit(messageId));\n instance.messagePinToggled.subscribe((msg: MJConversationDetailEntity) => this.messagePinToggled.emit(msg));\n instance.beforeResponseFormSubmitted.subscribe((e: BeforeResponseFormSubmittedEventArgs) => this.beforeResponseFormSubmitted.emit(e));\n instance.afterResponseFormSubmitted.subscribe((e: AfterResponseFormSubmittedEventArgs) => this.afterResponseFormSubmitted.emit(e));\n\n if (instance.artifactActionPerformed) {\n instance.artifactActionPerformed.subscribe((data: {action: string; artifactId: string}) => {\n // Parent can handle artifact actions (save, fork, history, share)\n console.log('Artifact action:', data);\n });\n }\n\n this._renderedMessages.set(key, { kind: 'component', ref: componentRef });\n // Preserve the existing back-ref pattern from the skip-chat performance design.\n (message as unknown as { _componentRef?: ComponentRef<MessageItemComponent> })._componentRef = componentRef;\n }\n\n /**\n * Resolves the DISTINCT artifacts for a message (one entry per artifactId at its\n * latest version), lazy-loads them all, and applies them to the rendered\n * message-item. Loads in the background so the UI never blocks.\n *\n * WHY WE SURFACE THEM ALL (design rationale — see PR discussion w/ Pranav & Ethan):\n * A single message can legitimately carry more than one DISTINCT artifact — e.g. a\n * research report PLUS a *standalone* generated infographic. This is deliberately\n * NOT in conflict with the server-side consolidation in AgentRunner\n * (Pranav, 5664b86: \"keep the report's embedded image in the report, not as a\n * duplicate artifact\"): that logic only suppresses media that is *embedded inline*\n * (base64) in another artifact's payload — a true duplicate. Genuinely standalone\n * sibling artifacts (the report uses SVG charts; the infographic is a separate JPEG)\n * are correctly kept as separate artifacts, and the UI must show every one of them.\n *\n * The earlier `artifactList[length - 1]` (\"show only the most recent\") approach\n * (EL-BC, 95492622) assumed consolidation always left exactly one artifact per\n * message; when it legitimately leaves two, that silently hid the report behind the\n * image. Grouping by artifactId (latest version each) shows all distinct artifacts\n * while still collapsing multiple *versions* of the same artifact to one card.\n */\n private applyArtifactsToInstance(\n instance: MessageItemComponent,\n messageId: string,\n childCdRef: ChangeDetectorRef\n ): void {\n const infos = this.resolveDistinctArtifacts(messageId);\n if (infos.length === 0) {\n instance.artifacts = [];\n instance.artifact = undefined;\n instance.artifactVersion = undefined;\n return;\n }\n\n Promise.all(\n infos.map(info =>\n Promise.all([info.getArtifact(), info.getVersion()]).then(([artifact, version]) => ({ artifact, version }))\n )\n )\n .then(refs => {\n instance.artifacts = refs;\n // Keep the legacy single inputs pointed at the first entry for back-compat.\n instance.artifact = refs[0]?.artifact;\n instance.artifactVersion = refs[0]?.version;\n // zone.js 0.15: parent detectChanges doesn't propagate to dynamically created children\n childCdRef.detectChanges();\n this.cdRef.detectChanges();\n })\n .catch(err => {\n console.error('Failed to lazy-load artifacts:', err);\n });\n }\n\n /**\n * Groups a message's artifact list by artifactId, keeping the highest version of\n * each. Multiple versions of the SAME artifact collapse to one card (latest wins),\n * while genuinely distinct artifacts are all retained.\n */\n private resolveDistinctArtifacts(messageId: string): LazyArtifactInfo[] {\n const list = this.artifactMap.get(messageId);\n if (!list || list.length === 0) {\n return [];\n }\n return selectDistinctLatestArtifacts(list);\n }\n\n /**\n * Generates a unique key for a message\n * Uses ID if available, otherwise uses a temporary key\n */\n private getMessageKey(message: MJConversationDetailEntity): string {\n return message.ID && message.ID.length > 0\n ? message.ID\n : `temp_${message.__mj_CreatedAt?.getTime() || Date.now()}`;\n }\n\n /**\n * Determines whether to show the date filter dropdown\n * Only show if conversation is long and spans multiple days\n */\n private updateDateFilterVisibility(): void {\n // `messages` is the loaded WINDOW, not the conversation. The 20-message / 3-day heuristic\n // below reads it as if it were full history, so under windowing a long multi-week thread\n // opens with ~10 items, fails the length check, and never offers date navigation at all —\n // the one case where it is most useful. `HasMoreAbove` is the only windowing-safe signal\n // that more conversation exists above, so it short-circuits the heuristic.\n if (this.HasMoreAbove) {\n this.shouldShowDateFilter = true;\n return;\n }\n if (!this.messages || this.messages.length < 20) {\n this.shouldShowDateFilter = false;\n return;\n }\n\n // Check if messages span more than 2 days\n const dates = this.messages\n .map(m => m.__mj_CreatedAt)\n .filter(d => d != null)\n .map(d => new Date(d!).setHours(0, 0, 0, 0));\n\n if (dates.length === 0) {\n this.shouldShowDateFilter = false;\n return;\n }\n\n const uniqueDates = new Set(dates);\n const daySpan = uniqueDates.size;\n\n // Show filter if conversation has 20+ messages and spans 3+ days\n this.shouldShowDateFilter = daySpan >= 3;\n }\n\n /**\n * Scrolls the message list to the bottom\n */\n private scrollToBottom(): void {\n if (this.scrollContainer && this.scrollContainer.nativeElement) {\n Promise.resolve().then(() => {\n const element = this.scrollContainer.nativeElement;\n element.scrollTop = element.scrollHeight;\n });\n }\n }\n\n /**\n * Removes a message from the rendered list\n * Called externally when a message is deleted\n */\n public removeMessage(message: MJConversationDetailEntity): void {\n const key = this.getMessageKey(message);\n const entry = this._renderedMessages.get(key);\n if (entry) {\n entry.ref.destroy();\n this._renderedMessages.delete(key);\n }\n }\n}","<div class=\"message-list-container\" #scrollContainer>\n <!-- Sticky Date Header (only show for long conversations spanning multiple days) -->\n @if (showDateNavigation && shouldShowDateFilter && messages.length > 0) {\n <div class=\"sticky-date-header\">\n <div class=\"sticky-date-wrapper\">\n <button class=\"sticky-date-button\" (click)=\"toggleDateNav()\">\n <span>{{ currentDateDisplay }}</span>\n <i class=\"fas fa-chevron-down\"></i>\n </button>\n <div class=\"date-nav-dropdown\" [class.show]=\"showDateNav\">\n <div class=\"date-nav-option jump-to\">Jump to...</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('today')\">Today</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('yesterday')\">Yesterday</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('last-week')\">Last week</div>\n <div class=\"date-nav-option\" (click)=\"jumpToDate('last-month')\">Last month</div>\n </div>\n </div>\n </div>\n }\n\n <!-- Windowed transcript: older pages load when this scrolls into view (IntersectionObserver\n in the component, not a scroll listener). Absent entirely once the top is reached. -->\n @if (HasMoreAbove) {\n <div #olderSentinel class=\"transcript-older-sentinel\">\n @if (IsLoadingOlder) {\n <mj-loading text=\"Loading earlier messages…\" size=\"small\"></mj-loading>\n } @else {\n <span class=\"transcript-older-label\">Earlier messages</span>\n }\n </div>\n }\n\n <!-- Height-holding stand-in for a timeline item that has been unmounted to keep the DOM\n bounded. Declared here but rendered into #messageContainer at the item's own index,\n so scroll geometry is unchanged. -->\n <ng-template #spacerTemplate let-height=\"height\">\n <div class=\"transcript-spacer\" [style.height.px]=\"height\" aria-hidden=\"true\"></div>\n </ng-template>\n\n <ng-container #messageContainer></ng-container>\n\n @if (messages.length === 0 && showEmptyFill) {\n <mj-empty-state\n class=\"messages-empty-fill\"\n Icon=\"fa-solid fa-comments\"\n Title=\"No messages yet. Start a conversation!\" />\n }\n</div>"]}
|
|
@@ -9,13 +9,32 @@ import { MentionParserService } from './mention-parser.service';
|
|
|
9
9
|
import { ConversationsRuntimeBootstrap } from './conversations-runtime-bootstrap.service';
|
|
10
10
|
import * as i0 from "@angular/core";
|
|
11
11
|
/**
|
|
12
|
-
* Context for artifact lookups
|
|
13
|
-
*
|
|
12
|
+
* Context for artifact lookups — pre-loaded conversation data.
|
|
13
|
+
*
|
|
14
|
+
* NO LONGER CONSUMED by this service. Both readers were converted to queries when transcript
|
|
15
|
+
* windowing made these maps a partial view: they are keyed to the loaded window, so any
|
|
16
|
+
* lookup for an older row silently missed. Retained as an exported type for API
|
|
17
|
+
* compatibility; new code should not build one.
|
|
14
18
|
*/
|
|
15
19
|
export interface ArtifactLookupContext {
|
|
16
20
|
agentRunsByDetailId: Map<string, MJAIAgentRunEntityExtended>;
|
|
17
21
|
artifactsByDetailId: Map<string, LazyArtifactInfo[]>;
|
|
18
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* An agent's prior OUTPUT artifact, resolved for payload continuity.
|
|
25
|
+
*
|
|
26
|
+
* `payload` is the parsed `ArtifactVersion.Content`, typed to match what actually consumes it
|
|
27
|
+
* — `executeAgentContinuation` and `invokeSubAgent` both take `Record<string, unknown> | null`.
|
|
28
|
+
* It is null when the version carried no content, the content did not parse, or the content
|
|
29
|
+
* parsed to something that is not a JSON object; callers treat all three the same as "no prior
|
|
30
|
+
* artifact", which is already a legal agent input.
|
|
31
|
+
*/
|
|
32
|
+
export interface AgentPayloadSource {
|
|
33
|
+
artifactId: string;
|
|
34
|
+
versionId: string;
|
|
35
|
+
versionNumber: number;
|
|
36
|
+
payload: Record<string, unknown> | null;
|
|
37
|
+
}
|
|
19
38
|
/**
|
|
20
39
|
* Result from intent check - indicates whether to continue with agent
|
|
21
40
|
* and which artifact version to use as payload
|
|
@@ -38,7 +57,7 @@ export interface IntentCheckResult {
|
|
|
38
57
|
* `message-input.component`.
|
|
39
58
|
* - `checkAgentContinuityIntent(...)` — fast intent classification when the
|
|
40
59
|
* user replies to a previous-agent thread.
|
|
41
|
-
* - `
|
|
60
|
+
* - `FindConfigurationPresetForAgent(...)` — locates an agent's preset
|
|
42
61
|
* from prior @mentions in the conversation.
|
|
43
62
|
* - `clearSession(...)` — per-conversation session-id bookkeeping.
|
|
44
63
|
*
|
|
@@ -106,15 +125,23 @@ export declare class ConversationAgentService {
|
|
|
106
125
|
*/
|
|
107
126
|
processMessage(conversationId: string, message: MJConversationDetailEntity, conversationHistory: MJConversationDetailEntity[], conversationDetailId: string, onProgress?: AgentExecutionProgressCallback, appContext?: Record<string, unknown> | null, planMode?: boolean, requestedSkillIDs?: string[]): Promise<ExecuteAgentResult | null>;
|
|
108
127
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
128
|
+
* Configuration preset an agent was pinned to by a previous `@mention` in this conversation.
|
|
129
|
+
*
|
|
130
|
+
* Resolved by QUERY, not by scanning the display array. The pinning `@mention` is normally
|
|
131
|
+
* the FIRST message of an exchange and everything after it is follow-up, so it is the
|
|
132
|
+
* message most likely to fall below the loaded transcript window — and `undefined` is a
|
|
133
|
+
* legal value for `configurationPresetId`, so the miss is silent. The visible consequence
|
|
134
|
+
* is a run executed under the default configuration (a different model tier) instead of the
|
|
135
|
+
* one the user explicitly chose, with a plausible-looking result and no error.
|
|
112
136
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
137
|
+
* There is no column to filter on: the preset lives inside the message body as a JSON
|
|
138
|
+
* mention blob (`@{"type":"agent","id":"…","configId":"…"}`). So SQL narrows and the parser
|
|
139
|
+
* decides — both `configId` and the agent id appear verbatim in that blob, which makes the
|
|
140
|
+
* two LIKEs a tight prefilter, and `parseMentions` is what actually confirms a match.
|
|
116
141
|
*/
|
|
117
|
-
|
|
142
|
+
FindConfigurationPresetForAgent(conversationId: string, agentId: string): Promise<string | undefined>;
|
|
143
|
+
/** Returns the configId this message pins for `agentId`, or null when it pins none. */
|
|
144
|
+
private readAgentConfigFromMention;
|
|
118
145
|
/**
|
|
119
146
|
* Clear the session for a conversation (useful when starting a new topic)
|
|
120
147
|
*/
|
|
@@ -133,7 +160,7 @@ export declare class ConversationAgentService {
|
|
|
133
160
|
* Stays on the Angular shim because it directly uses AgentClientService.
|
|
134
161
|
* Could move to the runtime in a follow-up if needed.
|
|
135
162
|
*/
|
|
136
|
-
invokeSubAgent(agentName: string, conversationId: string, message: MJConversationDetailEntity, conversationHistory: MJConversationDetailEntity[], reasoning: string, conversationDetailId: string, payload?: unknown, onProgress?: AgentExecutionProgressCallback, sourceArtifactId?: string, sourceArtifactVersionId?: string, agentConfigurationPresetId?: string, appContext?: Record<string, unknown> | null, planMode?: boolean, requestedSkillIDs?: string[]): Promise<ExecuteAgentResult | null>;
|
|
163
|
+
invokeSubAgent(agentName: string, conversationId: string, message: MJConversationDetailEntity, conversationHistory: MJConversationDetailEntity[], reasoning: string, conversationDetailId: string, payload?: Record<string, unknown> | null, onProgress?: AgentExecutionProgressCallback, sourceArtifactId?: string, sourceArtifactVersionId?: string, agentConfigurationPresetId?: string, appContext?: Record<string, unknown> | null, planMode?: boolean, requestedSkillIDs?: string[]): Promise<ExecuteAgentResult | null>;
|
|
137
164
|
/**
|
|
138
165
|
* Check if user's latest message should continue with the previous agent or route through Sage.
|
|
139
166
|
* Uses fast inference (<500ms) to determine intent and avoid unnecessary Sage overhead.
|
|
@@ -141,15 +168,70 @@ export declare class ConversationAgentService {
|
|
|
141
168
|
* Stays on the Angular shim because it directly uses GraphQLAIClient.
|
|
142
169
|
* Could move to the runtime in a follow-up.
|
|
143
170
|
*/
|
|
144
|
-
checkAgentContinuityIntent(agentId: string, latestMessage: string, conversationHistory: MJConversationDetailEntity[]
|
|
171
|
+
checkAgentContinuityIntent(conversationId: string, agentId: string, latestMessage: string, conversationHistory: MJConversationDetailEntity[]): Promise<IntentCheckResult>;
|
|
145
172
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* Enables LLM to reason about which artifact/version user is referencing.
|
|
173
|
+
* Every artifact this agent produced in this conversation, newest version first — resolved
|
|
174
|
+
* by QUERY, not by scanning the display array.
|
|
149
175
|
*
|
|
150
|
-
*
|
|
176
|
+
* The scan this replaces walked `conversationDetails` and looked each row up in the
|
|
177
|
+
* caller's `artifactsByDetailId` / `agentRunsByDetailId` maps. Both are scoped to the
|
|
178
|
+
* LOADED WINDOW, so under transcript windowing it saw only the artifacts attached to the
|
|
179
|
+
* page currently on screen.
|
|
180
|
+
*
|
|
181
|
+
* That matters because this list is the "Prior Artifacts Created by This Agent" block fed
|
|
182
|
+
* to the Check Sage Intent prompt, which is what produces `targetArtifactVersionId`. A
|
|
183
|
+
* truncated list does not make the classifier fail — it makes it reason over a partial
|
|
184
|
+
* history and confidently name the wrong version, or miss continuity altogether. Silent,
|
|
185
|
+
* plausible, and wrong: the same failure class as {@link FindLatestAgentOutputVersion},
|
|
186
|
+
* closed the same way.
|
|
187
|
+
*
|
|
188
|
+
* Two reads, not the four the old shape would have needed — see
|
|
189
|
+
* {@link AgentArtifactSummary} for why dropping `runId` removes the join back to agent runs.
|
|
151
190
|
*/
|
|
152
191
|
private findAllAgentArtifacts;
|
|
192
|
+
/** Names and types for the artifacts behind a set of versions. */
|
|
193
|
+
private loadArtifactNames;
|
|
194
|
+
/**
|
|
195
|
+
* Newest OUTPUT artifact version an agent produced in this conversation — resolved by
|
|
196
|
+
* QUERY, not by scanning the display array.
|
|
197
|
+
*
|
|
198
|
+
* The array scan this replaces was correct only while `conversationHistory` held the whole
|
|
199
|
+
* conversation. Under transcript windowing it holds one page, so the scan silently returns
|
|
200
|
+
* null for any artifact below the window's oldest row — exactly the long "modify this
|
|
201
|
+
* again" exchanges where payload continuity matters most. A null payload is a LEGAL agent
|
|
202
|
+
* input, so the failure is silent: the agent regenerates from scratch instead of modifying.
|
|
203
|
+
*
|
|
204
|
+
* One round trip. The subquery walks details -> Output junctions, and versions carry
|
|
205
|
+
* `__mj_CreatedAt`, so "newest" is expressible without joining back for `Sequence`.
|
|
206
|
+
*/
|
|
207
|
+
FindLatestAgentOutputVersion(conversationId: string, agentId: string): Promise<AgentPayloadSource | null>;
|
|
208
|
+
/**
|
|
209
|
+
* `ArtifactVersion.ID IN (...)` for every OUTPUT artifact an agent produced in one
|
|
210
|
+
* conversation. Shared by {@link FindLatestAgentOutputVersion} and
|
|
211
|
+
* {@link findAllAgentArtifacts} so the two can never disagree about what "this agent's
|
|
212
|
+
* artifacts" means.
|
|
213
|
+
*
|
|
214
|
+
* Filters on the DETAIL's `Status <> 'Error'` rather than the agent run's
|
|
215
|
+
* `Status = 'Completed'` (which is what the array scan this replaced used). Doing it on the
|
|
216
|
+
* run would mean joining back to `MJ: AI Agent Runs` purely to restate a condition the
|
|
217
|
+
* detail already carries.
|
|
218
|
+
*/
|
|
219
|
+
private agentOutputVersionFilter;
|
|
220
|
+
/**
|
|
221
|
+
* One artifact version by ID, as a payload source.
|
|
222
|
+
*
|
|
223
|
+
* Used by the continuity path after the intent check names a specific version: that ID may
|
|
224
|
+
* belong to a message below the loaded window, so it cannot be resolved from the window's
|
|
225
|
+
* artifact maps.
|
|
226
|
+
*/
|
|
227
|
+
FindArtifactVersionById(versionId: string): Promise<AgentPayloadSource | null>;
|
|
228
|
+
/**
|
|
229
|
+
* Shared read behind {@link FindLatestAgentOutputVersion} and {@link FindArtifactVersionById}.
|
|
230
|
+
*
|
|
231
|
+
* `ResultType: 'simple'` with an explicit `Fields` list: nothing here is mutated, and under
|
|
232
|
+
* `entity_object` the `Fields` narrowing would be silently discarded by `PreRunView`.
|
|
233
|
+
*/
|
|
234
|
+
private runPayloadSourceQuery;
|
|
153
235
|
static ɵfac: i0.ɵɵFactoryDeclaration<ConversationAgentService, never>;
|
|
154
236
|
static ɵprov: i0.ɵɵInjectableDeclaration<ConversationAgentService>;
|
|
155
237
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-agent.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-agent.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAY,iBAAiB,
|
|
1
|
+
{"version":3,"file":"conversation-agent.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-agent.service.ts"],"names":[],"mappings":"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"}
|