@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.
- package/README.md +9 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +146 -6
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +603 -130
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +3 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +22 -8
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.d.ts +12 -0
- package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.js +60 -12
- package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +93 -4
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +224 -25
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +87 -2
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +214 -32
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +20 -1
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +76 -1
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +4 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +12 -2
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
- package/dist/lib/models/agent-turn.model.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +21 -0
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +28 -2
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-liveness-dom.service.d.ts +42 -0
- package/dist/lib/services/conversation-liveness-dom.service.d.ts.map +1 -0
- package/dist/lib/services/conversation-liveness-dom.service.js +74 -0
- package/dist/lib/services/conversation-liveness-dom.service.js.map +1 -0
- package/dist/lib/services/ui-command-handler.service.d.ts +40 -3
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +78 -9
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/util/frame-zone.d.ts +10 -0
- package/dist/lib/util/frame-zone.d.ts.map +1 -0
- package/dist/lib/util/frame-zone.js +10 -0
- package/dist/lib/util/frame-zone.js.map +1 -0
- package/dist/lib/utils/agent-turn-routing.d.ts +7 -6
- package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -1
- package/dist/lib/utils/agent-turn-routing.js +4 -16
- package/dist/lib/utils/agent-turn-routing.js.map +1 -1
- package/dist/lib/utils/decision-routing.d.ts +68 -0
- package/dist/lib/utils/decision-routing.d.ts.map +1 -0
- package/dist/lib/utils/decision-routing.js +101 -0
- package/dist/lib/utils/decision-routing.js.map +1 -0
- package/dist/public-api.d.ts +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +5 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +33 -32
|
@@ -20,6 +20,7 @@ import { RealtimeSessionReviewService } from '../../services/realtime-session-re
|
|
|
20
20
|
import { GenerateAndApplyConversationName } from '../../services/conversation-naming';
|
|
21
21
|
import { CollectRealtimeSessionIDs, MapRealtimeSessionMeta, REALTIME_SESSION_META_FIELDS } from '../../utils/realtime-session-timeline';
|
|
22
22
|
import { ResolveDateJumpTarget, CombineDateJumpOutcome, DescribeDateJumpOutcome, DATE_JUMP_MAX_PAGES } from '../../utils/date-jump';
|
|
23
|
+
import { InjectFrameZone } from '../../util/frame-zone';
|
|
23
24
|
import { MessageListComponent } from '../message/message-list.component';
|
|
24
25
|
import { DecideArtifactPanelAction, SnapshotArtifactVersions } from '../../utils/artifact-panel-action';
|
|
25
26
|
import { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
|
|
@@ -28,36 +29,37 @@ import { ChatSlotDirective } from '../../directives/chat-slot.directive';
|
|
|
28
29
|
import { BeforeToolInvokedEventArgs, AfterToolInvokedEventArgs, SessionStartedEventArgs, SessionChannelStateChangedEventArgs, SessionEndedEventArgs, } from '../../events/chat-events';
|
|
29
30
|
import * as i0 from "@angular/core";
|
|
30
31
|
import * as i1 from "../../services/agent-state.service";
|
|
31
|
-
import * as i2 from "../../services/conversation-
|
|
32
|
-
import * as i3 from "../../services/
|
|
33
|
-
import * as i4 from "../../services/
|
|
34
|
-
import * as i5 from "../../services/
|
|
35
|
-
import * as i6 from "../../services/conversation-
|
|
36
|
-
import * as i7 from "../../services/
|
|
37
|
-
import * as i8 from "../../services/
|
|
38
|
-
import * as i9 from "
|
|
39
|
-
import * as i10 from "
|
|
40
|
-
import * as i11 from "
|
|
41
|
-
import * as i12 from "@
|
|
42
|
-
import * as i13 from "@
|
|
43
|
-
import * as i14 from "@memberjunction/ng-
|
|
44
|
-
import * as i15 from "@memberjunction/ng-
|
|
45
|
-
import * as i16 from "@memberjunction/ng-
|
|
46
|
-
import * as i17 from "
|
|
47
|
-
import * as i18 from "../
|
|
48
|
-
import * as i19 from "../
|
|
49
|
-
import * as i20 from "../
|
|
50
|
-
import * as i21 from "../
|
|
51
|
-
import * as i22 from "../message/message-
|
|
52
|
-
import * as i23 from "
|
|
53
|
-
import * as i24 from "./conversation-
|
|
54
|
-
import * as i25 from "./conversation-
|
|
55
|
-
import * as i26 from "
|
|
56
|
-
import * as i27 from "../
|
|
57
|
-
import * as i28 from "../
|
|
58
|
-
import * as i29 from "../
|
|
59
|
-
import * as i30 from "../
|
|
60
|
-
import * as i31 from "
|
|
32
|
+
import * as i2 from "../../services/conversation-liveness-dom.service";
|
|
33
|
+
import * as i3 from "../../services/conversation-agent.service";
|
|
34
|
+
import * as i4 from "../../services/active-tasks.service";
|
|
35
|
+
import * as i5 from "../../services/artifact-permission.service";
|
|
36
|
+
import * as i6 from "../../services/conversation-attachment.service";
|
|
37
|
+
import * as i7 from "../../services/conversation-streaming.service";
|
|
38
|
+
import * as i8 from "../../services/dialog.service";
|
|
39
|
+
import * as i9 from "../../services/conversation-bridge.service";
|
|
40
|
+
import * as i10 from "@memberjunction/ng-artifacts";
|
|
41
|
+
import * as i11 from "../../services/ui-command-handler.service";
|
|
42
|
+
import * as i12 from "@memberjunction/ng-agent-client";
|
|
43
|
+
import * as i13 from "@angular/common";
|
|
44
|
+
import * as i14 from "@memberjunction/ng-ui-components";
|
|
45
|
+
import * as i15 from "@memberjunction/ng-testing";
|
|
46
|
+
import * as i16 from "@memberjunction/ng-shared-generic";
|
|
47
|
+
import * as i17 from "@memberjunction/ng-resource-permissions";
|
|
48
|
+
import * as i18 from "../collection/artifact-collection-picker-modal.component";
|
|
49
|
+
import * as i19 from "../artifact/artifact-share-modal.component";
|
|
50
|
+
import * as i20 from "../slots/mj-chat-agent-presence-default.component";
|
|
51
|
+
import * as i21 from "../realtime/realtime-session-overlay.component";
|
|
52
|
+
import * as i22 from "../message/message-list.component";
|
|
53
|
+
import * as i23 from "../message/message-input.component";
|
|
54
|
+
import * as i24 from "./conversation-empty-state.component";
|
|
55
|
+
import * as i25 from "./conversation-agent-picker.component";
|
|
56
|
+
import * as i26 from "./conversation-mode-picker.component";
|
|
57
|
+
import * as i27 from "../thread/thread-panel.component";
|
|
58
|
+
import * as i28 from "../project/project-selector.component";
|
|
59
|
+
import * as i29 from "../members/members-modal.component";
|
|
60
|
+
import * as i30 from "../export/export-modal.component";
|
|
61
|
+
import * as i31 from "../attachment/image-viewer.component";
|
|
62
|
+
import * as i32 from "./pinned-messages-panel.component";
|
|
61
63
|
const _c0 = ["scrollContainer"];
|
|
62
64
|
const _c1 = ["messageInput"];
|
|
63
65
|
const _c2 = (a0, a1, a2, a3, a4) => ({ $implicit: a0, state: a1, agentName: a2, avatarUrl: a3, mode: a4 });
|
|
@@ -143,6 +145,7 @@ function ConversationChatAreaComponent_Conditional_3_Conditional_5_Template(rf,
|
|
|
143
145
|
i0.ɵɵelementEnd()();
|
|
144
146
|
} if (rf & 2) {
|
|
145
147
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
148
|
+
i0.ɵɵattribute("title", ctx_r0.EffectiveReadOnly ? "Project" : "Assign to project");
|
|
146
149
|
i0.ɵɵadvance(3);
|
|
147
150
|
i0.ɵɵtextInterpolate(ctx_r0.conversation.Project || "Project");
|
|
148
151
|
} }
|
|
@@ -208,7 +211,7 @@ function ConversationChatAreaComponent_Conditional_3_Conditional_12_Template(rf,
|
|
|
208
211
|
i0.ɵɵelement(0, "mj-conversation-agent-picker", 34);
|
|
209
212
|
} if (rf & 2) {
|
|
210
213
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
211
|
-
i0.ɵɵproperty("Conversation", ctx_r0.conversation)("CurrentUser", ctx_r0.currentUser)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("Disabled", ctx_r0.
|
|
214
|
+
i0.ɵɵproperty("Conversation", ctx_r0.conversation)("CurrentUser", ctx_r0.currentUser)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("Disabled", ctx_r0.EffectiveReadOnly);
|
|
212
215
|
} }
|
|
213
216
|
function ConversationChatAreaComponent_Conditional_3_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
214
217
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
@@ -253,7 +256,7 @@ function ConversationChatAreaComponent_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
253
256
|
i0.ɵɵconditionalCreate(2, ConversationChatAreaComponent_Conditional_3_Conditional_2_Template, 2, 0, "button", 24);
|
|
254
257
|
i0.ɵɵconditionalCreate(3, ConversationChatAreaComponent_Conditional_3_Conditional_3_Template, 2, 1, "div", 25);
|
|
255
258
|
i0.ɵɵconditionalCreate(4, ConversationChatAreaComponent_Conditional_3_Conditional_4_Template, 4, 2, "span", 26);
|
|
256
|
-
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_3_Conditional_5_Template, 4,
|
|
259
|
+
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_3_Conditional_5_Template, 4, 2, "button", 27);
|
|
257
260
|
i0.ɵɵconditionalCreate(6, ConversationChatAreaComponent_Conditional_3_Conditional_6_Template, 4, 0, "button", 28);
|
|
258
261
|
i0.ɵɵelementEnd();
|
|
259
262
|
i0.ɵɵelementStart(7, "div", 29);
|
|
@@ -288,7 +291,7 @@ function ConversationChatAreaComponent_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
288
291
|
i0.ɵɵadvance();
|
|
289
292
|
i0.ɵɵconditional(ctx_r0.memberCount > 1 ? 10 : -1);
|
|
290
293
|
i0.ɵɵadvance();
|
|
291
|
-
i0.ɵɵconditional(!ctx_r0.overlayMode && ctx_r0.showAgentModePicker && ctx_r0.ModePickerTargetAgentId ? 11 : -1);
|
|
294
|
+
i0.ɵɵconditional(!ctx_r0.overlayMode && ctx_r0.showAgentModePicker && ctx_r0.ModePickerTargetAgentId && !ctx_r0.EffectiveReadOnly ? 11 : -1);
|
|
292
295
|
i0.ɵɵadvance();
|
|
293
296
|
i0.ɵɵconditional(ctx_r0.showAgentPicker && ctx_r0.conversation ? 12 : -1);
|
|
294
297
|
i0.ɵɵadvance();
|
|
@@ -321,63 +324,92 @@ function ConversationChatAreaComponent_Conditional_7_Template(rf, ctx) { if (rf
|
|
|
321
324
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
322
325
|
i0.ɵɵconditional(ctx_r0.showLoadingState ? 0 : -1);
|
|
323
326
|
} }
|
|
324
|
-
function
|
|
327
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
328
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
329
|
+
i0.ɵɵelement(1, "i", 60);
|
|
330
|
+
i0.ɵɵelementStart(2, "span");
|
|
331
|
+
i0.ɵɵtext(3);
|
|
332
|
+
i0.ɵɵelementEnd()();
|
|
333
|
+
} if (rf & 2) {
|
|
334
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
335
|
+
i0.ɵɵadvance(3);
|
|
336
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
337
|
+
} }
|
|
338
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_1_ng_container_0_Template(rf, ctx) { if (rf & 1) {
|
|
325
339
|
i0.ɵɵelementContainer(0);
|
|
326
340
|
} }
|
|
327
|
-
function
|
|
328
|
-
i0.ɵɵtemplate(0,
|
|
341
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
342
|
+
i0.ɵɵtemplate(0, ConversationChatAreaComponent_Conditional_8_Conditional_1_ng_container_0_Template, 1, 0, "ng-container", 22);
|
|
329
343
|
} if (rf & 2) {
|
|
330
344
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
331
345
|
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction4(3, _c7, ctx_r0.emptyStateConfig, (ctx_r0.emptyStateConfig == null ? null : ctx_r0.emptyStateConfig.greeting) ?? ctx_r0.emptyStateGreeting, ctx_r0.emptyStateConfig == null ? null : ctx_r0.emptyStateConfig.subtext, (ctx_r0.emptyStateConfig == null ? null : ctx_r0.emptyStateConfig.suggestedPrompts) ?? i0.ɵɵpureFunction0(2, _c6)));
|
|
332
346
|
} }
|
|
333
|
-
function
|
|
347
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
334
348
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
335
|
-
i0.ɵɵelementStart(0, "mj-conversation-empty-state",
|
|
336
|
-
i0.ɵɵlistener("initialDraftApplied", function
|
|
349
|
+
i0.ɵɵelementStart(0, "mj-conversation-empty-state", 61);
|
|
350
|
+
i0.ɵɵlistener("initialDraftApplied", function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template_mj_conversation_empty_state_initialDraftApplied_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnComposerDraftApplied()); })("DraftStateChanged", function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template_mj_conversation_empty_state_DraftStateChanged_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnDraftStateChanged(null, $event)); })("ComposerBlurred", function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template_mj_conversation_empty_state_ComposerBlurred_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnComposerBlurred()); })("sidebarToggleClicked", function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template_mj_conversation_empty_state_sidebarToggleClicked_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.sidebarToggleClicked.emit()); })("messageSent", function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template_mj_conversation_empty_state_messageSent_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onEmptyStateMessageSent($event)); });
|
|
337
351
|
i0.ɵɵelementEnd();
|
|
338
352
|
} if (rf & 2) {
|
|
339
353
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
340
354
|
i0.ɵɵproperty("currentUser", ctx_r0.currentUser)("initialDraft", ctx_r0.GetInitialDraftFor(null))("disabled", ctx_r0.isProcessing)("showSidebarToggle", ctx_r0.showSidebarToggle)("overlayMode", ctx_r0.overlayMode)("greeting", (ctx_r0.emptyStateConfig == null ? null : ctx_r0.emptyStateConfig.greeting) ?? ctx_r0.emptyStateGreeting)("showSuggestedPrompts", ctx_r0.showSuggestedPrompts)("enableAttachments", ctx_r0.enableAttachments && ctx_r0.allowAttachments)("enableMentions", ctx_r0.allowMentions)("enableAgentMentions", ctx_r0.allowAgentMentions)("enableEntityMentions", ctx_r0.allowEntityMentions)("enableSkillCommands", ctx_r0.allowSkillCommands)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("MentionPeople", ctx_r0.MentionPeople)("ComposerExtraTemplate", ctx_r0.slotTemplate("composerExtra"))("maxAttachments", ctx_r0.maxAttachments)("maxAttachmentSizeBytes", ctx_r0.maxAttachmentSizeBytes)("acceptedFileTypes", ctx_r0.acceptedFileTypes);
|
|
341
355
|
} }
|
|
342
356
|
function ConversationChatAreaComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
343
|
-
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_8_Conditional_0_Template, 1, 8, "ng-container")(
|
|
357
|
+
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_8_Conditional_0_Template, 4, 1, "div", 58)(1, ConversationChatAreaComponent_Conditional_8_Conditional_1_Template, 1, 8, "ng-container")(2, ConversationChatAreaComponent_Conditional_8_Conditional_2_Template, 1, 18, "mj-conversation-empty-state", 59);
|
|
344
358
|
} if (rf & 2) {
|
|
345
359
|
let tmp_1_0;
|
|
346
360
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
347
|
-
i0.ɵɵconditional((tmp_1_0 = ctx_r0.slotTemplate("emptyState")) ?
|
|
361
|
+
i0.ɵɵconditional(ctx_r0.ReadOnly ? 0 : (tmp_1_0 = ctx_r0.slotTemplate("emptyState")) ? 1 : 2, tmp_1_0);
|
|
362
|
+
} }
|
|
363
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
364
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
365
|
+
i0.ɵɵelement(1, "i", 60);
|
|
366
|
+
i0.ɵɵelementStart(2, "span");
|
|
367
|
+
i0.ɵɵtext(3);
|
|
368
|
+
i0.ɵɵelementEnd()();
|
|
369
|
+
} if (rf & 2) {
|
|
370
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
371
|
+
i0.ɵɵadvance(3);
|
|
372
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
348
373
|
} }
|
|
349
|
-
function
|
|
374
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_ng_container_1_Template(rf, ctx) { if (rf & 1) {
|
|
350
375
|
i0.ɵɵelementContainer(0);
|
|
351
376
|
} }
|
|
352
|
-
function
|
|
353
|
-
i0.ɵɵelementStart(0, "div",
|
|
354
|
-
i0.ɵɵtemplate(1,
|
|
377
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
378
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
379
|
+
i0.ɵɵtemplate(1, ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_ng_container_1_Template, 1, 0, "ng-container", 22);
|
|
355
380
|
i0.ɵɵelementEnd();
|
|
356
381
|
} if (rf & 2) {
|
|
357
|
-
const ctx_r0 = i0.ɵɵnextContext(
|
|
382
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
358
383
|
i0.ɵɵadvance();
|
|
359
384
|
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction3(2, _c8, ctx_r0.conversation, ctx_r0.conversationId, ctx_r0.isProcessing));
|
|
360
385
|
} }
|
|
361
|
-
function
|
|
386
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
362
387
|
const _r12 = i0.ɵɵgetCurrentView();
|
|
388
|
+
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_Template, 2, 6, "div", 64);
|
|
389
|
+
i0.ɵɵelementStart(1, "div", 65)(2, "mj-message-input", 66, 0);
|
|
390
|
+
i0.ɵɵlistener("initialDraftApplied", function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template_mj_message_input_initialDraftApplied_2_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnComposerDraftApplied()); })("DraftStateChanged", function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template_mj_message_input_DraftStateChanged_2_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnDraftStateChanged(null, $event)); })("ComposerBlurred", function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template_mj_message_input_ComposerBlurred_2_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnComposerBlurred()); })("emptyStateSubmit", function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template_mj_message_input_emptyStateSubmit_2_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onEmptyStateMessageSent($event)); });
|
|
391
|
+
i0.ɵɵelementEnd()();
|
|
392
|
+
} if (rf & 2) {
|
|
393
|
+
let tmp_3_0;
|
|
394
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
395
|
+
i0.ɵɵconditional((tmp_3_0 = ctx_r0.slotTemplate("composerExtra")) ? 0 : -1, tmp_3_0);
|
|
396
|
+
i0.ɵɵadvance(2);
|
|
397
|
+
i0.ɵɵproperty("emptyStateMode", true)("initialDraft", ctx_r0.GetInitialDraftFor(null))("currentUser", ctx_r0.currentUser)("disabled", ctx_r0.isProcessing)("ReadOnly", ctx_r0.EffectiveReadOnly)("enableAttachments", ctx_r0.enableAttachments && ctx_r0.allowAttachments)("enableMentions", ctx_r0.allowMentions)("enableAgentMentions", ctx_r0.allowAgentMentions)("enableEntityMentions", ctx_r0.allowEntityMentions)("enableSkillCommands", ctx_r0.allowSkillCommands)("enablePlanMode", ctx_r0.allowPlanMode)("enableRealtime", ctx_r0.allowRealtime)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("MentionPeople", ctx_r0.MentionPeople)("maxAttachments", ctx_r0.maxAttachments)("maxAttachmentSizeBytes", ctx_r0.maxAttachmentSizeBytes)("acceptedFileTypes", ctx_r0.acceptedFileTypes);
|
|
398
|
+
} }
|
|
399
|
+
function ConversationChatAreaComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
363
400
|
i0.ɵɵelementStart(0, "div", 9);
|
|
364
|
-
i0.ɵɵelement(1, "div",
|
|
365
|
-
i0.ɵɵelementStart(2, "div",
|
|
366
|
-
i0.ɵɵconditionalCreate(3, ConversationChatAreaComponent_Conditional_9_Conditional_3_Template,
|
|
367
|
-
i0.ɵɵ
|
|
368
|
-
i0.ɵɵlistener("initialDraftApplied", function ConversationChatAreaComponent_Conditional_9_Template_mj_message_input_initialDraftApplied_5_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnComposerDraftApplied()); })("DraftStateChanged", function ConversationChatAreaComponent_Conditional_9_Template_mj_message_input_DraftStateChanged_5_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnDraftStateChanged(null, $event)); })("ComposerBlurred", function ConversationChatAreaComponent_Conditional_9_Template_mj_message_input_ComposerBlurred_5_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnComposerBlurred()); })("emptyStateSubmit", function ConversationChatAreaComponent_Conditional_9_Template_mj_message_input_emptyStateSubmit_5_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onEmptyStateMessageSent($event)); });
|
|
369
|
-
i0.ɵɵelementEnd()()()();
|
|
401
|
+
i0.ɵɵelement(1, "div", 62);
|
|
402
|
+
i0.ɵɵelementStart(2, "div", 63);
|
|
403
|
+
i0.ɵɵconditionalCreate(3, ConversationChatAreaComponent_Conditional_9_Conditional_3_Template, 4, 1, "div", 58)(4, ConversationChatAreaComponent_Conditional_9_Conditional_4_Template, 4, 18);
|
|
404
|
+
i0.ɵɵelementEnd()();
|
|
370
405
|
} if (rf & 2) {
|
|
371
|
-
let tmp_2_0;
|
|
372
406
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
373
407
|
i0.ɵɵadvance(3);
|
|
374
|
-
i0.ɵɵconditional(
|
|
375
|
-
i0.ɵɵadvance(2);
|
|
376
|
-
i0.ɵɵproperty("emptyStateMode", true)("initialDraft", ctx_r0.GetInitialDraftFor(null))("currentUser", ctx_r0.currentUser)("disabled", ctx_r0.isProcessing)("enableAttachments", ctx_r0.enableAttachments && ctx_r0.allowAttachments)("enableMentions", ctx_r0.allowMentions)("enableAgentMentions", ctx_r0.allowAgentMentions)("enableEntityMentions", ctx_r0.allowEntityMentions)("enableSkillCommands", ctx_r0.allowSkillCommands)("enablePlanMode", ctx_r0.allowPlanMode)("enableRealtime", ctx_r0.allowRealtime)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("MentionPeople", ctx_r0.MentionPeople)("maxAttachments", ctx_r0.maxAttachments)("maxAttachmentSizeBytes", ctx_r0.maxAttachmentSizeBytes)("acceptedFileTypes", ctx_r0.acceptedFileTypes);
|
|
408
|
+
i0.ɵɵconditional(ctx_r0.ReadOnly ? 3 : 4);
|
|
377
409
|
} }
|
|
378
410
|
function ConversationChatAreaComponent_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
379
|
-
i0.ɵɵelementStart(0, "div",
|
|
380
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
411
|
+
i0.ɵɵelementStart(0, "div", 67);
|
|
412
|
+
i0.ɵɵelement(1, "mj-loading", 72);
|
|
381
413
|
i0.ɵɵelementEnd();
|
|
382
414
|
} if (rf & 2) {
|
|
383
415
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -386,50 +418,61 @@ function ConversationChatAreaComponent_Conditional_10_Conditional_1_Template(rf,
|
|
|
386
418
|
} }
|
|
387
419
|
function ConversationChatAreaComponent_Conditional_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
388
420
|
const _r14 = i0.ɵɵgetCurrentView();
|
|
389
|
-
i0.ɵɵelementStart(0, "span",
|
|
421
|
+
i0.ɵɵelementStart(0, "span", 73);
|
|
390
422
|
i0.ɵɵlistener("click", function ConversationChatAreaComponent_Conditional_10_Conditional_5_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.scrollToBottomAnimate()); });
|
|
391
|
-
i0.ɵɵelement(1, "i",
|
|
423
|
+
i0.ɵɵelement(1, "i", 74);
|
|
392
424
|
i0.ɵɵelementEnd();
|
|
393
425
|
} }
|
|
394
426
|
function ConversationChatAreaComponent_Conditional_10_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
395
|
-
i0.ɵɵelementStart(0, "div",
|
|
396
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
427
|
+
i0.ɵɵelementStart(0, "div", 71);
|
|
428
|
+
i0.ɵɵelement(1, "mj-loading", 75);
|
|
397
429
|
i0.ɵɵelementEnd();
|
|
398
430
|
} }
|
|
399
|
-
function
|
|
400
|
-
i0.ɵɵelementStart(0, "div",
|
|
401
|
-
i0.ɵɵelement(1, "i",
|
|
431
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
432
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
433
|
+
i0.ɵɵelement(1, "i", 60);
|
|
434
|
+
i0.ɵɵelementStart(2, "span");
|
|
435
|
+
i0.ɵɵtext(3);
|
|
436
|
+
i0.ɵɵelementEnd()();
|
|
437
|
+
} if (rf & 2) {
|
|
438
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
439
|
+
i0.ɵɵadvance(3);
|
|
440
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
441
|
+
} }
|
|
442
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
443
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
444
|
+
i0.ɵɵelement(1, "i", 60);
|
|
402
445
|
i0.ɵɵelementStart(2, "span");
|
|
403
446
|
i0.ɵɵtext(3, "You have view-only access to this conversation.");
|
|
404
447
|
i0.ɵɵelementEnd()();
|
|
405
448
|
} }
|
|
406
|
-
function
|
|
449
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_ng_container_1_Template(rf, ctx) { if (rf & 1) {
|
|
407
450
|
i0.ɵɵelementContainer(0);
|
|
408
451
|
} }
|
|
409
|
-
function
|
|
410
|
-
i0.ɵɵelementStart(0, "div",
|
|
411
|
-
i0.ɵɵtemplate(1,
|
|
452
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
453
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
454
|
+
i0.ɵɵtemplate(1, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_ng_container_1_Template, 1, 0, "ng-container", 22);
|
|
412
455
|
i0.ɵɵelementEnd();
|
|
413
456
|
} if (rf & 2) {
|
|
414
457
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
415
458
|
i0.ɵɵadvance();
|
|
416
459
|
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction3(2, _c8, ctx_r0.conversation, ctx_r0.conversationId, ctx_r0.isProcessing));
|
|
417
460
|
} }
|
|
418
|
-
function
|
|
461
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
419
462
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
420
463
|
i0.ɵɵelementStart(0, "mj-message-input", 77, 2);
|
|
421
|
-
i0.ɵɵlistener("DraftStateChanged", function
|
|
464
|
+
i0.ɵɵlistener("DraftStateChanged", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_DraftStateChanged_0_listener($event) { const inputRef_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnDraftStateChanged(inputRef_r16.conversationId, $event)); })("ComposerBlurred", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_ComposerBlurred_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnComposerBlurred()); })("initialMessageAutoSendStarted", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_initialMessageAutoSendStarted_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onInitialMessageAutoSendStarted($event)); })("initialMessageAutoSendFailed", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_initialMessageAutoSendFailed_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onInitialMessageAutoSendFailed($event)); })("messageSent", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_messageSent_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onMessageSent($event)); })("MessageStreamed", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_MessageStreamed_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnMessageStreamed($event)); })("agentResponse", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_agentResponse_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onAgentResponse($event)); })("agentRunDetected", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_agentRunDetected_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onAgentRunDetected($event)); })("agentRunUpdate", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_agentRunUpdate_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onAgentRunUpdate($event)); })("messageComplete", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_messageComplete_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onMessageComplete($event)); })("artifactCreated", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_artifactCreated_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onArtifactCreated($event)); })("conversationRenamed", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_conversationRenamed_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onConversationRenamed($event)); })("intentCheckStarted", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_intentCheckStarted_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onIntentCheckStarted($event)); })("intentCheckCompleted", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_intentCheckCompleted_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onIntentCheckCompleted($event)); })("beforeAgentTurn", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_beforeAgentTurn_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.beforeAgentTurn.emit($event)); })("afterAgentTurn", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_afterAgentTurn_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.afterAgentTurn.emit($event)); })("uploadStateChanged", function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template_mj_message_input_uploadStateChanged_0_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onUploadStateChanged($event)); });
|
|
422
465
|
i0.ɵɵelementEnd();
|
|
423
466
|
} if (rf & 2) {
|
|
424
467
|
const inputRef_r16 = ctx.$implicit;
|
|
425
468
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
426
|
-
i0.ɵɵproperty("hidden", inputRef_r16.conversationId !== ctx_r0.conversationId)("initialDraft", ctx_r0.GetInitialDraftFor(inputRef_r16.conversationId))("conversationId", inputRef_r16.conversationId)("conversationName", inputRef_r16.conversationName)("currentUser", ctx_r0.currentUser)("conversationHistory", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.messages : i0.ɵɵpureFunction0(
|
|
469
|
+
i0.ɵɵproperty("hidden", inputRef_r16.conversationId !== ctx_r0.conversationId)("initialDraft", ctx_r0.GetInitialDraftFor(inputRef_r16.conversationId))("conversationId", inputRef_r16.conversationId)("conversationName", inputRef_r16.conversationName)("currentUser", ctx_r0.currentUser)("conversationHistory", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.messages : i0.ɵɵpureFunction0(36, _c6))("artifactsByDetailId", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.artifactsByDetailId : ctx_r0.emptyArtifactsMap)("systemArtifactsByDetailId", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.systemArtifactsByDetailId : ctx_r0.emptyArtifactsMap)("agentRunsByDetailId", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.agentRunsByDetailId : ctx_r0.emptyAgentRunsMap)("appContext", ctx_r0.appContext)("applicationId", ctx_r0.applicationId)("defaultAgentId", ctx_r0.defaultAgentId)("conversationDefaultAgentId", inputRef_r16.conversationId === ctx_r0.conversationId ? (ctx_r0.conversation == null ? null : ctx_r0.conversation.DefaultAgentID) ?? null : null)("agentConfigurationPresetId", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.ActiveAgentConfigurationPresetId : null)("AgentReplyMode", ctx_r0.AgentReplyMode)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("MentionPeople", ctx_r0.MentionPeople)("AgentHistoryFrom", ctx_r0.AgentHistoryFrom)("AgentTurnHandler", ctx_r0.AgentTurnHandler)("AutoNameConversation", ctx_r0.AutoNameConversation)("EnableDecisionRouting", ctx_r0.EnableDecisionRouting)("inProgressMessageIds", inputRef_r16.conversationId === ctx_r0.conversationId ? ctx_r0.inProgressMessageIds : ctx_r0.emptyInProgressIds)("disabled", ctx_r0.isProcessing || ctx_r0.isReadOnlyView)("ReadOnly", ctx_r0.EffectiveReadOnly)("enableAttachments", ctx_r0.enableAttachments && ctx_r0.allowAttachments)("enableMentions", ctx_r0.allowMentions)("enableAgentMentions", ctx_r0.allowAgentMentions)("enableEntityMentions", ctx_r0.allowEntityMentions)("enableSkillCommands", ctx_r0.allowSkillCommands)("enablePlanMode", ctx_r0.allowPlanMode)("enableRealtime", ctx_r0.allowRealtime)("maxAttachments", ctx_r0.maxAttachments)("maxAttachmentSizeBytes", ctx_r0.maxAttachmentSizeBytes)("acceptedFileTypes", ctx_r0.acceptedFileTypes)("initialMessage", ctx_r0.shouldDeliverPendingMessageTo(inputRef_r16.conversationId) ? ctx_r0.pendingMessage : null)("initialAttachments", ctx_r0.shouldDeliverPendingMessageTo(inputRef_r16.conversationId) ? ctx_r0.pendingAttachments : null);
|
|
427
470
|
} }
|
|
428
|
-
function
|
|
429
|
-
i0.ɵɵconditionalCreate(0,
|
|
430
|
-
i0.ɵɵconditionalCreate(1,
|
|
431
|
-
i0.ɵɵelementStart(2, "div",
|
|
432
|
-
i0.ɵɵrepeaterCreate(3,
|
|
471
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
472
|
+
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_0_Template, 4, 0, "div", 58);
|
|
473
|
+
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_Template, 2, 6, "div", 64);
|
|
474
|
+
i0.ɵɵelementStart(2, "div", 65);
|
|
475
|
+
i0.ɵɵrepeaterCreate(3, ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template, 2, 37, "mj-message-input", 76, _forTrack0);
|
|
433
476
|
i0.ɵɵelementEnd();
|
|
434
477
|
} if (rf & 2) {
|
|
435
478
|
let tmp_4_0;
|
|
@@ -443,27 +486,27 @@ function ConversationChatAreaComponent_Conditional_10_Conditional_8_Template(rf,
|
|
|
443
486
|
function ConversationChatAreaComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
444
487
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
445
488
|
i0.ɵɵelementStart(0, "div", 9);
|
|
446
|
-
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_1_Template, 2, 1, "div",
|
|
447
|
-
i0.ɵɵelementStart(2, "div",
|
|
489
|
+
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_1_Template, 2, 1, "div", 67);
|
|
490
|
+
i0.ɵɵelementStart(2, "div", 68, 1);
|
|
448
491
|
i0.ɵɵlistener("scroll", function ConversationChatAreaComponent_Conditional_10_Template_div_scroll_2_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.checkScroll()); });
|
|
449
|
-
i0.ɵɵelementStart(4, "mj-conversation-message-list",
|
|
450
|
-
i0.ɵɵlistener("OlderRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_OlderRequested_4_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOlderMessagesRequested()); })("DateJumpRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_DateJumpRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDateJumpRequested($event)); })("realtimeSessionOpenRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_realtimeSessionOpenRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OpenRealtimeSessionReview($event)); })("replyInThread", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_replyInThread_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onReplyInThread($event)); })("viewThread", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_viewThread_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onViewThread($event)); })("deleteMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_deleteMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDeleteMessage($event)); })("retryMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_retryMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onRetryMessage($event)); })("testFeedbackMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_testFeedbackMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTestFeedbackMessage($event)); })("artifactClicked", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_artifactClicked_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onArtifactClicked($event)); })("messageEdited", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_messageEdited_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMessageEdited($event)); })("openEntityRecord", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_openEntityRecord_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOpenEntityRecord($event)); })("suggestedResponseSelected", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_suggestedResponseSelected_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onSuggestedResponseSelected($event)); })("attachmentClicked", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_attachmentClicked_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onAttachmentClicked($event)); })("diagnosticRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_diagnosticRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDiagnosticRequested($event)); })("messagePinToggled", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_messagePinToggled_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMessagePinToggled($event)); })("beforeResponseFormSubmitted", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_beforeResponseFormSubmitted_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.beforeResponseFormSubmitted.emit($event)); })("afterResponseFormSubmitted", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_afterResponseFormSubmitted_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.afterResponseFormSubmitted.emit($event)); });
|
|
492
|
+
i0.ɵɵelementStart(4, "mj-conversation-message-list", 69);
|
|
493
|
+
i0.ɵɵlistener("OlderRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_OlderRequested_4_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOlderMessagesRequested()); })("DateJumpRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_DateJumpRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDateJumpRequested($event)); })("realtimeSessionOpenRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_realtimeSessionOpenRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OpenRealtimeSessionReview($event)); })("replyInThread", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_replyInThread_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onReplyInThread($event)); })("viewThread", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_viewThread_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onViewThread($event)); })("deleteMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_deleteMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDeleteMessage($event)); })("retryMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_retryMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onRetryMessage($event)); })("testFeedbackMessage", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_testFeedbackMessage_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTestFeedbackMessage($event)); })("artifactClicked", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_artifactClicked_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onArtifactClicked($event)); })("messageEdited", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_messageEdited_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMessageEdited($event)); })("openEntityRecord", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_openEntityRecord_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOpenEntityRecord($event)); })("suggestedResponseSelected", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_suggestedResponseSelected_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onSuggestedResponseSelected($event)); })("attachmentClicked", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_attachmentClicked_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onAttachmentClicked($event)); })("diagnosticRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_diagnosticRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDiagnosticRequested($event)); })("LivenessCheckRequested", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_LivenessCheckRequested_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnLivenessCheckRequested($event)); })("messagePinToggled", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_messagePinToggled_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onMessagePinToggled($event)); })("beforeResponseFormSubmitted", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_beforeResponseFormSubmitted_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.beforeResponseFormSubmitted.emit($event)); })("afterResponseFormSubmitted", function ConversationChatAreaComponent_Conditional_10_Template_mj_conversation_message_list_afterResponseFormSubmitted_4_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.afterResponseFormSubmitted.emit($event)); });
|
|
451
494
|
i0.ɵɵelementEnd();
|
|
452
|
-
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_10_Conditional_5_Template, 2, 0, "span",
|
|
495
|
+
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_10_Conditional_5_Template, 2, 0, "span", 70);
|
|
453
496
|
i0.ɵɵelementEnd();
|
|
454
|
-
i0.ɵɵelementStart(6, "div",
|
|
455
|
-
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_10_Conditional_7_Template, 2, 0, "div",
|
|
497
|
+
i0.ɵɵelementStart(6, "div", 63);
|
|
498
|
+
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_10_Conditional_7_Template, 2, 0, "div", 71)(8, ConversationChatAreaComponent_Conditional_10_Conditional_8_Template, 4, 1, "div", 58)(9, ConversationChatAreaComponent_Conditional_10_Conditional_9_Template, 5, 2);
|
|
456
499
|
i0.ɵɵelementEnd()();
|
|
457
500
|
} if (rf & 2) {
|
|
458
501
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
459
502
|
i0.ɵɵadvance();
|
|
460
503
|
i0.ɵɵconditional(ctx_r0.isUploadingAttachments ? 1 : -1);
|
|
461
504
|
i0.ɵɵadvance(3);
|
|
462
|
-
i0.ɵɵproperty("showEmptyFill", ctx_r0.showEmptyFill)("showDateNavigation", ctx_r0.showDateNavigation)("showAgentRunDetails", ctx_r0.showAgentRunDetails)("showReactions", ctx_r0.showReactions)("showMessageRating", ctx_r0.showMessageRating)("allowPinning", ctx_r0.allowPinning)("allowMessageEdit", ctx_r0.allowMessageEdit)("allowMessageDelete", ctx_r0.allowMessageDelete)("assistantDisplayName", ctx_r0.assistantDisplayName)("assistantAvatarUrl", ctx_r0.assistantAvatarUrl)("messages", ctx_r0.messages)("HasMoreAbove", ctx_r0.hasMoreMessagesAbove)("IsLoadingOlder", ctx_r0.isLoadingOlderMessages)("ScrollRoot", ctx_r0.messageScrollRoot)("conversation", ctx_r0.conversation)("currentUser", ctx_r0.currentUser)("isProcessing", ctx_r0.isProcessing)("artifactMap", ctx_r0.effectiveArtifactsMap)("agentRunMap", ctx_r0.agentRunsByDetailId)("ratingsMap", ctx_r0.ratingsByDetailId)("userAvatarMap", ctx_r0.userAvatarMap)("attachmentsMap", ctx_r0.attachmentsByDetailId)("messageRendererTemplate", ctx_r0.slotTemplate("messageRenderer"))("messageExtraTemplate", ctx_r0.slotTemplate("messageExtra"))("sessionMetaMap", ctx_r0.realtimeSessionMetaMap);
|
|
505
|
+
i0.ɵɵproperty("showEmptyFill", ctx_r0.showEmptyFill)("showDateNavigation", ctx_r0.showDateNavigation)("showAgentRunDetails", ctx_r0.showAgentRunDetails)("showReactions", ctx_r0.showReactions)("showMessageRating", ctx_r0.showMessageRating)("allowPinning", ctx_r0.allowPinning && !ctx_r0.EffectiveReadOnly)("allowMessageEdit", ctx_r0.allowMessageEdit && !ctx_r0.EffectiveReadOnly)("allowMessageDelete", ctx_r0.allowMessageDelete && !ctx_r0.EffectiveReadOnly)("ReadOnly", ctx_r0.EffectiveReadOnly)("assistantDisplayName", ctx_r0.assistantDisplayName)("assistantAvatarUrl", ctx_r0.assistantAvatarUrl)("messages", ctx_r0.messages)("HasMoreAbove", ctx_r0.hasMoreMessagesAbove)("IsLoadingOlder", ctx_r0.isLoadingOlderMessages)("ScrollRoot", ctx_r0.messageScrollRoot)("conversation", ctx_r0.conversation)("currentUser", ctx_r0.currentUser)("isProcessing", ctx_r0.isProcessing)("artifactMap", ctx_r0.effectiveArtifactsMap)("agentRunMap", ctx_r0.agentRunsByDetailId)("ratingsMap", ctx_r0.ratingsByDetailId)("userAvatarMap", ctx_r0.userAvatarMap)("attachmentsMap", ctx_r0.attachmentsByDetailId)("messageRendererTemplate", ctx_r0.slotTemplate("messageRenderer"))("messageExtraTemplate", ctx_r0.slotTemplate("messageExtra"))("sessionMetaMap", ctx_r0.realtimeSessionMetaMap);
|
|
463
506
|
i0.ɵɵadvance();
|
|
464
507
|
i0.ɵɵconditional(ctx_r0.showScrollToBottomIcon && ctx_r0.messages && ctx_r0.messages.length > 0 ? 5 : -1);
|
|
465
508
|
i0.ɵɵadvance(2);
|
|
466
|
-
i0.ɵɵconditional(ctx_r0.isLoadingPeripheralData ? 7 : 8);
|
|
509
|
+
i0.ɵɵconditional(ctx_r0.isLoadingPeripheralData ? 7 : ctx_r0.ReadOnly ? 8 : 9);
|
|
467
510
|
} }
|
|
468
511
|
function ConversationChatAreaComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
469
512
|
const _r18 = i0.ɵɵgetCurrentView();
|
|
@@ -493,7 +536,7 @@ function ConversationChatAreaComponent_Conditional_13_Template(rf, ctx) { if (rf
|
|
|
493
536
|
i0.ɵɵelementEnd();
|
|
494
537
|
} if (rf & 2) {
|
|
495
538
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
496
|
-
i0.ɵɵproperty("pinnedMessages", ctx_r0.pinnedMessages)("isLoading", ctx_r0.isLoadingPins);
|
|
539
|
+
i0.ɵɵproperty("pinnedMessages", ctx_r0.pinnedMessages)("isLoading", ctx_r0.isLoadingPins)("AllowUnpin", !ctx_r0.EffectiveReadOnly);
|
|
497
540
|
} }
|
|
498
541
|
function ConversationChatAreaComponent_Conditional_14_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
499
542
|
const _r21 = i0.ɵɵgetCurrentView();
|
|
@@ -708,10 +751,22 @@ function ConversationChatAreaComponent_Conditional_24_Template(rf, ctx) { if (rf
|
|
|
708
751
|
} }
|
|
709
752
|
/** `MJ: Resource Types.ID` for Conversations. */
|
|
710
753
|
const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
|
|
754
|
+
/** Run statuses that mean the run is over, for the run-list fallback. `Paused` is still working. */
|
|
755
|
+
const RUN_LIST_TERMINAL_STATUSES = ['Completed', 'AwaitingFeedback', 'Failed', 'Cancelled'];
|
|
711
756
|
/** Default width (percentage) for the artifact viewer pane */
|
|
712
757
|
export const DEFAULT_ARTIFACT_PANE_WIDTH = 40;
|
|
758
|
+
/**
|
|
759
|
+
* ReadReplyFromTop: how long bottom-follow stays off after a turn lands at its top, so a status
|
|
760
|
+
* row or a repeated completion emit arriving right behind the landing cannot yank the reader
|
|
761
|
+
* back down. Re-armed per frame while a streamed reply grows beneath an anchored turn, so a turn
|
|
762
|
+
* that never settles (a cancelled run, a dropped socket) releases it a moment after its last delta.
|
|
763
|
+
*/
|
|
764
|
+
const POST_LANDING_FOLLOW_HOLD_MS = 1500;
|
|
765
|
+
/** A scroll position this far from where the stream last pinned it means the reader moved. */
|
|
766
|
+
const STREAM_ANCHOR_TOLERANCE_PX = 2;
|
|
713
767
|
export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
714
768
|
agentStateService;
|
|
769
|
+
livenessDom;
|
|
715
770
|
conversationAgentService;
|
|
716
771
|
activeTasks;
|
|
717
772
|
cdr;
|
|
@@ -1016,6 +1071,13 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
1016
1071
|
get allowMessageDelete() {
|
|
1017
1072
|
return this.AllowMessageDelete;
|
|
1018
1073
|
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Host-forced read-only. Hides every composer. A View share
|
|
1076
|
+
* ({@link IsReadOnlyView}) with this left false keeps today's disabled composer.
|
|
1077
|
+
*/
|
|
1078
|
+
ReadOnly = false;
|
|
1079
|
+
/** Banner copy when {@link ReadOnly} is set. Null uses the View-share text. */
|
|
1080
|
+
ReadOnlyMessage = null;
|
|
1019
1081
|
/** Show the empty-state's built-in suggested-prompt chips (and the @mention tip). */
|
|
1020
1082
|
ShowSuggestedPrompts = true;
|
|
1021
1083
|
/** @deprecated Use {@link ShowSuggestedPrompts}. */
|
|
@@ -1335,6 +1397,21 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
1335
1397
|
* True (the default) keeps today's behavior; a host that names its own chats turns it off.
|
|
1336
1398
|
*/
|
|
1337
1399
|
AutoNameConversation = true;
|
|
1400
|
+
/**
|
|
1401
|
+
* Whether an untagged message asks one fast typed decision which agent in the conversation
|
|
1402
|
+
* should answer it, instead of always going back to the last agent that answered. It replaces
|
|
1403
|
+
* that agent only when the answer is confident and arrives within `DECISION_ROUTING_TIMEOUT_MS`
|
|
1404
|
+
* (250 ms). False (the default)
|
|
1405
|
+
* changes nothing: no decision call, and today's routing. See
|
|
1406
|
+
* `MessageInputComponent.EnableDecisionRouting`.
|
|
1407
|
+
*
|
|
1408
|
+
* Turning it on sends conversation text to the model behind the `Default Decision` prompt, which
|
|
1409
|
+
* can be a different vendor from the agents' own: the first 1,000 characters of the new message,
|
|
1410
|
+
* the last 6 turns (150 characters each), each participant's name, description and last reply,
|
|
1411
|
+
* and the names of their artifact versions. Each call writes an `MJ: AI Prompt Runs` row, even
|
|
1412
|
+
* when the answer comes too late to be used.
|
|
1413
|
+
*/
|
|
1414
|
+
EnableDecisionRouting = false;
|
|
1338
1415
|
/**
|
|
1339
1416
|
* Scope to apply when this surface CREATES a new conversation. Forwarded
|
|
1340
1417
|
* to `ConversationEngine.CreateConversation` so the new row's
|
|
@@ -2031,12 +2108,29 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
2031
2108
|
* last progress updates must not fire and drag the reader back down.
|
|
2032
2109
|
*/
|
|
2033
2110
|
bottomFollowSuppressedUntil = 0;
|
|
2111
|
+
/**
|
|
2112
|
+
* ReadReplyFromTop while a reply streams: the scroll position the turn's top was last pinned
|
|
2113
|
+
* to, `'declined'` once the reader has moved away (they are then left alone and completion
|
|
2114
|
+
* decides as it always has), null before the turn's first delta. Reset where the turn opens.
|
|
2115
|
+
*/
|
|
2116
|
+
streamAnchor = null;
|
|
2117
|
+
/**
|
|
2118
|
+
* The turn's first message as rendered, and the clearance above it, resolved once per turn for
|
|
2119
|
+
* the stream pin: both are stable across frames and finding them is a timeline walk plus a
|
|
2120
|
+
* computed style, which is not work for a 60fps path. Re-resolved only if the node leaves the DOM.
|
|
2121
|
+
*/
|
|
2122
|
+
streamPin = null;
|
|
2123
|
+
ngZone = InjectFrameZone();
|
|
2034
2124
|
turnStartRetryHandle = null;
|
|
2035
2125
|
/** Gap kept between the pane's top edge and the turn's first message. */
|
|
2036
2126
|
static TURN_TOP_GAP_PX = 16;
|
|
2037
2127
|
lastLoadedConversationId = null; // Track which conversation's peripheral data was loaded
|
|
2038
2128
|
currentlyLoadingConversationId = null; // Track which conversation is currently being loaded
|
|
2039
2129
|
conversationLoadToken = 0; // Monotonic token to discard stale async conversation loads
|
|
2130
|
+
/** The reconcile passes in progress, shared by every caller that arrives while they run. */
|
|
2131
|
+
reconcileInFlight = null;
|
|
2132
|
+
/** Reason for one more reconcile pass, requested while a pass was running. */
|
|
2133
|
+
reconcileRerunReason = null;
|
|
2040
2134
|
IsProcessing = false;
|
|
2041
2135
|
/** @deprecated Use {@link IsProcessing}. */
|
|
2042
2136
|
get isProcessing() {
|
|
@@ -2835,9 +2929,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
2835
2929
|
}
|
|
2836
2930
|
// Shared AI mention/suggestion engine (BaseSingleton — same instance the composer plugins use)
|
|
2837
2931
|
mentionAutocompleteService = MentionAutocompleteService.Instance;
|
|
2838
|
-
constructor(agentStateService, conversationAgentService, activeTasks, cdr, artifactPermissionService, attachmentService, streamingService, confirmDialog, bridge, analyzeArtifactService, uiCommandHandler, interactiveFormApplyService, agentClientService) {
|
|
2932
|
+
constructor(agentStateService, livenessDom, conversationAgentService, activeTasks, cdr, artifactPermissionService, attachmentService, streamingService, confirmDialog, bridge, analyzeArtifactService, uiCommandHandler, interactiveFormApplyService, agentClientService) {
|
|
2839
2933
|
super();
|
|
2840
2934
|
this.agentStateService = agentStateService;
|
|
2935
|
+
this.livenessDom = livenessDom;
|
|
2841
2936
|
this.conversationAgentService = conversationAgentService;
|
|
2842
2937
|
this.activeTasks = activeTasks;
|
|
2843
2938
|
this.cdr = cdr;
|
|
@@ -2852,13 +2947,19 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
2852
2947
|
this.agentClientService = agentClientService;
|
|
2853
2948
|
}
|
|
2854
2949
|
/**
|
|
2855
|
-
* Apply a form-role artifact's spec
|
|
2856
|
-
*
|
|
2857
|
-
*
|
|
2858
|
-
*
|
|
2950
|
+
* Apply a form-role artifact's spec for the current user — an EntityFormOverride for a
|
|
2951
|
+
* whole form, a form contribution for a panel. The service picks the path, handles the
|
|
2952
|
+
* Create-vs-Modify decision, confirms via dialog, and notifies.
|
|
2953
|
+
*
|
|
2954
|
+
* The agent context names the record form the user has open (`AdditionalContext.Form`,
|
|
2955
|
+
* published by the record tab). The service reads that form's full composition from the
|
|
2956
|
+
* `FormCompositionRegistry`, to check a panel's placement against the live form and detect
|
|
2957
|
+
* an installed contribution holding the same key. With no open form it asks the server for
|
|
2958
|
+
* the composition instead.
|
|
2859
2959
|
*/
|
|
2860
2960
|
async OnApplyFormRequested(event) {
|
|
2861
|
-
|
|
2961
|
+
const additional = (this.AppContext?.['AdditionalContext'] ?? null);
|
|
2962
|
+
await this.interactiveFormApplyService.ConfirmAndApply(event.spec, event.entityName, this.ProviderToUse, additional?.Form ?? null);
|
|
2862
2963
|
}
|
|
2863
2964
|
async ngOnInit() {
|
|
2864
2965
|
// Bind provider-aware services to this component's provider so multi-server
|
|
@@ -3037,6 +3138,27 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3037
3138
|
if (message && conversationId) {
|
|
3038
3139
|
await this.handleMessageCompletion(message, event.agentRunId, conversationId);
|
|
3039
3140
|
}
|
|
3141
|
+
else if (conversationId) {
|
|
3142
|
+
// The completion is for a message we do not currently hold — it belongs to another
|
|
3143
|
+
// conversation, or to one scrolled out of the loaded window. Previously this event was
|
|
3144
|
+
// simply dropped, and for the scrolled-out case nothing else ever picked it up: the
|
|
3145
|
+
// `recentCompletions` replay only fires on conversation OPEN. Reconciling reads durable
|
|
3146
|
+
// state for every in-progress message we do hold, which repairs it if it is ours and
|
|
3147
|
+
// costs one narrow query if it is not.
|
|
3148
|
+
await this.ReconcileNow('completion-for-unloaded-message');
|
|
3149
|
+
}
|
|
3150
|
+
});
|
|
3151
|
+
// Reconciliation triggers that do NOT depend on a clean socket close. This is the
|
|
3152
|
+
// independent second layer: `retryAttempts`, `_socketStateSubject`,
|
|
3153
|
+
// `ServerConnectivityService`, `scheduleReconnection()` and `FireAndForgetHelper.onStreamEnd`
|
|
3154
|
+
// are all downstream of `on('closed')`, so on a half-open socket they fail together. The
|
|
3155
|
+
// supervisor coalesces socket-reconnect, stream-reconnect, tab-visible and browser-online
|
|
3156
|
+
// into one pass (MJ #4222).
|
|
3157
|
+
this.livenessDom.Start();
|
|
3158
|
+
ConversationsRuntime.Instance.Liveness.ReconciliationRequired$
|
|
3159
|
+
.pipe(takeUntil(this.destroy$))
|
|
3160
|
+
.subscribe((reason) => {
|
|
3161
|
+
void this.ReconcileNow(reason);
|
|
3040
3162
|
});
|
|
3041
3163
|
// Subscribe to polling-based agent state as a secondary fallback for completion detection.
|
|
3042
3164
|
// The sessionId is persisted in localStorage and reused on refresh, so WebSocket events
|
|
@@ -3405,14 +3527,14 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3405
3527
|
// Check for missed completions (user navigated away, agent completed, user returned)
|
|
3406
3528
|
for (const message of this.messages) {
|
|
3407
3529
|
if (message.Status === 'In-Progress' && message.ID) {
|
|
3408
|
-
const recentCompletion = this.streamingService.
|
|
3530
|
+
const recentCompletion = this.streamingService.GetRecentCompletion(message.ID);
|
|
3409
3531
|
if (recentCompletion) {
|
|
3410
3532
|
LogStatusEx({ message: `📥 Found missed completion for message ${message.ID}, handling...`, verboseOnly: true });
|
|
3411
3533
|
await this.handleMessageCompletion(message, recentCompletion.agentRunId, conversationId, loadToken);
|
|
3412
3534
|
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
3413
3535
|
return;
|
|
3414
3536
|
}
|
|
3415
|
-
this.streamingService.
|
|
3537
|
+
this.streamingService.ClearRecentCompletion(message.ID);
|
|
3416
3538
|
}
|
|
3417
3539
|
}
|
|
3418
3540
|
}
|
|
@@ -3717,6 +3839,44 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3717
3839
|
// Intentionally empty - ActiveTasksService only tracks in-memory running tasks
|
|
3718
3840
|
// Database tasks are loaded separately by TasksDropdownComponent
|
|
3719
3841
|
}
|
|
3842
|
+
/**
|
|
3843
|
+
* A streamed delta landed on an in-progress message (MessageInputComponent.MessageStreamed).
|
|
3844
|
+
* Unlike {@link OnMessageSent} this does not replace the `messages` array: that rebuilt the
|
|
3845
|
+
* whole timeline, re-measured the mounted range and armed a scroll-to-bottom timer on every
|
|
3846
|
+
* delta, which is what made a streaming reply flash and jump. The bubble is refreshed in place
|
|
3847
|
+
* and the viewport is kept steady. With `ReadReplyFromTop` the turn lands at its top once, on
|
|
3848
|
+
* the first delta, and the reply grows beneath it; otherwise the bottom is pinned in the same
|
|
3849
|
+
* frame as the DOM update, so the growth and the scroll paint together.
|
|
3850
|
+
*/
|
|
3851
|
+
OnMessageStreamed(message) {
|
|
3852
|
+
if (!this.isActiveConversation(message.ConversationID) || message.Status !== 'In-Progress') {
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
const index = this.messages.findIndex(m => UUIDsEqual(m.ID, message.ID));
|
|
3856
|
+
if (index >= 0 && this.messages[index] !== message) {
|
|
3857
|
+
if (this.isSettled(this.messages[index])) {
|
|
3858
|
+
return; // a frame that outlived completion; the completion path owns the bubble
|
|
3859
|
+
}
|
|
3860
|
+
// Keep the array and the window pointing at the entity the stream mutates, in place: a new
|
|
3861
|
+
// array reference would rebuild the timeline, which is the cost this path exists to avoid.
|
|
3862
|
+
this.messages[index] = message;
|
|
3863
|
+
this.windowStore.ApplyLocalDetail(message);
|
|
3864
|
+
}
|
|
3865
|
+
if (!this.messageListComponent?.RefreshRenderedMessage(message)) {
|
|
3866
|
+
// The first delta can beat the bubble's own render; the full path handles that one update.
|
|
3867
|
+
this.ngZone.run(() => void this.OnMessageSent(message));
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
this.followTranscript('stream');
|
|
3871
|
+
}
|
|
3872
|
+
/** Drops a landing still queued or retrying, so it cannot resolve after a newer one. */
|
|
3873
|
+
cancelPendingLanding() {
|
|
3874
|
+
this.pendingTurnStartMessageId = null;
|
|
3875
|
+
if (this.turnStartRetryHandle) {
|
|
3876
|
+
clearTimeout(this.turnStartRetryHandle);
|
|
3877
|
+
this.turnStartRetryHandle = null;
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3720
3880
|
async OnMessageSent(message) {
|
|
3721
3881
|
// The draft became a message — remove it from the persisted map + snapshot.
|
|
3722
3882
|
const sentKey = (message.ConversationID ?? this.ConversationId ?? '').trim().toLowerCase();
|
|
@@ -3770,14 +3930,22 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3770
3930
|
if (!this.isActiveConversation(message.ConversationID)) {
|
|
3771
3931
|
return;
|
|
3772
3932
|
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3933
|
+
}
|
|
3934
|
+
// A host turn can finish before this row is on screen. The completion is already in the
|
|
3935
|
+
// streaming service's replay window; apply it the way a conversation load does, so the
|
|
3936
|
+
// row does not stay In-Progress until the conversation is opened again. Register the row
|
|
3937
|
+
// for the live callback either way — an update of an existing In-Progress row included.
|
|
3938
|
+
if (message.Status === 'In-Progress' && message.ID) {
|
|
3939
|
+
if (!this.InProgressMessageIds.some((id) => UUIDsEqual(id, message.ID))) {
|
|
3779
3940
|
this.InProgressMessageIds = [...this.InProgressMessageIds, message.ID];
|
|
3780
3941
|
}
|
|
3942
|
+
const recentCompletion = this.streamingService.GetRecentCompletion(message.ID);
|
|
3943
|
+
if (recentCompletion) {
|
|
3944
|
+
await this.handleMessageCompletion(message, recentCompletion.agentRunId, message.ConversationID);
|
|
3945
|
+
if (this.isActiveConversation(message.ConversationID)) {
|
|
3946
|
+
this.streamingService.ClearRecentCompletion(message.ID);
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3781
3949
|
}
|
|
3782
3950
|
// Where the viewport goes: a fresh send follows — an in-place update of a message that
|
|
3783
3951
|
// is already on screen must not re-run the send path's scroll.
|
|
@@ -4024,6 +4192,8 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4024
4192
|
console.error('Failed to reload messages for active conversation:', error);
|
|
4025
4193
|
}
|
|
4026
4194
|
}
|
|
4195
|
+
/** Detail ids whose completion this instance has already applied. A live callback and the replay window can both deliver one finish. */
|
|
4196
|
+
handledCompletionIds;
|
|
4027
4197
|
/**
|
|
4028
4198
|
* Handle message completion triggered by PubSub completion event
|
|
4029
4199
|
* Reloads message, agent run, and artifacts, then updates UI
|
|
@@ -4031,6 +4201,15 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4031
4201
|
* @param agentRunId The ID of the agent run that completed
|
|
4032
4202
|
*/
|
|
4033
4203
|
async handleMessageCompletion(message, _agentRunId, expectedConversationId = message.ConversationID, loadToken) {
|
|
4204
|
+
const completionId = message.ID ? NormalizeUUID(message.ID) : '';
|
|
4205
|
+
if (completionId) {
|
|
4206
|
+
this.handledCompletionIds ??= new Set();
|
|
4207
|
+
if (this.handledCompletionIds.has(completionId)) {
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
this.handledCompletionIds.add(completionId);
|
|
4211
|
+
}
|
|
4212
|
+
let finished = false;
|
|
4034
4213
|
try {
|
|
4035
4214
|
const isCurrent = () => this.isCurrentConversationContext(expectedConversationId, loadToken);
|
|
4036
4215
|
LogStatusEx({ message: `🎉 Handling completion for message ${message.ID}`, verboseOnly: true });
|
|
@@ -4089,11 +4268,18 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4089
4268
|
this.messages = [...this.messages];
|
|
4090
4269
|
this.cdr.detectChanges();
|
|
4091
4270
|
LogStatusEx({ message: `✅ Completion handled for message ${message.ID}`, verboseOnly: true });
|
|
4271
|
+
finished = true;
|
|
4092
4272
|
}
|
|
4093
4273
|
catch (error) {
|
|
4094
4274
|
console.error(`Error handling message completion for ${message.ID}:`, error);
|
|
4095
4275
|
this.cdr.detectChanges();
|
|
4096
4276
|
}
|
|
4277
|
+
finally {
|
|
4278
|
+
// A switch away mid-reload must not consume the completion. The next load still has the replay entry.
|
|
4279
|
+
if (!finished && completionId) {
|
|
4280
|
+
this.handledCompletionIds?.delete(completionId);
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4097
4283
|
}
|
|
4098
4284
|
async OnAgentResponse(event) {
|
|
4099
4285
|
// Guard: ignore agent responses from background inputs for other conversations.
|
|
@@ -4225,6 +4411,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4225
4411
|
}
|
|
4226
4412
|
}
|
|
4227
4413
|
OpenProjectSelector() {
|
|
4414
|
+
if (this.EffectiveReadOnly) {
|
|
4415
|
+
return;
|
|
4416
|
+
}
|
|
4228
4417
|
this.ShowProjectSelector = true;
|
|
4229
4418
|
}
|
|
4230
4419
|
/** @deprecated Use {@link OpenProjectSelector}. */
|
|
@@ -4620,6 +4809,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4620
4809
|
get isReadOnlyView() {
|
|
4621
4810
|
return this.IsReadOnlyView;
|
|
4622
4811
|
}
|
|
4812
|
+
/** Read-only for any reason: the host said so, or the conversation is shared with View access. */
|
|
4813
|
+
get EffectiveReadOnly() {
|
|
4814
|
+
return this.ReadOnly || this.IsReadOnlyView;
|
|
4815
|
+
}
|
|
4623
4816
|
/**
|
|
4624
4817
|
* `true` when the current user is allowed to create new shares on this
|
|
4625
4818
|
* conversation: the owner, or a user with an Owner-level grant. Uses the same
|
|
@@ -4812,6 +5005,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4812
5005
|
* Unpins a message from the pins panel — saves to DB and patches the cache.
|
|
4813
5006
|
*/
|
|
4814
5007
|
async OnUnpinFromPanel(message) {
|
|
5008
|
+
if (this.EffectiveReadOnly) {
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
4815
5011
|
const previous = message.IsPinned;
|
|
4816
5012
|
message.IsPinned = false;
|
|
4817
5013
|
this.cdr.detectChanges();
|
|
@@ -4834,6 +5030,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4834
5030
|
* Sends the selected response as a new user message WITHOUT modifying the visible input
|
|
4835
5031
|
*/
|
|
4836
5032
|
async OnSuggestedResponseSelected(event) {
|
|
5033
|
+
if (this.EffectiveReadOnly) {
|
|
5034
|
+
return;
|
|
5035
|
+
}
|
|
4837
5036
|
const messageText = event.customInput || event.text;
|
|
4838
5037
|
// Get the active message input for the current conversation
|
|
4839
5038
|
// (we cache multiple instances, one per visited conversation)
|
|
@@ -5556,6 +5755,18 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
5556
5755
|
onReviewClosed() {
|
|
5557
5756
|
return this.OnReviewClosed();
|
|
5558
5757
|
}
|
|
5758
|
+
/**
|
|
5759
|
+
* A message reports that its run has gone quiet (MJ #4222).
|
|
5760
|
+
*
|
|
5761
|
+
* The reconciliation triggers all fire on transport events — a socket retry, a tab regaining
|
|
5762
|
+
* focus. This one fires on the symptom itself: a run that simply stopped reporting, with no event
|
|
5763
|
+
* anywhere to notice it. Each pass covers every in-progress message, so the request goes through
|
|
5764
|
+
* the runtime's coalescing trigger: quiet rows asking at about the same time share one pass.
|
|
5765
|
+
*/
|
|
5766
|
+
OnLivenessCheckRequested(messageId) {
|
|
5767
|
+
LogStatusEx({ message: `🫀 Message ${messageId} reports no recent progress — reconciling`, verboseOnly: true });
|
|
5768
|
+
ConversationsRuntime.Instance.Liveness.Trigger('message-liveness');
|
|
5769
|
+
}
|
|
5559
5770
|
/**
|
|
5560
5771
|
* Handles Shift+Click on an AI message bubble.
|
|
5561
5772
|
* Dumps a live snapshot of in-memory streaming and agent-run state to the browser
|
|
@@ -5865,6 +6076,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
5865
6076
|
// 3. a generic re-prompt — last resort if no user message found
|
|
5866
6077
|
// OnAnalyzeArtifact prefilled messageText with 'Analyze "..." — '; we
|
|
5867
6078
|
// overwrite that with the resolved followup before sending.
|
|
6079
|
+
// Read-only (host flag or a View share) must not auto-send the follow-up.
|
|
6080
|
+
if (this.EffectiveReadOnly) {
|
|
6081
|
+
return;
|
|
6082
|
+
}
|
|
5868
6083
|
const messageInput = this.getActiveMessageInputComponent();
|
|
5869
6084
|
if (messageInput) {
|
|
5870
6085
|
let followup = command.followupMessage?.trim();
|
|
@@ -6156,15 +6371,28 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6156
6371
|
this.scrollToBottom = true;
|
|
6157
6372
|
return;
|
|
6158
6373
|
}
|
|
6374
|
+
if (change === 'stream') {
|
|
6375
|
+
this.followStream();
|
|
6376
|
+
return;
|
|
6377
|
+
}
|
|
6159
6378
|
if (this.ReadReplyFromTop) {
|
|
6160
6379
|
if (message?.Role === 'User' && message.ID && message.ID !== this.currentTurnStartMessageId) {
|
|
6161
6380
|
this.currentTurnStartMessageId = message.ID;
|
|
6381
|
+
this.streamAnchor = null;
|
|
6382
|
+
this.streamPin = null;
|
|
6162
6383
|
}
|
|
6163
6384
|
else if (this.currentTurnStartMessageId && message?.Role === 'AI' && this.isSettled(message)) {
|
|
6385
|
+
if (this.streamAnchor !== null) {
|
|
6386
|
+
// The stream either pinned the turn's top or the reader took the viewport for this turn by
|
|
6387
|
+
// scrolling during it. Either way completion must not land it again; keep the post-landing
|
|
6388
|
+
// hold a normal landing gets so a status row right behind cannot yank the reader either.
|
|
6389
|
+
this.bottomFollowSuppressedUntil = Date.now() + POST_LANDING_FOLLOW_HOLD_MS;
|
|
6390
|
+
return;
|
|
6391
|
+
}
|
|
6164
6392
|
if (this.readerAtBottom) {
|
|
6165
6393
|
this.pendingTurnStartMessageId = this.currentTurnStartMessageId;
|
|
6166
6394
|
this.scrollToBottom = false;
|
|
6167
|
-
this.bottomFollowSuppressedUntil = Date.now() +
|
|
6395
|
+
this.bottomFollowSuppressedUntil = Date.now() + POST_LANDING_FOLLOW_HOLD_MS;
|
|
6168
6396
|
}
|
|
6169
6397
|
return;
|
|
6170
6398
|
}
|
|
@@ -6182,6 +6410,63 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6182
6410
|
isSettled(message) {
|
|
6183
6411
|
return message.Status === 'Complete' || message.Status === 'Error';
|
|
6184
6412
|
}
|
|
6413
|
+
/**
|
|
6414
|
+
* Where the viewport goes on a streamed delta, in the same frame as the DOM change so growth and
|
|
6415
|
+
* scroll paint together. Without ReadReplyFromTop, or for a turn this component never saw open
|
|
6416
|
+
* (a reload mid-stream), a reader at the bottom is followed there. With it, the turn's top is
|
|
6417
|
+
* pinned as high as the content allows on every frame: the question rises to the top as the
|
|
6418
|
+
* reply grows beneath it, and once the reader scrolls away the pin is released for the turn.
|
|
6419
|
+
*/
|
|
6420
|
+
followStream() {
|
|
6421
|
+
const turnId = this.ReadReplyFromTop ? this.currentTurnStartMessageId : null;
|
|
6422
|
+
if (!turnId) {
|
|
6423
|
+
if (this.readerAtBottom) {
|
|
6424
|
+
this.ScrollToBottomNow();
|
|
6425
|
+
}
|
|
6426
|
+
return;
|
|
6427
|
+
}
|
|
6428
|
+
if (this.streamAnchor === 'declined') {
|
|
6429
|
+
return;
|
|
6430
|
+
}
|
|
6431
|
+
const container = this.scrollContainer?.nativeElement;
|
|
6432
|
+
if (!container) {
|
|
6433
|
+
return;
|
|
6434
|
+
}
|
|
6435
|
+
const pin = this.resolveStreamPin(turnId, container);
|
|
6436
|
+
if (!pin) {
|
|
6437
|
+
return;
|
|
6438
|
+
}
|
|
6439
|
+
if (this.streamAnchor === null) {
|
|
6440
|
+
if (!this.readerAtBottom) {
|
|
6441
|
+
this.streamAnchor = 'declined';
|
|
6442
|
+
return;
|
|
6443
|
+
}
|
|
6444
|
+
this.cancelPendingLanding();
|
|
6445
|
+
}
|
|
6446
|
+
else if (Math.abs(container.scrollTop - this.streamAnchor) > STREAM_ANCHOR_TOLERANCE_PX) {
|
|
6447
|
+
this.streamAnchor = 'declined';
|
|
6448
|
+
return;
|
|
6449
|
+
}
|
|
6450
|
+
const turnTop = this.offsetWithinScroller(pin.target) - pin.clearance;
|
|
6451
|
+
container.scrollTop = Math.max(0, Math.min(turnTop, container.scrollHeight - container.clientHeight));
|
|
6452
|
+
// Read the position back: the browser clamps and rounds, and the next frame compares against
|
|
6453
|
+
// what it will actually read, not what was asked for.
|
|
6454
|
+
this.streamAnchor = container.scrollTop;
|
|
6455
|
+
this.scrollToBottom = false;
|
|
6456
|
+
this.bottomFollowSuppressedUntil = Date.now() + POST_LANDING_FOLLOW_HOLD_MS;
|
|
6457
|
+
// The pin moves the viewport without a scroll event once the turn's top is reached, so the
|
|
6458
|
+
// at-bottom state and the jump-to-bottom affordance would otherwise go stale for the stream.
|
|
6459
|
+
this.CheckScroll();
|
|
6460
|
+
}
|
|
6461
|
+
/** The stream pin's target and clearance for this turn, resolved once and kept while the node is in the DOM. */
|
|
6462
|
+
resolveStreamPin(turnId, container) {
|
|
6463
|
+
if (this.streamPin && this.streamPin.target.isConnected) {
|
|
6464
|
+
return this.streamPin;
|
|
6465
|
+
}
|
|
6466
|
+
const target = this.messageListComponent?.FindTimelineElement(turnId) ?? null;
|
|
6467
|
+
this.streamPin = target ? { target, clearance: this.turnTopClearance(container) } : null;
|
|
6468
|
+
return this.streamPin;
|
|
6469
|
+
}
|
|
6185
6470
|
/**
|
|
6186
6471
|
* readReplyFromTop: once the reply has rendered, scrolls the turn so its first message
|
|
6187
6472
|
* sits at the top of the pane — but only if the turn is taller than the pane. A turn that
|
|
@@ -6237,12 +6522,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6237
6522
|
}
|
|
6238
6523
|
clearTurnTracking() {
|
|
6239
6524
|
this.currentTurnStartMessageId = null;
|
|
6240
|
-
this.
|
|
6525
|
+
this.streamAnchor = null;
|
|
6526
|
+
this.streamPin = null;
|
|
6241
6527
|
this.bottomFollowSuppressedUntil = 0;
|
|
6242
|
-
|
|
6243
|
-
clearTimeout(this.turnStartRetryHandle);
|
|
6244
|
-
this.turnStartRetryHandle = null;
|
|
6245
|
-
}
|
|
6528
|
+
this.cancelPendingLanding();
|
|
6246
6529
|
}
|
|
6247
6530
|
/**
|
|
6248
6531
|
* Detect and reconcile agent run states against conversation detail statuses.
|
|
@@ -6257,6 +6540,190 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6257
6540
|
* completed successfully, we detect the mismatch and correct it. This prevents
|
|
6258
6541
|
* the race condition where the client overwrites a server-completed record.
|
|
6259
6542
|
*/
|
|
6543
|
+
/**
|
|
6544
|
+
* Re-read the agent-run rows backing this conversation's in-progress messages, refreshing
|
|
6545
|
+
* {@link AgentRunsByDetailId} in place.
|
|
6546
|
+
*
|
|
6547
|
+
* REQUIRED BEFORE ANY ON-DEMAND RECONCILE. {@link reconnectInProgressRuns} compares against
|
|
6548
|
+
* the in-memory map and never reloads it; on the conversation-load path that is safe only
|
|
6549
|
+
* because `loadPeripheralData` ran moments earlier off a fresh fetch. Invoked from a socket
|
|
6550
|
+
* reconnect or a tab regaining focus there has been no such fetch, so the map still holds the
|
|
6551
|
+
* stale `Running` status the outage froze it at — and the reconcile silently finds nothing to
|
|
6552
|
+
* do, which is indistinguishable from working (MJ #4222).
|
|
6553
|
+
*
|
|
6554
|
+
* Deliberately narrow in rows: only the in-progress details, with `BypassCache` because the
|
|
6555
|
+
* server wrote these rows through a different provider. Cheaper than
|
|
6556
|
+
* `windowStore.RefreshLatest()`, and cheap enough to run on every trigger. Full entity rows are
|
|
6557
|
+
* read, not a few fields: each row replaces the run object the message renders from and that the
|
|
6558
|
+
* completion path reloads, so a partial row would blank the run's duration, tokens and cost.
|
|
6559
|
+
*/
|
|
6560
|
+
async refreshAgentRunsForInProgress(conversationId, loadToken) {
|
|
6561
|
+
const inProgressIds = this.messages
|
|
6562
|
+
.filter(m => m.Status === 'In-Progress' && m.Role === 'AI' && m.ID)
|
|
6563
|
+
.map(m => m.ID);
|
|
6564
|
+
if (inProgressIds.length === 0) {
|
|
6565
|
+
return;
|
|
6566
|
+
}
|
|
6567
|
+
const quoted = inProgressIds.map(id => `'${id}'`).join(',');
|
|
6568
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
6569
|
+
const result = await rv.RunView({
|
|
6570
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
6571
|
+
ExtraFilter: `ConversationDetailID IN (${quoted})`,
|
|
6572
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
6573
|
+
ResultType: 'entity_object',
|
|
6574
|
+
BypassCache: true
|
|
6575
|
+
}, this.currentUser);
|
|
6576
|
+
if (!result.Success || !this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6577
|
+
return;
|
|
6578
|
+
}
|
|
6579
|
+
// `OrderBy __mj_CreatedAt DESC` puts the newest run first, so the first row seen for a detail
|
|
6580
|
+
// in THIS pass wins — a retried message must reconcile against its latest run, not its first.
|
|
6581
|
+
// Tracked per pass rather than by consulting the map, which usually already holds a run from
|
|
6582
|
+
// an earlier pass and is cleared only on conversation load.
|
|
6583
|
+
const seenDetailIds = new Set();
|
|
6584
|
+
for (const run of result.Results || []) {
|
|
6585
|
+
const detailId = run.ConversationDetailID;
|
|
6586
|
+
if (!detailId || seenDetailIds.has(detailId)) {
|
|
6587
|
+
continue;
|
|
6588
|
+
}
|
|
6589
|
+
seenDetailIds.add(detailId);
|
|
6590
|
+
this.AgentRunsByDetailId.set(detailId, run);
|
|
6591
|
+
}
|
|
6592
|
+
// New map reference so OnPush children re-read it.
|
|
6593
|
+
this.AgentRunsByDetailId = new Map(this.AgentRunsByDetailId);
|
|
6594
|
+
}
|
|
6595
|
+
/**
|
|
6596
|
+
* Reconcile in-progress messages against durable server state, on demand.
|
|
6597
|
+
*
|
|
6598
|
+
* This is the recovery path for the case the five close-event-driven mechanisms all miss: a
|
|
6599
|
+
* completion published while the client's transport was silently dead. Tier 0 makes the socket
|
|
6600
|
+
* close; this is what recovers the event that was dropped while it was down.
|
|
6601
|
+
*
|
|
6602
|
+
* Only one pass runs at a time. A request that arrives during a pass shares it and schedules one
|
|
6603
|
+
* follow-up pass, so every caller resolves after a pass that started after its request.
|
|
6604
|
+
*
|
|
6605
|
+
* @param reason What prompted it — carried only for logging.
|
|
6606
|
+
*/
|
|
6607
|
+
async ReconcileNow(reason) {
|
|
6608
|
+
if (this.reconcileInFlight) {
|
|
6609
|
+
this.reconcileRerunReason = reason;
|
|
6610
|
+
return this.reconcileInFlight;
|
|
6611
|
+
}
|
|
6612
|
+
this.reconcileInFlight = this.runReconcilePasses(reason);
|
|
6613
|
+
return this.reconcileInFlight;
|
|
6614
|
+
}
|
|
6615
|
+
/** Runs passes until no caller has asked for another. Clears the in-flight marker on exit. */
|
|
6616
|
+
async runReconcilePasses(reason) {
|
|
6617
|
+
try {
|
|
6618
|
+
let next = reason;
|
|
6619
|
+
while (next) {
|
|
6620
|
+
this.reconcileRerunReason = null;
|
|
6621
|
+
await this.reconcileOnce(next);
|
|
6622
|
+
next = this.reconcileRerunReason;
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
finally {
|
|
6626
|
+
this.reconcileInFlight = null;
|
|
6627
|
+
}
|
|
6628
|
+
}
|
|
6629
|
+
/** One reconcile pass over the in-progress messages of the active conversation. */
|
|
6630
|
+
async reconcileOnce(reason) {
|
|
6631
|
+
const conversationId = this.conversationId;
|
|
6632
|
+
if (!conversationId || !this.currentUser) {
|
|
6633
|
+
return;
|
|
6634
|
+
}
|
|
6635
|
+
// READ the token, never `++` it. `conversationLoadToken` is a CANCELLATION token: every
|
|
6636
|
+
// in-flight conversation load checks it and bails when it changes, so incrementing here
|
|
6637
|
+
// would abort a load already running rather than merely tagging this work.
|
|
6638
|
+
const loadToken = this.conversationLoadToken;
|
|
6639
|
+
LogStatusEx({ message: `🔁 Reconciling in-progress runs (${reason})`, verboseOnly: true });
|
|
6640
|
+
try {
|
|
6641
|
+
await this.refreshAgentRunsForInProgress(conversationId, loadToken);
|
|
6642
|
+
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6643
|
+
return;
|
|
6644
|
+
}
|
|
6645
|
+
await this.detectAndReconcileAgentRuns(conversationId, loadToken);
|
|
6646
|
+
}
|
|
6647
|
+
catch (error) {
|
|
6648
|
+
// Recovery is best-effort: a failed reconcile must never surface as a user-facing error,
|
|
6649
|
+
// and the next trigger will try again.
|
|
6650
|
+
console.error('[ConversationChatArea] Reconciliation failed:', error);
|
|
6651
|
+
}
|
|
6652
|
+
}
|
|
6653
|
+
/**
|
|
6654
|
+
* Ask the durable read model whether a message we still show as in-progress has in fact finished.
|
|
6655
|
+
*
|
|
6656
|
+
* The last gap in the recovery chain. Everything else here reads `MJ: AI Agent Runs` through the
|
|
6657
|
+
* client's own provider; when that returns nothing the message simply waits. The tail query reads
|
|
6658
|
+
* the same truth server-side from a cursor, reports the conversation detail's own status, and runs
|
|
6659
|
+
* over HTTP — so it answers while the WebSocket is still down, which is the whole point.
|
|
6660
|
+
*
|
|
6661
|
+
* Completion is routed through the existing {@link handleMessageCompletion}, never written here:
|
|
6662
|
+
* four writers already move a message out of In-Progress and a fifth would race them.
|
|
6663
|
+
*
|
|
6664
|
+
* @returns true when the message was completed from durable state.
|
|
6665
|
+
*/
|
|
6666
|
+
async tryRecoverFromTail(message, conversationId, loadToken) {
|
|
6667
|
+
const tail = ConversationsRuntime.Instance.Tail;
|
|
6668
|
+
const result = await tail.Tail(message.ID);
|
|
6669
|
+
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6670
|
+
return false;
|
|
6671
|
+
}
|
|
6672
|
+
if (!result.Success) {
|
|
6673
|
+
// An older server has no tail query, and a new client then gets a failure on every call.
|
|
6674
|
+
// Decide from the run list instead, as the client did before the tail existed.
|
|
6675
|
+
return this.recoverFromRunList(message, conversationId, loadToken);
|
|
6676
|
+
}
|
|
6677
|
+
// `IsInFlight` false means the server considers the run finished. A terminal `DetailStatus`
|
|
6678
|
+
// with no run at all covers the case where the detail was completed by something other than an
|
|
6679
|
+
// agent run. Either way the message must stop spinning.
|
|
6680
|
+
const detailIsTerminal = result.DetailStatus === 'Complete' || result.DetailStatus === 'Error';
|
|
6681
|
+
const runIsTerminal = result.RunID != null && !result.IsInFlight;
|
|
6682
|
+
if (!runIsTerminal && !detailIsTerminal) {
|
|
6683
|
+
return false;
|
|
6684
|
+
}
|
|
6685
|
+
// A terminal run beside a detail the server still reports as open is the orphan window, which
|
|
6686
|
+
// the server-side reconciler closes after its grace period. `handleMessageCompletion` re-reads
|
|
6687
|
+
// the detail rather than writing it, so completing here cannot settle the message; it would
|
|
6688
|
+
// reload the whole conversation on every trigger and leave it spinning regardless. Keep the
|
|
6689
|
+
// cursor and wait for the row to close.
|
|
6690
|
+
if (!detailIsTerminal && result.DetailStatus === 'In-Progress') {
|
|
6691
|
+
LogStatusEx({
|
|
6692
|
+
message: `📼 Tail reports run ${result.RunID} finished but detail ${message.ID} is still open — leaving it to the reconciler`,
|
|
6693
|
+
verboseOnly: true
|
|
6694
|
+
});
|
|
6695
|
+
return false;
|
|
6696
|
+
}
|
|
6697
|
+
LogStatusEx({
|
|
6698
|
+
message: `📼 Tail reports message ${message.ID} finished (run ${result.RunID ?? 'none'}, status ${result.RunStatus ?? result.DetailStatus}) — completing`,
|
|
6699
|
+
verboseOnly: true
|
|
6700
|
+
});
|
|
6701
|
+
await this.handleMessageCompletion(message, result.RunID ?? '', conversationId, loadToken);
|
|
6702
|
+
// The message is terminal, so its cursor will never advance again.
|
|
6703
|
+
tail.Forget(message.ID);
|
|
6704
|
+
return true;
|
|
6705
|
+
}
|
|
6706
|
+
/**
|
|
6707
|
+
* Complete a message from the run list alone. Used only when the tail call fails.
|
|
6708
|
+
*
|
|
6709
|
+
* Less precise than the tail: it cannot see the conversation detail's own status, so during the
|
|
6710
|
+
* orphan window it reloads the message without settling it. That was the behavior before the
|
|
6711
|
+
* tail existed, and it is better than leaving a finished message spinning.
|
|
6712
|
+
*
|
|
6713
|
+
* @returns true when the message was completed.
|
|
6714
|
+
*/
|
|
6715
|
+
async recoverFromRunList(message, conversationId, loadToken) {
|
|
6716
|
+
const run = this.AgentRunsByDetailId.get(message.ID);
|
|
6717
|
+
if (!run || !RUN_LIST_TERMINAL_STATUSES.includes(run.Status)) {
|
|
6718
|
+
return false;
|
|
6719
|
+
}
|
|
6720
|
+
LogStatusEx({
|
|
6721
|
+
message: `📼 Tail unavailable; run ${run.ID} (${run.Status}) for message ${message.ID} is finished — completing from the run list`,
|
|
6722
|
+
verboseOnly: true
|
|
6723
|
+
});
|
|
6724
|
+
await this.handleMessageCompletion(message, run.ID, conversationId, loadToken);
|
|
6725
|
+
return true;
|
|
6726
|
+
}
|
|
6260
6727
|
async detectAndReconcileAgentRuns(conversationId, loadToken) {
|
|
6261
6728
|
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6262
6729
|
return;
|
|
@@ -6276,22 +6743,22 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6276
6743
|
return;
|
|
6277
6744
|
}
|
|
6278
6745
|
LogStatusEx({ message: `🔄 Found ${inProgressMessages.length} in-progress messages, checking status...`, verboseOnly: true });
|
|
6279
|
-
const completedStatuses = ['Completed', 'Failed', 'Error', 'Cancelled'];
|
|
6280
6746
|
for (const message of inProgressMessages) {
|
|
6281
6747
|
const agentRun = this.AgentRunsByDetailId.get(message.ID);
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
LogStatusEx({
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6748
|
+
// Ask durable state for every in-progress message, whatever the run map says. The run is not
|
|
6749
|
+
// the only thing that decides a message: the tail reports the conversation detail's own
|
|
6750
|
+
// status, which the run map does not carry at all. A finished run beside a detail that is
|
|
6751
|
+
// still open is the orphan window, and completing from the run alone would reload the whole
|
|
6752
|
+
// conversation on every trigger while the message kept spinning. The tail leaves that case
|
|
6753
|
+
// to the server-side reconciler, and completes a detail that was closed by anything.
|
|
6754
|
+
const recovered = await this.tryRecoverFromTail(message, conversationId, loadToken);
|
|
6755
|
+
if (!recovered) {
|
|
6756
|
+
LogStatusEx({
|
|
6757
|
+
message: agentRun
|
|
6758
|
+
? `🔌 Agent run ${agentRun.ID} (${agentRun.Status}) for message ${message.ID}; durable state does not show the message finished`
|
|
6759
|
+
: `⏳ No agent run found for in-progress message ${message.ID}, waiting for server...`,
|
|
6760
|
+
verboseOnly: true
|
|
6761
|
+
});
|
|
6295
6762
|
}
|
|
6296
6763
|
}
|
|
6297
6764
|
}
|
|
@@ -6438,7 +6905,7 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6438
6905
|
onIntentCheckCompleted(event) {
|
|
6439
6906
|
return this.OnIntentCheckCompleted(event);
|
|
6440
6907
|
}
|
|
6441
|
-
static ɵfac = function ConversationChatAreaComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationChatAreaComponent)(i0.ɵɵdirectiveInject(i1.AgentStateService), i0.ɵɵdirectiveInject(i2.
|
|
6908
|
+
static ɵfac = function ConversationChatAreaComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationChatAreaComponent)(i0.ɵɵdirectiveInject(i1.AgentStateService), i0.ɵɵdirectiveInject(i2.ConversationLivenessDomService), i0.ɵɵdirectiveInject(i3.ConversationAgentService), i0.ɵɵdirectiveInject(i4.ActiveTasksService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i5.ArtifactPermissionService), i0.ɵɵdirectiveInject(i6.ConversationAttachmentService), i0.ɵɵdirectiveInject(i7.ConversationStreamingService), i0.ɵɵdirectiveInject(i8.DialogService), i0.ɵɵdirectiveInject(i9.ConversationBridgeService), i0.ɵɵdirectiveInject(i10.AnalyzeArtifactService), i0.ɵɵdirectiveInject(i11.UICommandHandlerService), i0.ɵɵdirectiveInject(i10.InteractiveFormApplyService), i0.ɵɵdirectiveInject(i12.AgentClientService)); };
|
|
6442
6909
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationChatAreaComponent, selectors: [["mj-conversation-chat-area"]], contentQueries: function ConversationChatAreaComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
|
|
6443
6910
|
i0.ɵɵcontentQuery(dirIndex, ChatSlotDirective, 4);
|
|
6444
6911
|
} if (rf & 2) {
|
|
@@ -6453,20 +6920,20 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6453
6920
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.emptyStateComponent = _t.first);
|
|
6454
6921
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageListComponent = _t.first);
|
|
6455
6922
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageInputComponents = _t);
|
|
6456
|
-
} }, inputs: { EnvironmentId: "EnvironmentId", environmentId: "environmentId", CurrentUser: "CurrentUser", currentUser: "currentUser", ConversationId: "ConversationId", conversationId: "conversationId", Conversation: "Conversation", conversation: "conversation", ThreadId: "ThreadId", threadId: "threadId", SuppressNewConversationEmptyState: "SuppressNewConversationEmptyState", suppressNewConversationEmptyState: "suppressNewConversationEmptyState", AllowMentions: "AllowMentions", allowMentions: "allowMentions", AllowAgentMentions: "AllowAgentMentions", allowAgentMentions: "allowAgentMentions", AllowEntityMentions: "AllowEntityMentions", allowEntityMentions: "allowEntityMentions", AllowSkillCommands: "AllowSkillCommands", allowSkillCommands: "allowSkillCommands", AllowAttachments: "AllowAttachments", allowAttachments: "allowAttachments", AllowPlanMode: "AllowPlanMode", allowPlanMode: "allowPlanMode", AllowRealtime: "AllowRealtime", allowRealtime: "allowRealtime", ShowEmptyFill: "ShowEmptyFill", showEmptyFill: "showEmptyFill", ShowLoadingState: "ShowLoadingState", showLoadingState: "showLoadingState", ReadReplyFromTop: "ReadReplyFromTop", readReplyFromTop: "readReplyFromTop", ShowAgentRunDetails: "ShowAgentRunDetails", showAgentRunDetails: "showAgentRunDetails", ShowReactions: "ShowReactions", showReactions: "showReactions", ShowMessageRating: "ShowMessageRating", showMessageRating: "showMessageRating", AllowPinning: "AllowPinning", allowPinning: "allowPinning", AllowMessageEdit: "AllowMessageEdit", allowMessageEdit: "allowMessageEdit", AllowMessageDelete: "AllowMessageDelete", allowMessageDelete: "allowMessageDelete", ShowSuggestedPrompts: "ShowSuggestedPrompts", showSuggestedPrompts: "showSuggestedPrompts", ShowDateNavigation: "ShowDateNavigation", showDateNavigation: "showDateNavigation", AssistantDisplayName: "AssistantDisplayName", assistantDisplayName: "assistantDisplayName", AssistantAvatarUrl: "AssistantAvatarUrl", assistantAvatarUrl: "assistantAvatarUrl", IsNewConversation: "IsNewConversation", isNewConversation: "isNewConversation", PendingMessage: "PendingMessage", pendingMessage: "pendingMessage", PendingMessageConversationId: "PendingMessageConversationId", pendingMessageConversationId: "pendingMessageConversationId", PendingAttachments: "PendingAttachments", pendingAttachments: "pendingAttachments", PendingArtifactId: "PendingArtifactId", pendingArtifactId: "pendingArtifactId", PendingArtifactVersionNumber: "PendingArtifactVersionNumber", pendingArtifactVersionNumber: "pendingArtifactVersionNumber", PendingArtifactConversationId: "PendingArtifactConversationId", pendingArtifactConversationId: "pendingArtifactConversationId", OverlayMode: "OverlayMode", overlayMode: "overlayMode", ShowExportButton: "ShowExportButton", showExportButton: "showExportButton", ExportButtonLabel: "ExportButtonLabel", exportButtonLabel: "exportButtonLabel", ExportButtonIcon: "ExportButtonIcon", exportButtonIcon: "exportButtonIcon", ExportBranding: "ExportBranding", exportBranding: "exportBranding", ShowShareButton: "ShowShareButton", showShareButton: "showShareButton", ShowArtifactIndicator: "ShowArtifactIndicator", showArtifactIndicator: "showArtifactIndicator", AppContext: "AppContext", appContext: "appContext", DefaultAgentId: "DefaultAgentId", defaultAgentId: "defaultAgentId", AgentReplyMode: "AgentReplyMode", AllowedAgentIDs: "AllowedAgentIDs", MentionPeople: "MentionPeople", AgentHistoryFrom: "AgentHistoryFrom", AgentTurnHandler: "AgentTurnHandler", AutoNameConversation: "AutoNameConversation", ApplicationScope: "ApplicationScope", applicationScope: "applicationScope", ApplicationId: "ApplicationId", applicationId: "applicationId", LinkedEntityId: "LinkedEntityId", linkedEntityId: "linkedEntityId", LinkedRecordId: "LinkedRecordId", linkedRecordId: "linkedRecordId", ShowAgentPicker: "ShowAgentPicker", showAgentPicker: "showAgentPicker", ShowAgentModePicker: "ShowAgentModePicker", showAgentModePicker: "showAgentModePicker", EmptyStateGreeting: "EmptyStateGreeting", emptyStateGreeting: "emptyStateGreeting", ShowSidebarToggle: "ShowSidebarToggle", showSidebarToggle: "showSidebarToggle", ShowAgentCharacter: "ShowAgentCharacter", showAgentCharacter: "showAgentCharacter", AgentCharacterConfig: "AgentCharacterConfig", agentCharacterConfig: "agentCharacterConfig", EmptyStateConfig: "EmptyStateConfig", emptyStateConfig: "emptyStateConfig", ShowDemonstrationSurface: "ShowDemonstrationSurface", showDemonstrationSurface: "showDemonstrationSurface", DemonstrationSurfaceContent: "DemonstrationSurfaceContent", demonstrationSurfaceContent: "demonstrationSurfaceContent", ComposerDraft: "ComposerDraft", composerDraft: "composerDraft", ComposerAgentMention: "ComposerAgentMention", composerAgentMention: "composerAgentMention" }, outputs: { 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" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 25, vars: 34, consts: [["emptyStateInput", ""], ["scrollContainer", ""], ["messageInput", ""], [1, "chat-area"], [1, "chat-agent-presence", 3, "chat-agent-presence--prominent"], [1, "chat-header"], [1, "chat-content-area"], [1, "chat-demonstration-stage"], [1, "chat-messages-pane"], [1, "chat-messages-wrapper"], [3, "saved", "cancelled", "isOpen", "artifact", "currentUser"], [3, "pinnedMessages", "isLoading"], [3, "parentMessageId", "conversationId", "currentUser"], [3, "cancelled", "exported", "branding", "isVisible", "conversation", "currentUser"], [3, "Result", "Visible", "Context", "Adapter"], [3, "cancelled", "membersChanged", "isVisible", "conversation", "currentUser"], [1, "modal-overlay"], [3, "isOpen", "environmentId", "currentUser", "excludeCollectionIds", "artifactVersionId", "artifactName", "artifactVersionNumber"], [3, "data", "visible"], [3, "imageUrl", "alt", "fileName", "visible"], [1, "chat-agent-presence"], [3, "State", "AgentName", "AvatarUrl", "Mode"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "chat-info"], ["title", "Show conversations", 1, "sidebar-toggle-btn"], [1, "chat-title"], [1, "shared-by-badge", 3, "title"], ["title", "Assign to project", 1, "project-tag"], ["title", "View Test Run", 1, "test-indicator"], [1, "chat-actions", "chat-actions-buttons"], ["title", "View pinned messages", 1, "pin-chip", 3, "active"], ["title", "View artifacts", 1, "artifact-indicator"], ["title", "View members", 1, "chat-members"], [3, "AgentID", "Disabled"], [3, "Conversation", "CurrentUser", "AllowedAgentIDs", "Disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "title"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "shared", "title"], ["title", "Show conversations", 1, "sidebar-toggle-btn", 3, "click"], [1, "fas", "fa-table-columns"], [1, "fas", "fa-share-nodes"], ["title", "Assign to project", 1, "project-tag", 3, "click"], [1, "fas", "fa-folder"], ["title", "View Test Run", 1, "test-indicator", 3, "click"], [1, "fas", "fa-flask"], ["title", "View pinned messages", 1, "pin-chip", 3, "click"], [1, "fas", "fa-thumbtack"], [1, "pin-chip-count"], ["title", "View artifacts", 1, "artifact-indicator", 3, "click"], [1, "fas", "fa-cube"], [1, "artifact-badge"], ["title", "View members", 1, "chat-members", 3, "click"], [1, "fas", "fa-users"], [1, "members-badge"], [3, "PresetChanged", "AgentID", "Disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], [1, "btn-label"], [1, "conversation-loading-state"], ["text", "Loading conversation...", "size", "large"], [3, "currentUser", "initialDraft", "disabled", "showSidebarToggle", "overlayMode", "greeting", "showSuggestedPrompts", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "AllowedAgentIDs", "MentionPeople", "ComposerExtraTemplate", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [3, "initialDraftApplied", "DraftStateChanged", "ComposerBlurred", "sidebarToggleClicked", "messageSent", "currentUser", "initialDraft", "disabled", "showSidebarToggle", "overlayMode", "greeting", "showSuggestedPrompts", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "AllowedAgentIDs", "MentionPeople", "ComposerExtraTemplate", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [1, "chat-messages-container"], [1, "chat-input-container"], [1, "chat-composer-extra"], [1, "message-input-container-wrapper"], [3, "initialDraftApplied", "DraftStateChanged", "ComposerBlurred", "emptyStateSubmit", "emptyStateMode", "initialDraft", "currentUser", "disabled", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "AllowedAgentIDs", "MentionPeople", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [1, "upload-indicator-overlay"], [1, "chat-messages-container", 3, "scroll"], [3, "OlderRequested", "DateJumpRequested", "realtimeSessionOpenRequested", "replyInThread", "viewThread", "deleteMessage", "retryMessage", "testFeedbackMessage", "artifactClicked", "messageEdited", "openEntityRecord", "suggestedResponseSelected", "attachmentClicked", "diagnosticRequested", "messagePinToggled", "beforeResponseFormSubmitted", "afterResponseFormSubmitted", "showEmptyFill", "showDateNavigation", "showAgentRunDetails", "showReactions", "showMessageRating", "allowPinning", "allowMessageEdit", "allowMessageDelete", "assistantDisplayName", "assistantAvatarUrl", "messages", "HasMoreAbove", "IsLoadingOlder", "ScrollRoot", "conversation", "currentUser", "isProcessing", "artifactMap", "agentRunMap", "ratingsMap", "userAvatarMap", "attachmentsMap", "messageRendererTemplate", "messageExtraTemplate", "sessionMetaMap"], [1, "scroll-to-bottom-icon", 2, "left", "50%"], [1, "loading-peripheral-placeholder"], ["size", "medium", 3, "text"], [1, "scroll-to-bottom-icon", 2, "left", "50%", 3, "click"], [1, "fas", "fa-arrow-down"], ["text", "Loading conversation data...", "size", "medium"], ["role", "status", 1, "read-only-banner"], [3, "hidden", "initialDraft", "conversationId", "conversationName", "currentUser", "conversationHistory", "artifactsByDetailId", "systemArtifactsByDetailId", "agentRunsByDetailId", "appContext", "applicationId", "defaultAgentId", "conversationDefaultAgentId", "agentConfigurationPresetId", "AgentReplyMode", "AllowedAgentIDs", "MentionPeople", "AgentHistoryFrom", "AgentTurnHandler", "AutoNameConversation", "inProgressMessageIds", "disabled", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "initialMessage", "initialAttachments"], [1, "fas", "fa-eye"], [3, "DraftStateChanged", "ComposerBlurred", "initialMessageAutoSendStarted", "initialMessageAutoSendFailed", "messageSent", "agentResponse", "agentRunDetected", "agentRunUpdate", "messageComplete", "artifactCreated", "conversationRenamed", "intentCheckStarted", "intentCheckCompleted", "beforeAgentTurn", "afterAgentTurn", "uploadStateChanged", "hidden", "initialDraft", "conversationId", "conversationName", "currentUser", "conversationHistory", "artifactsByDetailId", "systemArtifactsByDetailId", "agentRunsByDetailId", "appContext", "applicationId", "defaultAgentId", "conversationDefaultAgentId", "agentConfigurationPresetId", "AgentReplyMode", "AllowedAgentIDs", "MentionPeople", "AgentHistoryFrom", "AgentTurnHandler", "AutoNameConversation", "inProgressMessageIds", "disabled", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "initialMessage", "initialAttachments"], [1, "resize-handle"], [1, "chat-artifact-pane"], [3, "closed", "saveToCollectionRequested", "navigateToLink", "shareRequested", "maximizeToggled", "openEntityRecord", "navigationRequest", "analyzeRequested", "applyFormRequested", "artifactId", "currentUser", "environmentId", "versionNumber", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"], [1, "resize-handle", 3, "mousedown", "touchstart"], [3, "closed", "jumpRequested", "unpinRequested", "pinnedMessages", "isLoading"], [3, "NavigateRequest", "StartLiveRequested", "ReviewClosed", "AgentName", "Hidden", "CurrentUser", "EnvironmentID", "ReviewData", "Chrome", "Compact", "ShowDevLinks", "ShowDensityPicker"], ["type", "button", "title", "Return to the live call", "aria-label", "Return to the live call", 1, "voice-call-pill"], ["type", "button", "title", "Return to the live call", "aria-label", "Return to the live call", 1, "voice-call-pill", 3, "click"], ["aria-hidden", "true", 1, "voice-call-pill__pulse"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone-volume"], [1, "voice-call-pill__text"], [1, "voice-call-pill__name"], [1, "voice-call-pill__hint"], [3, "closed", "replyAdded", "parentMessageId", "conversationId", "currentUser"], [1, "modal-overlay", 3, "click"], [1, "modal-content", "project-selector-modal", 3, "click"], [1, "modal-header"], [1, "modal-close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "modal-body"], [3, "projectSelected", "environmentId", "currentUser", "selectedProjectId"], [1, "modal-content", "artifacts-modal", 3, "click"], [1, "modal-header-actions"], ["title", "Toggle system artifacts visibility", 1, "toggle-system-btn", 3, "active"], [1, "modal-body", "artifacts-grid"], ["Icon", "fa-solid fa-cube", "Title", "No artifacts in this conversation yet", 1, "artifacts-empty-fill"], [1, "artifact-modal-card", 3, "expanded", "system-artifact"], ["title", "Toggle system artifacts visibility", 1, "toggle-system-btn", 3, "click"], [1, "fas", "fa-cog"], [1, "artifact-modal-card"], [1, "artifact-card-header", 3, "click"], [1, "artifact-modal-icon"], [1, "fas", "fa-file-code"], [1, "artifact-modal-info"], [1, "artifact-modal-title"], [1, "artifact-modal-meta"], [1, "expand-btn"], [1, "artifact-modal-action"], [1, "fas", "fa-external-link-alt"], [1, "artifact-versions-list"], [1, "expand-btn", 3, "click"], [1, "fas"], [1, "artifact-version-item"], [1, "artifact-version-item", 3, "click"], [1, "version-badge"], [1, "version-open-text"], [1, "fas", "fa-arrow-right"], [3, "completed", "cancelled", "isOpen", "environmentId", "currentUser", "excludeCollectionIds", "artifactVersionId", "artifactName", "artifactVersionNumber"], [3, "closed", "data", "visible"], [3, "closed", "imageUrl", "alt", "fileName", "visible"]], template: function ConversationChatAreaComponent_Template(rf, ctx) { if (rf & 1) {
|
|
6923
|
+
} }, inputs: { EnvironmentId: "EnvironmentId", environmentId: "environmentId", CurrentUser: "CurrentUser", currentUser: "currentUser", ConversationId: "ConversationId", conversationId: "conversationId", Conversation: "Conversation", conversation: "conversation", ThreadId: "ThreadId", threadId: "threadId", SuppressNewConversationEmptyState: "SuppressNewConversationEmptyState", suppressNewConversationEmptyState: "suppressNewConversationEmptyState", AllowMentions: "AllowMentions", allowMentions: "allowMentions", AllowAgentMentions: "AllowAgentMentions", allowAgentMentions: "allowAgentMentions", AllowEntityMentions: "AllowEntityMentions", allowEntityMentions: "allowEntityMentions", AllowSkillCommands: "AllowSkillCommands", allowSkillCommands: "allowSkillCommands", AllowAttachments: "AllowAttachments", allowAttachments: "allowAttachments", AllowPlanMode: "AllowPlanMode", allowPlanMode: "allowPlanMode", AllowRealtime: "AllowRealtime", allowRealtime: "allowRealtime", ShowEmptyFill: "ShowEmptyFill", showEmptyFill: "showEmptyFill", ShowLoadingState: "ShowLoadingState", showLoadingState: "showLoadingState", ReadReplyFromTop: "ReadReplyFromTop", readReplyFromTop: "readReplyFromTop", ShowAgentRunDetails: "ShowAgentRunDetails", showAgentRunDetails: "showAgentRunDetails", ShowReactions: "ShowReactions", showReactions: "showReactions", ShowMessageRating: "ShowMessageRating", showMessageRating: "showMessageRating", AllowPinning: "AllowPinning", allowPinning: "allowPinning", AllowMessageEdit: "AllowMessageEdit", allowMessageEdit: "allowMessageEdit", AllowMessageDelete: "AllowMessageDelete", allowMessageDelete: "allowMessageDelete", ReadOnly: "ReadOnly", ReadOnlyMessage: "ReadOnlyMessage", ShowSuggestedPrompts: "ShowSuggestedPrompts", showSuggestedPrompts: "showSuggestedPrompts", ShowDateNavigation: "ShowDateNavigation", showDateNavigation: "showDateNavigation", AssistantDisplayName: "AssistantDisplayName", assistantDisplayName: "assistantDisplayName", AssistantAvatarUrl: "AssistantAvatarUrl", assistantAvatarUrl: "assistantAvatarUrl", IsNewConversation: "IsNewConversation", isNewConversation: "isNewConversation", PendingMessage: "PendingMessage", pendingMessage: "pendingMessage", PendingMessageConversationId: "PendingMessageConversationId", pendingMessageConversationId: "pendingMessageConversationId", PendingAttachments: "PendingAttachments", pendingAttachments: "pendingAttachments", PendingArtifactId: "PendingArtifactId", pendingArtifactId: "pendingArtifactId", PendingArtifactVersionNumber: "PendingArtifactVersionNumber", pendingArtifactVersionNumber: "pendingArtifactVersionNumber", PendingArtifactConversationId: "PendingArtifactConversationId", pendingArtifactConversationId: "pendingArtifactConversationId", OverlayMode: "OverlayMode", overlayMode: "overlayMode", ShowExportButton: "ShowExportButton", showExportButton: "showExportButton", ExportButtonLabel: "ExportButtonLabel", exportButtonLabel: "exportButtonLabel", ExportButtonIcon: "ExportButtonIcon", exportButtonIcon: "exportButtonIcon", ExportBranding: "ExportBranding", exportBranding: "exportBranding", ShowShareButton: "ShowShareButton", showShareButton: "showShareButton", ShowArtifactIndicator: "ShowArtifactIndicator", showArtifactIndicator: "showArtifactIndicator", AppContext: "AppContext", appContext: "appContext", DefaultAgentId: "DefaultAgentId", defaultAgentId: "defaultAgentId", AgentReplyMode: "AgentReplyMode", AllowedAgentIDs: "AllowedAgentIDs", MentionPeople: "MentionPeople", AgentHistoryFrom: "AgentHistoryFrom", AgentTurnHandler: "AgentTurnHandler", AutoNameConversation: "AutoNameConversation", EnableDecisionRouting: "EnableDecisionRouting", ApplicationScope: "ApplicationScope", applicationScope: "applicationScope", ApplicationId: "ApplicationId", applicationId: "applicationId", LinkedEntityId: "LinkedEntityId", linkedEntityId: "linkedEntityId", LinkedRecordId: "LinkedRecordId", linkedRecordId: "linkedRecordId", ShowAgentPicker: "ShowAgentPicker", showAgentPicker: "showAgentPicker", ShowAgentModePicker: "ShowAgentModePicker", showAgentModePicker: "showAgentModePicker", EmptyStateGreeting: "EmptyStateGreeting", emptyStateGreeting: "emptyStateGreeting", ShowSidebarToggle: "ShowSidebarToggle", showSidebarToggle: "showSidebarToggle", ShowAgentCharacter: "ShowAgentCharacter", showAgentCharacter: "showAgentCharacter", AgentCharacterConfig: "AgentCharacterConfig", agentCharacterConfig: "agentCharacterConfig", EmptyStateConfig: "EmptyStateConfig", emptyStateConfig: "emptyStateConfig", ShowDemonstrationSurface: "ShowDemonstrationSurface", showDemonstrationSurface: "showDemonstrationSurface", DemonstrationSurfaceContent: "DemonstrationSurfaceContent", demonstrationSurfaceContent: "demonstrationSurfaceContent", ComposerDraft: "ComposerDraft", composerDraft: "composerDraft", ComposerAgentMention: "ComposerAgentMention", composerAgentMention: "composerAgentMention" }, outputs: { 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" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 25, vars: 34, consts: [["emptyStateInput", ""], ["scrollContainer", ""], ["messageInput", ""], [1, "chat-area"], [1, "chat-agent-presence", 3, "chat-agent-presence--prominent"], [1, "chat-header"], [1, "chat-content-area"], [1, "chat-demonstration-stage"], [1, "chat-messages-pane"], [1, "chat-messages-wrapper"], [3, "saved", "cancelled", "isOpen", "artifact", "currentUser"], [3, "pinnedMessages", "isLoading", "AllowUnpin"], [3, "parentMessageId", "conversationId", "currentUser"], [3, "cancelled", "exported", "branding", "isVisible", "conversation", "currentUser"], [3, "Result", "Visible", "Context", "Adapter"], [3, "cancelled", "membersChanged", "isVisible", "conversation", "currentUser"], [1, "modal-overlay"], [3, "isOpen", "environmentId", "currentUser", "excludeCollectionIds", "artifactVersionId", "artifactName", "artifactVersionNumber"], [3, "data", "visible"], [3, "imageUrl", "alt", "fileName", "visible"], [1, "chat-agent-presence"], [3, "State", "AgentName", "AvatarUrl", "Mode"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "chat-info"], ["title", "Show conversations", 1, "sidebar-toggle-btn"], [1, "chat-title"], [1, "shared-by-badge", 3, "title"], [1, "project-tag"], ["title", "View Test Run", 1, "test-indicator"], [1, "chat-actions", "chat-actions-buttons"], ["title", "View pinned messages", 1, "pin-chip", 3, "active"], ["title", "View artifacts", 1, "artifact-indicator"], ["title", "View members", 1, "chat-members"], [3, "AgentID", "Disabled"], [3, "Conversation", "CurrentUser", "AllowedAgentIDs", "Disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "title"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "shared", "title"], ["title", "Show conversations", 1, "sidebar-toggle-btn", 3, "click"], [1, "fas", "fa-table-columns"], [1, "fas", "fa-share-nodes"], [1, "project-tag", 3, "click"], [1, "fas", "fa-folder"], ["title", "View Test Run", 1, "test-indicator", 3, "click"], [1, "fas", "fa-flask"], ["title", "View pinned messages", 1, "pin-chip", 3, "click"], [1, "fas", "fa-thumbtack"], [1, "pin-chip-count"], ["title", "View artifacts", 1, "artifact-indicator", 3, "click"], [1, "fas", "fa-cube"], [1, "artifact-badge"], ["title", "View members", 1, "chat-members", 3, "click"], [1, "fas", "fa-users"], [1, "members-badge"], [3, "PresetChanged", "AgentID", "Disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], [1, "btn-label"], [1, "conversation-loading-state"], ["text", "Loading conversation...", "size", "large"], ["role", "status", 1, "read-only-banner"], [3, "currentUser", "initialDraft", "disabled", "showSidebarToggle", "overlayMode", "greeting", "showSuggestedPrompts", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "AllowedAgentIDs", "MentionPeople", "ComposerExtraTemplate", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [1, "fas", "fa-eye"], [3, "initialDraftApplied", "DraftStateChanged", "ComposerBlurred", "sidebarToggleClicked", "messageSent", "currentUser", "initialDraft", "disabled", "showSidebarToggle", "overlayMode", "greeting", "showSuggestedPrompts", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "AllowedAgentIDs", "MentionPeople", "ComposerExtraTemplate", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [1, "chat-messages-container"], [1, "chat-input-container"], [1, "chat-composer-extra"], [1, "message-input-container-wrapper"], [3, "initialDraftApplied", "DraftStateChanged", "ComposerBlurred", "emptyStateSubmit", "emptyStateMode", "initialDraft", "currentUser", "disabled", "ReadOnly", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "AllowedAgentIDs", "MentionPeople", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes"], [1, "upload-indicator-overlay"], [1, "chat-messages-container", 3, "scroll"], [3, "OlderRequested", "DateJumpRequested", "realtimeSessionOpenRequested", "replyInThread", "viewThread", "deleteMessage", "retryMessage", "testFeedbackMessage", "artifactClicked", "messageEdited", "openEntityRecord", "suggestedResponseSelected", "attachmentClicked", "diagnosticRequested", "LivenessCheckRequested", "messagePinToggled", "beforeResponseFormSubmitted", "afterResponseFormSubmitted", "showEmptyFill", "showDateNavigation", "showAgentRunDetails", "showReactions", "showMessageRating", "allowPinning", "allowMessageEdit", "allowMessageDelete", "ReadOnly", "assistantDisplayName", "assistantAvatarUrl", "messages", "HasMoreAbove", "IsLoadingOlder", "ScrollRoot", "conversation", "currentUser", "isProcessing", "artifactMap", "agentRunMap", "ratingsMap", "userAvatarMap", "attachmentsMap", "messageRendererTemplate", "messageExtraTemplate", "sessionMetaMap"], [1, "scroll-to-bottom-icon", 2, "left", "50%"], [1, "loading-peripheral-placeholder"], ["size", "medium", 3, "text"], [1, "scroll-to-bottom-icon", 2, "left", "50%", 3, "click"], [1, "fas", "fa-arrow-down"], ["text", "Loading conversation data...", "size", "medium"], [3, "hidden", "initialDraft", "conversationId", "conversationName", "currentUser", "conversationHistory", "artifactsByDetailId", "systemArtifactsByDetailId", "agentRunsByDetailId", "appContext", "applicationId", "defaultAgentId", "conversationDefaultAgentId", "agentConfigurationPresetId", "AgentReplyMode", "AllowedAgentIDs", "MentionPeople", "AgentHistoryFrom", "AgentTurnHandler", "AutoNameConversation", "EnableDecisionRouting", "inProgressMessageIds", "disabled", "ReadOnly", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "initialMessage", "initialAttachments"], [3, "DraftStateChanged", "ComposerBlurred", "initialMessageAutoSendStarted", "initialMessageAutoSendFailed", "messageSent", "MessageStreamed", "agentResponse", "agentRunDetected", "agentRunUpdate", "messageComplete", "artifactCreated", "conversationRenamed", "intentCheckStarted", "intentCheckCompleted", "beforeAgentTurn", "afterAgentTurn", "uploadStateChanged", "hidden", "initialDraft", "conversationId", "conversationName", "currentUser", "conversationHistory", "artifactsByDetailId", "systemArtifactsByDetailId", "agentRunsByDetailId", "appContext", "applicationId", "defaultAgentId", "conversationDefaultAgentId", "agentConfigurationPresetId", "AgentReplyMode", "AllowedAgentIDs", "MentionPeople", "AgentHistoryFrom", "AgentTurnHandler", "AutoNameConversation", "EnableDecisionRouting", "inProgressMessageIds", "disabled", "ReadOnly", "enableAttachments", "enableMentions", "enableAgentMentions", "enableEntityMentions", "enableSkillCommands", "enablePlanMode", "enableRealtime", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "initialMessage", "initialAttachments"], [1, "resize-handle"], [1, "chat-artifact-pane"], [3, "closed", "saveToCollectionRequested", "navigateToLink", "shareRequested", "maximizeToggled", "openEntityRecord", "navigationRequest", "analyzeRequested", "applyFormRequested", "artifactId", "currentUser", "environmentId", "versionNumber", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"], [1, "resize-handle", 3, "mousedown", "touchstart"], [3, "closed", "jumpRequested", "unpinRequested", "pinnedMessages", "isLoading", "AllowUnpin"], [3, "NavigateRequest", "StartLiveRequested", "ReviewClosed", "AgentName", "Hidden", "CurrentUser", "EnvironmentID", "ReviewData", "Chrome", "Compact", "ShowDevLinks", "ShowDensityPicker"], ["type", "button", "title", "Return to the live call", "aria-label", "Return to the live call", 1, "voice-call-pill"], ["type", "button", "title", "Return to the live call", "aria-label", "Return to the live call", 1, "voice-call-pill", 3, "click"], ["aria-hidden", "true", 1, "voice-call-pill__pulse"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone-volume"], [1, "voice-call-pill__text"], [1, "voice-call-pill__name"], [1, "voice-call-pill__hint"], [3, "closed", "replyAdded", "parentMessageId", "conversationId", "currentUser"], [1, "modal-overlay", 3, "click"], [1, "modal-content", "project-selector-modal", 3, "click"], [1, "modal-header"], [1, "modal-close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "modal-body"], [3, "projectSelected", "environmentId", "currentUser", "selectedProjectId"], [1, "modal-content", "artifacts-modal", 3, "click"], [1, "modal-header-actions"], ["title", "Toggle system artifacts visibility", 1, "toggle-system-btn", 3, "active"], [1, "modal-body", "artifacts-grid"], ["Icon", "fa-solid fa-cube", "Title", "No artifacts in this conversation yet", 1, "artifacts-empty-fill"], [1, "artifact-modal-card", 3, "expanded", "system-artifact"], ["title", "Toggle system artifacts visibility", 1, "toggle-system-btn", 3, "click"], [1, "fas", "fa-cog"], [1, "artifact-modal-card"], [1, "artifact-card-header", 3, "click"], [1, "artifact-modal-icon"], [1, "fas", "fa-file-code"], [1, "artifact-modal-info"], [1, "artifact-modal-title"], [1, "artifact-modal-meta"], [1, "expand-btn"], [1, "artifact-modal-action"], [1, "fas", "fa-external-link-alt"], [1, "artifact-versions-list"], [1, "expand-btn", 3, "click"], [1, "fas"], [1, "artifact-version-item"], [1, "artifact-version-item", 3, "click"], [1, "version-badge"], [1, "version-open-text"], [1, "fas", "fa-arrow-right"], [3, "completed", "cancelled", "isOpen", "environmentId", "currentUser", "excludeCollectionIds", "artifactVersionId", "artifactName", "artifactVersionNumber"], [3, "closed", "data", "visible"], [3, "closed", "imageUrl", "alt", "fileName", "visible"]], template: function ConversationChatAreaComponent_Template(rf, ctx) { if (rf & 1) {
|
|
6457
6924
|
i0.ɵɵelementStart(0, "div", 3);
|
|
6458
6925
|
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_1_Template, 3, 3, "div", 4);
|
|
6459
6926
|
i0.ɵɵconditionalCreate(2, ConversationChatAreaComponent_Conditional_2_Template, 1, 8, "ng-container")(3, ConversationChatAreaComponent_Conditional_3_Template, 16, 15, "div", 5);
|
|
6460
6927
|
i0.ɵɵelementStart(4, "div", 6);
|
|
6461
6928
|
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_5_Template, 2, 6, "div", 7);
|
|
6462
6929
|
i0.ɵɵelementStart(6, "div", 8);
|
|
6463
|
-
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_7_Template, 1, 1)(8, ConversationChatAreaComponent_Conditional_8_Template,
|
|
6930
|
+
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_7_Template, 1, 1)(8, ConversationChatAreaComponent_Conditional_8_Template, 3, 1)(9, ConversationChatAreaComponent_Conditional_9_Template, 5, 1, "div", 9)(10, ConversationChatAreaComponent_Conditional_10_Template, 10, 29, "div", 9);
|
|
6464
6931
|
i0.ɵɵelementEnd();
|
|
6465
6932
|
i0.ɵɵconditionalCreate(11, ConversationChatAreaComponent_Conditional_11_Template, 3, 14);
|
|
6466
6933
|
i0.ɵɵelementStart(12, "mj-artifact-share-modal", 10);
|
|
6467
6934
|
i0.ɵɵlistener("saved", function ConversationChatAreaComponent_Template_mj_artifact_share_modal_saved_12_listener() { return ctx.onArtifactShared(); })("cancelled", function ConversationChatAreaComponent_Template_mj_artifact_share_modal_cancelled_12_listener() { return ctx.onArtifactShareModalClose(); });
|
|
6468
6935
|
i0.ɵɵelementEnd();
|
|
6469
|
-
i0.ɵɵconditionalCreate(13, ConversationChatAreaComponent_Conditional_13_Template, 1,
|
|
6936
|
+
i0.ɵɵconditionalCreate(13, ConversationChatAreaComponent_Conditional_13_Template, 1, 3, "mj-pinned-messages-panel", 11);
|
|
6470
6937
|
i0.ɵɵelementEnd();
|
|
6471
6938
|
i0.ɵɵconditionalCreate(14, ConversationChatAreaComponent_Conditional_14_Template, 4, 14);
|
|
6472
6939
|
i0.ɵɵpipe(15, "async");
|
|
@@ -6526,12 +6993,12 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6526
6993
|
i0.ɵɵconditional(ctx.testFeedbackDialogData ? 23 : -1);
|
|
6527
6994
|
i0.ɵɵadvance();
|
|
6528
6995
|
i0.ɵɵconditional(ctx.showImageViewer ? 24 : -1);
|
|
6529
|
-
} }, dependencies: [i12.NgTemplateOutlet, i13.MJButtonDirective, i13.MJEmptyStateComponent, i9.ArtifactViewerPanelComponent, i14.TestFeedbackDialogComponent, i15.LoadingComponent, i16.GenericShareDialogComponent, i17.ArtifactCollectionPickerModalComponent, i18.ArtifactShareModalComponent, i19.MJChatAgentPresenceDefaultComponent, i20.RealtimeSessionOverlayComponent, i21.MessageListComponent, i22.MessageInputComponent, i23.ConversationEmptyStateComponent, i24.ConversationAgentPickerComponent, i25.ConversationModePickerComponent, i26.ThreadPanelComponent, i27.ProjectSelectorComponent, i28.MembersModalComponent, i29.ExportModalComponent, i30.ImageViewerComponent, i31.PinnedMessagesPanelComponent, i12.AsyncPipe], styles: ["[_nghost-%COMP%] {\n display: flex;\n width: 100%;\n height: 100%;\n}\n\n.chat-area[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n \n position: relative;\n}\n\n.chat-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n background: var(--mj-bg-surface-card);\n z-index: 10;\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n\n.chat-agent-presence[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 8px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n z-index: 11;\n}\n\n.chat-agent-presence--prominent[_ngcontent-%COMP%] {\n padding: 16px 20px;\n justify-content: center;\n}\n\n.chat-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n\n.sidebar-toggle-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: transparent;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-text-primary) 12%, transparent);\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: color 0.15s ease;\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n}\n\n.chat-title[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-tag[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 12px;\n}\n\n.project-tag[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-text-muted);\n}\n\n.project-tag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.test-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-status-warning);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 8px;\n}\n\n.test-indicator[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.test-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n.pin-chip[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, transparent);\n border-radius: 20px;\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.pin-chip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.pin-chip[_ngcontent-%COMP%]:hover, \n.pin-chip.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.pin-chip-count[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n}\n\n.chat-members[_ngcontent-%COMP%], \n.artifact-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n padding: 6px 8px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.chat-members[_ngcontent-%COMP%]:hover, \n.artifact-indicator[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n.artifact-badge[_ngcontent-%COMP%], \n.members-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n.members-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.ambient-agent-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n animation: _ngcontent-%COMP%_pulse 2s ease-in-out infinite;\n}\n\n.ambient-agent-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n}\n.chat-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.share-btn.shared[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-brand-primary-hover);\n}\n\n.share-btn.shared[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.chat-content-area[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: row;\n position: relative;\n}\n\n.chat-messages-pane[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n min-width: min(300px, 100%); \n overflow: hidden;\n transition: width 0.3s ease;\n}\n\n.chat-messages-pane.full-width[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.chat-messages-pane[_ngcontent-%COMP%]:not(.full-width) {\n flex: 1;\n}\n\n.chat-messages-pane.hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n.resize-handle[_ngcontent-%COMP%] {\n width: 4px;\n background: transparent;\n cursor: col-resize;\n flex-shrink: 0;\n position: relative;\n transition: background-color 0.2s;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n}\n\n.resize-handle[_ngcontent-%COMP%]::before {\n content: \"\";\n position: absolute;\n left: -4px;\n right: -4px;\n top: 0;\n bottom: 0;\n}\n\n.chat-artifact-pane[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.chat-artifact-pane.maximized[_ngcontent-%COMP%] {\n width: 100% !important;\n}\n\n.chat-artifact-pane[_ngcontent-%COMP%] > mj-artifact-viewer-panel[_ngcontent-%COMP%] {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.chat-messages-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n position: relative; \n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.chat-demonstration-stage[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: auto;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n flex: 1;\n min-width: 0;\n}\n\n.chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane[_ngcontent-%COMP%], \n.chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane.full-width[_ngcontent-%COMP%] {\n flex: 0 0 320px;\n width: 320px;\n min-width: 0;\n}\n\n@media (max-width: 768px) {\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-demonstration-stage[_ngcontent-%COMP%] {\n flex: 1 1 60%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n height: auto;\n }\n\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane[_ngcontent-%COMP%], \n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane.full-width[_ngcontent-%COMP%] {\n flex: 1 1 40%;\n width: 100%;\n height: auto;\n }\n}\n\n\n.upload-indicator-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem 1.5rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n z-index: 100;\n pointer-events: none;\n}\n\n.chat-messages-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-surface-card);\n min-height: 0;\n position: relative;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%] {\n position: sticky;\n bottom: 21px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 40px;\n margin-top: -40px;\n margin-left: auto;\n margin-right: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: var(--mj-shadow-md);\n transition: all 0.2s ease;\n z-index: 100;\n pointer-events: auto;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n transform: translateX(-50%) translateY(-2px);\n box-shadow: color-mix(in srgb, var(--mj-brand-primary) 20%, transparent) 0 4px 12px;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 16px;\n transition: color 0.2s;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.chat-input-container[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n padding: 0 1.25rem 1.25rem 1.25rem;\n overflow: visible;\n}\n\n\n.chat-composer-extra[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n\n.read-only-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 1.25rem 0.5rem 1.25rem;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n font-size: 12px;\n}\n\n.read-only-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.loading-peripheral-placeholder[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 140px;\n padding: 24px;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 50%, transparent);\n backdrop-filter: blur(2px);\n border-radius: 12px;\n margin: 12px;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease-in-out;\n}\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.project-selector-modal[_ngcontent-%COMP%] {\n width: 600px;\n height: 500px;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n}\n\n.modal-header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toggle-system-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 6px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.toggle-system-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.toggle-system-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.toggle-system-btn.active[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.toggle-system-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.modal-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s;\n}\n\n.modal-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n}\n\n.artifacts-modal[_ngcontent-%COMP%] {\n width: 700px;\n max-height: 600px;\n}\n\n.artifacts-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n\n.artifacts-empty-fill[_ngcontent-%COMP%] {\n grid-column: 1/-1;\n}\n\n.artifact-modal-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1.5px solid var(--mj-border-default);\n border-radius: 12px;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.artifact-modal-card.expanded[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%] {\n opacity: 0.85;\n border-color: var(--mj-border-default);\n border-style: dashed;\n position: relative;\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%]::before {\n content: \"SYSTEM\";\n position: absolute;\n top: 8px;\n right: 8px;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 3px;\n letter-spacing: 0.5px;\n z-index: 10;\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-text-muted);\n box-shadow: var(--mj-shadow-md);\n}\n\n.artifact-card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n}\n\n.artifact-card-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-modal-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.artifact-modal-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-radius: 10px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.artifact-modal-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n}\n\n.artifact-modal-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.artifact-modal-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.artifact-modal-meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.artifact-modal-action[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.artifact-modal-card[_ngcontent-%COMP%]:hover .artifact-modal-action[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.artifact-versions-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n padding: 0 1rem 1rem 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-version-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px 12px 68px;\n cursor: pointer;\n transition: background 0.15s;\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n.artifact-version-item[_ngcontent-%COMP%] .version-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 600;\n font-family: monospace;\n border-radius: 4px;\n}\n.artifact-version-item[_ngcontent-%COMP%] .version-open-text[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n.artifact-version-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover .version-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover .version-open-text[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.loading-peripheral-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n}\n.loading-peripheral-content[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.conversation-loading-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n width: 100%;\n}\n\n.loading-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 20px;\n gap: 16px;\n color: var(--mj-text-secondary);\n font-size: 15px;\n}\n.loading-content[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n.loading-content[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n@media (max-width: 768px) {\n .chat-header[_ngcontent-%COMP%] {\n padding: 8px 12px;\n gap: 6px;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n position: relative;\n }\n .chat-info[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n order: 1;\n }\n .chat-title[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 700;\n width: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n }\n .project-tag[_ngcontent-%COMP%] {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n display: none; \n }\n .test-indicator[_ngcontent-%COMP%] {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n }\n \n .chat-actions-buttons[_ngcontent-%COMP%] {\n order: 2;\n flex-shrink: 0;\n }\n .chat-actions-buttons[_ngcontent-%COMP%] .action-btn[_ngcontent-%COMP%] {\n padding: 6px 8px;\n min-width: auto;\n }\n .chat-actions-buttons[_ngcontent-%COMP%] .action-btn[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n display: none;\n }\n .chat-actions[_ngcontent-%COMP%] {\n flex-wrap: nowrap;\n }\n .chat-members[_ngcontent-%COMP%], \n .artifact-indicator[_ngcontent-%COMP%] {\n padding: 5px 7px;\n font-size: 13px;\n }\n .action-btn[_ngcontent-%COMP%] {\n padding: 6px 8px;\n font-size: 12px;\n }\n .ambient-agent-indicator[_ngcontent-%COMP%] {\n font-size: 12px;\n padding: 4px 8px;\n }\n .project-selector-modal[_ngcontent-%COMP%] {\n width: min(95vw, 600px);\n height: auto;\n }\n .artifacts-modal[_ngcontent-%COMP%] {\n width: min(95vw, 700px);\n }\n .artifacts-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n .chat-input-container[_ngcontent-%COMP%] {\n padding: 0 0.75rem 0.75rem 0.75rem;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] {\n bottom: 16px;\n width: 36px;\n height: 36px;\n }\n \n .chat-content-area[_ngcontent-%COMP%] {\n position: relative;\n }\n .chat-artifact-pane[_ngcontent-%COMP%] {\n position: fixed;\n left: 0;\n right: 0;\n top: 56px; \n bottom: 0;\n width: 100% !important;\n z-index: 100;\n background: var(--mj-bg-surface-card);\n }\n .resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n@media (max-width: 480px) {\n .chat-header[_ngcontent-%COMP%] {\n padding: 6px 8px;\n gap: 4px;\n }\n .chat-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 700;\n }\n .project-tag[_ngcontent-%COMP%] {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n display: none;\n }\n .test-indicator[_ngcontent-%COMP%] {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n }\n .chat-members[_ngcontent-%COMP%], \n .artifact-indicator[_ngcontent-%COMP%] {\n padding: 4px 8px;\n font-size: 11px;\n }\n .action-btn[_ngcontent-%COMP%] {\n padding: 5px 7px;\n font-size: 11px;\n }\n .ambient-agent-indicator[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 3px 6px;\n }\n .project-selector-modal[_ngcontent-%COMP%], \n .artifacts-modal[_ngcontent-%COMP%] {\n width: 100vw;\n height: 100vh;\n border-radius: 0;\n }\n .chat-input-container[_ngcontent-%COMP%] {\n padding: 0 0.5rem 0.5rem 0.5rem;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] {\n bottom: 12px;\n width: 32px;\n height: 32px;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}\n\n\n.artifact-picker-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n.artifact-picker-panel[_ngcontent-%COMP%] {\n position: fixed;\n right: 0;\n top: 0;\n width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n animation: _ngcontent-%COMP%_slideInRight 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n}\n\n.artifact-picker-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.artifact-picker-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-close[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n border-radius: 4px;\n}\n\n.artifact-picker-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n\n.artifact-picker-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.artifact-picker-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n}\n\n.artifact-picker-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n width: 24px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-pdf[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-excel[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-word[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.artifact-picker-item-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.artifact-picker-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.artifact-picker-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n.voice-call-pill[_ngcontent-%COMP%] {\n position: absolute;\n right: 18px;\n bottom: 18px;\n z-index: 49; \n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 16px 9px 13px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-elevated, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-family: inherit;\n cursor: pointer;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;\n}\n.voice-call-pill[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 10px 28px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent);\n transform: translateY(-1px);\n}\n.voice-call-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n.voice-call-pill__pulse[_ngcontent-%COMP%] {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n animation: _ngcontent-%COMP%_voice-pill-pulse 1.6s ease-in-out infinite;\n}\n.voice-call-pill__text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n line-height: 1.25;\n}\n.voice-call-pill__name[_ngcontent-%COMP%] {\n font-size: 12.5px;\n font-weight: 700;\n}\n.voice-call-pill__hint[_ngcontent-%COMP%] {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n}\n@keyframes _ngcontent-%COMP%_voice-pill-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-status-success) 0%, transparent);\n }\n}"] });
|
|
6996
|
+
} }, dependencies: [i13.NgTemplateOutlet, i14.MJButtonDirective, i14.MJEmptyStateComponent, i10.ArtifactViewerPanelComponent, i15.TestFeedbackDialogComponent, i16.LoadingComponent, i17.GenericShareDialogComponent, i18.ArtifactCollectionPickerModalComponent, i19.ArtifactShareModalComponent, i20.MJChatAgentPresenceDefaultComponent, i21.RealtimeSessionOverlayComponent, i22.MessageListComponent, i23.MessageInputComponent, i24.ConversationEmptyStateComponent, i25.ConversationAgentPickerComponent, i26.ConversationModePickerComponent, i27.ThreadPanelComponent, i28.ProjectSelectorComponent, i29.MembersModalComponent, i30.ExportModalComponent, i31.ImageViewerComponent, i32.PinnedMessagesPanelComponent, i13.AsyncPipe], styles: ["[_nghost-%COMP%] {\n display: flex;\n width: 100%;\n height: 100%;\n}\n\n.chat-area[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n \n position: relative;\n}\n\n.chat-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n background: var(--mj-bg-surface-card);\n z-index: 10;\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n\n.chat-agent-presence[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 8px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n z-index: 11;\n}\n\n.chat-agent-presence--prominent[_ngcontent-%COMP%] {\n padding: 16px 20px;\n justify-content: center;\n}\n\n.chat-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n\n.sidebar-toggle-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: transparent;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-text-primary) 12%, transparent);\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: color 0.15s ease;\n}\n\n.sidebar-toggle-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n}\n\n.chat-title[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.shared-by-badge[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-tag[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 12px;\n}\n\n.project-tag[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-text-muted);\n}\n\n.project-tag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.test-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-status-warning);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 8px;\n}\n\n.test-indicator[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.test-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n.pin-chip[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, transparent);\n border-radius: 20px;\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.pin-chip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.pin-chip[_ngcontent-%COMP%]:hover, \n.pin-chip.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.pin-chip-count[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n}\n\n.chat-members[_ngcontent-%COMP%], \n.artifact-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n padding: 6px 8px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.chat-members[_ngcontent-%COMP%]:hover, \n.artifact-indicator[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n.artifact-badge[_ngcontent-%COMP%], \n.members-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n.members-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.ambient-agent-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n animation: _ngcontent-%COMP%_pulse 2s ease-in-out infinite;\n}\n\n.ambient-agent-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n}\n.chat-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.share-btn.shared[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-brand-primary-hover);\n}\n\n.share-btn.shared[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.chat-content-area[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: row;\n position: relative;\n}\n\n.chat-messages-pane[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n min-width: min(300px, 100%); \n overflow: hidden;\n transition: width 0.3s ease;\n}\n\n.chat-messages-pane.full-width[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.chat-messages-pane[_ngcontent-%COMP%]:not(.full-width) {\n flex: 1;\n}\n\n.chat-messages-pane.hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n.resize-handle[_ngcontent-%COMP%] {\n width: 4px;\n background: transparent;\n cursor: col-resize;\n flex-shrink: 0;\n position: relative;\n transition: background-color 0.2s;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n}\n\n.resize-handle[_ngcontent-%COMP%]::before {\n content: \"\";\n position: absolute;\n left: -4px;\n right: -4px;\n top: 0;\n bottom: 0;\n}\n\n.chat-artifact-pane[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.chat-artifact-pane.maximized[_ngcontent-%COMP%] {\n width: 100% !important;\n}\n\n.chat-artifact-pane[_ngcontent-%COMP%] > mj-artifact-viewer-panel[_ngcontent-%COMP%] {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.chat-messages-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n position: relative; \n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.chat-demonstration-stage[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: auto;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n flex: 1;\n min-width: 0;\n}\n\n.chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane[_ngcontent-%COMP%], \n.chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane.full-width[_ngcontent-%COMP%] {\n flex: 0 0 320px;\n width: 320px;\n min-width: 0;\n}\n\n@media (max-width: 768px) {\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-demonstration-stage[_ngcontent-%COMP%] {\n flex: 1 1 60%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n height: auto;\n }\n\n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane[_ngcontent-%COMP%], \n .chat-content-area.demonstration-mode[_ngcontent-%COMP%] .chat-messages-pane.full-width[_ngcontent-%COMP%] {\n flex: 1 1 40%;\n width: 100%;\n height: auto;\n }\n}\n\n\n.upload-indicator-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem 1.5rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n z-index: 100;\n pointer-events: none;\n}\n\n.chat-messages-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-surface-card);\n min-height: 0;\n position: relative;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%] {\n position: sticky;\n bottom: 21px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 40px;\n margin-top: -40px;\n margin-left: auto;\n margin-right: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: var(--mj-shadow-md);\n transition: all 0.2s ease;\n z-index: 100;\n pointer-events: auto;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n transform: translateX(-50%) translateY(-2px);\n box-shadow: color-mix(in srgb, var(--mj-brand-primary) 20%, transparent) 0 4px 12px;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 16px;\n transition: color 0.2s;\n}\n\n.scroll-to-bottom-icon[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.chat-input-container[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n padding: 0 1.25rem 1.25rem 1.25rem;\n overflow: visible;\n}\n\n\n.chat-composer-extra[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n\n.read-only-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 1.25rem 0.5rem 1.25rem;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n font-size: 12px;\n}\n\n.read-only-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.loading-peripheral-placeholder[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 140px;\n padding: 24px;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 50%, transparent);\n backdrop-filter: blur(2px);\n border-radius: 12px;\n margin: 12px;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease-in-out;\n}\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.project-selector-modal[_ngcontent-%COMP%] {\n width: 600px;\n height: 500px;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n}\n\n.modal-header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toggle-system-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 6px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.toggle-system-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.toggle-system-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.toggle-system-btn.active[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.toggle-system-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.modal-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s;\n}\n\n.modal-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n}\n\n.artifacts-modal[_ngcontent-%COMP%] {\n width: 700px;\n max-height: 600px;\n}\n\n.artifacts-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n\n.artifacts-empty-fill[_ngcontent-%COMP%] {\n grid-column: 1/-1;\n}\n\n.artifact-modal-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1.5px solid var(--mj-border-default);\n border-radius: 12px;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.artifact-modal-card.expanded[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%] {\n opacity: 0.85;\n border-color: var(--mj-border-default);\n border-style: dashed;\n position: relative;\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%]::before {\n content: \"SYSTEM\";\n position: absolute;\n top: 8px;\n right: 8px;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 3px;\n letter-spacing: 0.5px;\n z-index: 10;\n}\n\n.artifact-modal-card.system-artifact[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-text-muted);\n box-shadow: var(--mj-shadow-md);\n}\n\n.artifact-card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n}\n\n.artifact-card-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-modal-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.artifact-modal-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-radius: 10px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.artifact-modal-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n}\n\n.artifact-modal-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.artifact-modal-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.artifact-modal-meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.artifact-modal-action[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.artifact-modal-card[_ngcontent-%COMP%]:hover .artifact-modal-action[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.artifact-versions-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n padding: 0 1rem 1rem 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-version-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px 12px 68px;\n cursor: pointer;\n transition: background 0.15s;\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n.artifact-version-item[_ngcontent-%COMP%] .version-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 600;\n font-family: monospace;\n border-radius: 4px;\n}\n.artifact-version-item[_ngcontent-%COMP%] .version-open-text[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n.artifact-version-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover .version-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover .version-open-text[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.artifact-version-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.loading-peripheral-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n}\n.loading-peripheral-content[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.conversation-loading-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n width: 100%;\n}\n\n.loading-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 20px;\n gap: 16px;\n color: var(--mj-text-secondary);\n font-size: 15px;\n}\n.loading-content[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n.loading-content[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n@media (max-width: 768px) {\n .chat-header[_ngcontent-%COMP%] {\n padding: 8px 12px;\n gap: 6px;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n position: relative;\n }\n .chat-info[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n order: 1;\n }\n .chat-title[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 700;\n width: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n }\n .project-tag[_ngcontent-%COMP%] {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n display: none; \n }\n .test-indicator[_ngcontent-%COMP%] {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n }\n \n .chat-actions-buttons[_ngcontent-%COMP%] {\n order: 2;\n flex-shrink: 0;\n }\n .chat-actions-buttons[_ngcontent-%COMP%] .action-btn[_ngcontent-%COMP%] {\n padding: 6px 8px;\n min-width: auto;\n }\n .chat-actions-buttons[_ngcontent-%COMP%] .action-btn[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n display: none;\n }\n .chat-actions[_ngcontent-%COMP%] {\n flex-wrap: nowrap;\n }\n .chat-members[_ngcontent-%COMP%], \n .artifact-indicator[_ngcontent-%COMP%] {\n padding: 5px 7px;\n font-size: 13px;\n }\n .action-btn[_ngcontent-%COMP%] {\n padding: 6px 8px;\n font-size: 12px;\n }\n .ambient-agent-indicator[_ngcontent-%COMP%] {\n font-size: 12px;\n padding: 4px 8px;\n }\n .project-selector-modal[_ngcontent-%COMP%] {\n width: min(95vw, 600px);\n height: auto;\n }\n .artifacts-modal[_ngcontent-%COMP%] {\n width: min(95vw, 700px);\n }\n .artifacts-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n .chat-input-container[_ngcontent-%COMP%] {\n padding: 0 0.75rem 0.75rem 0.75rem;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] {\n bottom: 16px;\n width: 36px;\n height: 36px;\n }\n \n .chat-content-area[_ngcontent-%COMP%] {\n position: relative;\n }\n .chat-artifact-pane[_ngcontent-%COMP%] {\n position: fixed;\n left: 0;\n right: 0;\n top: 56px; \n bottom: 0;\n width: 100% !important;\n z-index: 100;\n background: var(--mj-bg-surface-card);\n }\n .resize-handle[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n@media (max-width: 480px) {\n .chat-header[_ngcontent-%COMP%] {\n padding: 6px 8px;\n gap: 4px;\n }\n .chat-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 700;\n }\n .project-tag[_ngcontent-%COMP%] {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n display: none;\n }\n .test-indicator[_ngcontent-%COMP%] {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n }\n .chat-members[_ngcontent-%COMP%], \n .artifact-indicator[_ngcontent-%COMP%] {\n padding: 4px 8px;\n font-size: 11px;\n }\n .action-btn[_ngcontent-%COMP%] {\n padding: 5px 7px;\n font-size: 11px;\n }\n .ambient-agent-indicator[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 3px 6px;\n }\n .project-selector-modal[_ngcontent-%COMP%], \n .artifacts-modal[_ngcontent-%COMP%] {\n width: 100vw;\n height: 100vh;\n border-radius: 0;\n }\n .chat-input-container[_ngcontent-%COMP%] {\n padding: 0 0.5rem 0.5rem 0.5rem;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] {\n bottom: 12px;\n width: 32px;\n height: 32px;\n }\n .scroll-to-bottom-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}\n\n\n.artifact-picker-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n.artifact-picker-panel[_ngcontent-%COMP%] {\n position: fixed;\n right: 0;\n top: 0;\n width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n animation: _ngcontent-%COMP%_slideInRight 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n}\n\n.artifact-picker-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.artifact-picker-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-close[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n border-radius: 4px;\n}\n\n.artifact-picker-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n\n.artifact-picker-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.artifact-picker-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n}\n\n.artifact-picker-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n width: 24px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-pdf[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-excel[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file-word[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.artifact-picker-item[_ngcontent-%COMP%] i.fa-file[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.artifact-picker-item-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.artifact-picker-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.artifact-picker-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n.voice-call-pill[_ngcontent-%COMP%] {\n position: absolute;\n right: 18px;\n bottom: 18px;\n z-index: 49; \n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 16px 9px 13px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-elevated, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-family: inherit;\n cursor: pointer;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;\n}\n.voice-call-pill[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 10px 28px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent);\n transform: translateY(-1px);\n}\n.voice-call-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n.voice-call-pill__pulse[_ngcontent-%COMP%] {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n animation: _ngcontent-%COMP%_voice-pill-pulse 1.6s ease-in-out infinite;\n}\n.voice-call-pill__text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n line-height: 1.25;\n}\n.voice-call-pill__name[_ngcontent-%COMP%] {\n font-size: 12.5px;\n font-weight: 700;\n}\n.voice-call-pill__hint[_ngcontent-%COMP%] {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n}\n@keyframes _ngcontent-%COMP%_voice-pill-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-status-success) 0%, transparent);\n }\n}"] });
|
|
6530
6997
|
}
|
|
6531
6998
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ConversationChatAreaComponent, [{
|
|
6532
6999
|
type: Component,
|
|
6533
|
-
args: [{ standalone: false, selector: 'mj-conversation-chat-area', template: "<div class=\"chat-area\">\n <!-- agentPresence slot \u2014 sticky top, anchored with the header. Per Matt's\n 06-10 design: persistent presence indicator (Sid's face + live voice\n state). Off by default; opt in via [showAgentCharacter]. When a\n consumer projects an `mjChatSlot=\"agentPresence\"` template, it\n replaces the default presence component. -->\n @if (showAgentCharacter) {\n <div class=\"chat-agent-presence\" [class.chat-agent-presence--prominent]=\"agentCharacterConfig?.voiceStateMode === 'prominent'\">\n @if (slotTemplate('agentPresence'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: agentCharacterConfig,\n state: agentCharacterConfig?.state ?? 'idle',\n agentName: agentCharacterConfig?.characterName,\n avatarUrl: agentCharacterConfig?.avatarUrl,\n mode: agentCharacterConfig?.voiceStateMode ?? 'subtle'\n }\"></ng-container>\n } @else {\n <mj-chat-agent-presence-default\n [State]=\"agentCharacterConfig?.state ?? 'idle'\"\n [AgentName]=\"agentCharacterConfig?.characterName\"\n [AvatarUrl]=\"agentCharacterConfig?.avatarUrl\"\n [Mode]=\"agentCharacterConfig?.voiceStateMode ?? 'subtle'\">\n </mj-chat-agent-presence-default>\n }\n </div>\n }\n\n <!-- header slot \u2014 replaces the entire chat-header chrome (title, badges,\n export/share/agent-picker buttons). When projected, the consumer owns\n the entire header rendering; the default chrome below is bypassed\n wholesale. Context exposes the minimal IMJChatHeaderComponent shape;\n consumers needing more app state should bind to chat-area inputs\n directly via @ViewChild or wrap the whole component. -->\n @if (slotTemplate('header'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n conversationTitle: conversation?.Name ?? null,\n sharedBy: sharedByBadge?.display ?? null,\n artifactCount: artifactCountDisplay,\n showArtifactIndicator: showArtifactIndicator\n }\"></ng-container>\n } @else if (conversation || HasPreConversationHeader) {\n <!-- Default header \u2014 also renders BEFORE a conversation exists when the\n embedder has pre-conversation chrome to surface (currently just the\n mode picker \u2014 agent / share / export / members / artifacts all\n require a conversation row and stay hidden). Lets embedded surfaces\n like the Form Builder cockpit show the mode picker above the\n empty-state on a fresh chat instead of waiting for the first\n message to round-trip. -->\n <div class=\"chat-header\">\n <div class=\"chat-info\" [class.with-sidebar-toggle]=\"showSidebarToggle\">\n @if (showSidebarToggle) {\n <button class=\"sidebar-toggle-btn\"\n (click)=\"sidebarToggleClicked.emit()\"\n title=\"Show conversations\">\n <i class=\"fas fa-table-columns\"></i>\n </button>\n }\n @if (conversation) {\n <div class=\"chat-title\">{{ conversation.Name || '' }}</div>\n }\n @if (sharedByBadge) {\n <span class=\"shared-by-badge\" [title]=\"sharedByBadge.fullTooltip\">\n <i class=\"fas fa-share-nodes\"></i>\n <span>Shared by {{ sharedByBadge.display }}</span>\n </span>\n }\n @if (conversation?.ProjectID) {\n <button class=\"project-tag\" (click)=\"openProjectSelector()\" title=\"Assign to project\">\n <i class=\"fas fa-folder\"></i>\n <span>{{ conversation!.Project || 'Project' }}</span>\n </button>\n }\n @if (conversation?.TestRunID) {\n <button class=\"test-indicator\" (click)=\"viewTestRun(conversation!.TestRunID!)\" title=\"View Test Run\">\n <i class=\"fas fa-flask\"></i>\n <span>Test</span>\n </button>\n }\n </div>\n <div class=\"chat-actions chat-actions-buttons\">\n @if (allowPinning && pinnedMessageCount > 0) {\n <button class=\"pin-chip\" [class.active]=\"showPinsPanel\" (click)=\"TogglePinsPanel()\" title=\"View pinned messages\">\n <i class=\"fas fa-thumbtack\"></i>\n <span class=\"pin-chip-count\">{{ pinnedMessageCount }}</span>\n </button>\n }\n @if (showArtifactIndicator && artifactCountDisplay > 0) {\n <button class=\"artifact-indicator\" (click)=\"viewArtifacts()\" title=\"View artifacts\">\n <i class=\"fas fa-cube\"></i>\n <span class=\"artifact-badge\">{{ artifactCountDisplay }}</span>\n </button>\n }\n @if (memberCount > 1) {\n <button class=\"chat-members\" (click)=\"toggleMembersModal()\" title=\"View members\">\n <i class=\"fas fa-users\"></i>\n <span class=\"members-badge\">{{ memberCount }}</span>\n </button>\n }\n @if (!overlayMode && showAgentModePicker && ModePickerTargetAgentId) {\n <!-- Per-agent mode/quality picker (Draft / Standard / High).\n Targets the agent the next non-mention message will route\n to. Auto-hides when that agent has fewer than 2 configured\n presets. Choice persists per-user, per-agent via\n UserInfoEngine; emits the picked configuration ID up so\n <mj-message-input> can forward it on the next route.\n Hidden in overlayMode (the compact chat overlay): the\n mode dropdown wastes the narrow top-right space there. -->\n <mj-conversation-mode-picker\n [AgentID]=\"ModePickerTargetAgentId\"\n [Disabled]=\"isProcessing\"\n (PresetChanged)=\"OnAgentModePresetChanged($event)\">\n </mj-conversation-mode-picker>\n }\n @if (showAgentPicker && conversation) {\n <!-- Per-conversation default-agent pin. When set, non-mention\n messages route to this agent instead of Sage. Persists to\n MJConversationEntity.DefaultAgentID. Hidden when no\n conversation is loaded or when the embedder disables it. -->\n <mj-conversation-agent-picker\n [Conversation]=\"conversation\"\n [CurrentUser]=\"currentUser\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [Disabled]=\"isReadOnlyView\">\n </mj-conversation-agent-picker>\n }\n @if (showExportButton) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"exportConversation()\" [title]=\"exportButtonLabel + ' conversation'\">\n <i [class]=\"exportButtonIcon\"></i>\n <span class=\"btn-label\">{{ exportButtonLabel }}</span>\n </button>\n }\n @if (showShareButton && canShareConversation) {\n <button mjButton variant=\"flat\" size=\"sm\"\n [class.shared]=\"isShared\"\n (click)=\"shareConversation()\"\n [title]=\"isShared ? 'Manage sharing' : 'Share conversation'\">\n <i class=\"fas fa-share-nodes\"></i>\n <span class=\"btn-label\">Share</span>\n </button>\n }\n <!-- headerActions slot \u2014 ADDITIVE host buttons rendered after the stock\n actions (unlike the `header` slot, which replaces the whole header\n and therefore never reaches this branch). For visual parity,\n projected buttons should use mjButton variant=\"flat\" size=\"sm\". -->\n @if (slotTemplate('headerActions'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n conversationId: conversationId,\n isProcessing: isProcessing\n }\"></ng-container>\n }\n </div>\n </div>\n }\n\n <!-- Messages and Artifact Split Layout \u2014 restructures into [stage | rail]\n when isDemonstrationActive (per Matt's 06-10 design). The .demonstration-mode\n class drives the CSS Grid switch; the stage container renders only when the\n slot is projected AND the host opts in via [showDemonstrationSurface]. -->\n <div class=\"chat-content-area\" [class.demonstration-mode]=\"isDemonstrationActive\">\n <!-- demonstrationSurface stage \u2014 takes the main pane; messages shrink to\n a side rail (or move below on mobile). Off unless both\n [showDemonstrationSurface] is true AND a slot template is projected. -->\n @if (isDemonstrationActive) {\n <div class=\"chat-demonstration-stage\">\n <ng-container *ngTemplateOutlet=\"slotTemplate('demonstrationSurface'); context: {\n $implicit: demonstrationSurfaceContent,\n content: demonstrationSurfaceContent,\n visible: showDemonstrationSurface\n }\"></ng-container>\n </div>\n }\n\n <!-- Messages Pane -->\n <div class=\"chat-messages-pane\"\n [class.full-width]=\"!showArtifactPanel\"\n [class.hidden]=\"isArtifactPaneMaximized\">\n @if (isLoadingConversation) {\n <!-- Loading State - checked FIRST to prevent empty state flash. The branch\n always short-circuits the panes below; showLoadingState only controls\n whether the built-in spinner renders (hosts with their own loading\n chrome set it false and get a blank pane instead). -->\n @if (showLoadingState) {\n <div class=\"conversation-loading-state\">\n <mj-loading text=\"Loading conversation...\" size=\"large\"></mj-loading>\n </div>\n }\n } @else if ((isNewConversation || !conversationId) && !suppressNewConversationEmptyState) {\n <!-- emptyState slot \u2014 when a consumer projects mjChatSlot=\"emptyState\",\n they take over the entire empty-state region (including any send\n affordance \u2014 the slot interface doesn't include a sendMessage\n output, so consumers handle send via their own input). When no\n slot is projected, the rich built-in <mj-conversation-empty-state>\n renders with its own greeting, prompt chips, and message input.\n emptyStateConfig (when supplied) takes precedence over the legacy\n [emptyStateGreeting] string for backwards compatibility. -->\n @if (slotTemplate('emptyState'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: emptyStateConfig,\n greeting: emptyStateConfig?.greeting ?? emptyStateGreeting,\n subtext: emptyStateConfig?.subtext,\n suggestedPrompts: emptyStateConfig?.suggestedPrompts ?? []\n }\"></ng-container>\n } @else {\n <mj-conversation-empty-state\n [currentUser]=\"currentUser\"\n [initialDraft]=\"GetInitialDraftFor(null)\"\n (initialDraftApplied)=\"OnComposerDraftApplied()\"\n (DraftStateChanged)=\"OnDraftStateChanged(null, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [disabled]=\"isProcessing\"\n [showSidebarToggle]=\"showSidebarToggle\"\n [overlayMode]=\"overlayMode\"\n [greeting]=\"emptyStateConfig?.greeting ?? emptyStateGreeting\"\n [showSuggestedPrompts]=\"showSuggestedPrompts\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [ComposerExtraTemplate]=\"slotTemplate('composerExtra')\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n (sidebarToggleClicked)=\"sidebarToggleClicked.emit()\"\n (messageSent)=\"onEmptyStateMessageSent($event)\">\n </mj-conversation-empty-state>\n }\n } @else if ((isNewConversation || !conversationId) && suppressNewConversationEmptyState) {\n <!-- Pre-conversation normal-view: empty message list + emptyStateMode input.\n Used when host (e.g. Form Builder cockpit) wants the header + mode picker\n visible on first open instead of the centered welcome card. First send\n routes through onEmptyStateMessageSent which creates the conversation. -->\n <div class=\"chat-messages-wrapper\">\n <div class=\"chat-messages-container\"></div>\n <div class=\"chat-input-container\">\n <!-- composerExtra slot \u2014 host UI directly above the composer (IMJChatComposerExtraContext). -->\n @if (slotTemplate('composerExtra'); as t) {\n <div class=\"chat-composer-extra\">\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n ConversationId: conversationId,\n IsProcessing: isProcessing\n }\"></ng-container>\n </div>\n }\n <div class=\"message-input-container-wrapper\">\n <mj-message-input\n #emptyStateInput\n [emptyStateMode]=\"true\"\n [initialDraft]=\"GetInitialDraftFor(null)\"\n (initialDraftApplied)=\"OnComposerDraftApplied()\"\n (DraftStateChanged)=\"OnDraftStateChanged(null, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [currentUser]=\"currentUser\"\n [disabled]=\"isProcessing\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [enablePlanMode]=\"allowPlanMode\"\n [enableRealtime]=\"allowRealtime\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n (emptyStateSubmit)=\"onEmptyStateMessageSent($event)\">\n </mj-message-input>\n </div>\n </div>\n </div>\n } @else {\n <!-- Normal Message View -->\n <div class=\"chat-messages-wrapper\">\n <!-- Upload Indicator Overlay (centered in conversation area) -->\n @if (isUploadingAttachments) {\n <div class=\"upload-indicator-overlay\">\n <mj-loading [text]=\"uploadingMessage\" size=\"medium\"></mj-loading>\n </div>\n }\n <div class=\"chat-messages-container\" #scrollContainer (scroll)=\"checkScroll()\">\n <mj-conversation-message-list\n [showEmptyFill]=\"showEmptyFill\"\n [showDateNavigation]=\"showDateNavigation\"\n [showAgentRunDetails]=\"showAgentRunDetails\"\n [showReactions]=\"showReactions\"\n [showMessageRating]=\"showMessageRating\"\n [allowPinning]=\"allowPinning\"\n [allowMessageEdit]=\"allowMessageEdit\"\n [allowMessageDelete]=\"allowMessageDelete\"\n [assistantDisplayName]=\"assistantDisplayName\"\n [assistantAvatarUrl]=\"assistantAvatarUrl\"\n [messages]=\"messages\"\n [HasMoreAbove]=\"hasMoreMessagesAbove\"\n [IsLoadingOlder]=\"isLoadingOlderMessages\"\n [ScrollRoot]=\"messageScrollRoot\"\n (OlderRequested)=\"onOlderMessagesRequested()\"\n (DateJumpRequested)=\"onDateJumpRequested($event)\"\n [conversation]=\"conversation\"\n [currentUser]=\"currentUser\"\n [isProcessing]=\"isProcessing\"\n [artifactMap]=\"effectiveArtifactsMap\"\n [agentRunMap]=\"agentRunsByDetailId\"\n [ratingsMap]=\"ratingsByDetailId\"\n [userAvatarMap]=\"userAvatarMap\"\n [attachmentsMap]=\"attachmentsByDetailId\"\n [messageRendererTemplate]=\"slotTemplate('messageRenderer')\"\n [messageExtraTemplate]=\"slotTemplate('messageExtra')\"\n [sessionMetaMap]=\"realtimeSessionMetaMap\"\n (realtimeSessionOpenRequested)=\"OpenRealtimeSessionReview($event)\"\n (replyInThread)=\"onReplyInThread($event)\"\n (viewThread)=\"onViewThread($event)\"\n (deleteMessage)=\"onDeleteMessage($event)\"\n (retryMessage)=\"onRetryMessage($event)\"\n (testFeedbackMessage)=\"onTestFeedbackMessage($event)\"\n (artifactClicked)=\"onArtifactClicked($event)\"\n (messageEdited)=\"onMessageEdited($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (suggestedResponseSelected)=\"onSuggestedResponseSelected($event)\"\n (attachmentClicked)=\"onAttachmentClicked($event)\"\n (diagnosticRequested)=\"onDiagnosticRequested($event)\"\n (messagePinToggled)=\"onMessagePinToggled($event)\"\n (beforeResponseFormSubmitted)=\"beforeResponseFormSubmitted.emit($event)\"\n (afterResponseFormSubmitted)=\"afterResponseFormSubmitted.emit($event)\">\n </mj-conversation-message-list>\n\n <!-- Scroll to Bottom Icon (positioned within scroll container for proper centering) -->\n @if (showScrollToBottomIcon && messages && messages.length > 0) {\n <span class=\"scroll-to-bottom-icon\" style=\"left: 50%;\"\n (click)=\"scrollToBottomAnimate()\">\n <i class=\"fas fa-arrow-down\"></i>\n </span>\n }\n </div>\n\n <!-- Fixed Input Area -->\n <div class=\"chat-input-container\">\n @if (isLoadingPeripheralData) {\n <!-- Loading State -->\n <div class=\"loading-peripheral-placeholder\">\n <mj-loading text=\"Loading conversation data...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n @if (isReadOnlyView) {\n <div class=\"read-only-banner\" role=\"status\">\n <i class=\"fas fa-eye\"></i>\n <span>You have view-only access to this conversation.</span>\n </div>\n }\n <!-- composerExtra slot \u2014 host UI directly above the composer (IMJChatComposerExtraContext). -->\n @if (slotTemplate('composerExtra'); as t) {\n <div class=\"chat-composer-extra\">\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n ConversationId: conversationId,\n IsProcessing: isProcessing\n }\"></ng-container>\n </div>\n }\n <!-- Input Component - Multiple instances cached, only one visible -->\n <div class=\"message-input-container-wrapper\">\n @for (inputRef of getCachedInputs(); track inputRef.conversationId) {\n <mj-message-input\n #messageInput\n [hidden]=\"inputRef.conversationId !== conversationId\"\n [initialDraft]=\"GetInitialDraftFor(inputRef.conversationId)\"\n (DraftStateChanged)=\"OnDraftStateChanged(inputRef.conversationId, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [conversationId]=\"inputRef.conversationId\"\n [conversationName]=\"inputRef.conversationName\"\n [currentUser]=\"currentUser\"\n [conversationHistory]=\"inputRef.conversationId === conversationId ? messages : []\"\n [artifactsByDetailId]=\"inputRef.conversationId === conversationId ? artifactsByDetailId : emptyArtifactsMap\"\n [systemArtifactsByDetailId]=\"inputRef.conversationId === conversationId ? systemArtifactsByDetailId : emptyArtifactsMap\"\n [agentRunsByDetailId]=\"inputRef.conversationId === conversationId ? agentRunsByDetailId : emptyAgentRunsMap\"\n [appContext]=\"appContext\"\n [applicationId]=\"applicationId\"\n [defaultAgentId]=\"defaultAgentId\"\n [conversationDefaultAgentId]=\"inputRef.conversationId === conversationId ? (conversation?.DefaultAgentID ?? null) : null\"\n [agentConfigurationPresetId]=\"inputRef.conversationId === conversationId ? ActiveAgentConfigurationPresetId : null\"\n [AgentReplyMode]=\"AgentReplyMode\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [AgentHistoryFrom]=\"AgentHistoryFrom\"\n [AgentTurnHandler]=\"AgentTurnHandler\"\n [AutoNameConversation]=\"AutoNameConversation\"\n [inProgressMessageIds]=\"inputRef.conversationId === conversationId ? inProgressMessageIds : emptyInProgressIds\"\n [disabled]=\"isProcessing || isReadOnlyView\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [enablePlanMode]=\"allowPlanMode\"\n [enableRealtime]=\"allowRealtime\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [initialMessage]=\"shouldDeliverPendingMessageTo(inputRef.conversationId) ? pendingMessage : null\"\n [initialAttachments]=\"shouldDeliverPendingMessageTo(inputRef.conversationId) ? pendingAttachments : null\"\n (initialMessageAutoSendStarted)=\"onInitialMessageAutoSendStarted($event)\"\n (initialMessageAutoSendFailed)=\"onInitialMessageAutoSendFailed($event)\"\n (messageSent)=\"onMessageSent($event)\"\n (agentResponse)=\"onAgentResponse($event)\"\n (agentRunDetected)=\"onAgentRunDetected($event)\"\n (agentRunUpdate)=\"onAgentRunUpdate($event)\"\n (messageComplete)=\"onMessageComplete($event)\"\n (artifactCreated)=\"onArtifactCreated($event)\"\n (conversationRenamed)=\"onConversationRenamed($event)\"\n (intentCheckStarted)=\"onIntentCheckStarted($event)\"\n (intentCheckCompleted)=\"onIntentCheckCompleted($event)\"\n (beforeAgentTurn)=\"beforeAgentTurn.emit($event)\"\n (afterAgentTurn)=\"afterAgentTurn.emit($event)\"\n (uploadStateChanged)=\"onUploadStateChanged($event)\">\n </mj-message-input>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Artifact Viewer Pane -->\n @if (showArtifactPanel && selectedArtifactId) {\n @if (!isArtifactPaneMaximized) {\n <div class=\"resize-handle\" (mousedown)=\"onResizeStart($event)\" (touchstart)=\"onResizeTouchStart($event)\"></div>\n }\n <div class=\"chat-artifact-pane\"\n [style.width.%]=\"artifactPaneWidth\"\n [class.maximized]=\"isArtifactPaneMaximized\">\n <mj-artifact-viewer-panel\n [artifactId]=\"selectedArtifactId\"\n [currentUser]=\"currentUser\"\n [environmentId]=\"environmentId\"\n [versionNumber]=\"selectedVersionNumber\"\n [viewContext]=\"'conversation'\"\n [canShare]=\"canShareSelectedArtifact\"\n [canEdit]=\"canEditSelectedArtifact\"\n [isMaximized]=\"isArtifactPaneMaximized\"\n [refreshTrigger]=\"artifactViewerRefresh$\"\n (closed)=\"onCloseArtifactPanel()\"\n (saveToCollectionRequested)=\"onSaveToCollectionRequested($event)\"\n (navigateToLink)=\"onArtifactLinkNavigation($event)\"\n (shareRequested)=\"onArtifactShareRequested($event)\"\n (maximizeToggled)=\"toggleMaximizeArtifactPane()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\"\n (analyzeRequested)=\"OnAnalyzeArtifact($event)\"\n (applyFormRequested)=\"OnApplyFormRequested($event)\">\n </mj-artifact-viewer-panel>\n </div>\n }\n\n <!-- Artifact Share Modal -->\n <mj-artifact-share-modal\n [isOpen]=\"isArtifactShareModalOpen\"\n [artifact]=\"artifactToShare\"\n [currentUser]=\"currentUser\"\n (saved)=\"onArtifactShared()\"\n (cancelled)=\"onArtifactShareModalClose()\">\n </mj-artifact-share-modal>\n\n <!-- Pinned Messages Panel (overlay) -->\n @if (allowPinning && showPinsPanel) {\n <mj-pinned-messages-panel\n [pinnedMessages]=\"pinnedMessages\"\n [isLoading]=\"isLoadingPins\"\n (closed)=\"showPinsPanel = false\"\n (jumpRequested)=\"onJumpToMessage($event)\"\n (unpinRequested)=\"onUnpinFromPanel($event)\">\n </mj-pinned-messages-panel>\n }\n </div>\n\n <!-- Live voice \"call mode\" overlay \u2014 fills this conversation panel in place\n (header + thread + composer) while a realtime session is active. When the\n call is MINIMIZED (e.g. a dev link navigated to a record) the overlay HIDES\n (not destroyed \u2014 its merged session state must survive), the session stays\n fully live, and a floating \"on call\" pill offers the way back.\n ALSO hosted in SESSION REVIEW mode (RealtimeReview set, no live call): the\n overlay renders what went down in a PAST session, with a \"Start live session\"\n button that resumes it as a new call. -->\n @if ((RealtimeSession.Active$ | async) || RealtimeReview) {\n <mj-realtime-session-overlay\n [AgentName]=\"realtimeOverlayAgentName\"\n [Hidden]=\"(RealtimeSession.Minimized$ | async) === true\"\n [CurrentUser]=\"currentUser\"\n [EnvironmentID]=\"environmentId\"\n [ReviewData]=\"RealtimeReview\"\n [Chrome]=\"overlayMode ? 'orb' : 'auto'\"\n [Compact]=\"overlayMode\"\n [ShowDevLinks]=\"!overlayMode\"\n [ShowDensityPicker]=\"!overlayMode\"\n (NavigateRequest)=\"onRealtimeNavigateRequest($event)\"\n (StartLiveRequested)=\"onReviewStartLive($event)\"\n (ReviewClosed)=\"onReviewClosed()\">\n </mj-realtime-session-overlay>\n @if (RealtimeSession.Minimized$ | async) {\n <button type=\"button\" class=\"voice-call-pill\" (click)=\"RealtimeSession.SetMinimized(false)\"\n title=\"Return to the live call\" aria-label=\"Return to the live call\">\n <span class=\"voice-call-pill__pulse\" aria-hidden=\"true\"></span>\n <i class=\"fa-solid fa-phone-volume\" aria-hidden=\"true\"></i>\n <span class=\"voice-call-pill__text\">\n <span class=\"voice-call-pill__name\">On call \u00B7 {{ RealtimeSession.CurrentAgentName }}</span>\n <span class=\"voice-call-pill__hint\">Tap to return</span>\n </span>\n </button>\n }\n }\n</div>\n\n<!-- Thread Panel -->\n@if (threadId) {\n <mj-thread-panel\n [parentMessageId]=\"threadId\"\n [conversationId]=\"conversationId || ''\"\n [currentUser]=\"currentUser\"\n (closed)=\"onLocalThreadClosed()\"\n (replyAdded)=\"onThreadReplyAdded($event)\">\n </mj-thread-panel>\n}\n\n<!-- Export Modal -->\n<!-- [branding] is bound BEFORE [isVisible] deliberately: Angular sets inputs in\n template order within a change-detection pass, and the modal's isVisible setter\n reads `branding` to default its \"Include branding\" checkbox on a fresh open. -->\n<mj-export-modal\n [branding]=\"exportBranding\"\n [isVisible]=\"showExportModal\"\n [conversation]=\"conversation || undefined\"\n [currentUser]=\"currentUser\"\n (cancelled)=\"onExportModalCancelled()\"\n (exported)=\"onExportModalComplete()\">\n</mj-export-modal>\n\n<!-- Share Dialog (generic, shared with dashboards) -->\n<mj-resource-share-dialog\n [Visible]=\"showShareModal\"\n [Context]=\"shareContext\"\n [Adapter]=\"shareAdapter\"\n (Result)=\"onShareDialogResult($event)\">\n</mj-resource-share-dialog>\n\n<!-- Members Modal -->\n<mj-members-modal\n [isVisible]=\"showMembersModal\"\n [conversation]=\"conversation || undefined\"\n [currentUser]=\"currentUser\"\n (cancelled)=\"showMembersModal = false\"\n (membersChanged)=\"showMembersModal = false\">\n</mj-members-modal>\n\n<!-- Project Selector Modal -->\n@if (showProjectSelector && conversation) {\n <div class=\"modal-overlay\" (click)=\"showProjectSelector = false\">\n <div class=\"modal-content project-selector-modal\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3>Assign Project</h3>\n <button class=\"modal-close-btn\" (click)=\"showProjectSelector = false\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\n <mj-project-selector\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [selectedProjectId]=\"conversation.ProjectID\"\n (projectSelected)=\"onProjectSelected($event)\">\n </mj-project-selector>\n </div>\n </div>\n </div>\n}\n\n<!-- Artifacts Modal -->\n@if (showArtifactsModal) {\n <div class=\"modal-overlay\" (click)=\"showArtifactsModal = false\">\n <div class=\"modal-content artifacts-modal\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3>Conversation Artifacts</h3>\n <div class=\"modal-header-actions\">\n @if (hasSystemArtifacts) {\n <button class=\"toggle-system-btn\"\n [class.active]=\"showSystemArtifacts\"\n (click)=\"toggleSystemArtifacts()\"\n title=\"Toggle system artifacts visibility\">\n <i class=\"fas fa-cog\"></i>\n <span>{{ showSystemArtifacts ? 'Hide' : 'Show' }} System</span>\n </button>\n }\n <button class=\"modal-close-btn\" (click)=\"showArtifactsModal = false\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"modal-body artifacts-grid\">\n @if (artifactsByDetailId.size === 0) {\n <mj-empty-state\n class=\"artifacts-empty-fill\"\n Icon=\"fa-solid fa-cube\"\n Title=\"No artifacts in this conversation yet\" />\n }\n @for (artifact of getArtifactsArray(); track artifact.artifactId) {\n <div class=\"artifact-modal-card\"\n [class.expanded]=\"expandedArtifactId === artifact.artifactId\"\n [class.system-artifact]=\"artifact.visibility === 'System Only'\">\n <!-- Main card header - click to open latest version -->\n <div class=\"artifact-card-header\" (click)=\"openArtifactFromModal(artifact.artifactId)\">\n <div class=\"artifact-modal-icon\">\n <i class=\"fas fa-file-code\"></i>\n </div>\n <div class=\"artifact-modal-info\">\n <div class=\"artifact-modal-title\">{{artifact.name}}</div>\n <div class=\"artifact-modal-meta\">\n @if (artifact.versionCount > 1) {\n {{artifact.versionCount}} versions\n } @else {\n 1 version\n }\n </div>\n </div>\n @if (artifact.versionCount > 1) {\n <button class=\"expand-btn\" (click)=\"toggleArtifactExpansion(artifact.artifactId, $event)\">\n <i class=\"fas\" [class.fa-chevron-down]=\"expandedArtifactId !== artifact.artifactId\"\n [class.fa-chevron-up]=\"expandedArtifactId === artifact.artifactId\"></i>\n </button>\n }\n <div class=\"artifact-modal-action\">\n <i class=\"fas fa-external-link-alt\"></i>\n </div>\n </div>\n\n <!-- Expanded version list -->\n @if (expandedArtifactId === artifact.artifactId && artifact.versionCount > 1) {\n <div class=\"artifact-versions-list\">\n @for (version of artifact.versions; track version.versionId) {\n <div class=\"artifact-version-item\" (click)=\"openArtifactFromModal(artifact.artifactId, version.versionNumber); $event.stopPropagation()\">\n <span class=\"version-badge\">v{{version.versionNumber}}</span>\n <span class=\"version-open-text\">Open this version</span>\n <i class=\"fas fa-arrow-right\"></i>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n}\n\n<!-- Collection Picker Modal -->\n@if (showCollectionPicker) {\n <mj-artifact-collection-picker-modal\n [isOpen]=\"showCollectionPicker\"\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [excludeCollectionIds]=\"collectionPickerExcludedIds\"\n [artifactVersionId]=\"collectionPickerVersionId\"\n [artifactName]=\"collectionPickerArtifactName\"\n [artifactVersionNumber]=\"collectionPickerVersionNumber\"\n (completed)=\"onCollectionPickerCompleted($event)\"\n (cancelled)=\"onCollectionPickerCancelled()\">\n </mj-artifact-collection-picker-modal>\n}\n\n<!-- Test Feedback Dialog -->\n@if (testFeedbackDialogData) {\n <mj-test-feedback-dialog\n [data]=\"testFeedbackDialogData\"\n [visible]=\"showTestFeedbackDialog\"\n (closed)=\"onTestFeedbackDialogClosed($event)\">\n </mj-test-feedback-dialog>\n}\n\n<!-- Image Viewer Modal -->\n@if (showImageViewer) {\n <mj-image-viewer\n [imageUrl]=\"selectedImageUrl\"\n [alt]=\"selectedImageAlt\"\n [fileName]=\"selectedImageFileName\"\n [visible]=\"showImageViewer\"\n (closed)=\"onImageViewerClosed()\">\n </mj-image-viewer>\n}\n", styles: [":host {\n display: flex;\n width: 100%;\n height: 100%;\n}\n\n.chat-area {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n /* Positioned context for the in-place realtime \"call mode\" overlay (absolute inset:0) */\n position: relative;\n}\n\n.chat-header {\n flex-shrink: 0;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n background: var(--mj-bg-surface-card);\n z-index: 10;\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* agentPresence slot \u2014 sticky top, anchored with the header. Per Matt's\n 06-10 placement design: persistent presence indicator above the messages.\n Renders only when [showAgentCharacter] is true, so existing embeds see no\n layout change. The prominent variant grows toward a centered presence\n (per Matt: \"can grow larger toward a centered presence\"). */\n.chat-agent-presence {\n flex-shrink: 0;\n padding: 8px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n z-index: 11;\n}\n\n.chat-agent-presence--prominent {\n padding: 16px 20px;\n justify-content: center;\n}\n\n.chat-info {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n/* Sidebar toggle button in header */\n.sidebar-toggle-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: transparent;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.sidebar-toggle-btn:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.sidebar-toggle-btn:active {\n background: color-mix(in srgb, var(--mj-text-primary) 12%, transparent);\n}\n\n.sidebar-toggle-btn i {\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: color 0.15s ease;\n}\n\n.sidebar-toggle-btn:hover i {\n color: var(--mj-text-primary);\n}\n\n.chat-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge i {\n font-size: 10px;\n}\n\n.shared-by-badge span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-tag {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 12px;\n}\n\n.project-tag:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-text-muted);\n}\n\n.project-tag i {\n font-size: 10px;\n}\n\n.test-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-status-warning);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 8px;\n}\n\n.test-indicator:hover {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.test-indicator i {\n font-size: 10px;\n}\n\n/* Pinned messages chip in chat header */\n.pin-chip {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, transparent);\n border-radius: 20px;\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.pin-chip i {\n font-size: 11px;\n}\n\n.pin-chip:hover,\n.pin-chip.active {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.pin-chip-count {\n font-size: 12px;\n font-weight: 700;\n}\n\n.chat-members,\n.artifact-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n padding: 6px 8px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.chat-members:hover,\n.artifact-indicator:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* Badge overlay for artifact and member counts */\n.artifact-badge,\n.members-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n.members-badge {\n background: var(--mj-brand-primary);\n}\n\n.ambient-agent-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n animation: pulse 2s ease-in-out infinite;\n}\n\n.ambient-agent-indicator i {\n color: var(--mj-brand-primary);\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n}\n.chat-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n\n.action-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.share-btn.shared {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-brand-primary-hover);\n}\n\n.share-btn.shared:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.chat-content-area {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: row;\n position: relative;\n}\n\n.chat-messages-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n min-width: min(300px, 100%); /* Respect container bounds while maintaining minimum */\n overflow: hidden;\n transition: width 0.3s ease;\n}\n\n.chat-messages-pane.full-width {\n width: 100%;\n}\n\n.chat-messages-pane:not(.full-width) {\n flex: 1;\n}\n\n.chat-messages-pane.hidden {\n display: none;\n}\n\n.resize-handle {\n width: 4px;\n background: transparent;\n cursor: col-resize;\n flex-shrink: 0;\n position: relative;\n transition: background-color 0.2s;\n}\n\n.resize-handle:hover {\n background: var(--mj-brand-primary);\n}\n\n.resize-handle::before {\n content: \"\";\n position: absolute;\n left: -4px;\n right: -4px;\n top: 0;\n bottom: 0;\n}\n\n.chat-artifact-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.chat-artifact-pane.maximized {\n width: 100% !important;\n}\n\n.chat-artifact-pane > mj-artifact-viewer-panel {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.chat-messages-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n position: relative; /* For upload overlay positioning */\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n demonstrationSurface layout-mode (Matt's 06-10 placement design)\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n When .chat-content-area gets .demonstration-mode, the layout flips\n from \"messages pane (+ optional artifact pane)\" to \"stage + side rail\":\n - stage (.chat-demonstration-stage) \u2014 left, flexible, holds the\n consumer's projected demonstrationSurface slot template\n - rail (.chat-messages-pane) \u2014 right, fixed-width 320px, holds the\n messages list + composer (\"the conversation as a companion rail\")\n On mobile (\u2264768px) the same two stack vertically (stage above, rail\n below) per Matt's note about mobile. The rail intentionally keeps the\n composer inside it \u2014 Matt's design refers to the conversation rail\n inclusively (messages + composer together), not as separate regions.\n*/\n.chat-demonstration-stage {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: auto;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n flex: 1;\n min-width: 0;\n}\n\n.chat-content-area.demonstration-mode .chat-messages-pane,\n.chat-content-area.demonstration-mode .chat-messages-pane.full-width {\n flex: 0 0 320px;\n width: 320px;\n min-width: 0;\n}\n\n@media (max-width: 768px) {\n .chat-content-area.demonstration-mode {\n flex-direction: column;\n }\n\n .chat-content-area.demonstration-mode .chat-demonstration-stage {\n flex: 1 1 60%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n height: auto;\n }\n\n .chat-content-area.demonstration-mode .chat-messages-pane,\n .chat-content-area.demonstration-mode .chat-messages-pane.full-width {\n flex: 1 1 40%;\n width: 100%;\n height: auto;\n }\n}\n\n/* Upload indicator overlay - centered in conversation area */\n.upload-indicator-overlay {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem 1.5rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n z-index: 100;\n pointer-events: none;\n}\n\n.chat-messages-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-surface-card);\n min-height: 0;\n position: relative;\n}\n\n.scroll-to-bottom-icon {\n position: sticky;\n bottom: 21px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 40px;\n margin-top: -40px;\n margin-left: auto;\n margin-right: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: var(--mj-shadow-md);\n transition: all 0.2s ease;\n z-index: 100;\n pointer-events: auto;\n}\n\n.scroll-to-bottom-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n transform: translateX(-50%) translateY(-2px);\n box-shadow: color-mix(in srgb, var(--mj-brand-primary) 20%, transparent) 0 4px 12px;\n}\n\n.scroll-to-bottom-icon i {\n color: var(--mj-text-secondary);\n font-size: 16px;\n transition: color 0.2s;\n}\n\n.scroll-to-bottom-icon:hover i {\n color: var(--mj-brand-primary);\n}\n\n.chat-input-container {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n padding: 0 1.25rem 1.25rem 1.25rem;\n overflow: visible;\n}\n\n/* composerExtra slot: host UI directly above the composer. Spacing only; the host styles its content. */\n.chat-composer-extra {\n margin-bottom: 0.5rem;\n}\n\n.read-only-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 1.25rem 0.5rem 1.25rem;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n font-size: 12px;\n}\n\n.read-only-banner i {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.loading-peripheral-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 140px;\n padding: 24px;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 50%, transparent);\n backdrop-filter: blur(2px);\n border-radius: 12px;\n margin: 12px;\n animation: fadeIn 0.2s ease-in-out;\n}\n\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.modal-content {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.project-selector-modal {\n width: 600px;\n height: 500px;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n}\n\n.modal-header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toggle-system-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 6px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.toggle-system-btn:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.toggle-system-btn.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.toggle-system-btn.active:hover {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.toggle-system-btn i {\n font-size: 12px;\n}\n\n.modal-close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s;\n}\n\n.modal-close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.modal-body {\n flex: 1;\n overflow: auto;\n padding: 20px;\n}\n\n.artifacts-modal {\n width: 700px;\n max-height: 600px;\n}\n\n.artifacts-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n/* Empty-state spans the full artifacts grid */\n.artifacts-empty-fill {\n grid-column: 1/-1;\n}\n\n.artifact-modal-card {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1.5px solid var(--mj-border-default);\n border-radius: 12px;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.artifact-modal-card.expanded {\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-modal-card.system-artifact {\n opacity: 0.85;\n border-color: var(--mj-border-default);\n border-style: dashed;\n position: relative;\n}\n\n.artifact-modal-card.system-artifact::before {\n content: \"SYSTEM\";\n position: absolute;\n top: 8px;\n right: 8px;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 3px;\n letter-spacing: 0.5px;\n z-index: 10;\n}\n\n.artifact-modal-card.system-artifact:hover {\n border-color: var(--mj-text-muted);\n box-shadow: var(--mj-shadow-md);\n}\n\n.artifact-card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n}\n\n.artifact-card-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-modal-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.artifact-modal-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-radius: 10px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.artifact-modal-icon i {\n font-size: 18px;\n}\n\n.artifact-modal-info {\n flex: 1;\n min-width: 0;\n}\n\n.artifact-modal-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.artifact-modal-meta {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.artifact-modal-action {\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.artifact-modal-card:hover .artifact-modal-action {\n color: var(--mj-brand-primary);\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.expand-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.artifact-versions-list {\n display: flex;\n flex-direction: column;\n padding: 0 1rem 1rem 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-version-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px 12px 68px;\n cursor: pointer;\n transition: background 0.15s;\n}\n.artifact-version-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n.artifact-version-item .version-badge {\n display: inline-block;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 600;\n font-family: monospace;\n border-radius: 4px;\n}\n.artifact-version-item .version-open-text {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n.artifact-version-item i {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n.artifact-version-item:hover .version-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.artifact-version-item:hover .version-open-text {\n color: var(--mj-brand-primary);\n}\n.artifact-version-item:hover i {\n color: var(--mj-brand-primary);\n}\n\n.loading-peripheral-content {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n}\n.loading-peripheral-content i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.conversation-loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n width: 100%;\n}\n\n.loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 20px;\n gap: 16px;\n color: var(--mj-text-secondary);\n font-size: 15px;\n}\n.loading-content i {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n.loading-content span {\n font-weight: 500;\n}\n\n/* Mobile adjustments: 481px - 768px */\n@media (max-width: 768px) {\n .chat-header {\n padding: 8px 12px;\n gap: 6px;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n position: relative;\n }\n .chat-info {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n order: 1;\n }\n .chat-title {\n font-size: 15px;\n font-weight: 700;\n width: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n }\n .project-tag {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n display: none; /* Hide on mobile to save space */\n }\n .test-indicator {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n }\n /* Action buttons - icon only on mobile */\n .chat-actions-buttons {\n order: 2;\n flex-shrink: 0;\n }\n .chat-actions-buttons .action-btn {\n padding: 6px 8px;\n min-width: auto;\n }\n .chat-actions-buttons .action-btn .btn-label {\n display: none;\n }\n .chat-actions {\n flex-wrap: nowrap;\n }\n .chat-members,\n .artifact-indicator {\n padding: 5px 7px;\n font-size: 13px;\n }\n .action-btn {\n padding: 6px 8px;\n font-size: 12px;\n }\n .ambient-agent-indicator {\n font-size: 12px;\n padding: 4px 8px;\n }\n .project-selector-modal {\n width: min(95vw, 600px);\n height: auto;\n }\n .artifacts-modal {\n width: min(95vw, 700px);\n }\n .artifacts-grid {\n grid-template-columns: 1fr;\n }\n .chat-input-container {\n padding: 0 0.75rem 0.75rem 0.75rem;\n }\n .scroll-to-bottom-icon {\n bottom: 16px;\n width: 36px;\n height: 36px;\n }\n /* Artifact pane - full width overlay on mobile, overlapping header */\n .chat-content-area {\n position: relative;\n }\n .chat-artifact-pane {\n position: fixed;\n left: 0;\n right: 0;\n top: 56px; /* 48px nav + 8px dark strip above blue border */\n bottom: 0;\n width: 100% !important;\n z-index: 100;\n background: var(--mj-bg-surface-card);\n }\n .resize-handle {\n display: none;\n }\n}\n/* Small Phone adjustments: <= 480px */\n@media (max-width: 480px) {\n .chat-header {\n padding: 6px 8px;\n gap: 4px;\n }\n .chat-title {\n font-size: 14px;\n font-weight: 700;\n }\n .project-tag {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n display: none;\n }\n .test-indicator {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n }\n .chat-members,\n .artifact-indicator {\n padding: 4px 8px;\n font-size: 11px;\n }\n .action-btn {\n padding: 5px 7px;\n font-size: 11px;\n }\n .ambient-agent-indicator {\n font-size: 11px;\n padding: 3px 6px;\n }\n .project-selector-modal,\n .artifacts-modal {\n width: 100vw;\n height: 100vh;\n border-radius: 0;\n }\n .chat-input-container {\n padding: 0 0.5rem 0.5rem 0.5rem;\n }\n .scroll-to-bottom-icon {\n bottom: 12px;\n width: 32px;\n height: 32px;\n }\n .scroll-to-bottom-icon i {\n font-size: 14px;\n }\n}\n\n/* Artifact Picker Panel */\n.artifact-picker-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n.artifact-picker-panel {\n position: fixed;\n right: 0;\n top: 0;\n width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n animation: slideInRight 0.2s ease-out;\n}\n\n@keyframes slideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n}\n\n.artifact-picker-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.artifact-picker-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n border-radius: 4px;\n}\n\n.artifact-picker-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n\n.artifact-picker-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.artifact-picker-hint {\n font-size: 12px;\n color: var(--mj-text-disabled);\n}\n\n.artifact-picker-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.artifact-picker-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.artifact-picker-item:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-picker-item i {\n font-size: 20px;\n width: 24px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.artifact-picker-item i.fa-file-pdf { color: var(--mj-status-error); }\n.artifact-picker-item i.fa-file-excel { color: var(--mj-status-success); }\n.artifact-picker-item i.fa-file-word { color: var(--mj-brand-primary); }\n.artifact-picker-item i.fa-file { color: var(--mj-text-muted); }\n\n.artifact-picker-item-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.artifact-picker-item-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.artifact-picker-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* ---------- Floating \"on call\" pill (minimized realtime voice session) ----------\n Shown bottom-right of the chat panel while the live call overlay is minimized\n (e.g. after a gear-gated dev link navigated to a record). The mic + session stay\n live; tapping the pill restores the full call overlay. */\n.voice-call-pill {\n position: absolute;\n right: 18px;\n bottom: 18px;\n z-index: 49; /* just under the full call overlay (z-index 50) */\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 16px 9px 13px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-elevated, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-family: inherit;\n cursor: pointer;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;\n}\n.voice-call-pill:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 10px 28px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent);\n transform: translateY(-1px);\n}\n.voice-call-pill i {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n.voice-call-pill__pulse {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n animation: voice-pill-pulse 1.6s ease-in-out infinite;\n}\n.voice-call-pill__text {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n line-height: 1.25;\n}\n.voice-call-pill__name {\n font-size: 12.5px;\n font-weight: 700;\n}\n.voice-call-pill__hint {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n}\n@keyframes voice-pill-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-status-success) 0%, transparent);\n }\n}\n"] }]
|
|
6534
|
-
}], () => [{ type: i1.AgentStateService }, { type: i2.
|
|
7000
|
+
args: [{ standalone: false, selector: 'mj-conversation-chat-area', template: "<div class=\"chat-area\">\n <!-- agentPresence slot \u2014 sticky top, anchored with the header. Per Matt's\n 06-10 design: persistent presence indicator (Sid's face + live voice\n state). Off by default; opt in via [showAgentCharacter]. When a\n consumer projects an `mjChatSlot=\"agentPresence\"` template, it\n replaces the default presence component. -->\n @if (showAgentCharacter) {\n <div class=\"chat-agent-presence\" [class.chat-agent-presence--prominent]=\"agentCharacterConfig?.voiceStateMode === 'prominent'\">\n @if (slotTemplate('agentPresence'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: agentCharacterConfig,\n state: agentCharacterConfig?.state ?? 'idle',\n agentName: agentCharacterConfig?.characterName,\n avatarUrl: agentCharacterConfig?.avatarUrl,\n mode: agentCharacterConfig?.voiceStateMode ?? 'subtle'\n }\"></ng-container>\n } @else {\n <mj-chat-agent-presence-default\n [State]=\"agentCharacterConfig?.state ?? 'idle'\"\n [AgentName]=\"agentCharacterConfig?.characterName\"\n [AvatarUrl]=\"agentCharacterConfig?.avatarUrl\"\n [Mode]=\"agentCharacterConfig?.voiceStateMode ?? 'subtle'\">\n </mj-chat-agent-presence-default>\n }\n </div>\n }\n\n <!-- header slot \u2014 replaces the entire chat-header chrome (title, badges,\n export/share/agent-picker buttons). When projected, the consumer owns\n the entire header rendering; the default chrome below is bypassed\n wholesale. Context exposes the minimal IMJChatHeaderComponent shape;\n consumers needing more app state should bind to chat-area inputs\n directly via @ViewChild or wrap the whole component. -->\n @if (slotTemplate('header'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n conversationTitle: conversation?.Name ?? null,\n sharedBy: sharedByBadge?.display ?? null,\n artifactCount: artifactCountDisplay,\n showArtifactIndicator: showArtifactIndicator\n }\"></ng-container>\n } @else if (conversation || HasPreConversationHeader) {\n <!-- Default header \u2014 also renders BEFORE a conversation exists when the\n embedder has pre-conversation chrome to surface (currently just the\n mode picker \u2014 agent / share / export / members / artifacts all\n require a conversation row and stay hidden). Lets embedded surfaces\n like the Form Builder cockpit show the mode picker above the\n empty-state on a fresh chat instead of waiting for the first\n message to round-trip. -->\n <div class=\"chat-header\">\n <div class=\"chat-info\" [class.with-sidebar-toggle]=\"showSidebarToggle\">\n @if (showSidebarToggle) {\n <button class=\"sidebar-toggle-btn\"\n (click)=\"sidebarToggleClicked.emit()\"\n title=\"Show conversations\">\n <i class=\"fas fa-table-columns\"></i>\n </button>\n }\n @if (conversation) {\n <div class=\"chat-title\">{{ conversation.Name || '' }}</div>\n }\n @if (sharedByBadge) {\n <span class=\"shared-by-badge\" [title]=\"sharedByBadge.fullTooltip\">\n <i class=\"fas fa-share-nodes\"></i>\n <span>Shared by {{ sharedByBadge.display }}</span>\n </span>\n }\n @if (conversation?.ProjectID) {\n <button class=\"project-tag\" (click)=\"openProjectSelector()\" [attr.title]=\"EffectiveReadOnly ? 'Project' : 'Assign to project'\">\n <i class=\"fas fa-folder\"></i>\n <span>{{ conversation!.Project || 'Project' }}</span>\n </button>\n }\n @if (conversation?.TestRunID) {\n <button class=\"test-indicator\" (click)=\"viewTestRun(conversation!.TestRunID!)\" title=\"View Test Run\">\n <i class=\"fas fa-flask\"></i>\n <span>Test</span>\n </button>\n }\n </div>\n <div class=\"chat-actions chat-actions-buttons\">\n @if (allowPinning && pinnedMessageCount > 0) {\n <button class=\"pin-chip\" [class.active]=\"showPinsPanel\" (click)=\"TogglePinsPanel()\" title=\"View pinned messages\">\n <i class=\"fas fa-thumbtack\"></i>\n <span class=\"pin-chip-count\">{{ pinnedMessageCount }}</span>\n </button>\n }\n @if (showArtifactIndicator && artifactCountDisplay > 0) {\n <button class=\"artifact-indicator\" (click)=\"viewArtifacts()\" title=\"View artifacts\">\n <i class=\"fas fa-cube\"></i>\n <span class=\"artifact-badge\">{{ artifactCountDisplay }}</span>\n </button>\n }\n @if (memberCount > 1) {\n <button class=\"chat-members\" (click)=\"toggleMembersModal()\" title=\"View members\">\n <i class=\"fas fa-users\"></i>\n <span class=\"members-badge\">{{ memberCount }}</span>\n </button>\n }\n @if (!overlayMode && showAgentModePicker && ModePickerTargetAgentId && !EffectiveReadOnly) {\n <!-- Per-agent mode/quality picker (Draft / Standard / High).\n Targets the agent the next non-mention message will route\n to. Auto-hides when that agent has fewer than 2 configured\n presets. Choice persists per-user, per-agent via\n UserInfoEngine; emits the picked configuration ID up so\n <mj-message-input> can forward it on the next route.\n Hidden in overlayMode (the compact chat overlay): the\n mode dropdown wastes the narrow top-right space there. -->\n <mj-conversation-mode-picker\n [AgentID]=\"ModePickerTargetAgentId\"\n [Disabled]=\"isProcessing\"\n (PresetChanged)=\"OnAgentModePresetChanged($event)\">\n </mj-conversation-mode-picker>\n }\n @if (showAgentPicker && conversation) {\n <!-- Per-conversation default-agent pin. When set, non-mention\n messages route to this agent instead of Sage. Persists to\n MJConversationEntity.DefaultAgentID. Hidden when no\n conversation is loaded or when the embedder disables it. -->\n <mj-conversation-agent-picker\n [Conversation]=\"conversation\"\n [CurrentUser]=\"currentUser\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [Disabled]=\"EffectiveReadOnly\">\n </mj-conversation-agent-picker>\n }\n @if (showExportButton) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"exportConversation()\" [title]=\"exportButtonLabel + ' conversation'\">\n <i [class]=\"exportButtonIcon\"></i>\n <span class=\"btn-label\">{{ exportButtonLabel }}</span>\n </button>\n }\n @if (showShareButton && canShareConversation) {\n <button mjButton variant=\"flat\" size=\"sm\"\n [class.shared]=\"isShared\"\n (click)=\"shareConversation()\"\n [title]=\"isShared ? 'Manage sharing' : 'Share conversation'\">\n <i class=\"fas fa-share-nodes\"></i>\n <span class=\"btn-label\">Share</span>\n </button>\n }\n <!-- headerActions slot \u2014 ADDITIVE host buttons rendered after the stock\n actions (unlike the `header` slot, which replaces the whole header\n and therefore never reaches this branch). For visual parity,\n projected buttons should use mjButton variant=\"flat\" size=\"sm\". -->\n @if (slotTemplate('headerActions'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n conversationId: conversationId,\n isProcessing: isProcessing\n }\"></ng-container>\n }\n </div>\n </div>\n }\n\n <!-- Messages and Artifact Split Layout \u2014 restructures into [stage | rail]\n when isDemonstrationActive (per Matt's 06-10 design). The .demonstration-mode\n class drives the CSS Grid switch; the stage container renders only when the\n slot is projected AND the host opts in via [showDemonstrationSurface]. -->\n <div class=\"chat-content-area\" [class.demonstration-mode]=\"isDemonstrationActive\">\n <!-- demonstrationSurface stage \u2014 takes the main pane; messages shrink to\n a side rail (or move below on mobile). Off unless both\n [showDemonstrationSurface] is true AND a slot template is projected. -->\n @if (isDemonstrationActive) {\n <div class=\"chat-demonstration-stage\">\n <ng-container *ngTemplateOutlet=\"slotTemplate('demonstrationSurface'); context: {\n $implicit: demonstrationSurfaceContent,\n content: demonstrationSurfaceContent,\n visible: showDemonstrationSurface\n }\"></ng-container>\n </div>\n }\n\n <!-- Messages Pane -->\n <div class=\"chat-messages-pane\"\n [class.full-width]=\"!showArtifactPanel\"\n [class.hidden]=\"isArtifactPaneMaximized\">\n @if (isLoadingConversation) {\n <!-- Loading State - checked FIRST to prevent empty state flash. The branch\n always short-circuits the panes below; showLoadingState only controls\n whether the built-in spinner renders (hosts with their own loading\n chrome set it false and get a blank pane instead). -->\n @if (showLoadingState) {\n <div class=\"conversation-loading-state\">\n <mj-loading text=\"Loading conversation...\" size=\"large\"></mj-loading>\n </div>\n }\n } @else if ((isNewConversation || !conversationId) && !suppressNewConversationEmptyState) {\n <!-- emptyState slot \u2014 when a consumer projects mjChatSlot=\"emptyState\",\n they take over the entire empty-state region (including any send\n affordance \u2014 the slot interface doesn't include a sendMessage\n output, so consumers handle send via their own input). When no\n slot is projected, the rich built-in <mj-conversation-empty-state>\n renders with its own greeting, prompt chips, and message input.\n emptyStateConfig (when supplied) takes precedence over the legacy\n [emptyStateGreeting] string for backwards compatibility. -->\n @if (ReadOnly) {\n <div class=\"read-only-banner\" role=\"status\">\n <i class=\"fas fa-eye\"></i>\n <span>{{ ReadOnlyMessage || 'You have view-only access to this conversation.' }}</span>\n </div>\n } @else if (slotTemplate('emptyState'); as t) {\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: emptyStateConfig,\n greeting: emptyStateConfig?.greeting ?? emptyStateGreeting,\n subtext: emptyStateConfig?.subtext,\n suggestedPrompts: emptyStateConfig?.suggestedPrompts ?? []\n }\"></ng-container>\n } @else {\n <mj-conversation-empty-state\n [currentUser]=\"currentUser\"\n [initialDraft]=\"GetInitialDraftFor(null)\"\n (initialDraftApplied)=\"OnComposerDraftApplied()\"\n (DraftStateChanged)=\"OnDraftStateChanged(null, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [disabled]=\"isProcessing\"\n [showSidebarToggle]=\"showSidebarToggle\"\n [overlayMode]=\"overlayMode\"\n [greeting]=\"emptyStateConfig?.greeting ?? emptyStateGreeting\"\n [showSuggestedPrompts]=\"showSuggestedPrompts\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [ComposerExtraTemplate]=\"slotTemplate('composerExtra')\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n (sidebarToggleClicked)=\"sidebarToggleClicked.emit()\"\n (messageSent)=\"onEmptyStateMessageSent($event)\">\n </mj-conversation-empty-state>\n }\n } @else if ((isNewConversation || !conversationId) && suppressNewConversationEmptyState) {\n <!-- Pre-conversation normal-view: empty message list + emptyStateMode input.\n Used when host (e.g. Form Builder cockpit) wants the header + mode picker\n visible on first open instead of the centered welcome card. First send\n routes through onEmptyStateMessageSent which creates the conversation. -->\n <div class=\"chat-messages-wrapper\">\n <div class=\"chat-messages-container\"></div>\n <div class=\"chat-input-container\">\n @if (ReadOnly) {\n <div class=\"read-only-banner\" role=\"status\">\n <i class=\"fas fa-eye\"></i>\n <span>{{ ReadOnlyMessage || 'You have view-only access to this conversation.' }}</span>\n </div>\n } @else {\n <!-- composerExtra slot \u2014 host UI directly above the composer (IMJChatComposerExtraContext). -->\n @if (slotTemplate('composerExtra'); as t) {\n <div class=\"chat-composer-extra\">\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n ConversationId: conversationId,\n IsProcessing: isProcessing\n }\"></ng-container>\n </div>\n }\n <div class=\"message-input-container-wrapper\">\n <mj-message-input\n #emptyStateInput\n [emptyStateMode]=\"true\"\n [initialDraft]=\"GetInitialDraftFor(null)\"\n (initialDraftApplied)=\"OnComposerDraftApplied()\"\n (DraftStateChanged)=\"OnDraftStateChanged(null, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [currentUser]=\"currentUser\"\n [disabled]=\"isProcessing\"\n [ReadOnly]=\"EffectiveReadOnly\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [enablePlanMode]=\"allowPlanMode\"\n [enableRealtime]=\"allowRealtime\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n (emptyStateSubmit)=\"onEmptyStateMessageSent($event)\">\n </mj-message-input>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Normal Message View -->\n <div class=\"chat-messages-wrapper\">\n <!-- Upload Indicator Overlay (centered in conversation area) -->\n @if (isUploadingAttachments) {\n <div class=\"upload-indicator-overlay\">\n <mj-loading [text]=\"uploadingMessage\" size=\"medium\"></mj-loading>\n </div>\n }\n <div class=\"chat-messages-container\" #scrollContainer (scroll)=\"checkScroll()\">\n <mj-conversation-message-list\n [showEmptyFill]=\"showEmptyFill\"\n [showDateNavigation]=\"showDateNavigation\"\n [showAgentRunDetails]=\"showAgentRunDetails\"\n [showReactions]=\"showReactions\"\n [showMessageRating]=\"showMessageRating\"\n [allowPinning]=\"allowPinning && !EffectiveReadOnly\"\n [allowMessageEdit]=\"allowMessageEdit && !EffectiveReadOnly\"\n [allowMessageDelete]=\"allowMessageDelete && !EffectiveReadOnly\"\n [ReadOnly]=\"EffectiveReadOnly\"\n [assistantDisplayName]=\"assistantDisplayName\"\n [assistantAvatarUrl]=\"assistantAvatarUrl\"\n [messages]=\"messages\"\n [HasMoreAbove]=\"hasMoreMessagesAbove\"\n [IsLoadingOlder]=\"isLoadingOlderMessages\"\n [ScrollRoot]=\"messageScrollRoot\"\n (OlderRequested)=\"onOlderMessagesRequested()\"\n (DateJumpRequested)=\"onDateJumpRequested($event)\"\n [conversation]=\"conversation\"\n [currentUser]=\"currentUser\"\n [isProcessing]=\"isProcessing\"\n [artifactMap]=\"effectiveArtifactsMap\"\n [agentRunMap]=\"agentRunsByDetailId\"\n [ratingsMap]=\"ratingsByDetailId\"\n [userAvatarMap]=\"userAvatarMap\"\n [attachmentsMap]=\"attachmentsByDetailId\"\n [messageRendererTemplate]=\"slotTemplate('messageRenderer')\"\n [messageExtraTemplate]=\"slotTemplate('messageExtra')\"\n [sessionMetaMap]=\"realtimeSessionMetaMap\"\n (realtimeSessionOpenRequested)=\"OpenRealtimeSessionReview($event)\"\n (replyInThread)=\"onReplyInThread($event)\"\n (viewThread)=\"onViewThread($event)\"\n (deleteMessage)=\"onDeleteMessage($event)\"\n (retryMessage)=\"onRetryMessage($event)\"\n (testFeedbackMessage)=\"onTestFeedbackMessage($event)\"\n (artifactClicked)=\"onArtifactClicked($event)\"\n (messageEdited)=\"onMessageEdited($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (suggestedResponseSelected)=\"onSuggestedResponseSelected($event)\"\n (attachmentClicked)=\"onAttachmentClicked($event)\"\n (diagnosticRequested)=\"onDiagnosticRequested($event)\"\n (LivenessCheckRequested)=\"OnLivenessCheckRequested($event)\"\n (messagePinToggled)=\"onMessagePinToggled($event)\"\n (beforeResponseFormSubmitted)=\"beforeResponseFormSubmitted.emit($event)\"\n (afterResponseFormSubmitted)=\"afterResponseFormSubmitted.emit($event)\">\n </mj-conversation-message-list>\n\n <!-- Scroll to Bottom Icon (positioned within scroll container for proper centering) -->\n @if (showScrollToBottomIcon && messages && messages.length > 0) {\n <span class=\"scroll-to-bottom-icon\" style=\"left: 50%;\"\n (click)=\"scrollToBottomAnimate()\">\n <i class=\"fas fa-arrow-down\"></i>\n </span>\n }\n </div>\n\n <!-- Fixed Input Area -->\n <div class=\"chat-input-container\">\n @if (isLoadingPeripheralData) {\n <!-- Loading State -->\n <div class=\"loading-peripheral-placeholder\">\n <mj-loading text=\"Loading conversation data...\" size=\"medium\"></mj-loading>\n </div>\n } @else if (ReadOnly) {\n <div class=\"read-only-banner\" role=\"status\">\n <i class=\"fas fa-eye\"></i>\n <span>{{ ReadOnlyMessage || 'You have view-only access to this conversation.' }}</span>\n </div>\n } @else {\n @if (isReadOnlyView) {\n <div class=\"read-only-banner\" role=\"status\">\n <i class=\"fas fa-eye\"></i>\n <span>You have view-only access to this conversation.</span>\n </div>\n }\n <!-- composerExtra slot \u2014 host UI directly above the composer (IMJChatComposerExtraContext). -->\n @if (slotTemplate('composerExtra'); as t) {\n <div class=\"chat-composer-extra\">\n <ng-container *ngTemplateOutlet=\"t; context: {\n $implicit: conversation,\n ConversationId: conversationId,\n IsProcessing: isProcessing\n }\"></ng-container>\n </div>\n }\n <!-- Input Component - Multiple instances cached, only one visible -->\n <div class=\"message-input-container-wrapper\">\n @for (inputRef of getCachedInputs(); track inputRef.conversationId) {\n <mj-message-input\n #messageInput\n [hidden]=\"inputRef.conversationId !== conversationId\"\n [initialDraft]=\"GetInitialDraftFor(inputRef.conversationId)\"\n (DraftStateChanged)=\"OnDraftStateChanged(inputRef.conversationId, $event)\"\n (ComposerBlurred)=\"OnComposerBlurred()\"\n [conversationId]=\"inputRef.conversationId\"\n [conversationName]=\"inputRef.conversationName\"\n [currentUser]=\"currentUser\"\n [conversationHistory]=\"inputRef.conversationId === conversationId ? messages : []\"\n [artifactsByDetailId]=\"inputRef.conversationId === conversationId ? artifactsByDetailId : emptyArtifactsMap\"\n [systemArtifactsByDetailId]=\"inputRef.conversationId === conversationId ? systemArtifactsByDetailId : emptyArtifactsMap\"\n [agentRunsByDetailId]=\"inputRef.conversationId === conversationId ? agentRunsByDetailId : emptyAgentRunsMap\"\n [appContext]=\"appContext\"\n [applicationId]=\"applicationId\"\n [defaultAgentId]=\"defaultAgentId\"\n [conversationDefaultAgentId]=\"inputRef.conversationId === conversationId ? (conversation?.DefaultAgentID ?? null) : null\"\n [agentConfigurationPresetId]=\"inputRef.conversationId === conversationId ? ActiveAgentConfigurationPresetId : null\"\n [AgentReplyMode]=\"AgentReplyMode\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [AgentHistoryFrom]=\"AgentHistoryFrom\"\n [AgentTurnHandler]=\"AgentTurnHandler\"\n [AutoNameConversation]=\"AutoNameConversation\"\n [EnableDecisionRouting]=\"EnableDecisionRouting\"\n [inProgressMessageIds]=\"inputRef.conversationId === conversationId ? inProgressMessageIds : emptyInProgressIds\"\n [disabled]=\"isProcessing || isReadOnlyView\"\n [ReadOnly]=\"EffectiveReadOnly\"\n [enableAttachments]=\"enableAttachments && allowAttachments\"\n [enableMentions]=\"allowMentions\"\n [enableAgentMentions]=\"allowAgentMentions\"\n [enableEntityMentions]=\"allowEntityMentions\"\n [enableSkillCommands]=\"allowSkillCommands\"\n [enablePlanMode]=\"allowPlanMode\"\n [enableRealtime]=\"allowRealtime\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [initialMessage]=\"shouldDeliverPendingMessageTo(inputRef.conversationId) ? pendingMessage : null\"\n [initialAttachments]=\"shouldDeliverPendingMessageTo(inputRef.conversationId) ? pendingAttachments : null\"\n (initialMessageAutoSendStarted)=\"onInitialMessageAutoSendStarted($event)\"\n (initialMessageAutoSendFailed)=\"onInitialMessageAutoSendFailed($event)\"\n (messageSent)=\"onMessageSent($event)\"\n (MessageStreamed)=\"OnMessageStreamed($event)\"\n (agentResponse)=\"onAgentResponse($event)\"\n (agentRunDetected)=\"onAgentRunDetected($event)\"\n (agentRunUpdate)=\"onAgentRunUpdate($event)\"\n (messageComplete)=\"onMessageComplete($event)\"\n (artifactCreated)=\"onArtifactCreated($event)\"\n (conversationRenamed)=\"onConversationRenamed($event)\"\n (intentCheckStarted)=\"onIntentCheckStarted($event)\"\n (intentCheckCompleted)=\"onIntentCheckCompleted($event)\"\n (beforeAgentTurn)=\"beforeAgentTurn.emit($event)\"\n (afterAgentTurn)=\"afterAgentTurn.emit($event)\"\n (uploadStateChanged)=\"onUploadStateChanged($event)\">\n </mj-message-input>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Artifact Viewer Pane -->\n @if (showArtifactPanel && selectedArtifactId) {\n @if (!isArtifactPaneMaximized) {\n <div class=\"resize-handle\" (mousedown)=\"onResizeStart($event)\" (touchstart)=\"onResizeTouchStart($event)\"></div>\n }\n <div class=\"chat-artifact-pane\"\n [style.width.%]=\"artifactPaneWidth\"\n [class.maximized]=\"isArtifactPaneMaximized\">\n <mj-artifact-viewer-panel\n [artifactId]=\"selectedArtifactId\"\n [currentUser]=\"currentUser\"\n [environmentId]=\"environmentId\"\n [versionNumber]=\"selectedVersionNumber\"\n [viewContext]=\"'conversation'\"\n [canShare]=\"canShareSelectedArtifact\"\n [canEdit]=\"canEditSelectedArtifact\"\n [isMaximized]=\"isArtifactPaneMaximized\"\n [refreshTrigger]=\"artifactViewerRefresh$\"\n (closed)=\"onCloseArtifactPanel()\"\n (saveToCollectionRequested)=\"onSaveToCollectionRequested($event)\"\n (navigateToLink)=\"onArtifactLinkNavigation($event)\"\n (shareRequested)=\"onArtifactShareRequested($event)\"\n (maximizeToggled)=\"toggleMaximizeArtifactPane()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\"\n (analyzeRequested)=\"OnAnalyzeArtifact($event)\"\n (applyFormRequested)=\"OnApplyFormRequested($event)\">\n </mj-artifact-viewer-panel>\n </div>\n }\n\n <!-- Artifact Share Modal -->\n <mj-artifact-share-modal\n [isOpen]=\"isArtifactShareModalOpen\"\n [artifact]=\"artifactToShare\"\n [currentUser]=\"currentUser\"\n (saved)=\"onArtifactShared()\"\n (cancelled)=\"onArtifactShareModalClose()\">\n </mj-artifact-share-modal>\n\n <!-- Pinned Messages Panel (overlay) -->\n @if (allowPinning && showPinsPanel) {\n <mj-pinned-messages-panel\n [pinnedMessages]=\"pinnedMessages\"\n [isLoading]=\"isLoadingPins\"\n [AllowUnpin]=\"!EffectiveReadOnly\"\n (closed)=\"showPinsPanel = false\"\n (jumpRequested)=\"onJumpToMessage($event)\"\n (unpinRequested)=\"onUnpinFromPanel($event)\">\n </mj-pinned-messages-panel>\n }\n </div>\n\n <!-- Live voice \"call mode\" overlay \u2014 fills this conversation panel in place\n (header + thread + composer) while a realtime session is active. When the\n call is MINIMIZED (e.g. a dev link navigated to a record) the overlay HIDES\n (not destroyed \u2014 its merged session state must survive), the session stays\n fully live, and a floating \"on call\" pill offers the way back.\n ALSO hosted in SESSION REVIEW mode (RealtimeReview set, no live call): the\n overlay renders what went down in a PAST session, with a \"Start live session\"\n button that resumes it as a new call. -->\n @if ((RealtimeSession.Active$ | async) || RealtimeReview) {\n <mj-realtime-session-overlay\n [AgentName]=\"realtimeOverlayAgentName\"\n [Hidden]=\"(RealtimeSession.Minimized$ | async) === true\"\n [CurrentUser]=\"currentUser\"\n [EnvironmentID]=\"environmentId\"\n [ReviewData]=\"RealtimeReview\"\n [Chrome]=\"overlayMode ? 'orb' : 'auto'\"\n [Compact]=\"overlayMode\"\n [ShowDevLinks]=\"!overlayMode\"\n [ShowDensityPicker]=\"!overlayMode\"\n (NavigateRequest)=\"onRealtimeNavigateRequest($event)\"\n (StartLiveRequested)=\"onReviewStartLive($event)\"\n (ReviewClosed)=\"onReviewClosed()\">\n </mj-realtime-session-overlay>\n @if (RealtimeSession.Minimized$ | async) {\n <button type=\"button\" class=\"voice-call-pill\" (click)=\"RealtimeSession.SetMinimized(false)\"\n title=\"Return to the live call\" aria-label=\"Return to the live call\">\n <span class=\"voice-call-pill__pulse\" aria-hidden=\"true\"></span>\n <i class=\"fa-solid fa-phone-volume\" aria-hidden=\"true\"></i>\n <span class=\"voice-call-pill__text\">\n <span class=\"voice-call-pill__name\">On call \u00B7 {{ RealtimeSession.CurrentAgentName }}</span>\n <span class=\"voice-call-pill__hint\">Tap to return</span>\n </span>\n </button>\n }\n }\n</div>\n\n<!-- Thread Panel -->\n@if (threadId) {\n <mj-thread-panel\n [parentMessageId]=\"threadId\"\n [conversationId]=\"conversationId || ''\"\n [currentUser]=\"currentUser\"\n (closed)=\"onLocalThreadClosed()\"\n (replyAdded)=\"onThreadReplyAdded($event)\">\n </mj-thread-panel>\n}\n\n<!-- Export Modal -->\n<!-- [branding] is bound BEFORE [isVisible] deliberately: Angular sets inputs in\n template order within a change-detection pass, and the modal's isVisible setter\n reads `branding` to default its \"Include branding\" checkbox on a fresh open. -->\n<mj-export-modal\n [branding]=\"exportBranding\"\n [isVisible]=\"showExportModal\"\n [conversation]=\"conversation || undefined\"\n [currentUser]=\"currentUser\"\n (cancelled)=\"onExportModalCancelled()\"\n (exported)=\"onExportModalComplete()\">\n</mj-export-modal>\n\n<!-- Share Dialog (generic, shared with dashboards) -->\n<mj-resource-share-dialog\n [Visible]=\"showShareModal\"\n [Context]=\"shareContext\"\n [Adapter]=\"shareAdapter\"\n (Result)=\"onShareDialogResult($event)\">\n</mj-resource-share-dialog>\n\n<!-- Members Modal -->\n<mj-members-modal\n [isVisible]=\"showMembersModal\"\n [conversation]=\"conversation || undefined\"\n [currentUser]=\"currentUser\"\n (cancelled)=\"showMembersModal = false\"\n (membersChanged)=\"showMembersModal = false\">\n</mj-members-modal>\n\n<!-- Project Selector Modal -->\n@if (showProjectSelector && conversation) {\n <div class=\"modal-overlay\" (click)=\"showProjectSelector = false\">\n <div class=\"modal-content project-selector-modal\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3>Assign Project</h3>\n <button class=\"modal-close-btn\" (click)=\"showProjectSelector = false\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\n <mj-project-selector\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [selectedProjectId]=\"conversation.ProjectID\"\n (projectSelected)=\"onProjectSelected($event)\">\n </mj-project-selector>\n </div>\n </div>\n </div>\n}\n\n<!-- Artifacts Modal -->\n@if (showArtifactsModal) {\n <div class=\"modal-overlay\" (click)=\"showArtifactsModal = false\">\n <div class=\"modal-content artifacts-modal\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3>Conversation Artifacts</h3>\n <div class=\"modal-header-actions\">\n @if (hasSystemArtifacts) {\n <button class=\"toggle-system-btn\"\n [class.active]=\"showSystemArtifacts\"\n (click)=\"toggleSystemArtifacts()\"\n title=\"Toggle system artifacts visibility\">\n <i class=\"fas fa-cog\"></i>\n <span>{{ showSystemArtifacts ? 'Hide' : 'Show' }} System</span>\n </button>\n }\n <button class=\"modal-close-btn\" (click)=\"showArtifactsModal = false\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n <div class=\"modal-body artifacts-grid\">\n @if (artifactsByDetailId.size === 0) {\n <mj-empty-state\n class=\"artifacts-empty-fill\"\n Icon=\"fa-solid fa-cube\"\n Title=\"No artifacts in this conversation yet\" />\n }\n @for (artifact of getArtifactsArray(); track artifact.artifactId) {\n <div class=\"artifact-modal-card\"\n [class.expanded]=\"expandedArtifactId === artifact.artifactId\"\n [class.system-artifact]=\"artifact.visibility === 'System Only'\">\n <!-- Main card header - click to open latest version -->\n <div class=\"artifact-card-header\" (click)=\"openArtifactFromModal(artifact.artifactId)\">\n <div class=\"artifact-modal-icon\">\n <i class=\"fas fa-file-code\"></i>\n </div>\n <div class=\"artifact-modal-info\">\n <div class=\"artifact-modal-title\">{{artifact.name}}</div>\n <div class=\"artifact-modal-meta\">\n @if (artifact.versionCount > 1) {\n {{artifact.versionCount}} versions\n } @else {\n 1 version\n }\n </div>\n </div>\n @if (artifact.versionCount > 1) {\n <button class=\"expand-btn\" (click)=\"toggleArtifactExpansion(artifact.artifactId, $event)\">\n <i class=\"fas\" [class.fa-chevron-down]=\"expandedArtifactId !== artifact.artifactId\"\n [class.fa-chevron-up]=\"expandedArtifactId === artifact.artifactId\"></i>\n </button>\n }\n <div class=\"artifact-modal-action\">\n <i class=\"fas fa-external-link-alt\"></i>\n </div>\n </div>\n\n <!-- Expanded version list -->\n @if (expandedArtifactId === artifact.artifactId && artifact.versionCount > 1) {\n <div class=\"artifact-versions-list\">\n @for (version of artifact.versions; track version.versionId) {\n <div class=\"artifact-version-item\" (click)=\"openArtifactFromModal(artifact.artifactId, version.versionNumber); $event.stopPropagation()\">\n <span class=\"version-badge\">v{{version.versionNumber}}</span>\n <span class=\"version-open-text\">Open this version</span>\n <i class=\"fas fa-arrow-right\"></i>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n}\n\n<!-- Collection Picker Modal -->\n@if (showCollectionPicker) {\n <mj-artifact-collection-picker-modal\n [isOpen]=\"showCollectionPicker\"\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [excludeCollectionIds]=\"collectionPickerExcludedIds\"\n [artifactVersionId]=\"collectionPickerVersionId\"\n [artifactName]=\"collectionPickerArtifactName\"\n [artifactVersionNumber]=\"collectionPickerVersionNumber\"\n (completed)=\"onCollectionPickerCompleted($event)\"\n (cancelled)=\"onCollectionPickerCancelled()\">\n </mj-artifact-collection-picker-modal>\n}\n\n<!-- Test Feedback Dialog -->\n@if (testFeedbackDialogData) {\n <mj-test-feedback-dialog\n [data]=\"testFeedbackDialogData\"\n [visible]=\"showTestFeedbackDialog\"\n (closed)=\"onTestFeedbackDialogClosed($event)\">\n </mj-test-feedback-dialog>\n}\n\n<!-- Image Viewer Modal -->\n@if (showImageViewer) {\n <mj-image-viewer\n [imageUrl]=\"selectedImageUrl\"\n [alt]=\"selectedImageAlt\"\n [fileName]=\"selectedImageFileName\"\n [visible]=\"showImageViewer\"\n (closed)=\"onImageViewerClosed()\">\n </mj-image-viewer>\n}\n", styles: [":host {\n display: flex;\n width: 100%;\n height: 100%;\n}\n\n.chat-area {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n /* Positioned context for the in-place realtime \"call mode\" overlay (absolute inset:0) */\n position: relative;\n}\n\n.chat-header {\n flex-shrink: 0;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n background: var(--mj-bg-surface-card);\n z-index: 10;\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* agentPresence slot \u2014 sticky top, anchored with the header. Per Matt's\n 06-10 placement design: persistent presence indicator above the messages.\n Renders only when [showAgentCharacter] is true, so existing embeds see no\n layout change. The prominent variant grows toward a centered presence\n (per Matt: \"can grow larger toward a centered presence\"). */\n.chat-agent-presence {\n flex-shrink: 0;\n padding: 8px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n z-index: 11;\n}\n\n.chat-agent-presence--prominent {\n padding: 16px 20px;\n justify-content: center;\n}\n\n.chat-info {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n/* Sidebar toggle button in header */\n.sidebar-toggle-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: transparent;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.sidebar-toggle-btn:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.sidebar-toggle-btn:active {\n background: color-mix(in srgb, var(--mj-text-primary) 12%, transparent);\n}\n\n.sidebar-toggle-btn i {\n color: var(--mj-text-secondary);\n font-size: 18px;\n transition: color 0.15s ease;\n}\n\n.sidebar-toggle-btn:hover i {\n color: var(--mj-text-primary);\n}\n\n.chat-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 500;\n flex-shrink: 0;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.shared-by-badge i {\n font-size: 10px;\n}\n\n.shared-by-badge span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-tag {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 12px;\n}\n\n.project-tag:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-text-muted);\n}\n\n.project-tag i {\n font-size: 10px;\n}\n\n.test-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-status-warning);\n cursor: pointer;\n transition: all 0.2s;\n height: 28px;\n margin-left: 8px;\n}\n\n.test-indicator:hover {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.test-indicator i {\n font-size: 10px;\n}\n\n/* Pinned messages chip in chat header */\n.pin-chip {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, transparent);\n border-radius: 20px;\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.pin-chip i {\n font-size: 11px;\n}\n\n.pin-chip:hover,\n.pin-chip.active {\n background: color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n}\n\n.pin-chip-count {\n font-size: 12px;\n font-weight: 700;\n}\n\n.chat-members,\n.artifact-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n padding: 6px 8px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.chat-members:hover,\n.artifact-indicator:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* Badge overlay for artifact and member counts */\n.artifact-badge,\n.members-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n.members-badge {\n background: var(--mj-brand-primary);\n}\n\n.ambient-agent-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n animation: pulse 2s ease-in-out infinite;\n}\n\n.ambient-agent-indicator i {\n color: var(--mj-brand-primary);\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n}\n.chat-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n border-radius: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n transition: all 150ms ease;\n}\n\n.action-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.share-btn.shared {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-brand-primary-hover);\n}\n\n.share-btn.shared:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.chat-content-area {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: row;\n position: relative;\n}\n\n.chat-messages-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n min-width: min(300px, 100%); /* Respect container bounds while maintaining minimum */\n overflow: hidden;\n transition: width 0.3s ease;\n}\n\n.chat-messages-pane.full-width {\n width: 100%;\n}\n\n.chat-messages-pane:not(.full-width) {\n flex: 1;\n}\n\n.chat-messages-pane.hidden {\n display: none;\n}\n\n.resize-handle {\n width: 4px;\n background: transparent;\n cursor: col-resize;\n flex-shrink: 0;\n position: relative;\n transition: background-color 0.2s;\n}\n\n.resize-handle:hover {\n background: var(--mj-brand-primary);\n}\n\n.resize-handle::before {\n content: \"\";\n position: absolute;\n left: -4px;\n right: -4px;\n top: 0;\n bottom: 0;\n}\n\n.chat-artifact-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.chat-artifact-pane.maximized {\n width: 100% !important;\n}\n\n.chat-artifact-pane > mj-artifact-viewer-panel {\n display: flex;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.chat-messages-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n position: relative; /* For upload overlay positioning */\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n demonstrationSurface layout-mode (Matt's 06-10 placement design)\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n When .chat-content-area gets .demonstration-mode, the layout flips\n from \"messages pane (+ optional artifact pane)\" to \"stage + side rail\":\n - stage (.chat-demonstration-stage) \u2014 left, flexible, holds the\n consumer's projected demonstrationSurface slot template\n - rail (.chat-messages-pane) \u2014 right, fixed-width 320px, holds the\n messages list + composer (\"the conversation as a companion rail\")\n On mobile (\u2264768px) the same two stack vertically (stage above, rail\n below) per Matt's note about mobile. The rail intentionally keeps the\n composer inside it \u2014 Matt's design refers to the conversation rail\n inclusively (messages + composer together), not as separate regions.\n*/\n.chat-demonstration-stage {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: auto;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n flex: 1;\n min-width: 0;\n}\n\n.chat-content-area.demonstration-mode .chat-messages-pane,\n.chat-content-area.demonstration-mode .chat-messages-pane.full-width {\n flex: 0 0 320px;\n width: 320px;\n min-width: 0;\n}\n\n@media (max-width: 768px) {\n .chat-content-area.demonstration-mode {\n flex-direction: column;\n }\n\n .chat-content-area.demonstration-mode .chat-demonstration-stage {\n flex: 1 1 60%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n height: auto;\n }\n\n .chat-content-area.demonstration-mode .chat-messages-pane,\n .chat-content-area.demonstration-mode .chat-messages-pane.full-width {\n flex: 1 1 40%;\n width: 100%;\n height: auto;\n }\n}\n\n/* Upload indicator overlay - centered in conversation area */\n.upload-indicator-overlay {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem 1.5rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n z-index: 100;\n pointer-events: none;\n}\n\n.chat-messages-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-surface-card);\n min-height: 0;\n position: relative;\n}\n\n.scroll-to-bottom-icon {\n position: sticky;\n bottom: 21px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 40px;\n margin-top: -40px;\n margin-left: auto;\n margin-right: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: var(--mj-shadow-md);\n transition: all 0.2s ease;\n z-index: 100;\n pointer-events: auto;\n}\n\n.scroll-to-bottom-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n transform: translateX(-50%) translateY(-2px);\n box-shadow: color-mix(in srgb, var(--mj-brand-primary) 20%, transparent) 0 4px 12px;\n}\n\n.scroll-to-bottom-icon i {\n color: var(--mj-text-secondary);\n font-size: 16px;\n transition: color 0.2s;\n}\n\n.scroll-to-bottom-icon:hover i {\n color: var(--mj-brand-primary);\n}\n\n.chat-input-container {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n padding: 0 1.25rem 1.25rem 1.25rem;\n overflow: visible;\n}\n\n/* composerExtra slot: host UI directly above the composer. Spacing only; the host styles its content. */\n.chat-composer-extra {\n margin-bottom: 0.5rem;\n}\n\n.read-only-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 1.25rem 0.5rem 1.25rem;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-secondary);\n border-radius: 6px;\n font-size: 12px;\n}\n\n.read-only-banner i {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.loading-peripheral-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 140px;\n padding: 24px;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 50%, transparent);\n backdrop-filter: blur(2px);\n border-radius: 12px;\n margin: 12px;\n animation: fadeIn 0.2s ease-in-out;\n}\n\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.modal-content {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n max-width: 90vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.project-selector-modal {\n width: 600px;\n height: 500px;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n}\n\n.modal-header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toggle-system-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 6px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.toggle-system-btn:hover {\n background: var(--mj-border-default);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.toggle-system-btn.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.toggle-system-btn.active:hover {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.toggle-system-btn i {\n font-size: 12px;\n}\n\n.modal-close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s;\n}\n\n.modal-close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.modal-body {\n flex: 1;\n overflow: auto;\n padding: 20px;\n}\n\n.artifacts-modal {\n width: 700px;\n max-height: 600px;\n}\n\n.artifacts-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n/* Empty-state spans the full artifacts grid */\n.artifacts-empty-fill {\n grid-column: 1/-1;\n}\n\n.artifact-modal-card {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1.5px solid var(--mj-border-default);\n border-radius: 12px;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.artifact-modal-card.expanded {\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-modal-card.system-artifact {\n opacity: 0.85;\n border-color: var(--mj-border-default);\n border-style: dashed;\n position: relative;\n}\n\n.artifact-modal-card.system-artifact::before {\n content: \"SYSTEM\";\n position: absolute;\n top: 8px;\n right: 8px;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 3px;\n letter-spacing: 0.5px;\n z-index: 10;\n}\n\n.artifact-modal-card.system-artifact:hover {\n border-color: var(--mj-text-muted);\n box-shadow: var(--mj-shadow-md);\n}\n\n.artifact-card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n}\n\n.artifact-card-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-modal-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.artifact-modal-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-radius: 10px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.artifact-modal-icon i {\n font-size: 18px;\n}\n\n.artifact-modal-info {\n flex: 1;\n min-width: 0;\n}\n\n.artifact-modal-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.artifact-modal-meta {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.artifact-modal-action {\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.artifact-modal-card:hover .artifact-modal-action {\n color: var(--mj-brand-primary);\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.expand-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.artifact-versions-list {\n display: flex;\n flex-direction: column;\n padding: 0 1rem 1rem 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n.artifact-version-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px 12px 68px;\n cursor: pointer;\n transition: background 0.15s;\n}\n.artifact-version-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n.artifact-version-item .version-badge {\n display: inline-block;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 600;\n font-family: monospace;\n border-radius: 4px;\n}\n.artifact-version-item .version-open-text {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n.artifact-version-item i {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n.artifact-version-item:hover .version-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n.artifact-version-item:hover .version-open-text {\n color: var(--mj-brand-primary);\n}\n.artifact-version-item:hover i {\n color: var(--mj-brand-primary);\n}\n\n.loading-peripheral-content {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n color: var(--mj-text-secondary);\n font-size: 14px;\n font-weight: 500;\n}\n.loading-peripheral-content i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.conversation-loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n width: 100%;\n}\n\n.loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 20px;\n gap: 16px;\n color: var(--mj-text-secondary);\n font-size: 15px;\n}\n.loading-content i {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n.loading-content span {\n font-weight: 500;\n}\n\n/* Mobile adjustments: 481px - 768px */\n@media (max-width: 768px) {\n .chat-header {\n padding: 8px 12px;\n gap: 6px;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n position: relative;\n }\n .chat-info {\n flex-direction: row;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n order: 1;\n }\n .chat-title {\n font-size: 15px;\n font-weight: 700;\n width: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n }\n .project-tag {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n display: none; /* Hide on mobile to save space */\n }\n .test-indicator {\n margin-left: 0;\n font-size: 10px;\n padding: 3px 8px;\n height: 24px;\n }\n /* Action buttons - icon only on mobile */\n .chat-actions-buttons {\n order: 2;\n flex-shrink: 0;\n }\n .chat-actions-buttons .action-btn {\n padding: 6px 8px;\n min-width: auto;\n }\n .chat-actions-buttons .action-btn .btn-label {\n display: none;\n }\n .chat-actions {\n flex-wrap: nowrap;\n }\n .chat-members,\n .artifact-indicator {\n padding: 5px 7px;\n font-size: 13px;\n }\n .action-btn {\n padding: 6px 8px;\n font-size: 12px;\n }\n .ambient-agent-indicator {\n font-size: 12px;\n padding: 4px 8px;\n }\n .project-selector-modal {\n width: min(95vw, 600px);\n height: auto;\n }\n .artifacts-modal {\n width: min(95vw, 700px);\n }\n .artifacts-grid {\n grid-template-columns: 1fr;\n }\n .chat-input-container {\n padding: 0 0.75rem 0.75rem 0.75rem;\n }\n .scroll-to-bottom-icon {\n bottom: 16px;\n width: 36px;\n height: 36px;\n }\n /* Artifact pane - full width overlay on mobile, overlapping header */\n .chat-content-area {\n position: relative;\n }\n .chat-artifact-pane {\n position: fixed;\n left: 0;\n right: 0;\n top: 56px; /* 48px nav + 8px dark strip above blue border */\n bottom: 0;\n width: 100% !important;\n z-index: 100;\n background: var(--mj-bg-surface-card);\n }\n .resize-handle {\n display: none;\n }\n}\n/* Small Phone adjustments: <= 480px */\n@media (max-width: 480px) {\n .chat-header {\n padding: 6px 8px;\n gap: 4px;\n }\n .chat-title {\n font-size: 14px;\n font-weight: 700;\n }\n .project-tag {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n display: none;\n }\n .test-indicator {\n font-size: 9px;\n padding: 2px 6px;\n height: 20px;\n }\n .chat-members,\n .artifact-indicator {\n padding: 4px 8px;\n font-size: 11px;\n }\n .action-btn {\n padding: 5px 7px;\n font-size: 11px;\n }\n .ambient-agent-indicator {\n font-size: 11px;\n padding: 3px 6px;\n }\n .project-selector-modal,\n .artifacts-modal {\n width: 100vw;\n height: 100vh;\n border-radius: 0;\n }\n .chat-input-container {\n padding: 0 0.5rem 0.5rem 0.5rem;\n }\n .scroll-to-bottom-icon {\n bottom: 12px;\n width: 32px;\n height: 32px;\n }\n .scroll-to-bottom-icon i {\n font-size: 14px;\n }\n}\n\n/* Artifact Picker Panel */\n.artifact-picker-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-overlay);\n z-index: 999;\n}\n\n.artifact-picker-panel {\n position: fixed;\n right: 0;\n top: 0;\n width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n animation: slideInRight 0.2s ease-out;\n}\n\n@keyframes slideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n}\n\n.artifact-picker-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.artifact-picker-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n border-radius: 4px;\n}\n\n.artifact-picker-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.artifact-picker-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n\n.artifact-picker-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n text-align: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.artifact-picker-hint {\n font-size: 12px;\n color: var(--mj-text-disabled);\n}\n\n.artifact-picker-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.artifact-picker-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.artifact-picker-item:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-brand-primary);\n}\n\n.artifact-picker-item i {\n font-size: 20px;\n width: 24px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.artifact-picker-item i.fa-file-pdf { color: var(--mj-status-error); }\n.artifact-picker-item i.fa-file-excel { color: var(--mj-status-success); }\n.artifact-picker-item i.fa-file-word { color: var(--mj-brand-primary); }\n.artifact-picker-item i.fa-file { color: var(--mj-text-muted); }\n\n.artifact-picker-item-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.artifact-picker-item-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.artifact-picker-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* ---------- Floating \"on call\" pill (minimized realtime voice session) ----------\n Shown bottom-right of the chat panel while the live call overlay is minimized\n (e.g. after a gear-gated dev link navigated to a record). The mic + session stay\n live; tapping the pill restores the full call overlay. */\n.voice-call-pill {\n position: absolute;\n right: 18px;\n bottom: 18px;\n z-index: 49; /* just under the full call overlay (z-index 50) */\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 16px 9px 13px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-elevated, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-family: inherit;\n cursor: pointer;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;\n}\n.voice-call-pill:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 10px 28px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent);\n transform: translateY(-1px);\n}\n.voice-call-pill i {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n.voice-call-pill__pulse {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n animation: voice-pill-pulse 1.6s ease-in-out infinite;\n}\n.voice-call-pill__text {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n line-height: 1.25;\n}\n.voice-call-pill__name {\n font-size: 12.5px;\n font-weight: 700;\n}\n.voice-call-pill__hint {\n font-size: 10.5px;\n color: var(--mj-text-muted);\n}\n@keyframes voice-pill-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-status-success) 0%, transparent);\n }\n}\n"] }]
|
|
7001
|
+
}], () => [{ type: i1.AgentStateService }, { type: i2.ConversationLivenessDomService }, { type: i3.ConversationAgentService }, { type: i4.ActiveTasksService }, { type: i0.ChangeDetectorRef }, { type: i5.ArtifactPermissionService }, { type: i6.ConversationAttachmentService }, { type: i7.ConversationStreamingService }, { type: i8.DialogService }, { type: i9.ConversationBridgeService }, { type: i10.AnalyzeArtifactService }, { type: i11.UICommandHandlerService }, { type: i10.InteractiveFormApplyService }, { type: i12.AgentClientService }], { EnvironmentId: [{
|
|
6535
7002
|
type: Input
|
|
6536
7003
|
}], environmentId: [{
|
|
6537
7004
|
type: Input
|
|
@@ -6619,6 +7086,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6619
7086
|
type: Input
|
|
6620
7087
|
}], allowMessageDelete: [{
|
|
6621
7088
|
type: Input
|
|
7089
|
+
}], ReadOnly: [{
|
|
7090
|
+
type: Input
|
|
7091
|
+
}], ReadOnlyMessage: [{
|
|
7092
|
+
type: Input
|
|
6622
7093
|
}], ShowSuggestedPrompts: [{
|
|
6623
7094
|
type: Input
|
|
6624
7095
|
}], showSuggestedPrompts: [{
|
|
@@ -6711,6 +7182,8 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6711
7182
|
type: Input
|
|
6712
7183
|
}], AutoNameConversation: [{
|
|
6713
7184
|
type: Input
|
|
7185
|
+
}], EnableDecisionRouting: [{
|
|
7186
|
+
type: Input
|
|
6714
7187
|
}], ApplicationScope: [{
|
|
6715
7188
|
type: Input
|
|
6716
7189
|
}], applicationScope: [{
|
|
@@ -6884,5 +7357,5 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6884
7357
|
type: ViewChild,
|
|
6885
7358
|
args: [MessageListComponent]
|
|
6886
7359
|
}] }); })();
|
|
6887
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber:
|
|
7360
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber: 136 }); })();
|
|
6888
7361
|
//# sourceMappingURL=conversation-chat-area.component.js.map
|