@memberjunction/ng-conversations 6.2.0-edge.1 → 6.2.0-edge.2
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 +102 -2
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +457 -119
- 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 +68 -4
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +161 -22
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +80 -1
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +193 -23
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +10 -1
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +38 -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/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 +32 -32
|
@@ -28,36 +28,37 @@ import { ChatSlotDirective } from '../../directives/chat-slot.directive';
|
|
|
28
28
|
import { BeforeToolInvokedEventArgs, AfterToolInvokedEventArgs, SessionStartedEventArgs, SessionChannelStateChangedEventArgs, SessionEndedEventArgs, } from '../../events/chat-events';
|
|
29
29
|
import * as i0 from "@angular/core";
|
|
30
30
|
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 "
|
|
31
|
+
import * as i2 from "../../services/conversation-liveness-dom.service";
|
|
32
|
+
import * as i3 from "../../services/conversation-agent.service";
|
|
33
|
+
import * as i4 from "../../services/active-tasks.service";
|
|
34
|
+
import * as i5 from "../../services/artifact-permission.service";
|
|
35
|
+
import * as i6 from "../../services/conversation-attachment.service";
|
|
36
|
+
import * as i7 from "../../services/conversation-streaming.service";
|
|
37
|
+
import * as i8 from "../../services/dialog.service";
|
|
38
|
+
import * as i9 from "../../services/conversation-bridge.service";
|
|
39
|
+
import * as i10 from "@memberjunction/ng-artifacts";
|
|
40
|
+
import * as i11 from "../../services/ui-command-handler.service";
|
|
41
|
+
import * as i12 from "@memberjunction/ng-agent-client";
|
|
42
|
+
import * as i13 from "@angular/common";
|
|
43
|
+
import * as i14 from "@memberjunction/ng-ui-components";
|
|
44
|
+
import * as i15 from "@memberjunction/ng-testing";
|
|
45
|
+
import * as i16 from "@memberjunction/ng-shared-generic";
|
|
46
|
+
import * as i17 from "@memberjunction/ng-resource-permissions";
|
|
47
|
+
import * as i18 from "../collection/artifact-collection-picker-modal.component";
|
|
48
|
+
import * as i19 from "../artifact/artifact-share-modal.component";
|
|
49
|
+
import * as i20 from "../slots/mj-chat-agent-presence-default.component";
|
|
50
|
+
import * as i21 from "../realtime/realtime-session-overlay.component";
|
|
51
|
+
import * as i22 from "../message/message-list.component";
|
|
52
|
+
import * as i23 from "../message/message-input.component";
|
|
53
|
+
import * as i24 from "./conversation-empty-state.component";
|
|
54
|
+
import * as i25 from "./conversation-agent-picker.component";
|
|
55
|
+
import * as i26 from "./conversation-mode-picker.component";
|
|
56
|
+
import * as i27 from "../thread/thread-panel.component";
|
|
57
|
+
import * as i28 from "../project/project-selector.component";
|
|
58
|
+
import * as i29 from "../members/members-modal.component";
|
|
59
|
+
import * as i30 from "../export/export-modal.component";
|
|
60
|
+
import * as i31 from "../attachment/image-viewer.component";
|
|
61
|
+
import * as i32 from "./pinned-messages-panel.component";
|
|
61
62
|
const _c0 = ["scrollContainer"];
|
|
62
63
|
const _c1 = ["messageInput"];
|
|
63
64
|
const _c2 = (a0, a1, a2, a3, a4) => ({ $implicit: a0, state: a1, agentName: a2, avatarUrl: a3, mode: a4 });
|
|
@@ -143,6 +144,7 @@ function ConversationChatAreaComponent_Conditional_3_Conditional_5_Template(rf,
|
|
|
143
144
|
i0.ɵɵelementEnd()();
|
|
144
145
|
} if (rf & 2) {
|
|
145
146
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
147
|
+
i0.ɵɵattribute("title", ctx_r0.EffectiveReadOnly ? "Project" : "Assign to project");
|
|
146
148
|
i0.ɵɵadvance(3);
|
|
147
149
|
i0.ɵɵtextInterpolate(ctx_r0.conversation.Project || "Project");
|
|
148
150
|
} }
|
|
@@ -208,7 +210,7 @@ function ConversationChatAreaComponent_Conditional_3_Conditional_12_Template(rf,
|
|
|
208
210
|
i0.ɵɵelement(0, "mj-conversation-agent-picker", 34);
|
|
209
211
|
} if (rf & 2) {
|
|
210
212
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
211
|
-
i0.ɵɵproperty("Conversation", ctx_r0.conversation)("CurrentUser", ctx_r0.currentUser)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("Disabled", ctx_r0.
|
|
213
|
+
i0.ɵɵproperty("Conversation", ctx_r0.conversation)("CurrentUser", ctx_r0.currentUser)("AllowedAgentIDs", ctx_r0.AllowedAgentIDs)("Disabled", ctx_r0.EffectiveReadOnly);
|
|
212
214
|
} }
|
|
213
215
|
function ConversationChatAreaComponent_Conditional_3_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
214
216
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
@@ -253,7 +255,7 @@ function ConversationChatAreaComponent_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
253
255
|
i0.ɵɵconditionalCreate(2, ConversationChatAreaComponent_Conditional_3_Conditional_2_Template, 2, 0, "button", 24);
|
|
254
256
|
i0.ɵɵconditionalCreate(3, ConversationChatAreaComponent_Conditional_3_Conditional_3_Template, 2, 1, "div", 25);
|
|
255
257
|
i0.ɵɵconditionalCreate(4, ConversationChatAreaComponent_Conditional_3_Conditional_4_Template, 4, 2, "span", 26);
|
|
256
|
-
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_3_Conditional_5_Template, 4,
|
|
258
|
+
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_3_Conditional_5_Template, 4, 2, "button", 27);
|
|
257
259
|
i0.ɵɵconditionalCreate(6, ConversationChatAreaComponent_Conditional_3_Conditional_6_Template, 4, 0, "button", 28);
|
|
258
260
|
i0.ɵɵelementEnd();
|
|
259
261
|
i0.ɵɵelementStart(7, "div", 29);
|
|
@@ -288,7 +290,7 @@ function ConversationChatAreaComponent_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
288
290
|
i0.ɵɵadvance();
|
|
289
291
|
i0.ɵɵconditional(ctx_r0.memberCount > 1 ? 10 : -1);
|
|
290
292
|
i0.ɵɵadvance();
|
|
291
|
-
i0.ɵɵconditional(!ctx_r0.overlayMode && ctx_r0.showAgentModePicker && ctx_r0.ModePickerTargetAgentId ? 11 : -1);
|
|
293
|
+
i0.ɵɵconditional(!ctx_r0.overlayMode && ctx_r0.showAgentModePicker && ctx_r0.ModePickerTargetAgentId && !ctx_r0.EffectiveReadOnly ? 11 : -1);
|
|
292
294
|
i0.ɵɵadvance();
|
|
293
295
|
i0.ɵɵconditional(ctx_r0.showAgentPicker && ctx_r0.conversation ? 12 : -1);
|
|
294
296
|
i0.ɵɵadvance();
|
|
@@ -321,63 +323,92 @@ function ConversationChatAreaComponent_Conditional_7_Template(rf, ctx) { if (rf
|
|
|
321
323
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
322
324
|
i0.ɵɵconditional(ctx_r0.showLoadingState ? 0 : -1);
|
|
323
325
|
} }
|
|
324
|
-
function
|
|
326
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
327
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
328
|
+
i0.ɵɵelement(1, "i", 60);
|
|
329
|
+
i0.ɵɵelementStart(2, "span");
|
|
330
|
+
i0.ɵɵtext(3);
|
|
331
|
+
i0.ɵɵelementEnd()();
|
|
332
|
+
} if (rf & 2) {
|
|
333
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
334
|
+
i0.ɵɵadvance(3);
|
|
335
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
336
|
+
} }
|
|
337
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_1_ng_container_0_Template(rf, ctx) { if (rf & 1) {
|
|
325
338
|
i0.ɵɵelementContainer(0);
|
|
326
339
|
} }
|
|
327
|
-
function
|
|
328
|
-
i0.ɵɵtemplate(0,
|
|
340
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
341
|
+
i0.ɵɵtemplate(0, ConversationChatAreaComponent_Conditional_8_Conditional_1_ng_container_0_Template, 1, 0, "ng-container", 22);
|
|
329
342
|
} if (rf & 2) {
|
|
330
343
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
331
344
|
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
345
|
} }
|
|
333
|
-
function
|
|
346
|
+
function ConversationChatAreaComponent_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
334
347
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
335
|
-
i0.ɵɵelementStart(0, "mj-conversation-empty-state",
|
|
336
|
-
i0.ɵɵlistener("initialDraftApplied", function
|
|
348
|
+
i0.ɵɵelementStart(0, "mj-conversation-empty-state", 61);
|
|
349
|
+
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
350
|
i0.ɵɵelementEnd();
|
|
338
351
|
} if (rf & 2) {
|
|
339
352
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
340
353
|
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
354
|
} }
|
|
342
355
|
function ConversationChatAreaComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
343
|
-
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_8_Conditional_0_Template, 1, 8, "ng-container")(
|
|
356
|
+
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
357
|
} if (rf & 2) {
|
|
345
358
|
let tmp_1_0;
|
|
346
359
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
347
|
-
i0.ɵɵconditional((tmp_1_0 = ctx_r0.slotTemplate("emptyState")) ?
|
|
360
|
+
i0.ɵɵconditional(ctx_r0.ReadOnly ? 0 : (tmp_1_0 = ctx_r0.slotTemplate("emptyState")) ? 1 : 2, tmp_1_0);
|
|
361
|
+
} }
|
|
362
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
363
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
364
|
+
i0.ɵɵelement(1, "i", 60);
|
|
365
|
+
i0.ɵɵelementStart(2, "span");
|
|
366
|
+
i0.ɵɵtext(3);
|
|
367
|
+
i0.ɵɵelementEnd()();
|
|
368
|
+
} if (rf & 2) {
|
|
369
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
370
|
+
i0.ɵɵadvance(3);
|
|
371
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
348
372
|
} }
|
|
349
|
-
function
|
|
373
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_ng_container_1_Template(rf, ctx) { if (rf & 1) {
|
|
350
374
|
i0.ɵɵelementContainer(0);
|
|
351
375
|
} }
|
|
352
|
-
function
|
|
353
|
-
i0.ɵɵelementStart(0, "div",
|
|
354
|
-
i0.ɵɵtemplate(1,
|
|
376
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
377
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
378
|
+
i0.ɵɵtemplate(1, ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_ng_container_1_Template, 1, 0, "ng-container", 22);
|
|
355
379
|
i0.ɵɵelementEnd();
|
|
356
380
|
} if (rf & 2) {
|
|
357
|
-
const ctx_r0 = i0.ɵɵnextContext(
|
|
381
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
358
382
|
i0.ɵɵadvance();
|
|
359
383
|
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction3(2, _c8, ctx_r0.conversation, ctx_r0.conversationId, ctx_r0.isProcessing));
|
|
360
384
|
} }
|
|
361
|
-
function
|
|
385
|
+
function ConversationChatAreaComponent_Conditional_9_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
362
386
|
const _r12 = i0.ɵɵgetCurrentView();
|
|
387
|
+
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_9_Conditional_4_Conditional_0_Template, 2, 6, "div", 64);
|
|
388
|
+
i0.ɵɵelementStart(1, "div", 65)(2, "mj-message-input", 66, 0);
|
|
389
|
+
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)); });
|
|
390
|
+
i0.ɵɵelementEnd()();
|
|
391
|
+
} if (rf & 2) {
|
|
392
|
+
let tmp_3_0;
|
|
393
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
394
|
+
i0.ɵɵconditional((tmp_3_0 = ctx_r0.slotTemplate("composerExtra")) ? 0 : -1, tmp_3_0);
|
|
395
|
+
i0.ɵɵadvance(2);
|
|
396
|
+
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);
|
|
397
|
+
} }
|
|
398
|
+
function ConversationChatAreaComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
363
399
|
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()()()();
|
|
400
|
+
i0.ɵɵelement(1, "div", 62);
|
|
401
|
+
i0.ɵɵelementStart(2, "div", 63);
|
|
402
|
+
i0.ɵɵconditionalCreate(3, ConversationChatAreaComponent_Conditional_9_Conditional_3_Template, 4, 1, "div", 58)(4, ConversationChatAreaComponent_Conditional_9_Conditional_4_Template, 4, 18);
|
|
403
|
+
i0.ɵɵelementEnd()();
|
|
370
404
|
} if (rf & 2) {
|
|
371
|
-
let tmp_2_0;
|
|
372
405
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
373
406
|
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);
|
|
407
|
+
i0.ɵɵconditional(ctx_r0.ReadOnly ? 3 : 4);
|
|
377
408
|
} }
|
|
378
409
|
function ConversationChatAreaComponent_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
379
|
-
i0.ɵɵelementStart(0, "div",
|
|
380
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
410
|
+
i0.ɵɵelementStart(0, "div", 67);
|
|
411
|
+
i0.ɵɵelement(1, "mj-loading", 72);
|
|
381
412
|
i0.ɵɵelementEnd();
|
|
382
413
|
} if (rf & 2) {
|
|
383
414
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -386,50 +417,61 @@ function ConversationChatAreaComponent_Conditional_10_Conditional_1_Template(rf,
|
|
|
386
417
|
} }
|
|
387
418
|
function ConversationChatAreaComponent_Conditional_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
388
419
|
const _r14 = i0.ɵɵgetCurrentView();
|
|
389
|
-
i0.ɵɵelementStart(0, "span",
|
|
420
|
+
i0.ɵɵelementStart(0, "span", 73);
|
|
390
421
|
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",
|
|
422
|
+
i0.ɵɵelement(1, "i", 74);
|
|
392
423
|
i0.ɵɵelementEnd();
|
|
393
424
|
} }
|
|
394
425
|
function ConversationChatAreaComponent_Conditional_10_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
395
|
-
i0.ɵɵelementStart(0, "div",
|
|
396
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
426
|
+
i0.ɵɵelementStart(0, "div", 71);
|
|
427
|
+
i0.ɵɵelement(1, "mj-loading", 75);
|
|
397
428
|
i0.ɵɵelementEnd();
|
|
398
429
|
} }
|
|
399
|
-
function
|
|
400
|
-
i0.ɵɵelementStart(0, "div",
|
|
401
|
-
i0.ɵɵelement(1, "i",
|
|
430
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
431
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
432
|
+
i0.ɵɵelement(1, "i", 60);
|
|
433
|
+
i0.ɵɵelementStart(2, "span");
|
|
434
|
+
i0.ɵɵtext(3);
|
|
435
|
+
i0.ɵɵelementEnd()();
|
|
436
|
+
} if (rf & 2) {
|
|
437
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
438
|
+
i0.ɵɵadvance(3);
|
|
439
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadOnlyMessage || "You have view-only access to this conversation.");
|
|
440
|
+
} }
|
|
441
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
442
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
443
|
+
i0.ɵɵelement(1, "i", 60);
|
|
402
444
|
i0.ɵɵelementStart(2, "span");
|
|
403
445
|
i0.ɵɵtext(3, "You have view-only access to this conversation.");
|
|
404
446
|
i0.ɵɵelementEnd()();
|
|
405
447
|
} }
|
|
406
|
-
function
|
|
448
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_ng_container_1_Template(rf, ctx) { if (rf & 1) {
|
|
407
449
|
i0.ɵɵelementContainer(0);
|
|
408
450
|
} }
|
|
409
|
-
function
|
|
410
|
-
i0.ɵɵelementStart(0, "div",
|
|
411
|
-
i0.ɵɵtemplate(1,
|
|
451
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
452
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
453
|
+
i0.ɵɵtemplate(1, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_ng_container_1_Template, 1, 0, "ng-container", 22);
|
|
412
454
|
i0.ɵɵelementEnd();
|
|
413
455
|
} if (rf & 2) {
|
|
414
456
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
415
457
|
i0.ɵɵadvance();
|
|
416
458
|
i0.ɵɵproperty("ngTemplateOutlet", ctx)("ngTemplateOutletContext", i0.ɵɵpureFunction3(2, _c8, ctx_r0.conversation, ctx_r0.conversationId, ctx_r0.isProcessing));
|
|
417
459
|
} }
|
|
418
|
-
function
|
|
460
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
419
461
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
420
462
|
i0.ɵɵelementStart(0, "mj-message-input", 77, 2);
|
|
421
|
-
i0.ɵɵlistener("DraftStateChanged", function
|
|
463
|
+
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)); })("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
464
|
i0.ɵɵelementEnd();
|
|
423
465
|
} if (rf & 2) {
|
|
424
466
|
const inputRef_r16 = ctx.$implicit;
|
|
425
467
|
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(
|
|
468
|
+
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
469
|
} }
|
|
428
|
-
function
|
|
429
|
-
i0.ɵɵconditionalCreate(0,
|
|
430
|
-
i0.ɵɵconditionalCreate(1,
|
|
431
|
-
i0.ɵɵelementStart(2, "div",
|
|
432
|
-
i0.ɵɵrepeaterCreate(3,
|
|
470
|
+
function ConversationChatAreaComponent_Conditional_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
471
|
+
i0.ɵɵconditionalCreate(0, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_0_Template, 4, 0, "div", 58);
|
|
472
|
+
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_9_Conditional_1_Template, 2, 6, "div", 64);
|
|
473
|
+
i0.ɵɵelementStart(2, "div", 65);
|
|
474
|
+
i0.ɵɵrepeaterCreate(3, ConversationChatAreaComponent_Conditional_10_Conditional_9_For_4_Template, 2, 37, "mj-message-input", 76, _forTrack0);
|
|
433
475
|
i0.ɵɵelementEnd();
|
|
434
476
|
} if (rf & 2) {
|
|
435
477
|
let tmp_4_0;
|
|
@@ -443,27 +485,27 @@ function ConversationChatAreaComponent_Conditional_10_Conditional_8_Template(rf,
|
|
|
443
485
|
function ConversationChatAreaComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
444
486
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
445
487
|
i0.ɵɵelementStart(0, "div", 9);
|
|
446
|
-
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_1_Template, 2, 1, "div",
|
|
447
|
-
i0.ɵɵelementStart(2, "div",
|
|
488
|
+
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_10_Conditional_1_Template, 2, 1, "div", 67);
|
|
489
|
+
i0.ɵɵelementStart(2, "div", 68, 1);
|
|
448
490
|
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)); });
|
|
491
|
+
i0.ɵɵelementStart(4, "mj-conversation-message-list", 69);
|
|
492
|
+
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
493
|
i0.ɵɵelementEnd();
|
|
452
|
-
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_10_Conditional_5_Template, 2, 0, "span",
|
|
494
|
+
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_10_Conditional_5_Template, 2, 0, "span", 70);
|
|
453
495
|
i0.ɵɵelementEnd();
|
|
454
|
-
i0.ɵɵelementStart(6, "div",
|
|
455
|
-
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_10_Conditional_7_Template, 2, 0, "div",
|
|
496
|
+
i0.ɵɵelementStart(6, "div", 63);
|
|
497
|
+
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
498
|
i0.ɵɵelementEnd()();
|
|
457
499
|
} if (rf & 2) {
|
|
458
500
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
459
501
|
i0.ɵɵadvance();
|
|
460
502
|
i0.ɵɵconditional(ctx_r0.isUploadingAttachments ? 1 : -1);
|
|
461
503
|
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);
|
|
504
|
+
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
505
|
i0.ɵɵadvance();
|
|
464
506
|
i0.ɵɵconditional(ctx_r0.showScrollToBottomIcon && ctx_r0.messages && ctx_r0.messages.length > 0 ? 5 : -1);
|
|
465
507
|
i0.ɵɵadvance(2);
|
|
466
|
-
i0.ɵɵconditional(ctx_r0.isLoadingPeripheralData ? 7 : 8);
|
|
508
|
+
i0.ɵɵconditional(ctx_r0.isLoadingPeripheralData ? 7 : ctx_r0.ReadOnly ? 8 : 9);
|
|
467
509
|
} }
|
|
468
510
|
function ConversationChatAreaComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
469
511
|
const _r18 = i0.ɵɵgetCurrentView();
|
|
@@ -493,7 +535,7 @@ function ConversationChatAreaComponent_Conditional_13_Template(rf, ctx) { if (rf
|
|
|
493
535
|
i0.ɵɵelementEnd();
|
|
494
536
|
} if (rf & 2) {
|
|
495
537
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
496
|
-
i0.ɵɵproperty("pinnedMessages", ctx_r0.pinnedMessages)("isLoading", ctx_r0.isLoadingPins);
|
|
538
|
+
i0.ɵɵproperty("pinnedMessages", ctx_r0.pinnedMessages)("isLoading", ctx_r0.isLoadingPins)("AllowUnpin", !ctx_r0.EffectiveReadOnly);
|
|
497
539
|
} }
|
|
498
540
|
function ConversationChatAreaComponent_Conditional_14_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
499
541
|
const _r21 = i0.ɵɵgetCurrentView();
|
|
@@ -708,10 +750,13 @@ function ConversationChatAreaComponent_Conditional_24_Template(rf, ctx) { if (rf
|
|
|
708
750
|
} }
|
|
709
751
|
/** `MJ: Resource Types.ID` for Conversations. */
|
|
710
752
|
const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
|
|
753
|
+
/** Run statuses that mean the run is over, for the run-list fallback. `Paused` is still working. */
|
|
754
|
+
const RUN_LIST_TERMINAL_STATUSES = ['Completed', 'AwaitingFeedback', 'Failed', 'Cancelled'];
|
|
711
755
|
/** Default width (percentage) for the artifact viewer pane */
|
|
712
756
|
export const DEFAULT_ARTIFACT_PANE_WIDTH = 40;
|
|
713
757
|
export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
714
758
|
agentStateService;
|
|
759
|
+
livenessDom;
|
|
715
760
|
conversationAgentService;
|
|
716
761
|
activeTasks;
|
|
717
762
|
cdr;
|
|
@@ -1016,6 +1061,13 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
1016
1061
|
get allowMessageDelete() {
|
|
1017
1062
|
return this.AllowMessageDelete;
|
|
1018
1063
|
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Host-forced read-only. Hides every composer. A View share
|
|
1066
|
+
* ({@link IsReadOnlyView}) with this left false keeps today's disabled composer.
|
|
1067
|
+
*/
|
|
1068
|
+
ReadOnly = false;
|
|
1069
|
+
/** Banner copy when {@link ReadOnly} is set. Null uses the View-share text. */
|
|
1070
|
+
ReadOnlyMessage = null;
|
|
1019
1071
|
/** Show the empty-state's built-in suggested-prompt chips (and the @mention tip). */
|
|
1020
1072
|
ShowSuggestedPrompts = true;
|
|
1021
1073
|
/** @deprecated Use {@link ShowSuggestedPrompts}. */
|
|
@@ -1335,6 +1387,21 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
1335
1387
|
* True (the default) keeps today's behavior; a host that names its own chats turns it off.
|
|
1336
1388
|
*/
|
|
1337
1389
|
AutoNameConversation = true;
|
|
1390
|
+
/**
|
|
1391
|
+
* Whether an untagged message asks one fast typed decision which agent in the conversation
|
|
1392
|
+
* should answer it, instead of always going back to the last agent that answered. It replaces
|
|
1393
|
+
* that agent only when the answer is confident and arrives within `DECISION_ROUTING_TIMEOUT_MS`
|
|
1394
|
+
* (250 ms). False (the default)
|
|
1395
|
+
* changes nothing: no decision call, and today's routing. See
|
|
1396
|
+
* `MessageInputComponent.EnableDecisionRouting`.
|
|
1397
|
+
*
|
|
1398
|
+
* Turning it on sends conversation text to the model behind the `Default Decision` prompt, which
|
|
1399
|
+
* can be a different vendor from the agents' own: the first 1,000 characters of the new message,
|
|
1400
|
+
* the last 6 turns (150 characters each), each participant's name, description and last reply,
|
|
1401
|
+
* and the names of their artifact versions. Each call writes an `MJ: AI Prompt Runs` row, even
|
|
1402
|
+
* when the answer comes too late to be used.
|
|
1403
|
+
*/
|
|
1404
|
+
EnableDecisionRouting = false;
|
|
1338
1405
|
/**
|
|
1339
1406
|
* Scope to apply when this surface CREATES a new conversation. Forwarded
|
|
1340
1407
|
* to `ConversationEngine.CreateConversation` so the new row's
|
|
@@ -2037,6 +2104,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
2037
2104
|
lastLoadedConversationId = null; // Track which conversation's peripheral data was loaded
|
|
2038
2105
|
currentlyLoadingConversationId = null; // Track which conversation is currently being loaded
|
|
2039
2106
|
conversationLoadToken = 0; // Monotonic token to discard stale async conversation loads
|
|
2107
|
+
/** The reconcile passes in progress, shared by every caller that arrives while they run. */
|
|
2108
|
+
reconcileInFlight = null;
|
|
2109
|
+
/** Reason for one more reconcile pass, requested while a pass was running. */
|
|
2110
|
+
reconcileRerunReason = null;
|
|
2040
2111
|
IsProcessing = false;
|
|
2041
2112
|
/** @deprecated Use {@link IsProcessing}. */
|
|
2042
2113
|
get isProcessing() {
|
|
@@ -2835,9 +2906,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
2835
2906
|
}
|
|
2836
2907
|
// Shared AI mention/suggestion engine (BaseSingleton — same instance the composer plugins use)
|
|
2837
2908
|
mentionAutocompleteService = MentionAutocompleteService.Instance;
|
|
2838
|
-
constructor(agentStateService, conversationAgentService, activeTasks, cdr, artifactPermissionService, attachmentService, streamingService, confirmDialog, bridge, analyzeArtifactService, uiCommandHandler, interactiveFormApplyService, agentClientService) {
|
|
2909
|
+
constructor(agentStateService, livenessDom, conversationAgentService, activeTasks, cdr, artifactPermissionService, attachmentService, streamingService, confirmDialog, bridge, analyzeArtifactService, uiCommandHandler, interactiveFormApplyService, agentClientService) {
|
|
2839
2910
|
super();
|
|
2840
2911
|
this.agentStateService = agentStateService;
|
|
2912
|
+
this.livenessDom = livenessDom;
|
|
2841
2913
|
this.conversationAgentService = conversationAgentService;
|
|
2842
2914
|
this.activeTasks = activeTasks;
|
|
2843
2915
|
this.cdr = cdr;
|
|
@@ -3037,6 +3109,27 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3037
3109
|
if (message && conversationId) {
|
|
3038
3110
|
await this.handleMessageCompletion(message, event.agentRunId, conversationId);
|
|
3039
3111
|
}
|
|
3112
|
+
else if (conversationId) {
|
|
3113
|
+
// The completion is for a message we do not currently hold — it belongs to another
|
|
3114
|
+
// conversation, or to one scrolled out of the loaded window. Previously this event was
|
|
3115
|
+
// simply dropped, and for the scrolled-out case nothing else ever picked it up: the
|
|
3116
|
+
// `recentCompletions` replay only fires on conversation OPEN. Reconciling reads durable
|
|
3117
|
+
// state for every in-progress message we do hold, which repairs it if it is ours and
|
|
3118
|
+
// costs one narrow query if it is not.
|
|
3119
|
+
await this.ReconcileNow('completion-for-unloaded-message');
|
|
3120
|
+
}
|
|
3121
|
+
});
|
|
3122
|
+
// Reconciliation triggers that do NOT depend on a clean socket close. This is the
|
|
3123
|
+
// independent second layer: `retryAttempts`, `_socketStateSubject`,
|
|
3124
|
+
// `ServerConnectivityService`, `scheduleReconnection()` and `FireAndForgetHelper.onStreamEnd`
|
|
3125
|
+
// are all downstream of `on('closed')`, so on a half-open socket they fail together. The
|
|
3126
|
+
// supervisor coalesces socket-reconnect, stream-reconnect, tab-visible and browser-online
|
|
3127
|
+
// into one pass (MJ #4222).
|
|
3128
|
+
this.livenessDom.Start();
|
|
3129
|
+
ConversationsRuntime.Instance.Liveness.ReconciliationRequired$
|
|
3130
|
+
.pipe(takeUntil(this.destroy$))
|
|
3131
|
+
.subscribe((reason) => {
|
|
3132
|
+
void this.ReconcileNow(reason);
|
|
3040
3133
|
});
|
|
3041
3134
|
// Subscribe to polling-based agent state as a secondary fallback for completion detection.
|
|
3042
3135
|
// The sessionId is persisted in localStorage and reused on refresh, so WebSocket events
|
|
@@ -3405,14 +3498,14 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3405
3498
|
// Check for missed completions (user navigated away, agent completed, user returned)
|
|
3406
3499
|
for (const message of this.messages) {
|
|
3407
3500
|
if (message.Status === 'In-Progress' && message.ID) {
|
|
3408
|
-
const recentCompletion = this.streamingService.
|
|
3501
|
+
const recentCompletion = this.streamingService.GetRecentCompletion(message.ID);
|
|
3409
3502
|
if (recentCompletion) {
|
|
3410
3503
|
LogStatusEx({ message: `📥 Found missed completion for message ${message.ID}, handling...`, verboseOnly: true });
|
|
3411
3504
|
await this.handleMessageCompletion(message, recentCompletion.agentRunId, conversationId, loadToken);
|
|
3412
3505
|
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
3413
3506
|
return;
|
|
3414
3507
|
}
|
|
3415
|
-
this.streamingService.
|
|
3508
|
+
this.streamingService.ClearRecentCompletion(message.ID);
|
|
3416
3509
|
}
|
|
3417
3510
|
}
|
|
3418
3511
|
}
|
|
@@ -3770,14 +3863,22 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
3770
3863
|
if (!this.isActiveConversation(message.ConversationID)) {
|
|
3771
3864
|
return;
|
|
3772
3865
|
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3866
|
+
}
|
|
3867
|
+
// A host turn can finish before this row is on screen. The completion is already in the
|
|
3868
|
+
// streaming service's replay window; apply it the way a conversation load does, so the
|
|
3869
|
+
// row does not stay In-Progress until the conversation is opened again. Register the row
|
|
3870
|
+
// for the live callback either way — an update of an existing In-Progress row included.
|
|
3871
|
+
if (message.Status === 'In-Progress' && message.ID) {
|
|
3872
|
+
if (!this.InProgressMessageIds.some((id) => UUIDsEqual(id, message.ID))) {
|
|
3779
3873
|
this.InProgressMessageIds = [...this.InProgressMessageIds, message.ID];
|
|
3780
3874
|
}
|
|
3875
|
+
const recentCompletion = this.streamingService.GetRecentCompletion(message.ID);
|
|
3876
|
+
if (recentCompletion) {
|
|
3877
|
+
await this.handleMessageCompletion(message, recentCompletion.agentRunId, message.ConversationID);
|
|
3878
|
+
if (this.isActiveConversation(message.ConversationID)) {
|
|
3879
|
+
this.streamingService.ClearRecentCompletion(message.ID);
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3781
3882
|
}
|
|
3782
3883
|
// Where the viewport goes: a fresh send follows — an in-place update of a message that
|
|
3783
3884
|
// is already on screen must not re-run the send path's scroll.
|
|
@@ -4024,6 +4125,8 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4024
4125
|
console.error('Failed to reload messages for active conversation:', error);
|
|
4025
4126
|
}
|
|
4026
4127
|
}
|
|
4128
|
+
/** Detail ids whose completion this instance has already applied. A live callback and the replay window can both deliver one finish. */
|
|
4129
|
+
handledCompletionIds;
|
|
4027
4130
|
/**
|
|
4028
4131
|
* Handle message completion triggered by PubSub completion event
|
|
4029
4132
|
* Reloads message, agent run, and artifacts, then updates UI
|
|
@@ -4031,6 +4134,15 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4031
4134
|
* @param agentRunId The ID of the agent run that completed
|
|
4032
4135
|
*/
|
|
4033
4136
|
async handleMessageCompletion(message, _agentRunId, expectedConversationId = message.ConversationID, loadToken) {
|
|
4137
|
+
const completionId = message.ID ? NormalizeUUID(message.ID) : '';
|
|
4138
|
+
if (completionId) {
|
|
4139
|
+
this.handledCompletionIds ??= new Set();
|
|
4140
|
+
if (this.handledCompletionIds.has(completionId)) {
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
this.handledCompletionIds.add(completionId);
|
|
4144
|
+
}
|
|
4145
|
+
let finished = false;
|
|
4034
4146
|
try {
|
|
4035
4147
|
const isCurrent = () => this.isCurrentConversationContext(expectedConversationId, loadToken);
|
|
4036
4148
|
LogStatusEx({ message: `🎉 Handling completion for message ${message.ID}`, verboseOnly: true });
|
|
@@ -4089,11 +4201,18 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4089
4201
|
this.messages = [...this.messages];
|
|
4090
4202
|
this.cdr.detectChanges();
|
|
4091
4203
|
LogStatusEx({ message: `✅ Completion handled for message ${message.ID}`, verboseOnly: true });
|
|
4204
|
+
finished = true;
|
|
4092
4205
|
}
|
|
4093
4206
|
catch (error) {
|
|
4094
4207
|
console.error(`Error handling message completion for ${message.ID}:`, error);
|
|
4095
4208
|
this.cdr.detectChanges();
|
|
4096
4209
|
}
|
|
4210
|
+
finally {
|
|
4211
|
+
// A switch away mid-reload must not consume the completion. The next load still has the replay entry.
|
|
4212
|
+
if (!finished && completionId) {
|
|
4213
|
+
this.handledCompletionIds?.delete(completionId);
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4097
4216
|
}
|
|
4098
4217
|
async OnAgentResponse(event) {
|
|
4099
4218
|
// Guard: ignore agent responses from background inputs for other conversations.
|
|
@@ -4225,6 +4344,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4225
4344
|
}
|
|
4226
4345
|
}
|
|
4227
4346
|
OpenProjectSelector() {
|
|
4347
|
+
if (this.EffectiveReadOnly) {
|
|
4348
|
+
return;
|
|
4349
|
+
}
|
|
4228
4350
|
this.ShowProjectSelector = true;
|
|
4229
4351
|
}
|
|
4230
4352
|
/** @deprecated Use {@link OpenProjectSelector}. */
|
|
@@ -4620,6 +4742,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4620
4742
|
get isReadOnlyView() {
|
|
4621
4743
|
return this.IsReadOnlyView;
|
|
4622
4744
|
}
|
|
4745
|
+
/** Read-only for any reason: the host said so, or the conversation is shared with View access. */
|
|
4746
|
+
get EffectiveReadOnly() {
|
|
4747
|
+
return this.ReadOnly || this.IsReadOnlyView;
|
|
4748
|
+
}
|
|
4623
4749
|
/**
|
|
4624
4750
|
* `true` when the current user is allowed to create new shares on this
|
|
4625
4751
|
* conversation: the owner, or a user with an Owner-level grant. Uses the same
|
|
@@ -4812,6 +4938,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4812
4938
|
* Unpins a message from the pins panel — saves to DB and patches the cache.
|
|
4813
4939
|
*/
|
|
4814
4940
|
async OnUnpinFromPanel(message) {
|
|
4941
|
+
if (this.EffectiveReadOnly) {
|
|
4942
|
+
return;
|
|
4943
|
+
}
|
|
4815
4944
|
const previous = message.IsPinned;
|
|
4816
4945
|
message.IsPinned = false;
|
|
4817
4946
|
this.cdr.detectChanges();
|
|
@@ -4834,6 +4963,9 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
4834
4963
|
* Sends the selected response as a new user message WITHOUT modifying the visible input
|
|
4835
4964
|
*/
|
|
4836
4965
|
async OnSuggestedResponseSelected(event) {
|
|
4966
|
+
if (this.EffectiveReadOnly) {
|
|
4967
|
+
return;
|
|
4968
|
+
}
|
|
4837
4969
|
const messageText = event.customInput || event.text;
|
|
4838
4970
|
// Get the active message input for the current conversation
|
|
4839
4971
|
// (we cache multiple instances, one per visited conversation)
|
|
@@ -5556,6 +5688,18 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
5556
5688
|
onReviewClosed() {
|
|
5557
5689
|
return this.OnReviewClosed();
|
|
5558
5690
|
}
|
|
5691
|
+
/**
|
|
5692
|
+
* A message reports that its run has gone quiet (MJ #4222).
|
|
5693
|
+
*
|
|
5694
|
+
* The reconciliation triggers all fire on transport events — a socket retry, a tab regaining
|
|
5695
|
+
* focus. This one fires on the symptom itself: a run that simply stopped reporting, with no event
|
|
5696
|
+
* anywhere to notice it. Each pass covers every in-progress message, so the request goes through
|
|
5697
|
+
* the runtime's coalescing trigger: quiet rows asking at about the same time share one pass.
|
|
5698
|
+
*/
|
|
5699
|
+
OnLivenessCheckRequested(messageId) {
|
|
5700
|
+
LogStatusEx({ message: `🫀 Message ${messageId} reports no recent progress — reconciling`, verboseOnly: true });
|
|
5701
|
+
ConversationsRuntime.Instance.Liveness.Trigger('message-liveness');
|
|
5702
|
+
}
|
|
5559
5703
|
/**
|
|
5560
5704
|
* Handles Shift+Click on an AI message bubble.
|
|
5561
5705
|
* Dumps a live snapshot of in-memory streaming and agent-run state to the browser
|
|
@@ -5865,6 +6009,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
5865
6009
|
// 3. a generic re-prompt — last resort if no user message found
|
|
5866
6010
|
// OnAnalyzeArtifact prefilled messageText with 'Analyze "..." — '; we
|
|
5867
6011
|
// overwrite that with the resolved followup before sending.
|
|
6012
|
+
// Read-only (host flag or a View share) must not auto-send the follow-up.
|
|
6013
|
+
if (this.EffectiveReadOnly) {
|
|
6014
|
+
return;
|
|
6015
|
+
}
|
|
5868
6016
|
const messageInput = this.getActiveMessageInputComponent();
|
|
5869
6017
|
if (messageInput) {
|
|
5870
6018
|
let followup = command.followupMessage?.trim();
|
|
@@ -6257,6 +6405,190 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6257
6405
|
* completed successfully, we detect the mismatch and correct it. This prevents
|
|
6258
6406
|
* the race condition where the client overwrites a server-completed record.
|
|
6259
6407
|
*/
|
|
6408
|
+
/**
|
|
6409
|
+
* Re-read the agent-run rows backing this conversation's in-progress messages, refreshing
|
|
6410
|
+
* {@link AgentRunsByDetailId} in place.
|
|
6411
|
+
*
|
|
6412
|
+
* REQUIRED BEFORE ANY ON-DEMAND RECONCILE. {@link reconnectInProgressRuns} compares against
|
|
6413
|
+
* the in-memory map and never reloads it; on the conversation-load path that is safe only
|
|
6414
|
+
* because `loadPeripheralData` ran moments earlier off a fresh fetch. Invoked from a socket
|
|
6415
|
+
* reconnect or a tab regaining focus there has been no such fetch, so the map still holds the
|
|
6416
|
+
* stale `Running` status the outage froze it at — and the reconcile silently finds nothing to
|
|
6417
|
+
* do, which is indistinguishable from working (MJ #4222).
|
|
6418
|
+
*
|
|
6419
|
+
* Deliberately narrow in rows: only the in-progress details, with `BypassCache` because the
|
|
6420
|
+
* server wrote these rows through a different provider. Cheaper than
|
|
6421
|
+
* `windowStore.RefreshLatest()`, and cheap enough to run on every trigger. Full entity rows are
|
|
6422
|
+
* read, not a few fields: each row replaces the run object the message renders from and that the
|
|
6423
|
+
* completion path reloads, so a partial row would blank the run's duration, tokens and cost.
|
|
6424
|
+
*/
|
|
6425
|
+
async refreshAgentRunsForInProgress(conversationId, loadToken) {
|
|
6426
|
+
const inProgressIds = this.messages
|
|
6427
|
+
.filter(m => m.Status === 'In-Progress' && m.Role === 'AI' && m.ID)
|
|
6428
|
+
.map(m => m.ID);
|
|
6429
|
+
if (inProgressIds.length === 0) {
|
|
6430
|
+
return;
|
|
6431
|
+
}
|
|
6432
|
+
const quoted = inProgressIds.map(id => `'${id}'`).join(',');
|
|
6433
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
6434
|
+
const result = await rv.RunView({
|
|
6435
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
6436
|
+
ExtraFilter: `ConversationDetailID IN (${quoted})`,
|
|
6437
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
6438
|
+
ResultType: 'entity_object',
|
|
6439
|
+
BypassCache: true
|
|
6440
|
+
}, this.currentUser);
|
|
6441
|
+
if (!result.Success || !this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6442
|
+
return;
|
|
6443
|
+
}
|
|
6444
|
+
// `OrderBy __mj_CreatedAt DESC` puts the newest run first, so the first row seen for a detail
|
|
6445
|
+
// in THIS pass wins — a retried message must reconcile against its latest run, not its first.
|
|
6446
|
+
// Tracked per pass rather than by consulting the map, which usually already holds a run from
|
|
6447
|
+
// an earlier pass and is cleared only on conversation load.
|
|
6448
|
+
const seenDetailIds = new Set();
|
|
6449
|
+
for (const run of result.Results || []) {
|
|
6450
|
+
const detailId = run.ConversationDetailID;
|
|
6451
|
+
if (!detailId || seenDetailIds.has(detailId)) {
|
|
6452
|
+
continue;
|
|
6453
|
+
}
|
|
6454
|
+
seenDetailIds.add(detailId);
|
|
6455
|
+
this.AgentRunsByDetailId.set(detailId, run);
|
|
6456
|
+
}
|
|
6457
|
+
// New map reference so OnPush children re-read it.
|
|
6458
|
+
this.AgentRunsByDetailId = new Map(this.AgentRunsByDetailId);
|
|
6459
|
+
}
|
|
6460
|
+
/**
|
|
6461
|
+
* Reconcile in-progress messages against durable server state, on demand.
|
|
6462
|
+
*
|
|
6463
|
+
* This is the recovery path for the case the five close-event-driven mechanisms all miss: a
|
|
6464
|
+
* completion published while the client's transport was silently dead. Tier 0 makes the socket
|
|
6465
|
+
* close; this is what recovers the event that was dropped while it was down.
|
|
6466
|
+
*
|
|
6467
|
+
* Only one pass runs at a time. A request that arrives during a pass shares it and schedules one
|
|
6468
|
+
* follow-up pass, so every caller resolves after a pass that started after its request.
|
|
6469
|
+
*
|
|
6470
|
+
* @param reason What prompted it — carried only for logging.
|
|
6471
|
+
*/
|
|
6472
|
+
async ReconcileNow(reason) {
|
|
6473
|
+
if (this.reconcileInFlight) {
|
|
6474
|
+
this.reconcileRerunReason = reason;
|
|
6475
|
+
return this.reconcileInFlight;
|
|
6476
|
+
}
|
|
6477
|
+
this.reconcileInFlight = this.runReconcilePasses(reason);
|
|
6478
|
+
return this.reconcileInFlight;
|
|
6479
|
+
}
|
|
6480
|
+
/** Runs passes until no caller has asked for another. Clears the in-flight marker on exit. */
|
|
6481
|
+
async runReconcilePasses(reason) {
|
|
6482
|
+
try {
|
|
6483
|
+
let next = reason;
|
|
6484
|
+
while (next) {
|
|
6485
|
+
this.reconcileRerunReason = null;
|
|
6486
|
+
await this.reconcileOnce(next);
|
|
6487
|
+
next = this.reconcileRerunReason;
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
finally {
|
|
6491
|
+
this.reconcileInFlight = null;
|
|
6492
|
+
}
|
|
6493
|
+
}
|
|
6494
|
+
/** One reconcile pass over the in-progress messages of the active conversation. */
|
|
6495
|
+
async reconcileOnce(reason) {
|
|
6496
|
+
const conversationId = this.conversationId;
|
|
6497
|
+
if (!conversationId || !this.currentUser) {
|
|
6498
|
+
return;
|
|
6499
|
+
}
|
|
6500
|
+
// READ the token, never `++` it. `conversationLoadToken` is a CANCELLATION token: every
|
|
6501
|
+
// in-flight conversation load checks it and bails when it changes, so incrementing here
|
|
6502
|
+
// would abort a load already running rather than merely tagging this work.
|
|
6503
|
+
const loadToken = this.conversationLoadToken;
|
|
6504
|
+
LogStatusEx({ message: `🔁 Reconciling in-progress runs (${reason})`, verboseOnly: true });
|
|
6505
|
+
try {
|
|
6506
|
+
await this.refreshAgentRunsForInProgress(conversationId, loadToken);
|
|
6507
|
+
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6508
|
+
return;
|
|
6509
|
+
}
|
|
6510
|
+
await this.detectAndReconcileAgentRuns(conversationId, loadToken);
|
|
6511
|
+
}
|
|
6512
|
+
catch (error) {
|
|
6513
|
+
// Recovery is best-effort: a failed reconcile must never surface as a user-facing error,
|
|
6514
|
+
// and the next trigger will try again.
|
|
6515
|
+
console.error('[ConversationChatArea] Reconciliation failed:', error);
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6518
|
+
/**
|
|
6519
|
+
* Ask the durable read model whether a message we still show as in-progress has in fact finished.
|
|
6520
|
+
*
|
|
6521
|
+
* The last gap in the recovery chain. Everything else here reads `MJ: AI Agent Runs` through the
|
|
6522
|
+
* client's own provider; when that returns nothing the message simply waits. The tail query reads
|
|
6523
|
+
* the same truth server-side from a cursor, reports the conversation detail's own status, and runs
|
|
6524
|
+
* over HTTP — so it answers while the WebSocket is still down, which is the whole point.
|
|
6525
|
+
*
|
|
6526
|
+
* Completion is routed through the existing {@link handleMessageCompletion}, never written here:
|
|
6527
|
+
* four writers already move a message out of In-Progress and a fifth would race them.
|
|
6528
|
+
*
|
|
6529
|
+
* @returns true when the message was completed from durable state.
|
|
6530
|
+
*/
|
|
6531
|
+
async tryRecoverFromTail(message, conversationId, loadToken) {
|
|
6532
|
+
const tail = ConversationsRuntime.Instance.Tail;
|
|
6533
|
+
const result = await tail.Tail(message.ID);
|
|
6534
|
+
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6535
|
+
return false;
|
|
6536
|
+
}
|
|
6537
|
+
if (!result.Success) {
|
|
6538
|
+
// An older server has no tail query, and a new client then gets a failure on every call.
|
|
6539
|
+
// Decide from the run list instead, as the client did before the tail existed.
|
|
6540
|
+
return this.recoverFromRunList(message, conversationId, loadToken);
|
|
6541
|
+
}
|
|
6542
|
+
// `IsInFlight` false means the server considers the run finished. A terminal `DetailStatus`
|
|
6543
|
+
// with no run at all covers the case where the detail was completed by something other than an
|
|
6544
|
+
// agent run. Either way the message must stop spinning.
|
|
6545
|
+
const detailIsTerminal = result.DetailStatus === 'Complete' || result.DetailStatus === 'Error';
|
|
6546
|
+
const runIsTerminal = result.RunID != null && !result.IsInFlight;
|
|
6547
|
+
if (!runIsTerminal && !detailIsTerminal) {
|
|
6548
|
+
return false;
|
|
6549
|
+
}
|
|
6550
|
+
// A terminal run beside a detail the server still reports as open is the orphan window, which
|
|
6551
|
+
// the server-side reconciler closes after its grace period. `handleMessageCompletion` re-reads
|
|
6552
|
+
// the detail rather than writing it, so completing here cannot settle the message; it would
|
|
6553
|
+
// reload the whole conversation on every trigger and leave it spinning regardless. Keep the
|
|
6554
|
+
// cursor and wait for the row to close.
|
|
6555
|
+
if (!detailIsTerminal && result.DetailStatus === 'In-Progress') {
|
|
6556
|
+
LogStatusEx({
|
|
6557
|
+
message: `📼 Tail reports run ${result.RunID} finished but detail ${message.ID} is still open — leaving it to the reconciler`,
|
|
6558
|
+
verboseOnly: true
|
|
6559
|
+
});
|
|
6560
|
+
return false;
|
|
6561
|
+
}
|
|
6562
|
+
LogStatusEx({
|
|
6563
|
+
message: `📼 Tail reports message ${message.ID} finished (run ${result.RunID ?? 'none'}, status ${result.RunStatus ?? result.DetailStatus}) — completing`,
|
|
6564
|
+
verboseOnly: true
|
|
6565
|
+
});
|
|
6566
|
+
await this.handleMessageCompletion(message, result.RunID ?? '', conversationId, loadToken);
|
|
6567
|
+
// The message is terminal, so its cursor will never advance again.
|
|
6568
|
+
tail.Forget(message.ID);
|
|
6569
|
+
return true;
|
|
6570
|
+
}
|
|
6571
|
+
/**
|
|
6572
|
+
* Complete a message from the run list alone. Used only when the tail call fails.
|
|
6573
|
+
*
|
|
6574
|
+
* Less precise than the tail: it cannot see the conversation detail's own status, so during the
|
|
6575
|
+
* orphan window it reloads the message without settling it. That was the behavior before the
|
|
6576
|
+
* tail existed, and it is better than leaving a finished message spinning.
|
|
6577
|
+
*
|
|
6578
|
+
* @returns true when the message was completed.
|
|
6579
|
+
*/
|
|
6580
|
+
async recoverFromRunList(message, conversationId, loadToken) {
|
|
6581
|
+
const run = this.AgentRunsByDetailId.get(message.ID);
|
|
6582
|
+
if (!run || !RUN_LIST_TERMINAL_STATUSES.includes(run.Status)) {
|
|
6583
|
+
return false;
|
|
6584
|
+
}
|
|
6585
|
+
LogStatusEx({
|
|
6586
|
+
message: `📼 Tail unavailable; run ${run.ID} (${run.Status}) for message ${message.ID} is finished — completing from the run list`,
|
|
6587
|
+
verboseOnly: true
|
|
6588
|
+
});
|
|
6589
|
+
await this.handleMessageCompletion(message, run.ID, conversationId, loadToken);
|
|
6590
|
+
return true;
|
|
6591
|
+
}
|
|
6260
6592
|
async detectAndReconcileAgentRuns(conversationId, loadToken) {
|
|
6261
6593
|
if (!this.isActiveConversationLoad(conversationId, loadToken)) {
|
|
6262
6594
|
return;
|
|
@@ -6276,22 +6608,22 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6276
6608
|
return;
|
|
6277
6609
|
}
|
|
6278
6610
|
LogStatusEx({ message: `🔄 Found ${inProgressMessages.length} in-progress messages, checking status...`, verboseOnly: true });
|
|
6279
|
-
const completedStatuses = ['Completed', 'Failed', 'Error', 'Cancelled'];
|
|
6280
6611
|
for (const message of inProgressMessages) {
|
|
6281
6612
|
const agentRun = this.AgentRunsByDetailId.get(message.ID);
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
LogStatusEx({
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6613
|
+
// Ask durable state for every in-progress message, whatever the run map says. The run is not
|
|
6614
|
+
// the only thing that decides a message: the tail reports the conversation detail's own
|
|
6615
|
+
// status, which the run map does not carry at all. A finished run beside a detail that is
|
|
6616
|
+
// still open is the orphan window, and completing from the run alone would reload the whole
|
|
6617
|
+
// conversation on every trigger while the message kept spinning. The tail leaves that case
|
|
6618
|
+
// to the server-side reconciler, and completes a detail that was closed by anything.
|
|
6619
|
+
const recovered = await this.tryRecoverFromTail(message, conversationId, loadToken);
|
|
6620
|
+
if (!recovered) {
|
|
6621
|
+
LogStatusEx({
|
|
6622
|
+
message: agentRun
|
|
6623
|
+
? `🔌 Agent run ${agentRun.ID} (${agentRun.Status}) for message ${message.ID}; durable state does not show the message finished`
|
|
6624
|
+
: `⏳ No agent run found for in-progress message ${message.ID}, waiting for server...`,
|
|
6625
|
+
verboseOnly: true
|
|
6626
|
+
});
|
|
6295
6627
|
}
|
|
6296
6628
|
}
|
|
6297
6629
|
}
|
|
@@ -6438,7 +6770,7 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6438
6770
|
onIntentCheckCompleted(event) {
|
|
6439
6771
|
return this.OnIntentCheckCompleted(event);
|
|
6440
6772
|
}
|
|
6441
|
-
static ɵfac = function ConversationChatAreaComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationChatAreaComponent)(i0.ɵɵdirectiveInject(i1.AgentStateService), i0.ɵɵdirectiveInject(i2.
|
|
6773
|
+
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
6774
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationChatAreaComponent, selectors: [["mj-conversation-chat-area"]], contentQueries: function ConversationChatAreaComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
|
|
6443
6775
|
i0.ɵɵcontentQuery(dirIndex, ChatSlotDirective, 4);
|
|
6444
6776
|
} if (rf & 2) {
|
|
@@ -6453,20 +6785,20 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6453
6785
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.emptyStateComponent = _t.first);
|
|
6454
6786
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageListComponent = _t.first);
|
|
6455
6787
|
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) {
|
|
6788
|
+
} }, 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", "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
6789
|
i0.ɵɵelementStart(0, "div", 3);
|
|
6458
6790
|
i0.ɵɵconditionalCreate(1, ConversationChatAreaComponent_Conditional_1_Template, 3, 3, "div", 4);
|
|
6459
6791
|
i0.ɵɵconditionalCreate(2, ConversationChatAreaComponent_Conditional_2_Template, 1, 8, "ng-container")(3, ConversationChatAreaComponent_Conditional_3_Template, 16, 15, "div", 5);
|
|
6460
6792
|
i0.ɵɵelementStart(4, "div", 6);
|
|
6461
6793
|
i0.ɵɵconditionalCreate(5, ConversationChatAreaComponent_Conditional_5_Template, 2, 6, "div", 7);
|
|
6462
6794
|
i0.ɵɵelementStart(6, "div", 8);
|
|
6463
|
-
i0.ɵɵconditionalCreate(7, ConversationChatAreaComponent_Conditional_7_Template, 1, 1)(8, ConversationChatAreaComponent_Conditional_8_Template,
|
|
6795
|
+
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
6796
|
i0.ɵɵelementEnd();
|
|
6465
6797
|
i0.ɵɵconditionalCreate(11, ConversationChatAreaComponent_Conditional_11_Template, 3, 14);
|
|
6466
6798
|
i0.ɵɵelementStart(12, "mj-artifact-share-modal", 10);
|
|
6467
6799
|
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
6800
|
i0.ɵɵelementEnd();
|
|
6469
|
-
i0.ɵɵconditionalCreate(13, ConversationChatAreaComponent_Conditional_13_Template, 1,
|
|
6801
|
+
i0.ɵɵconditionalCreate(13, ConversationChatAreaComponent_Conditional_13_Template, 1, 3, "mj-pinned-messages-panel", 11);
|
|
6470
6802
|
i0.ɵɵelementEnd();
|
|
6471
6803
|
i0.ɵɵconditionalCreate(14, ConversationChatAreaComponent_Conditional_14_Template, 4, 14);
|
|
6472
6804
|
i0.ɵɵpipe(15, "async");
|
|
@@ -6526,12 +6858,12 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6526
6858
|
i0.ɵɵconditional(ctx.testFeedbackDialogData ? 23 : -1);
|
|
6527
6859
|
i0.ɵɵadvance();
|
|
6528
6860
|
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}"] });
|
|
6861
|
+
} }, 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
6862
|
}
|
|
6531
6863
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ConversationChatAreaComponent, [{
|
|
6532
6864
|
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.
|
|
6865
|
+
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 (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"] }]
|
|
6866
|
+
}], () => [{ 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
6867
|
type: Input
|
|
6536
6868
|
}], environmentId: [{
|
|
6537
6869
|
type: Input
|
|
@@ -6619,6 +6951,10 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6619
6951
|
type: Input
|
|
6620
6952
|
}], allowMessageDelete: [{
|
|
6621
6953
|
type: Input
|
|
6954
|
+
}], ReadOnly: [{
|
|
6955
|
+
type: Input
|
|
6956
|
+
}], ReadOnlyMessage: [{
|
|
6957
|
+
type: Input
|
|
6622
6958
|
}], ShowSuggestedPrompts: [{
|
|
6623
6959
|
type: Input
|
|
6624
6960
|
}], showSuggestedPrompts: [{
|
|
@@ -6711,6 +7047,8 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6711
7047
|
type: Input
|
|
6712
7048
|
}], AutoNameConversation: [{
|
|
6713
7049
|
type: Input
|
|
7050
|
+
}], EnableDecisionRouting: [{
|
|
7051
|
+
type: Input
|
|
6714
7052
|
}], ApplicationScope: [{
|
|
6715
7053
|
type: Input
|
|
6716
7054
|
}], applicationScope: [{
|
|
@@ -6884,5 +7222,5 @@ export class ConversationChatAreaComponent extends BaseAngularComponent {
|
|
|
6884
7222
|
type: ViewChild,
|
|
6885
7223
|
args: [MessageListComponent]
|
|
6886
7224
|
}] }); })();
|
|
6887
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber:
|
|
7225
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber: 124 }); })();
|
|
6888
7226
|
//# sourceMappingURL=conversation-chat-area.component.js.map
|