@memberjunction/ng-conversations 6.2.0-edge.1 → 6.2.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.
Files changed (62) hide show
  1. package/README.md +9 -1
  2. package/dist/lib/components/conversation/conversation-agent-picker.component.js +1 -1
  3. package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
  4. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +146 -6
  5. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  6. package/dist/lib/components/conversation/conversation-chat-area.component.js +603 -130
  7. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  8. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +3 -1
  9. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
  10. package/dist/lib/components/conversation/pinned-messages-panel.component.js +22 -8
  11. package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
  12. package/dist/lib/components/message/actionable-commands.component.d.ts +12 -0
  13. package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
  14. package/dist/lib/components/message/actionable-commands.component.js +60 -12
  15. package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
  16. package/dist/lib/components/message/message-input.component.d.ts +93 -4
  17. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  18. package/dist/lib/components/message/message-input.component.js +224 -25
  19. package/dist/lib/components/message/message-input.component.js.map +1 -1
  20. package/dist/lib/components/message/message-item.component.d.ts +87 -2
  21. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  22. package/dist/lib/components/message/message-item.component.js +214 -32
  23. package/dist/lib/components/message/message-item.component.js.map +1 -1
  24. package/dist/lib/components/message/message-list.component.d.ts +20 -1
  25. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  26. package/dist/lib/components/message/message-list.component.js +76 -1
  27. package/dist/lib/components/message/message-list.component.js.map +1 -1
  28. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  29. package/dist/lib/components/workspace/conversation-workspace.component.js +4 -1
  30. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  31. package/dist/lib/models/agent-turn.model.d.ts +12 -2
  32. package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
  33. package/dist/lib/models/agent-turn.model.js.map +1 -1
  34. package/dist/lib/services/conversation-agent.service.d.ts +21 -0
  35. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  36. package/dist/lib/services/conversation-agent.service.js +28 -2
  37. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  38. package/dist/lib/services/conversation-liveness-dom.service.d.ts +42 -0
  39. package/dist/lib/services/conversation-liveness-dom.service.d.ts.map +1 -0
  40. package/dist/lib/services/conversation-liveness-dom.service.js +74 -0
  41. package/dist/lib/services/conversation-liveness-dom.service.js.map +1 -0
  42. package/dist/lib/services/ui-command-handler.service.d.ts +40 -3
  43. package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
  44. package/dist/lib/services/ui-command-handler.service.js +78 -9
  45. package/dist/lib/services/ui-command-handler.service.js.map +1 -1
  46. package/dist/lib/util/frame-zone.d.ts +10 -0
  47. package/dist/lib/util/frame-zone.d.ts.map +1 -0
  48. package/dist/lib/util/frame-zone.js +10 -0
  49. package/dist/lib/util/frame-zone.js.map +1 -0
  50. package/dist/lib/utils/agent-turn-routing.d.ts +7 -6
  51. package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -1
  52. package/dist/lib/utils/agent-turn-routing.js +4 -16
  53. package/dist/lib/utils/agent-turn-routing.js.map +1 -1
  54. package/dist/lib/utils/decision-routing.d.ts +68 -0
  55. package/dist/lib/utils/decision-routing.d.ts.map +1 -0
  56. package/dist/lib/utils/decision-routing.js +101 -0
  57. package/dist/lib/utils/decision-routing.js.map +1 -0
  58. package/dist/public-api.d.ts +2 -0
  59. package/dist/public-api.d.ts.map +1 -1
  60. package/dist/public-api.js +5 -0
  61. package/dist/public-api.js.map +1 -1
  62. package/package.json +33 -32
package/README.md CHANGED
@@ -215,11 +215,19 @@ A host that puts several people in one conversation (a team room, a shared chat)
215
215
  | `AllowedAgentIDs` | `null` (every agent) | The agents that may answer. Narrows the `@` list, every route (a tagged agent, continuity, the pinned and host default agents, the conversation manager), the manager's delegation, including each agent step of a workflow it plans, and the pin and voice pickers. An empty list allows none |
216
216
  | `MentionPeople` | `null` (the current user only) | The people the `@` list offers, such as the chat's members (`MentionPerson` from `@memberjunction/conversations-runtime`). Each composer keeps its own list |
217
217
  | `AgentHistoryFrom` | `null` (the whole conversation) | The first moment of the conversation an agent turn may read. The server loads the agent's history from there, uses no summary of earlier messages, and holds the same floor in the run's other reads of the conversation. Sent only when set, so leaving it null keeps working against an older MJAPI |
218
- | `AgentTurnHandler` | `null` (MJ's own path) | An async hook that runs each turn on the host's server. The chat area calls it once per turn, after `BeforeAgentTurn` and before any reply row exists, and shows the rows it reports |
218
+ | `AgentTurnHandler` | `null` (MJ's own path) | An async hook that runs each turn on the host's server. The chat area calls it once per turn, after `BeforeAgentTurn` and before any reply row exists, and shows the rows it reports. A reply it reports as `In-Progress` is followed like any other in-progress reply. The host publishes that row's live status with `AgentRunStatusPublisher` from `@memberjunction/server`, on the caller's session: significant-step progress, streamed text, the partial result, and the completion, with the reply row's id on the completion. When the turn throws instead of returning a result, call `PublishFailure` with the reply row's id and the error |
219
219
  | `AutoNameConversation` | `true` | `false` stops MJ naming a new conversation from its first message or first voice utterance |
220
220
 
221
221
  Routing picks one agent per turn, in this order: a tagged agent, then (under `'Always'` only) the last agent that answered other than the conversation manager, the conversation's pinned agent, the host's `DefaultAgentId`, and the conversation manager. An agent `AllowedAgentIDs` leaves out is skipped. `BeforeAgentTurn` then fires once, carrying the resolved `AgentId`, `AgentName`, `Route` and `UserMessageId`: a listener can cancel the turn, which then writes nothing more, or set `RedirectAgentId` to another allowed agent.
222
222
 
223
+ #### Read-only
224
+
225
+ `ReadOnly` hides every composer and shows a banner. `ReadOnlyMessage` is that banner's text; leave it null to use the View-share sentence. `EffectiveReadOnly` is true when the host set `ReadOnly` or the conversation is shared with View access. A View share with `ReadOnly` left false still shows today's disabled composer.
226
+
227
+ Pin, edit, and delete on the message list, the mode picker, the agent picker, suggested responses, project assignment, and unpinning all follow `EffectiveReadOnly`. Each `mj-message-input` the chat area renders gets `[ReadOnly]="EffectiveReadOnly"`, so send, the initial auto-send, and starting realtime refuse. Ratings close too: `canEdit` is false while that message is read-only. The pins panel's `AllowUnpin` is bound to `!EffectiveReadOnly`. With it false the panel still lists pins and still jumps, and it hides Unpin.
228
+
229
+ A reply the host reports as `In-Progress` is followed as soon as the chat area takes the row. If that turn already finished, the completion waiting in the replay window is applied then, so the row does not stay in progress until the conversation is opened again.
230
+
223
231
  The `composerExtra` slot renders host UI directly above the composer, wherever the chat area shows one (the new-conversation composer and the empty state's included). Its context is `IMJChatComposerExtraContext`: the conversation as `$implicit`, plus `ConversationId` and `IsProcessing`.
224
232
 
225
233
  ```html
@@ -3,7 +3,7 @@ import { LogError } from '@memberjunction/core';
3
3
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
4
4
  import { MJNotificationService } from '@memberjunction/ng-notifications';
5
5
  import { UUIDsEqual } from '@memberjunction/global';
6
- import { IsAgentAllowed } from '../../utils/agent-turn-routing';
6
+ import { IsAgentAllowed } from '@memberjunction/ai-core-plus';
7
7
  import * as i0 from "@angular/core";
8
8
  const _forTrack0 = ($index, $item) => $item.ID;
9
9
  function ConversationAgentPickerComponent_Conditional_6_Conditional_7_Template(rf, ctx) { if (rf & 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-agent-picker.component.js","sourceRoot":"","sources":["../../../../src/lib/components/conversation/conversation-agent-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n HostListener,\n Input,\n OnInit,\n Output,\n inject,\n} from '@angular/core';\nimport { LogError } from '@memberjunction/core';\nimport type { UserInfo } from '@memberjunction/core';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport type { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport type { MJConversationEntity } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { IsAgentAllowed } from '../../utils/agent-turn-routing';\n\n/**\n * Header widget that lets a user pin a default AI agent on the active\n * conversation. The pinned agent (saved to\n * `MJConversationEntity.DefaultAgentID`) takes precedence over the\n * embedder-supplied default in `MessageInputComponent.routeMessage()` —\n * non-mention messages route to it instead of Sage.\n *\n * Eligible agents are top-level, Active, non-Sub-Agent rows from\n * `AIEngineBase.Instance.Agents`. The widget renders as a compact button\n * showing the current pin (or \"Auto\" when nothing is pinned). Clicking\n * opens an inline list with a \"Clear\" option to remove the pin.\n *\n * The host controls visibility via `<mj-conversation-chat-area>`'s\n * `[showAgentPicker]` input (default true). Surfaces that don't want this\n * UX (e.g. agent-less embed) set it to false.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-agent-picker',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-cv-agent-picker\" [class.mj-cv-agent-picker--open]=\"IsOpen\">\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__trigger\"\n [title]=\"ButtonTitle\"\n [disabled]=\"Disabled || !Conversation\"\n (click)=\"Toggle($event)\">\n <i class=\"fa-solid fa-robot\"></i>\n <span class=\"mj-cv-agent-picker__label\">{{ CurrentAgentLabel }}</span>\n <i class=\"fa-solid fa-caret-down mj-cv-agent-picker__caret\"></i>\n </button>\n @if (IsOpen) {\n <div class=\"mj-cv-agent-picker__menu\" (click)=\"$event.stopPropagation()\">\n <div class=\"mj-cv-agent-picker__menu-header\">Default agent for this conversation</div>\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__item\"\n [class.mj-cv-agent-picker__item--selected]=\"!Conversation?.DefaultAgentID\"\n (click)=\"PickAgent(null)\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <span>Auto (use default)</span>\n </button>\n @if (EligibleAgents.length === 0) {\n <div class=\"mj-cv-agent-picker__empty\">No agents available</div>\n } @else {\n @for (agent of EligibleAgents; track agent.ID) {\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__item\"\n [class.mj-cv-agent-picker__item--selected]=\"IsSelected(agent)\"\n [title]=\"agent.Description || agent.Name\"\n (click)=\"PickAgent(agent)\">\n <i [class]=\"IconClassFor(agent)\"></i>\n <span>{{ agent.Name }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n `,\n styles: [`\n /* Match mjButton size=\"sm\" so the trigger lines up with neighboring\n Export / Share buttons: min-height 32px, 6px/12px padding,\n 0.8125rem font. Same border-radius as the other chrome buttons. */\n .mj-cv-agent-picker { position: relative; display: inline-flex; align-items: center; }\n .mj-cv-agent-picker__trigger {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 6px 12px; min-height: 32px; box-sizing: border-box;\n background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-default);\n border-radius: 4px; cursor: pointer;\n color: var(--mj-text-primary); font-size: 0.8125rem; line-height: 1.5;\n transition: background 120ms, border-color 120ms;\n }\n .mj-cv-agent-picker__trigger:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover); border-color: var(--mj-border-strong);\n }\n .mj-cv-agent-picker__trigger:disabled { opacity: 0.5; cursor: not-allowed; }\n .mj-cv-agent-picker--open .mj-cv-agent-picker__trigger { border-color: var(--mj-border-focus); }\n .mj-cv-agent-picker__label { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .mj-cv-agent-picker__caret { font-size: 10px; opacity: 0.7; }\n .mj-cv-agent-picker__menu {\n position: absolute; top: calc(100% + 4px); right: 0; z-index: 50;\n min-width: 220px; max-height: 320px; overflow-y: auto;\n background: var(--mj-bg-surface-elevated); border: 1px solid var(--mj-border-default);\n border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n padding: 4px 0;\n }\n .mj-cv-agent-picker__menu-header {\n padding: 6px 12px 4px; font-size: 11px; text-transform: uppercase;\n letter-spacing: 0.04em; color: var(--mj-text-muted);\n }\n .mj-cv-agent-picker__item {\n display: flex; align-items: center; gap: 8px; width: 100%;\n padding: 6px 12px; background: transparent; border: none; cursor: pointer;\n color: var(--mj-text-primary); font-size: 13px; text-align: left;\n }\n .mj-cv-agent-picker__item i { width: 14px; text-align: center; color: var(--mj-text-secondary); }\n .mj-cv-agent-picker__item:hover { background: var(--mj-bg-surface-hover); }\n .mj-cv-agent-picker__item--selected { background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent); }\n .mj-cv-agent-picker__item--selected i { color: var(--mj-brand-primary); }\n .mj-cv-agent-picker__empty { padding: 8px 12px; font-size: 12px; color: var(--mj-text-muted); }\n `]\n})\nexport class ConversationAgentPickerComponent implements OnInit {\n /** The conversation whose `DefaultAgentID` this widget edits. */\n @Input() Conversation: MJConversationEntity | null = null;\n\n /** Required for the Save() audit context. */\n @Input() CurrentUser: UserInfo | null = null;\n\n /** Disable the picker (e.g. read-only conversation). */\n @Input() Disabled: boolean = false;\n\n /**\n * The agents the chat allows (the chat area's `AllowedAgentIDs`). Only these can be pinned.\n * Null (the default) offers every eligible agent.\n */\n @Input()\n set AllowedAgentIDs(value: readonly string[] | null) {\n this._allowedAgentIDs = value ?? null;\n this.applyAllowedAgents();\n }\n get AllowedAgentIDs(): readonly string[] | null {\n return this._allowedAgentIDs;\n }\n\n /** Emitted after a successful save with the new (or null) agent ID. */\n @Output() AgentChanged = new EventEmitter<string | null>();\n\n public IsOpen = false;\n public EligibleAgents: MJAIAgentEntityExtended[] = [];\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly notifications = inject(MJNotificationService);\n private _allowedAgentIDs: readonly string[] | null = null;\n /** Every top-level, active agent, before the allowed list narrows it. */\n private catalogAgents: MJAIAgentEntityExtended[] = [];\n\n public async ngOnInit(): Promise<void> {\n try {\n // AIEngineBase is the live, cached agent catalog. Ensure it's\n // loaded — most app shells warm it up at boot, but the picker\n // could mount before that completes.\n await AIEngineBase.Instance.Config(false);\n this.catalogAgents = (AIEngineBase.Instance.Agents ?? [])\n .filter(a =>\n !a.ParentID &&\n a.Status === 'Active' &&\n a.InvocationMode !== 'Sub-Agent'\n )\n .sort((a, b) => (a.Name ?? '').localeCompare(b.Name ?? ''));\n this.applyAllowedAgents();\n } catch (err) {\n LogError(`ConversationAgentPicker.ngOnInit: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n /** Narrows the catalog to the allowed agents. */\n private applyAllowedAgents(): void {\n this.EligibleAgents = this.catalogAgents.filter(a => IsAgentAllowed(a.ID, this._allowedAgentIDs));\n this.cdr.markForCheck();\n }\n\n public get CurrentAgentLabel(): string {\n const id = this.Conversation?.DefaultAgentID;\n if (!id) return 'Auto';\n const match = this.EligibleAgents.find(a => UUIDsEqual(a.ID, id));\n // If the pinned agent is no longer eligible (deactivated, demoted to\n // sub-agent), still surface its name from the cache so the user can\n // see what was pinned even though they can't re-pin it.\n const fromCache = match\n ?? (AIEngineBase.Instance.Agents ?? []).find(a => UUIDsEqual(a.ID, id));\n return fromCache?.Name ?? 'Pinned agent';\n }\n\n public get ButtonTitle(): string {\n return this.Conversation?.DefaultAgentID\n ? `This conversation routes to ${this.CurrentAgentLabel}. Click to change.`\n : 'No agent pinned — messages route via the standard rules. Click to pin an agent.';\n }\n\n public IconClassFor(agent: MJAIAgentEntityExtended): string {\n return agent.IconClass?.trim() || 'fa-solid fa-robot';\n }\n\n public IsSelected(agent: MJAIAgentEntityExtended): boolean {\n return !!this.Conversation?.DefaultAgentID\n && UUIDsEqual(agent.ID, this.Conversation.DefaultAgentID);\n }\n\n public Toggle(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Disabled || !this.Conversation) return;\n this.IsOpen = !this.IsOpen;\n this.cdr.markForCheck();\n }\n\n public async PickAgent(agent: MJAIAgentEntityExtended | null): Promise<void> {\n this.IsOpen = false;\n const conv = this.Conversation;\n if (!conv) return;\n const newId = agent?.ID ?? null;\n if (conv.DefaultAgentID === newId) {\n this.cdr.markForCheck();\n return;\n }\n const prev = conv.DefaultAgentID;\n conv.DefaultAgentID = newId;\n try {\n const saved = await conv.Save();\n if (!saved) {\n conv.DefaultAgentID = prev;\n this.notifications.CreateSimpleNotification(\n conv.LatestResult?.CompleteMessage ?? 'Failed to update conversation default agent.',\n 'error', 4500);\n return;\n }\n this.AgentChanged.emit(newId);\n } catch (err) {\n conv.DefaultAgentID = prev;\n LogError(`ConversationAgentPicker.PickAgent: ${err instanceof Error ? err.message : String(err)}`);\n } finally {\n this.cdr.markForCheck();\n }\n }\n\n /** Close the menu when the user clicks outside the picker. */\n @HostListener('document:click', ['$event'])\n public OnDocumentClick(_event: MouseEvent): void {\n if (this.IsOpen) {\n this.IsOpen = false;\n this.cdr.markForCheck();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"conversation-agent-picker.component.js","sourceRoot":"","sources":["../../../../src/lib/components/conversation/conversation-agent-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n HostListener,\n Input,\n OnInit,\n Output,\n inject,\n} from '@angular/core';\nimport { LogError } from '@memberjunction/core';\nimport type { UserInfo } from '@memberjunction/core';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport type { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport type { MJConversationEntity } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { IsAgentAllowed } from '@memberjunction/ai-core-plus';\n\n/**\n * Header widget that lets a user pin a default AI agent on the active\n * conversation. The pinned agent (saved to\n * `MJConversationEntity.DefaultAgentID`) takes precedence over the\n * embedder-supplied default in `MessageInputComponent.routeMessage()` —\n * non-mention messages route to it instead of Sage.\n *\n * Eligible agents are top-level, Active, non-Sub-Agent rows from\n * `AIEngineBase.Instance.Agents`. The widget renders as a compact button\n * showing the current pin (or \"Auto\" when nothing is pinned). Clicking\n * opens an inline list with a \"Clear\" option to remove the pin.\n *\n * The host controls visibility via `<mj-conversation-chat-area>`'s\n * `[showAgentPicker]` input (default true). Surfaces that don't want this\n * UX (e.g. agent-less embed) set it to false.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-agent-picker',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-cv-agent-picker\" [class.mj-cv-agent-picker--open]=\"IsOpen\">\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__trigger\"\n [title]=\"ButtonTitle\"\n [disabled]=\"Disabled || !Conversation\"\n (click)=\"Toggle($event)\">\n <i class=\"fa-solid fa-robot\"></i>\n <span class=\"mj-cv-agent-picker__label\">{{ CurrentAgentLabel }}</span>\n <i class=\"fa-solid fa-caret-down mj-cv-agent-picker__caret\"></i>\n </button>\n @if (IsOpen) {\n <div class=\"mj-cv-agent-picker__menu\" (click)=\"$event.stopPropagation()\">\n <div class=\"mj-cv-agent-picker__menu-header\">Default agent for this conversation</div>\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__item\"\n [class.mj-cv-agent-picker__item--selected]=\"!Conversation?.DefaultAgentID\"\n (click)=\"PickAgent(null)\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <span>Auto (use default)</span>\n </button>\n @if (EligibleAgents.length === 0) {\n <div class=\"mj-cv-agent-picker__empty\">No agents available</div>\n } @else {\n @for (agent of EligibleAgents; track agent.ID) {\n <button\n type=\"button\"\n class=\"mj-cv-agent-picker__item\"\n [class.mj-cv-agent-picker__item--selected]=\"IsSelected(agent)\"\n [title]=\"agent.Description || agent.Name\"\n (click)=\"PickAgent(agent)\">\n <i [class]=\"IconClassFor(agent)\"></i>\n <span>{{ agent.Name }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n `,\n styles: [`\n /* Match mjButton size=\"sm\" so the trigger lines up with neighboring\n Export / Share buttons: min-height 32px, 6px/12px padding,\n 0.8125rem font. Same border-radius as the other chrome buttons. */\n .mj-cv-agent-picker { position: relative; display: inline-flex; align-items: center; }\n .mj-cv-agent-picker__trigger {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 6px 12px; min-height: 32px; box-sizing: border-box;\n background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-default);\n border-radius: 4px; cursor: pointer;\n color: var(--mj-text-primary); font-size: 0.8125rem; line-height: 1.5;\n transition: background 120ms, border-color 120ms;\n }\n .mj-cv-agent-picker__trigger:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover); border-color: var(--mj-border-strong);\n }\n .mj-cv-agent-picker__trigger:disabled { opacity: 0.5; cursor: not-allowed; }\n .mj-cv-agent-picker--open .mj-cv-agent-picker__trigger { border-color: var(--mj-border-focus); }\n .mj-cv-agent-picker__label { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .mj-cv-agent-picker__caret { font-size: 10px; opacity: 0.7; }\n .mj-cv-agent-picker__menu {\n position: absolute; top: calc(100% + 4px); right: 0; z-index: 50;\n min-width: 220px; max-height: 320px; overflow-y: auto;\n background: var(--mj-bg-surface-elevated); border: 1px solid var(--mj-border-default);\n border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n padding: 4px 0;\n }\n .mj-cv-agent-picker__menu-header {\n padding: 6px 12px 4px; font-size: 11px; text-transform: uppercase;\n letter-spacing: 0.04em; color: var(--mj-text-muted);\n }\n .mj-cv-agent-picker__item {\n display: flex; align-items: center; gap: 8px; width: 100%;\n padding: 6px 12px; background: transparent; border: none; cursor: pointer;\n color: var(--mj-text-primary); font-size: 13px; text-align: left;\n }\n .mj-cv-agent-picker__item i { width: 14px; text-align: center; color: var(--mj-text-secondary); }\n .mj-cv-agent-picker__item:hover { background: var(--mj-bg-surface-hover); }\n .mj-cv-agent-picker__item--selected { background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent); }\n .mj-cv-agent-picker__item--selected i { color: var(--mj-brand-primary); }\n .mj-cv-agent-picker__empty { padding: 8px 12px; font-size: 12px; color: var(--mj-text-muted); }\n `]\n})\nexport class ConversationAgentPickerComponent implements OnInit {\n /** The conversation whose `DefaultAgentID` this widget edits. */\n @Input() Conversation: MJConversationEntity | null = null;\n\n /** Required for the Save() audit context. */\n @Input() CurrentUser: UserInfo | null = null;\n\n /** Disable the picker (e.g. read-only conversation). */\n @Input() Disabled: boolean = false;\n\n /**\n * The agents the chat allows (the chat area's `AllowedAgentIDs`). Only these can be pinned.\n * Null (the default) offers every eligible agent.\n */\n @Input()\n set AllowedAgentIDs(value: readonly string[] | null) {\n this._allowedAgentIDs = value ?? null;\n this.applyAllowedAgents();\n }\n get AllowedAgentIDs(): readonly string[] | null {\n return this._allowedAgentIDs;\n }\n\n /** Emitted after a successful save with the new (or null) agent ID. */\n @Output() AgentChanged = new EventEmitter<string | null>();\n\n public IsOpen = false;\n public EligibleAgents: MJAIAgentEntityExtended[] = [];\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly notifications = inject(MJNotificationService);\n private _allowedAgentIDs: readonly string[] | null = null;\n /** Every top-level, active agent, before the allowed list narrows it. */\n private catalogAgents: MJAIAgentEntityExtended[] = [];\n\n public async ngOnInit(): Promise<void> {\n try {\n // AIEngineBase is the live, cached agent catalog. Ensure it's\n // loaded — most app shells warm it up at boot, but the picker\n // could mount before that completes.\n await AIEngineBase.Instance.Config(false);\n this.catalogAgents = (AIEngineBase.Instance.Agents ?? [])\n .filter(a =>\n !a.ParentID &&\n a.Status === 'Active' &&\n a.InvocationMode !== 'Sub-Agent'\n )\n .sort((a, b) => (a.Name ?? '').localeCompare(b.Name ?? ''));\n this.applyAllowedAgents();\n } catch (err) {\n LogError(`ConversationAgentPicker.ngOnInit: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n /** Narrows the catalog to the allowed agents. */\n private applyAllowedAgents(): void {\n this.EligibleAgents = this.catalogAgents.filter(a => IsAgentAllowed(a.ID, this._allowedAgentIDs));\n this.cdr.markForCheck();\n }\n\n public get CurrentAgentLabel(): string {\n const id = this.Conversation?.DefaultAgentID;\n if (!id) return 'Auto';\n const match = this.EligibleAgents.find(a => UUIDsEqual(a.ID, id));\n // If the pinned agent is no longer eligible (deactivated, demoted to\n // sub-agent), still surface its name from the cache so the user can\n // see what was pinned even though they can't re-pin it.\n const fromCache = match\n ?? (AIEngineBase.Instance.Agents ?? []).find(a => UUIDsEqual(a.ID, id));\n return fromCache?.Name ?? 'Pinned agent';\n }\n\n public get ButtonTitle(): string {\n return this.Conversation?.DefaultAgentID\n ? `This conversation routes to ${this.CurrentAgentLabel}. Click to change.`\n : 'No agent pinned — messages route via the standard rules. Click to pin an agent.';\n }\n\n public IconClassFor(agent: MJAIAgentEntityExtended): string {\n return agent.IconClass?.trim() || 'fa-solid fa-robot';\n }\n\n public IsSelected(agent: MJAIAgentEntityExtended): boolean {\n return !!this.Conversation?.DefaultAgentID\n && UUIDsEqual(agent.ID, this.Conversation.DefaultAgentID);\n }\n\n public Toggle(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Disabled || !this.Conversation) return;\n this.IsOpen = !this.IsOpen;\n this.cdr.markForCheck();\n }\n\n public async PickAgent(agent: MJAIAgentEntityExtended | null): Promise<void> {\n this.IsOpen = false;\n const conv = this.Conversation;\n if (!conv) return;\n const newId = agent?.ID ?? null;\n if (conv.DefaultAgentID === newId) {\n this.cdr.markForCheck();\n return;\n }\n const prev = conv.DefaultAgentID;\n conv.DefaultAgentID = newId;\n try {\n const saved = await conv.Save();\n if (!saved) {\n conv.DefaultAgentID = prev;\n this.notifications.CreateSimpleNotification(\n conv.LatestResult?.CompleteMessage ?? 'Failed to update conversation default agent.',\n 'error', 4500);\n return;\n }\n this.AgentChanged.emit(newId);\n } catch (err) {\n conv.DefaultAgentID = prev;\n LogError(`ConversationAgentPicker.PickAgent: ${err instanceof Error ? err.message : String(err)}`);\n } finally {\n this.cdr.markForCheck();\n }\n }\n\n /** Close the menu when the user clicks outside the picker. */\n @HostListener('document:click', ['$event'])\n public OnDocumentClick(_event: MouseEvent): void {\n if (this.IsOpen) {\n this.IsOpen = false;\n this.cdr.markForCheck();\n }\n }\n}\n"]}
@@ -5,6 +5,7 @@ import { MJConversationEntity, MJConversationDetailEntity, MJAIAgentRunEntity, M
5
5
  import { MJAIAgentRunEntityExtended } from "@memberjunction/ai-core-plus";
6
6
  import { UICommandHandlerService } from '../../services/ui-command-handler.service';
7
7
  import { AgentStateService } from '../../services/agent-state.service';
8
+ import { ConversationLivenessDomService } from '../../services/conversation-liveness-dom.service';
8
9
  import { ConversationAgentService } from '../../services/conversation-agent.service';
9
10
  import { ActiveTasksService } from '../../services/active-tasks.service';
10
11
  import { PendingAttachment } from '@memberjunction/ng-composer';
@@ -61,6 +62,7 @@ export interface EmptyStateConfig {
61
62
  export declare const DEFAULT_ARTIFACT_PANE_WIDTH = 40;
62
63
  export declare class ConversationChatAreaComponent extends BaseAngularComponent implements OnInit, OnDestroy, AfterViewChecked {
63
64
  private agentStateService;
65
+ private livenessDom;
64
66
  private conversationAgentService;
65
67
  private activeTasks;
66
68
  private cdr;
@@ -253,6 +255,13 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
253
255
  set allowMessageDelete(value: ConversationChatAreaComponent['AllowMessageDelete']);
254
256
  /** @deprecated Use {@link AllowMessageDelete}. */
255
257
  get allowMessageDelete(): ConversationChatAreaComponent['AllowMessageDelete'];
258
+ /**
259
+ * Host-forced read-only. Hides every composer. A View share
260
+ * ({@link IsReadOnlyView}) with this left false keeps today's disabled composer.
261
+ */
262
+ ReadOnly: boolean;
263
+ /** Banner copy when {@link ReadOnly} is set. Null uses the View-share text. */
264
+ ReadOnlyMessage: string | null;
256
265
  /** Show the empty-state's built-in suggested-prompt chips (and the @mention tip). */
257
266
  ShowSuggestedPrompts: boolean;
258
267
  /** @deprecated Use {@link ShowSuggestedPrompts}. */
@@ -443,6 +452,21 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
443
452
  * True (the default) keeps today's behavior; a host that names its own chats turns it off.
444
453
  */
445
454
  AutoNameConversation: boolean;
455
+ /**
456
+ * Whether an untagged message asks one fast typed decision which agent in the conversation
457
+ * should answer it, instead of always going back to the last agent that answered. It replaces
458
+ * that agent only when the answer is confident and arrives within `DECISION_ROUTING_TIMEOUT_MS`
459
+ * (250 ms). False (the default)
460
+ * changes nothing: no decision call, and today's routing. See
461
+ * `MessageInputComponent.EnableDecisionRouting`.
462
+ *
463
+ * Turning it on sends conversation text to the model behind the `Default Decision` prompt, which
464
+ * can be a different vendor from the agents' own: the first 1,000 characters of the new message,
465
+ * the last 6 turns (150 characters each), each participant's name, description and last reply,
466
+ * and the names of their artifact versions. Each call writes an `MJ: AI Prompt Runs` row, even
467
+ * when the answer comes too late to be used.
468
+ */
469
+ EnableDecisionRouting: boolean;
446
470
  /**
447
471
  * Scope to apply when this surface CREATES a new conversation. Forwarded
448
472
  * to `ConversationEngine.CreateConversation` so the new row's
@@ -987,12 +1011,29 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
987
1011
  * last progress updates must not fire and drag the reader back down.
988
1012
  */
989
1013
  private bottomFollowSuppressedUntil;
1014
+ /**
1015
+ * ReadReplyFromTop while a reply streams: the scroll position the turn's top was last pinned
1016
+ * to, `'declined'` once the reader has moved away (they are then left alone and completion
1017
+ * decides as it always has), null before the turn's first delta. Reset where the turn opens.
1018
+ */
1019
+ private streamAnchor;
1020
+ /**
1021
+ * The turn's first message as rendered, and the clearance above it, resolved once per turn for
1022
+ * the stream pin: both are stable across frames and finding them is a timeline walk plus a
1023
+ * computed style, which is not work for a 60fps path. Re-resolved only if the node leaves the DOM.
1024
+ */
1025
+ private streamPin;
1026
+ private readonly ngZone;
990
1027
  private turnStartRetryHandle;
991
1028
  /** Gap kept between the pane's top edge and the turn's first message. */
992
1029
  private static readonly TURN_TOP_GAP_PX;
993
1030
  private lastLoadedConversationId;
994
1031
  private currentlyLoadingConversationId;
995
1032
  private conversationLoadToken;
1033
+ /** The reconcile passes in progress, shared by every caller that arrives while they run. */
1034
+ private reconcileInFlight;
1035
+ /** Reason for one more reconcile pass, requested while a pass was running. */
1036
+ private reconcileRerunReason;
996
1037
  IsProcessing: boolean;
997
1038
  /** @deprecated Use {@link IsProcessing}. */
998
1039
  get isProcessing(): boolean;
@@ -1460,12 +1501,17 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
1460
1501
  /** @deprecated Use {@link RealtimeOverlayAgentName}. */
1461
1502
  get realtimeOverlayAgentName(): string;
1462
1503
  private mentionAutocompleteService;
1463
- constructor(agentStateService: AgentStateService, conversationAgentService: ConversationAgentService, activeTasks: ActiveTasksService, cdr: ChangeDetectorRef, artifactPermissionService: ArtifactPermissionService, attachmentService: ConversationAttachmentService, streamingService: ConversationStreamingService, confirmDialog: ConversationsDialogService, bridge: ConversationBridgeService, analyzeArtifactService: AnalyzeArtifactService, uiCommandHandler: UICommandHandlerService, interactiveFormApplyService: InteractiveFormApplyService, agentClientService: AgentClientService);
1504
+ constructor(agentStateService: AgentStateService, livenessDom: ConversationLivenessDomService, conversationAgentService: ConversationAgentService, activeTasks: ActiveTasksService, cdr: ChangeDetectorRef, artifactPermissionService: ArtifactPermissionService, attachmentService: ConversationAttachmentService, streamingService: ConversationStreamingService, confirmDialog: ConversationsDialogService, bridge: ConversationBridgeService, analyzeArtifactService: AnalyzeArtifactService, uiCommandHandler: UICommandHandlerService, interactiveFormApplyService: InteractiveFormApplyService, agentClientService: AgentClientService);
1464
1505
  /**
1465
- * Apply a form-role artifact's spec as an EntityFormOverride for the
1466
- * current user. The service handles the Create-vs-Modify decision (based
1467
- * on whether an Active override already exists), confirms via dialog,
1468
- * and surfaces success/failure via notification.
1506
+ * Apply a form-role artifact's spec for the current user — an EntityFormOverride for a
1507
+ * whole form, a form contribution for a panel. The service picks the path, handles the
1508
+ * Create-vs-Modify decision, confirms via dialog, and notifies.
1509
+ *
1510
+ * The agent context names the record form the user has open (`AdditionalContext.Form`,
1511
+ * published by the record tab). The service reads that form's full composition from the
1512
+ * `FormCompositionRegistry`, to check a panel's placement against the live form and detect
1513
+ * an installed contribution holding the same key. With no open form it asks the server for
1514
+ * the composition instead.
1469
1515
  */
1470
1516
  OnApplyFormRequested(event: {
1471
1517
  spec: unknown;
@@ -1597,6 +1643,18 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
1597
1643
  * Restoring them here causes duplicate "Agent Processing..." entries.
1598
1644
  */
1599
1645
  private restoreActiveTasks;
1646
+ /**
1647
+ * A streamed delta landed on an in-progress message (MessageInputComponent.MessageStreamed).
1648
+ * Unlike {@link OnMessageSent} this does not replace the `messages` array: that rebuilt the
1649
+ * whole timeline, re-measured the mounted range and armed a scroll-to-bottom timer on every
1650
+ * delta, which is what made a streaming reply flash and jump. The bubble is refreshed in place
1651
+ * and the viewport is kept steady. With `ReadReplyFromTop` the turn lands at its top once, on
1652
+ * the first delta, and the reply grows beneath it; otherwise the bottom is pinned in the same
1653
+ * frame as the DOM update, so the growth and the scroll paint together.
1654
+ */
1655
+ OnMessageStreamed(message: MJConversationDetailEntity): void;
1656
+ /** Drops a landing still queued or retrying, so it cannot resolve after a newer one. */
1657
+ private cancelPendingLanding;
1600
1658
  OnMessageSent(message: MJConversationDetailEntity): Promise<void>;
1601
1659
  /** @deprecated Use {@link OnMessageSent}. */
1602
1660
  onMessageSent(message: MJConversationDetailEntity): Promise<void>;
@@ -1688,6 +1746,8 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
1688
1746
  * Called when agent completion is detected to discover newly delegated agent messages.
1689
1747
  */
1690
1748
  private reloadMessagesForActiveConversation;
1749
+ /** Detail ids whose completion this instance has already applied. A live callback and the replay window can both deliver one finish. */
1750
+ private handledCompletionIds?;
1691
1751
  /**
1692
1752
  * Handle message completion triggered by PubSub completion event
1693
1753
  * Reloads message, agent run, and artifacts, then updates UI
@@ -1879,6 +1939,8 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
1879
1939
  get IsReadOnlyView(): boolean;
1880
1940
  /** @deprecated Use {@link IsReadOnlyView}. */
1881
1941
  get isReadOnlyView(): boolean;
1942
+ /** Read-only for any reason: the host said so, or the conversation is shared with View access. */
1943
+ get EffectiveReadOnly(): boolean;
1882
1944
  /**
1883
1945
  * `true` when the current user is allowed to create new shares on this
1884
1946
  * conversation: the owner, or a user with an Owner-level grant. Uses the same
@@ -2195,6 +2257,15 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
2195
2257
  OnReviewClosed(): void;
2196
2258
  /** @deprecated Use {@link OnReviewClosed}. */
2197
2259
  onReviewClosed(): void;
2260
+ /**
2261
+ * A message reports that its run has gone quiet (MJ #4222).
2262
+ *
2263
+ * The reconciliation triggers all fire on transport events — a socket retry, a tab regaining
2264
+ * focus. This one fires on the symptom itself: a run that simply stopped reporting, with no event
2265
+ * anywhere to notice it. Each pass covers every in-progress message, so the request goes through
2266
+ * the runtime's coalescing trigger: quiet rows asking at about the same time share one pass.
2267
+ */
2268
+ OnLivenessCheckRequested(messageId: string): void;
2198
2269
  /**
2199
2270
  * Handles Shift+Click on an AI message bubble.
2200
2271
  * Dumps a live snapshot of in-memory streaming and agent-run state to the browser
@@ -2379,6 +2450,16 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
2379
2450
  */
2380
2451
  private followTranscript;
2381
2452
  private isSettled;
2453
+ /**
2454
+ * Where the viewport goes on a streamed delta, in the same frame as the DOM change so growth and
2455
+ * scroll paint together. Without ReadReplyFromTop, or for a turn this component never saw open
2456
+ * (a reload mid-stream), a reader at the bottom is followed there. With it, the turn's top is
2457
+ * pinned as high as the content allows on every frame: the question rises to the top as the
2458
+ * reply grows beneath it, and once the reader scrolls away the pin is released for the turn.
2459
+ */
2460
+ private followStream;
2461
+ /** The stream pin's target and clearance for this turn, resolved once and kept while the node is in the DOM. */
2462
+ private resolveStreamPin;
2382
2463
  /**
2383
2464
  * readReplyFromTop: once the reply has rendered, scrolls the turn so its first message
2384
2465
  * sits at the top of the pane — but only if the turn is taller than the pane. A turn that
@@ -2407,6 +2488,65 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
2407
2488
  * completed successfully, we detect the mismatch and correct it. This prevents
2408
2489
  * the race condition where the client overwrites a server-completed record.
2409
2490
  */
2491
+ /**
2492
+ * Re-read the agent-run rows backing this conversation's in-progress messages, refreshing
2493
+ * {@link AgentRunsByDetailId} in place.
2494
+ *
2495
+ * REQUIRED BEFORE ANY ON-DEMAND RECONCILE. {@link reconnectInProgressRuns} compares against
2496
+ * the in-memory map and never reloads it; on the conversation-load path that is safe only
2497
+ * because `loadPeripheralData` ran moments earlier off a fresh fetch. Invoked from a socket
2498
+ * reconnect or a tab regaining focus there has been no such fetch, so the map still holds the
2499
+ * stale `Running` status the outage froze it at — and the reconcile silently finds nothing to
2500
+ * do, which is indistinguishable from working (MJ #4222).
2501
+ *
2502
+ * Deliberately narrow in rows: only the in-progress details, with `BypassCache` because the
2503
+ * server wrote these rows through a different provider. Cheaper than
2504
+ * `windowStore.RefreshLatest()`, and cheap enough to run on every trigger. Full entity rows are
2505
+ * read, not a few fields: each row replaces the run object the message renders from and that the
2506
+ * completion path reloads, so a partial row would blank the run's duration, tokens and cost.
2507
+ */
2508
+ private refreshAgentRunsForInProgress;
2509
+ /**
2510
+ * Reconcile in-progress messages against durable server state, on demand.
2511
+ *
2512
+ * This is the recovery path for the case the five close-event-driven mechanisms all miss: a
2513
+ * completion published while the client's transport was silently dead. Tier 0 makes the socket
2514
+ * close; this is what recovers the event that was dropped while it was down.
2515
+ *
2516
+ * Only one pass runs at a time. A request that arrives during a pass shares it and schedules one
2517
+ * follow-up pass, so every caller resolves after a pass that started after its request.
2518
+ *
2519
+ * @param reason What prompted it — carried only for logging.
2520
+ */
2521
+ ReconcileNow(reason: string): Promise<void>;
2522
+ /** Runs passes until no caller has asked for another. Clears the in-flight marker on exit. */
2523
+ private runReconcilePasses;
2524
+ /** One reconcile pass over the in-progress messages of the active conversation. */
2525
+ private reconcileOnce;
2526
+ /**
2527
+ * Ask the durable read model whether a message we still show as in-progress has in fact finished.
2528
+ *
2529
+ * The last gap in the recovery chain. Everything else here reads `MJ: AI Agent Runs` through the
2530
+ * client's own provider; when that returns nothing the message simply waits. The tail query reads
2531
+ * the same truth server-side from a cursor, reports the conversation detail's own status, and runs
2532
+ * over HTTP — so it answers while the WebSocket is still down, which is the whole point.
2533
+ *
2534
+ * Completion is routed through the existing {@link handleMessageCompletion}, never written here:
2535
+ * four writers already move a message out of In-Progress and a fifth would race them.
2536
+ *
2537
+ * @returns true when the message was completed from durable state.
2538
+ */
2539
+ private tryRecoverFromTail;
2540
+ /**
2541
+ * Complete a message from the run list alone. Used only when the tail call fails.
2542
+ *
2543
+ * Less precise than the tail: it cannot see the conversation detail's own status, so during the
2544
+ * orphan window it reloads the message without settling it. That was the behavior before the
2545
+ * tail existed, and it is better than leaving a finished message spinning.
2546
+ *
2547
+ * @returns true when the message was completed.
2548
+ */
2549
+ private recoverFromRunList;
2410
2550
  private detectAndReconcileAgentRuns;
2411
2551
  /**
2412
2552
  * Reconnect to in-progress agent runs whose completion events were missed.
@@ -2449,6 +2589,6 @@ export declare class ConversationChatAreaComponent extends BaseAngularComponent
2449
2589
  conversationId: string;
2450
2590
  }): void;
2451
2591
  static ɵfac: i0.ɵɵFactoryDeclaration<ConversationChatAreaComponent, never>;
2452
- static ɵcmp: i0.ɵɵComponentDeclaration<ConversationChatAreaComponent, "mj-conversation-chat-area", never, { "EnvironmentId": { "alias": "EnvironmentId"; "required": false; }; "environmentId": { "alias": "environmentId"; "required": false; }; "CurrentUser": { "alias": "CurrentUser"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "ConversationId": { "alias": "ConversationId"; "required": false; }; "conversationId": { "alias": "conversationId"; "required": false; }; "Conversation": { "alias": "Conversation"; "required": false; }; "conversation": { "alias": "conversation"; "required": false; }; "ThreadId": { "alias": "ThreadId"; "required": false; }; "threadId": { "alias": "threadId"; "required": false; }; "SuppressNewConversationEmptyState": { "alias": "SuppressNewConversationEmptyState"; "required": false; }; "suppressNewConversationEmptyState": { "alias": "suppressNewConversationEmptyState"; "required": false; }; "AllowMentions": { "alias": "AllowMentions"; "required": false; }; "allowMentions": { "alias": "allowMentions"; "required": false; }; "AllowAgentMentions": { "alias": "AllowAgentMentions"; "required": false; }; "allowAgentMentions": { "alias": "allowAgentMentions"; "required": false; }; "AllowEntityMentions": { "alias": "AllowEntityMentions"; "required": false; }; "allowEntityMentions": { "alias": "allowEntityMentions"; "required": false; }; "AllowSkillCommands": { "alias": "AllowSkillCommands"; "required": false; }; "allowSkillCommands": { "alias": "allowSkillCommands"; "required": false; }; "AllowAttachments": { "alias": "AllowAttachments"; "required": false; }; "allowAttachments": { "alias": "allowAttachments"; "required": false; }; "AllowPlanMode": { "alias": "AllowPlanMode"; "required": false; }; "allowPlanMode": { "alias": "allowPlanMode"; "required": false; }; "AllowRealtime": { "alias": "AllowRealtime"; "required": false; }; "allowRealtime": { "alias": "allowRealtime"; "required": false; }; "ShowEmptyFill": { "alias": "ShowEmptyFill"; "required": false; }; "showEmptyFill": { "alias": "showEmptyFill"; "required": false; }; "ShowLoadingState": { "alias": "ShowLoadingState"; "required": false; }; "showLoadingState": { "alias": "showLoadingState"; "required": false; }; "ReadReplyFromTop": { "alias": "ReadReplyFromTop"; "required": false; }; "readReplyFromTop": { "alias": "readReplyFromTop"; "required": false; }; "ShowAgentRunDetails": { "alias": "ShowAgentRunDetails"; "required": false; }; "showAgentRunDetails": { "alias": "showAgentRunDetails"; "required": false; }; "ShowReactions": { "alias": "ShowReactions"; "required": false; }; "showReactions": { "alias": "showReactions"; "required": false; }; "ShowMessageRating": { "alias": "ShowMessageRating"; "required": false; }; "showMessageRating": { "alias": "showMessageRating"; "required": false; }; "AllowPinning": { "alias": "AllowPinning"; "required": false; }; "allowPinning": { "alias": "allowPinning"; "required": false; }; "AllowMessageEdit": { "alias": "AllowMessageEdit"; "required": false; }; "allowMessageEdit": { "alias": "allowMessageEdit"; "required": false; }; "AllowMessageDelete": { "alias": "AllowMessageDelete"; "required": false; }; "allowMessageDelete": { "alias": "allowMessageDelete"; "required": false; }; "ShowSuggestedPrompts": { "alias": "ShowSuggestedPrompts"; "required": false; }; "showSuggestedPrompts": { "alias": "showSuggestedPrompts"; "required": false; }; "ShowDateNavigation": { "alias": "ShowDateNavigation"; "required": false; }; "showDateNavigation": { "alias": "showDateNavigation"; "required": false; }; "AssistantDisplayName": { "alias": "AssistantDisplayName"; "required": false; }; "assistantDisplayName": { "alias": "assistantDisplayName"; "required": false; }; "AssistantAvatarUrl": { "alias": "AssistantAvatarUrl"; "required": false; }; "assistantAvatarUrl": { "alias": "assistantAvatarUrl"; "required": false; }; "IsNewConversation": { "alias": "IsNewConversation"; "required": false; }; "isNewConversation": { "alias": "isNewConversation"; "required": false; }; "PendingMessage": { "alias": "PendingMessage"; "required": false; }; "pendingMessage": { "alias": "pendingMessage"; "required": false; }; "PendingMessageConversationId": { "alias": "PendingMessageConversationId"; "required": false; }; "pendingMessageConversationId": { "alias": "pendingMessageConversationId"; "required": false; }; "PendingAttachments": { "alias": "PendingAttachments"; "required": false; }; "pendingAttachments": { "alias": "pendingAttachments"; "required": false; }; "PendingArtifactId": { "alias": "PendingArtifactId"; "required": false; }; "pendingArtifactId": { "alias": "pendingArtifactId"; "required": false; }; "PendingArtifactVersionNumber": { "alias": "PendingArtifactVersionNumber"; "required": false; }; "pendingArtifactVersionNumber": { "alias": "pendingArtifactVersionNumber"; "required": false; }; "PendingArtifactConversationId": { "alias": "PendingArtifactConversationId"; "required": false; }; "pendingArtifactConversationId": { "alias": "pendingArtifactConversationId"; "required": false; }; "OverlayMode": { "alias": "OverlayMode"; "required": false; }; "overlayMode": { "alias": "overlayMode"; "required": false; }; "ShowExportButton": { "alias": "ShowExportButton"; "required": false; }; "showExportButton": { "alias": "showExportButton"; "required": false; }; "ExportButtonLabel": { "alias": "ExportButtonLabel"; "required": false; }; "exportButtonLabel": { "alias": "exportButtonLabel"; "required": false; }; "ExportButtonIcon": { "alias": "ExportButtonIcon"; "required": false; }; "exportButtonIcon": { "alias": "exportButtonIcon"; "required": false; }; "ExportBranding": { "alias": "ExportBranding"; "required": false; }; "exportBranding": { "alias": "exportBranding"; "required": false; }; "ShowShareButton": { "alias": "ShowShareButton"; "required": false; }; "showShareButton": { "alias": "showShareButton"; "required": false; }; "ShowArtifactIndicator": { "alias": "ShowArtifactIndicator"; "required": false; }; "showArtifactIndicator": { "alias": "showArtifactIndicator"; "required": false; }; "AppContext": { "alias": "AppContext"; "required": false; }; "appContext": { "alias": "appContext"; "required": false; }; "DefaultAgentId": { "alias": "DefaultAgentId"; "required": false; }; "defaultAgentId": { "alias": "defaultAgentId"; "required": false; }; "AgentReplyMode": { "alias": "AgentReplyMode"; "required": false; }; "AllowedAgentIDs": { "alias": "AllowedAgentIDs"; "required": false; }; "MentionPeople": { "alias": "MentionPeople"; "required": false; }; "AgentHistoryFrom": { "alias": "AgentHistoryFrom"; "required": false; }; "AgentTurnHandler": { "alias": "AgentTurnHandler"; "required": false; }; "AutoNameConversation": { "alias": "AutoNameConversation"; "required": false; }; "ApplicationScope": { "alias": "ApplicationScope"; "required": false; }; "applicationScope": { "alias": "applicationScope"; "required": false; }; "ApplicationId": { "alias": "ApplicationId"; "required": false; }; "applicationId": { "alias": "applicationId"; "required": false; }; "LinkedEntityId": { "alias": "LinkedEntityId"; "required": false; }; "linkedEntityId": { "alias": "linkedEntityId"; "required": false; }; "LinkedRecordId": { "alias": "LinkedRecordId"; "required": false; }; "linkedRecordId": { "alias": "linkedRecordId"; "required": false; }; "ShowAgentPicker": { "alias": "ShowAgentPicker"; "required": false; }; "showAgentPicker": { "alias": "showAgentPicker"; "required": false; }; "ShowAgentModePicker": { "alias": "ShowAgentModePicker"; "required": false; }; "showAgentModePicker": { "alias": "showAgentModePicker"; "required": false; }; "EmptyStateGreeting": { "alias": "EmptyStateGreeting"; "required": false; }; "emptyStateGreeting": { "alias": "emptyStateGreeting"; "required": false; }; "ShowSidebarToggle": { "alias": "ShowSidebarToggle"; "required": false; }; "showSidebarToggle": { "alias": "showSidebarToggle"; "required": false; }; "ShowAgentCharacter": { "alias": "ShowAgentCharacter"; "required": false; }; "showAgentCharacter": { "alias": "showAgentCharacter"; "required": false; }; "AgentCharacterConfig": { "alias": "AgentCharacterConfig"; "required": false; }; "agentCharacterConfig": { "alias": "agentCharacterConfig"; "required": false; }; "EmptyStateConfig": { "alias": "EmptyStateConfig"; "required": false; }; "emptyStateConfig": { "alias": "emptyStateConfig"; "required": false; }; "ShowDemonstrationSurface": { "alias": "ShowDemonstrationSurface"; "required": false; }; "showDemonstrationSurface": { "alias": "showDemonstrationSurface"; "required": false; }; "DemonstrationSurfaceContent": { "alias": "DemonstrationSurfaceContent"; "required": false; }; "demonstrationSurfaceContent": { "alias": "demonstrationSurfaceContent"; "required": false; }; "ComposerDraft": { "alias": "ComposerDraft"; "required": false; }; "composerDraft": { "alias": "composerDraft"; "required": false; }; "ComposerAgentMention": { "alias": "ComposerAgentMention"; "required": false; }; "composerAgentMention": { "alias": "composerAgentMention"; "required": false; }; }, { "BeforeAgentTurn": "BeforeAgentTurn"; "beforeAgentTurn": "beforeAgentTurn"; "AfterAgentTurn": "AfterAgentTurn"; "afterAgentTurn": "afterAgentTurn"; "BeforeToolInvoked": "BeforeToolInvoked"; "beforeToolInvoked": "beforeToolInvoked"; "AfterToolInvoked": "AfterToolInvoked"; "afterToolInvoked": "afterToolInvoked"; "BeforeResponseFormSubmitted": "BeforeResponseFormSubmitted"; "beforeResponseFormSubmitted": "beforeResponseFormSubmitted"; "AfterResponseFormSubmitted": "AfterResponseFormSubmitted"; "afterResponseFormSubmitted": "afterResponseFormSubmitted"; "SessionStarted": "SessionStarted"; "sessionStarted": "sessionStarted"; "SessionChannelStateChanged": "SessionChannelStateChanged"; "sessionChannelStateChanged": "sessionChannelStateChanged"; "SessionEnded": "SessionEnded"; "sessionEnded": "sessionEnded"; "ConversationRenamed": "ConversationRenamed"; "conversationRenamed": "conversationRenamed"; "OpenEntityRecord": "OpenEntityRecord"; "openEntityRecord": "openEntityRecord"; "RealtimeConversationReady": "RealtimeConversationReady"; "realtimeConversationReady": "realtimeConversationReady"; "navigationRequest": "navigationRequest"; "TaskClicked": "TaskClicked"; "taskClicked": "taskClicked"; "ArtifactLinkClicked": "ArtifactLinkClicked"; "artifactLinkClicked": "artifactLinkClicked"; "SidebarToggleClicked": "SidebarToggleClicked"; "sidebarToggleClicked": "sidebarToggleClicked"; "ConversationCreated": "ConversationCreated"; "conversationCreated": "conversationCreated"; "ThreadOpened": "ThreadOpened"; "threadOpened": "threadOpened"; "ThreadClosed": "ThreadClosed"; "threadClosed": "threadClosed"; "PendingArtifactConsumed": "PendingArtifactConsumed"; "pendingArtifactConsumed": "pendingArtifactConsumed"; "PendingMessageConsumed": "PendingMessageConsumed"; "pendingMessageConsumed": "pendingMessageConsumed"; "PendingMessageRequested": "PendingMessageRequested"; "pendingMessageRequested": "pendingMessageRequested"; "ComposerDraftConsumed": "ComposerDraftConsumed"; "composerDraftConsumed": "composerDraftConsumed"; "ComposerAgentMentionConsumed": "ComposerAgentMentionConsumed"; "composerAgentMentionConsumed": "composerAgentMentionConsumed"; }, ["chatSlotChildren"], never, false, never>;
2592
+ static ɵcmp: i0.ɵɵComponentDeclaration<ConversationChatAreaComponent, "mj-conversation-chat-area", never, { "EnvironmentId": { "alias": "EnvironmentId"; "required": false; }; "environmentId": { "alias": "environmentId"; "required": false; }; "CurrentUser": { "alias": "CurrentUser"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "ConversationId": { "alias": "ConversationId"; "required": false; }; "conversationId": { "alias": "conversationId"; "required": false; }; "Conversation": { "alias": "Conversation"; "required": false; }; "conversation": { "alias": "conversation"; "required": false; }; "ThreadId": { "alias": "ThreadId"; "required": false; }; "threadId": { "alias": "threadId"; "required": false; }; "SuppressNewConversationEmptyState": { "alias": "SuppressNewConversationEmptyState"; "required": false; }; "suppressNewConversationEmptyState": { "alias": "suppressNewConversationEmptyState"; "required": false; }; "AllowMentions": { "alias": "AllowMentions"; "required": false; }; "allowMentions": { "alias": "allowMentions"; "required": false; }; "AllowAgentMentions": { "alias": "AllowAgentMentions"; "required": false; }; "allowAgentMentions": { "alias": "allowAgentMentions"; "required": false; }; "AllowEntityMentions": { "alias": "AllowEntityMentions"; "required": false; }; "allowEntityMentions": { "alias": "allowEntityMentions"; "required": false; }; "AllowSkillCommands": { "alias": "AllowSkillCommands"; "required": false; }; "allowSkillCommands": { "alias": "allowSkillCommands"; "required": false; }; "AllowAttachments": { "alias": "AllowAttachments"; "required": false; }; "allowAttachments": { "alias": "allowAttachments"; "required": false; }; "AllowPlanMode": { "alias": "AllowPlanMode"; "required": false; }; "allowPlanMode": { "alias": "allowPlanMode"; "required": false; }; "AllowRealtime": { "alias": "AllowRealtime"; "required": false; }; "allowRealtime": { "alias": "allowRealtime"; "required": false; }; "ShowEmptyFill": { "alias": "ShowEmptyFill"; "required": false; }; "showEmptyFill": { "alias": "showEmptyFill"; "required": false; }; "ShowLoadingState": { "alias": "ShowLoadingState"; "required": false; }; "showLoadingState": { "alias": "showLoadingState"; "required": false; }; "ReadReplyFromTop": { "alias": "ReadReplyFromTop"; "required": false; }; "readReplyFromTop": { "alias": "readReplyFromTop"; "required": false; }; "ShowAgentRunDetails": { "alias": "ShowAgentRunDetails"; "required": false; }; "showAgentRunDetails": { "alias": "showAgentRunDetails"; "required": false; }; "ShowReactions": { "alias": "ShowReactions"; "required": false; }; "showReactions": { "alias": "showReactions"; "required": false; }; "ShowMessageRating": { "alias": "ShowMessageRating"; "required": false; }; "showMessageRating": { "alias": "showMessageRating"; "required": false; }; "AllowPinning": { "alias": "AllowPinning"; "required": false; }; "allowPinning": { "alias": "allowPinning"; "required": false; }; "AllowMessageEdit": { "alias": "AllowMessageEdit"; "required": false; }; "allowMessageEdit": { "alias": "allowMessageEdit"; "required": false; }; "AllowMessageDelete": { "alias": "AllowMessageDelete"; "required": false; }; "allowMessageDelete": { "alias": "allowMessageDelete"; "required": false; }; "ReadOnly": { "alias": "ReadOnly"; "required": false; }; "ReadOnlyMessage": { "alias": "ReadOnlyMessage"; "required": false; }; "ShowSuggestedPrompts": { "alias": "ShowSuggestedPrompts"; "required": false; }; "showSuggestedPrompts": { "alias": "showSuggestedPrompts"; "required": false; }; "ShowDateNavigation": { "alias": "ShowDateNavigation"; "required": false; }; "showDateNavigation": { "alias": "showDateNavigation"; "required": false; }; "AssistantDisplayName": { "alias": "AssistantDisplayName"; "required": false; }; "assistantDisplayName": { "alias": "assistantDisplayName"; "required": false; }; "AssistantAvatarUrl": { "alias": "AssistantAvatarUrl"; "required": false; }; "assistantAvatarUrl": { "alias": "assistantAvatarUrl"; "required": false; }; "IsNewConversation": { "alias": "IsNewConversation"; "required": false; }; "isNewConversation": { "alias": "isNewConversation"; "required": false; }; "PendingMessage": { "alias": "PendingMessage"; "required": false; }; "pendingMessage": { "alias": "pendingMessage"; "required": false; }; "PendingMessageConversationId": { "alias": "PendingMessageConversationId"; "required": false; }; "pendingMessageConversationId": { "alias": "pendingMessageConversationId"; "required": false; }; "PendingAttachments": { "alias": "PendingAttachments"; "required": false; }; "pendingAttachments": { "alias": "pendingAttachments"; "required": false; }; "PendingArtifactId": { "alias": "PendingArtifactId"; "required": false; }; "pendingArtifactId": { "alias": "pendingArtifactId"; "required": false; }; "PendingArtifactVersionNumber": { "alias": "PendingArtifactVersionNumber"; "required": false; }; "pendingArtifactVersionNumber": { "alias": "pendingArtifactVersionNumber"; "required": false; }; "PendingArtifactConversationId": { "alias": "PendingArtifactConversationId"; "required": false; }; "pendingArtifactConversationId": { "alias": "pendingArtifactConversationId"; "required": false; }; "OverlayMode": { "alias": "OverlayMode"; "required": false; }; "overlayMode": { "alias": "overlayMode"; "required": false; }; "ShowExportButton": { "alias": "ShowExportButton"; "required": false; }; "showExportButton": { "alias": "showExportButton"; "required": false; }; "ExportButtonLabel": { "alias": "ExportButtonLabel"; "required": false; }; "exportButtonLabel": { "alias": "exportButtonLabel"; "required": false; }; "ExportButtonIcon": { "alias": "ExportButtonIcon"; "required": false; }; "exportButtonIcon": { "alias": "exportButtonIcon"; "required": false; }; "ExportBranding": { "alias": "ExportBranding"; "required": false; }; "exportBranding": { "alias": "exportBranding"; "required": false; }; "ShowShareButton": { "alias": "ShowShareButton"; "required": false; }; "showShareButton": { "alias": "showShareButton"; "required": false; }; "ShowArtifactIndicator": { "alias": "ShowArtifactIndicator"; "required": false; }; "showArtifactIndicator": { "alias": "showArtifactIndicator"; "required": false; }; "AppContext": { "alias": "AppContext"; "required": false; }; "appContext": { "alias": "appContext"; "required": false; }; "DefaultAgentId": { "alias": "DefaultAgentId"; "required": false; }; "defaultAgentId": { "alias": "defaultAgentId"; "required": false; }; "AgentReplyMode": { "alias": "AgentReplyMode"; "required": false; }; "AllowedAgentIDs": { "alias": "AllowedAgentIDs"; "required": false; }; "MentionPeople": { "alias": "MentionPeople"; "required": false; }; "AgentHistoryFrom": { "alias": "AgentHistoryFrom"; "required": false; }; "AgentTurnHandler": { "alias": "AgentTurnHandler"; "required": false; }; "AutoNameConversation": { "alias": "AutoNameConversation"; "required": false; }; "EnableDecisionRouting": { "alias": "EnableDecisionRouting"; "required": false; }; "ApplicationScope": { "alias": "ApplicationScope"; "required": false; }; "applicationScope": { "alias": "applicationScope"; "required": false; }; "ApplicationId": { "alias": "ApplicationId"; "required": false; }; "applicationId": { "alias": "applicationId"; "required": false; }; "LinkedEntityId": { "alias": "LinkedEntityId"; "required": false; }; "linkedEntityId": { "alias": "linkedEntityId"; "required": false; }; "LinkedRecordId": { "alias": "LinkedRecordId"; "required": false; }; "linkedRecordId": { "alias": "linkedRecordId"; "required": false; }; "ShowAgentPicker": { "alias": "ShowAgentPicker"; "required": false; }; "showAgentPicker": { "alias": "showAgentPicker"; "required": false; }; "ShowAgentModePicker": { "alias": "ShowAgentModePicker"; "required": false; }; "showAgentModePicker": { "alias": "showAgentModePicker"; "required": false; }; "EmptyStateGreeting": { "alias": "EmptyStateGreeting"; "required": false; }; "emptyStateGreeting": { "alias": "emptyStateGreeting"; "required": false; }; "ShowSidebarToggle": { "alias": "ShowSidebarToggle"; "required": false; }; "showSidebarToggle": { "alias": "showSidebarToggle"; "required": false; }; "ShowAgentCharacter": { "alias": "ShowAgentCharacter"; "required": false; }; "showAgentCharacter": { "alias": "showAgentCharacter"; "required": false; }; "AgentCharacterConfig": { "alias": "AgentCharacterConfig"; "required": false; }; "agentCharacterConfig": { "alias": "agentCharacterConfig"; "required": false; }; "EmptyStateConfig": { "alias": "EmptyStateConfig"; "required": false; }; "emptyStateConfig": { "alias": "emptyStateConfig"; "required": false; }; "ShowDemonstrationSurface": { "alias": "ShowDemonstrationSurface"; "required": false; }; "showDemonstrationSurface": { "alias": "showDemonstrationSurface"; "required": false; }; "DemonstrationSurfaceContent": { "alias": "DemonstrationSurfaceContent"; "required": false; }; "demonstrationSurfaceContent": { "alias": "demonstrationSurfaceContent"; "required": false; }; "ComposerDraft": { "alias": "ComposerDraft"; "required": false; }; "composerDraft": { "alias": "composerDraft"; "required": false; }; "ComposerAgentMention": { "alias": "ComposerAgentMention"; "required": false; }; "composerAgentMention": { "alias": "composerAgentMention"; "required": false; }; }, { "BeforeAgentTurn": "BeforeAgentTurn"; "beforeAgentTurn": "beforeAgentTurn"; "AfterAgentTurn": "AfterAgentTurn"; "afterAgentTurn": "afterAgentTurn"; "BeforeToolInvoked": "BeforeToolInvoked"; "beforeToolInvoked": "beforeToolInvoked"; "AfterToolInvoked": "AfterToolInvoked"; "afterToolInvoked": "afterToolInvoked"; "BeforeResponseFormSubmitted": "BeforeResponseFormSubmitted"; "beforeResponseFormSubmitted": "beforeResponseFormSubmitted"; "AfterResponseFormSubmitted": "AfterResponseFormSubmitted"; "afterResponseFormSubmitted": "afterResponseFormSubmitted"; "SessionStarted": "SessionStarted"; "sessionStarted": "sessionStarted"; "SessionChannelStateChanged": "SessionChannelStateChanged"; "sessionChannelStateChanged": "sessionChannelStateChanged"; "SessionEnded": "SessionEnded"; "sessionEnded": "sessionEnded"; "ConversationRenamed": "ConversationRenamed"; "conversationRenamed": "conversationRenamed"; "OpenEntityRecord": "OpenEntityRecord"; "openEntityRecord": "openEntityRecord"; "RealtimeConversationReady": "RealtimeConversationReady"; "realtimeConversationReady": "realtimeConversationReady"; "navigationRequest": "navigationRequest"; "TaskClicked": "TaskClicked"; "taskClicked": "taskClicked"; "ArtifactLinkClicked": "ArtifactLinkClicked"; "artifactLinkClicked": "artifactLinkClicked"; "SidebarToggleClicked": "SidebarToggleClicked"; "sidebarToggleClicked": "sidebarToggleClicked"; "ConversationCreated": "ConversationCreated"; "conversationCreated": "conversationCreated"; "ThreadOpened": "ThreadOpened"; "threadOpened": "threadOpened"; "ThreadClosed": "ThreadClosed"; "threadClosed": "threadClosed"; "PendingArtifactConsumed": "PendingArtifactConsumed"; "pendingArtifactConsumed": "pendingArtifactConsumed"; "PendingMessageConsumed": "PendingMessageConsumed"; "pendingMessageConsumed": "pendingMessageConsumed"; "PendingMessageRequested": "PendingMessageRequested"; "pendingMessageRequested": "pendingMessageRequested"; "ComposerDraftConsumed": "ComposerDraftConsumed"; "composerDraftConsumed": "composerDraftConsumed"; "ComposerAgentMentionConsumed": "ComposerAgentMentionConsumed"; "composerAgentMentionConsumed": "composerAgentMentionConsumed"; }, ["chatSlotChildren"], never, false, never>;
2453
2593
  }
2454
2594
  //# sourceMappingURL=conversation-chat-area.component.d.ts.map