@memberjunction/ng-ai-test-harness 5.44.0 → 5.45.0

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.
@@ -3,6 +3,7 @@ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
3
  import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
4
4
  import { MJAIAgentEntityExtended, MJAIPromptEntityExtended, MJAIAgentRunEntityExtended, MJAIAgentRunStepEntityExtended } from "@memberjunction/ai-core-plus";
5
5
  import { MJAIConfigurationEntity } from '@memberjunction/core-entities';
6
+ import { MJConfirmService } from '@memberjunction/ng-ui-components';
6
7
  import { ChatMessage } from '@memberjunction/ai';
7
8
  import * as i0 from "@angular/core";
8
9
  /**
@@ -136,12 +137,13 @@ export interface SavedConversation {
136
137
  export declare class AITestHarnessComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges, AfterViewChecked {
137
138
  private sanitizer;
138
139
  private cdr;
140
+ private confirmService;
139
141
  /**
140
142
  * Creates a new AI Test Harness component instance.
141
143
  * @param sanitizer - Angular DomSanitizer for safe HTML rendering of formatted content
142
144
  * @param cdr - Angular ChangeDetectorRef for managing change detection
143
145
  */
144
- constructor(sanitizer: DomSanitizer, cdr: ChangeDetectorRef);
146
+ constructor(sanitizer: DomSanitizer, cdr: ChangeDetectorRef, confirmService: MJConfirmService);
145
147
  /** The mode of operation - either 'agent' or 'prompt' */
146
148
  mode: TestHarnessMode;
147
149
  /** The entity to test - either an AI Agent or AI Prompt */
@@ -371,7 +373,7 @@ export declare class AITestHarnessComponent extends BaseAngularComponent impleme
371
373
  /**
372
374
  * Starts a new conversation
373
375
  */
374
- newConversation(): void;
376
+ newConversation(): Promise<void>;
375
377
  /**
376
378
  * Closes the test harness by setting visibility to false and emitting the change event.
377
379
  * Used by dialog implementations and close buttons.
@@ -452,7 +454,7 @@ export declare class AITestHarnessComponent extends BaseAngularComponent impleme
452
454
  * Clears the current conversation after user confirmation.
453
455
  * Resets both the message history and the current conversation ID.
454
456
  */
455
- clearConversation(): void;
457
+ clearConversation(): Promise<void>;
456
458
  private scrollToBottom;
457
459
  private generateMessageId;
458
460
  private loadSavedConversations;
@@ -1 +1 @@
1
- {"version":3,"file":"ai-test-harness.component.d.ts","sourceRoot":"","sources":["../../src/lib/ai-test-harness.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai-test-harness.component.d.ts","sourceRoot":"","sources":["../../src/lib/ai-test-harness.component.ts"],"names":[],"mappings":"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"}
@@ -5,12 +5,12 @@ import { MJNotificationService } from '@memberjunction/ng-notifications';
5
5
  import { SharedService } from '@memberjunction/ng-shared';
6
6
  import { Subject } from 'rxjs';
7
7
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
8
- import { ParseJSONRecursive, UUIDsEqual } from '@memberjunction/global';
8
+ import { ParseJSONRecursive, UUIDsEqual, EscapeHTML } from '@memberjunction/global';
9
9
  import * as i0 from "@angular/core";
10
10
  import * as i1 from "@angular/platform-browser";
11
- import * as i2 from "@angular/common";
12
- import * as i3 from "@angular/forms";
13
- import * as i4 from "@memberjunction/ng-ui-components";
11
+ import * as i2 from "@memberjunction/ng-ui-components";
12
+ import * as i3 from "@angular/common";
13
+ import * as i4 from "@angular/forms";
14
14
  import * as i5 from "angular-split";
15
15
  import * as i6 from "@memberjunction/ng-code-editor";
16
16
  import * as i7 from "./json-viewer-window.component";
@@ -1209,10 +1209,11 @@ export class AITestHarnessComponent extends BaseAngularComponent {
1209
1209
  * @param sanitizer - Angular DomSanitizer for safe HTML rendering of formatted content
1210
1210
  * @param cdr - Angular ChangeDetectorRef for managing change detection
1211
1211
  */
1212
- constructor(sanitizer, cdr) {
1212
+ constructor(sanitizer, cdr, confirmService) {
1213
1213
  super();
1214
1214
  this.sanitizer = sanitizer;
1215
1215
  this.cdr = cdr;
1216
+ this.confirmService = confirmService;
1216
1217
  /** The mode of operation - either 'agent' or 'prompt' */
1217
1218
  this.mode = 'agent';
1218
1219
  /** The entity to test - either an AI Agent or AI Prompt */
@@ -1968,10 +1969,10 @@ export class AITestHarnessComponent extends BaseAngularComponent {
1968
1969
  /**
1969
1970
  * Starts a new conversation
1970
1971
  */
1971
- newConversation() {
1972
+ async newConversation() {
1972
1973
  if (this.conversationMessages.length > 0 && !this.currentConversationId) {
1973
1974
  // Unsaved conversation exists - use our custom dialog
1974
- if (confirm('You have an unsaved conversation. Would you like to save it first?')) {
1975
+ if (await this.confirmService.Confirm({ title: 'Unsaved conversation', message: 'You have an unsaved conversation. Would you like to save it first?', confirmText: 'Save' })) {
1975
1976
  this.saveConversation();
1976
1977
  return;
1977
1978
  }
@@ -2625,9 +2626,9 @@ export class AITestHarnessComponent extends BaseAngularComponent {
2625
2626
  * Clears the current conversation after user confirmation.
2626
2627
  * Resets both the message history and the current conversation ID.
2627
2628
  */
2628
- clearConversation() {
2629
+ async clearConversation() {
2629
2630
  if (this.conversationMessages.length > 0) {
2630
- if (confirm('Are you sure you want to clear the conversation?')) {
2631
+ if (await this.confirmService.Confirm({ title: 'Clear conversation', message: 'Are you sure you want to clear the conversation?' })) {
2631
2632
  this.conversationMessages = [];
2632
2633
  this.currentConversationId = null;
2633
2634
  }
@@ -2944,7 +2945,7 @@ export class AITestHarnessComponent extends BaseAngularComponent {
2944
2945
  }
2945
2946
  async deleteConversation(conversation, event) {
2946
2947
  event.stopPropagation();
2947
- if (confirm(`Delete conversation "${conversation.name}"?`)) {
2948
+ if (await this.confirmService.ConfirmDelete({ title: 'Delete Conversation', message: `Delete conversation "${conversation.name}"?` })) {
2948
2949
  const index = this.savedConversations.findIndex(c => c.id === conversation.id);
2949
2950
  if (index >= 0) {
2950
2951
  this.savedConversations.splice(index, 1);
@@ -3007,13 +3008,13 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3007
3008
  if (input.files && input.files[0]) {
3008
3009
  const file = input.files[0];
3009
3010
  const reader = new FileReader();
3010
- reader.onload = (e) => {
3011
+ reader.onload = async (e) => {
3011
3012
  try {
3012
3013
  const data = JSON.parse(e.target?.result);
3013
3014
  // Validate and import
3014
3015
  if (data.messages && Array.isArray(data.messages)) {
3015
3016
  if (this.conversationMessages.length > 0) {
3016
- if (!confirm('Importing will replace the current conversation. Continue?')) {
3017
+ if (!(await this.confirmService.Confirm({ title: 'Import conversation', message: 'Importing will replace the current conversation. Continue?' }))) {
3017
3018
  return;
3018
3019
  }
3019
3020
  }
@@ -3369,9 +3370,7 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3369
3370
  // Basic markdown to HTML conversion with improved formatting
3370
3371
  let html = content;
3371
3372
  // Escape HTML first
3372
- html = html.replace(/&/g, '&amp;')
3373
- .replace(/</g, '&lt;')
3374
- .replace(/>/g, '&gt;');
3373
+ html = EscapeHTML(html);
3375
3374
  // Code blocks with language support
3376
3375
  html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
3377
3376
  const language = lang || '';
@@ -3461,12 +3460,7 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3461
3460
  * Escapes HTML content for use in attributes
3462
3461
  */
3463
3462
  escapeHtmlAttribute(text) {
3464
- return text
3465
- .replace(/&/g, '&amp;')
3466
- .replace(/"/g, '&quot;')
3467
- .replace(/'/g, '&#39;')
3468
- .replace(/</g, '&lt;')
3469
- .replace(/>/g, '&gt;');
3463
+ return EscapeHTML(text);
3470
3464
  }
3471
3465
  /**
3472
3466
  * Renders JSON content with human-readable content prominently displayed
@@ -3590,9 +3584,7 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3590
3584
  return (message.rawContent && !message.isStreaming) || this.hasExtractableContent(message);
3591
3585
  }
3592
3586
  escapeHtml(text) {
3593
- const div = document.createElement('div');
3594
- div.textContent = text;
3595
- return div.innerHTML;
3587
+ return EscapeHTML(text);
3596
3588
  }
3597
3589
  /**
3598
3590
  * Formats JSON for proper display with text wrapping instead of wide code blocks.
@@ -3822,7 +3814,7 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3822
3814
  IsConfigMatchById(config, id) {
3823
3815
  return UUIDsEqual(config.ID, id);
3824
3816
  }
3825
- static { this.ɵfac = function AITestHarnessComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AITestHarnessComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
3817
+ static { this.ɵfac = function AITestHarnessComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AITestHarnessComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.MJConfirmService)); }; }
3826
3818
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AITestHarnessComponent, selectors: [["mj-ai-test-harness"]], viewQuery: function AITestHarnessComponent_Query(rf, ctx) { if (rf & 1) {
3827
3819
  i0.ɵɵviewQuery(_c0, 5)(_c1, 5)(_c2, 5)(_c3, 5);
3828
3820
  } if (rf & 2) {
@@ -3844,12 +3836,12 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3844
3836
  i0.ɵɵconditional(ctx.showLoadConfirmDialog ? 2 : -1);
3845
3837
  i0.ɵɵadvance();
3846
3838
  i0.ɵɵconditional(ctx.showJsonWindow ? 3 : -1);
3847
- } }, dependencies: [i2.NgClass, i3.DefaultValueAccessor, i3.CheckboxControlValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MJWindowComponent, i4.MJButtonDirective, i4.MJDropdownComponent, i4.MJNumericInputComponent, i4.MJSwitchComponent, i4.MJAccordionPanelComponent, i4.MJDialogComponent, i4.MJDialogTitlebarComponent, i4.MJDialogActionsComponent, i4.MJEmptyStateComponent, i5.SplitComponent, i5.SplitAreaComponent, i6.CodeEditorComponent, i7.JsonViewerWindowComponent, i8.AgentExecutionMonitorComponent, i2.DatePipe], styles: ["\n\n.harness-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.custom-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.custom-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.custom-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.custom-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.custom-button.icon-only[_ngcontent-%COMP%] {\n padding: 6px 8px;\n}\n\n.custom-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.send-button[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-radius: 4px;\n padding: 8px 16px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n font-family: inherit;\n}\n\n.send-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.send-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.add-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n\n\n.remove-button[_ngcontent-%COMP%], \n.delete-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: var(--mj-status-error);\n padding: 4px 8px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover, \n.delete-button[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n color: var(--mj-color-error-600);\n}\n\n\n\n.copy-button-in-bubble[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n padding: 6px;\n font-size: 14px;\n color: var(--mj-border-strong);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0;\n z-index: 10; \n\n}\n\n.message-content[_ngcontent-%COMP%]:hover .copy-button-in-bubble[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.08);\n color: var(--mj-text-muted);\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.model-settings[_ngcontent-%COMP%] {\n padding: 16px;\n}\n\n.setting-group[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.setting-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n}\n\n.model-selector[_ngcontent-%COMP%], \n.vendor-selector[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.temperature-slider[_ngcontent-%COMP%] {\n width: 100%;\n margin-top: 8px;\n}\n\n.max-tokens-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.setting-help[_ngcontent-%COMP%] {\n margin-top: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n cursor: pointer;\n}\n\n.skip-validation-checkbox[_ngcontent-%COMP%] {\n margin-right: 8px;\n cursor: pointer;\n width: 16px;\n height: 16px;\n}\n\n\n\n.harness-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.agent-info[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.agent-details[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.agent-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n color: var(--mj-brand-primary);\n}\n\n.agent-details[_ngcontent-%COMP%] .entity-logo[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n object-fit: cover;\n border-radius: 8px;\n}\n\n.agent-details[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.agent-details[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n\n.harness-body[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n\n\n.chat-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n height: 100%;\n min-height: 0; \n\n}\n\n\n\n.messages-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n.messages-container[_ngcontent-%COMP%] mj-empty-state[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.message-user[_ngcontent-%COMP%] {\n margin-left: auto;\n max-width: 70%;\n}\n\n.message-assistant[_ngcontent-%COMP%] {\n margin-right: auto;\n max-width: 70%;\n}\n\n.message-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 13px;\n}\n\n.message-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.message-role[_ngcontent-%COMP%] .message-role-logo[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n object-fit: cover;\n border-radius: 3px;\n display: inline-block;\n vertical-align: middle;\n}\n\n.message-user[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.message-time[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.execution-time[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.raw-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n margin-left: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n}\n\n.raw-toggle[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.05);\n color: var(--mj-text-secondary);\n}\n\n.raw-toggle[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n\n.message-user[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface));\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.message.streaming[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.streaming-content[_ngcontent-%COMP%] {\n display: inline;\n}\n\n.streaming-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.streaming-wrapper[_ngcontent-%COMP%] .cursor[_ngcontent-%COMP%] {\n display: inline;\n margin-left: 2px;\n}\n\n.cursor[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_blink 1s infinite;\n font-weight: 100;\n color: var(--mj-text-secondary);\n}\n\n@keyframes _ngcontent-%COMP%_blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n.error-details[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n border-radius: 6px;\n color: var(--mj-color-error-600);\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.payload-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.payload-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\n.payload-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.payload-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.payload-content[_ngcontent-%COMP%] {\n max-height: 250px;\n overflow: auto;\n background: var(--mj-bg-surface-card);\n}\n\n.payload-content[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n background: transparent;\n}\n\n.payload-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.payload-toggle[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.payload-toggle[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.payload-section.collapsed[_ngcontent-%COMP%] .payload-header[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n\n\n.save-dialog[_ngcontent-%COMP%], \n.confirm-dialog[_ngcontent-%COMP%] {\n .dialog-content {\n padding: 20px;\n\n p {\n margin: 0 0 16px 0;\n color: var(--mj-text-primary);\n font-size: 14px;\n line-height: 1.5;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .full-width {\n width: 100%;\n }\n\n input.k-textbox {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n\n &:focus {\n outline: none;\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--mj-status-error) 25%, transparent);\n }\n }\n }\n}\n\n\n\n.markdown-content[_ngcontent-%COMP%] {\n line-height: 1.6;\n word-wrap: break-word;\n overflow-wrap: break-word;\n max-width: 100%;\n}\n\n\n\n.inline-json-editor[_ngcontent-%COMP%] {\n margin: 8px 0;\n\n .json-editor-container {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n max-height: 400px;\n\n pre {\n margin: 0;\n padding: 12px;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n height: 100%;\n background: transparent;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n }\n}\n\n.markdown-paragraph[_ngcontent-%COMP%] {\n margin: 8px 0;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.markdown-h1[_ngcontent-%COMP%] {\n font-size: 1.5em;\n font-weight: 600;\n margin: 16px 0 8px 0;\n color: var(--mj-text-primary);\n border-bottom: 2px solid var(--mj-bg-surface-sunken);\n padding-bottom: 4px;\n}\n\n.markdown-h2[_ngcontent-%COMP%] {\n font-size: 1.3em;\n font-weight: 600;\n margin: 14px 0 6px 0;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n padding-bottom: 2px;\n}\n\n.markdown-h3[_ngcontent-%COMP%] {\n font-size: 1.1em;\n font-weight: 600;\n margin: 12px 0 4px 0;\n color: var(--mj-text-primary);\n}\n\n.code-block[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n padding: 16px;\n margin: 12px 0;\n overflow-x: auto;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre;\n word-wrap: normal;\n max-width: 100%;\n}\n\n.code-block[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre;\n word-wrap: normal;\n}\n\n.language-json[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.inline-code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 0.9em;\n color: var(--mj-status-error);\n white-space: nowrap;\n}\n\n.markdown-list[_ngcontent-%COMP%] {\n margin: 8px 0;\n padding-left: 24px;\n}\n\n.markdown-list[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin: 4px 0;\n line-height: 1.5;\n}\n\n.markdown-link[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: none;\n}\n\n\n\n.message-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n padding: 12px 40px 12px 16px; \n\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n position: relative;\n overflow-wrap: break-word;\n hyphens: auto;\n max-width: 100%;\n overflow-x: hidden;\n}\n\n\n\n.json-content-wrapper[_ngcontent-%COMP%] {\n margin: 8px 0;\n}\n\n.json-main-content[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n.json-toggle-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.json-toggle-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.json-toggle-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n margin: 8px 0 0 0;\n font-size: 12px;\n max-height: 300px;\n overflow-y: auto;\n}\n\n\n\n@media (max-width: 768px) {\n .json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n font-size: 11px;\n max-height: 200px;\n }\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n\n\n.input-area[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0; \n\n margin-top: auto; \n\n}\n\n.input-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n}\n\n.rerun-mode-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 8px;\n gap: 16px;\n}\n\n.rerun-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.rerun-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.rerun-message[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-family: 'Fira Code', 'Consolas', monospace;\n}\n\n.rerun-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 100px;\n justify-content: center;\n}\n\n.rerun-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.rerun-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.reset-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 120px;\n justify-content: center;\n background-color: var(--mj-text-muted);\n}\n\n.reset-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: var(--mj-text-secondary);\n}\n\n.reset-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.message-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.message-input[_ngcontent-%COMP%] textarea[_ngcontent-%COMP%] {\n resize: none;\n font-size: 14px;\n}\n\n.send-button[_ngcontent-%COMP%] {\n margin-bottom: 1px;\n}\n\n\n\n.sidebar[_ngcontent-%COMP%] {\n width: 100%; \n\n background: var(--mj-bg-surface);\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n.sidebar-tabs[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.tab-button[_ngcontent-%COMP%] {\n flex: 1;\n padding: 12px 8px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.tab-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.tab-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tab-button[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: var(--mj-text-muted);\n color: var(--mj-text-inverse);\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n margin-left: 4px;\n}\n\n.tab-button.active[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.tab-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n\n\n.sidebar-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n width: 100%; \n\n}\n\n.tab-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%; \n\n box-sizing: border-box; \n\n}\n\n.tab-header[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.icon-only[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.tab-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.tab-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] {\n align-self: flex-start;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n\n\n.variables-list[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n width: 100%;\n}\n\n.variable-item[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n align-items: center;\n width: 100%;\n}\n\n.variable-name[_ngcontent-%COMP%] {\n width: 30%; \n\n min-width: 100px;\n}\n\n.variable-type[_ngcontent-%COMP%] {\n width: 25%; \n\n min-width: 80px;\n}\n\n.variable-value[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0; \n\n}\n\n.remove-button[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.add-variable-button[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.saved-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.saved-item[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 12px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.saved-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.saved-item.current[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.saved-info[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.saved-info[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.saved-date[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n@media (max-width: 1200px) {\n .sidebar[_ngcontent-%COMP%] {\n width: 320px;\n }\n}\n\n@media (max-width: 992px) {\n .message-user[_ngcontent-%COMP%], \n .message-assistant[_ngcontent-%COMP%] {\n max-width: 85%;\n }\n\n .sidebar[_ngcontent-%COMP%] {\n width: 280px;\n }\n}\n\n\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n\n\n .ai-agent-test-harness .k-dialog-wrapper {\n border-radius: 8px;\n overflow: hidden;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-inverse);\n}\n\n .ai-agent-test-harness .k-dialog-title {\n font-weight: 600;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar-actions .k-button {\n color: var(--mj-text-inverse);\n}\n\n .ai-agent-test-harness .k-dialog-content {\n padding: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n\n\n\n.advanced-params-panel[_ngcontent-%COMP%] {\n margin-top: 24px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n}\n\n.advanced-params-panel[_ngcontent-%COMP%] .k-expander-title {\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.advanced-settings[_ngcontent-%COMP%] {\n padding: 16px;\n}\n\n.advanced-param-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.advanced-param-switch[_ngcontent-%COMP%] {\n margin-top: 8px;\n}\n\n\n\n.format-selector[_ngcontent-%COMP%] {\n width: 100%;\n}"] }); }
3839
+ } }, dependencies: [i3.NgClass, i4.DefaultValueAccessor, i4.CheckboxControlValueAccessor, i4.NgControlStatus, i4.NgModel, i2.MJWindowComponent, i2.MJButtonDirective, i2.MJDropdownComponent, i2.MJNumericInputComponent, i2.MJSwitchComponent, i2.MJAccordionPanelComponent, i2.MJDialogComponent, i2.MJDialogTitlebarComponent, i2.MJDialogActionsComponent, i2.MJEmptyStateComponent, i5.SplitComponent, i5.SplitAreaComponent, i6.CodeEditorComponent, i7.JsonViewerWindowComponent, i8.AgentExecutionMonitorComponent, i3.DatePipe], styles: ["\n\n.harness-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.custom-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.custom-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.custom-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.custom-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.custom-button.icon-only[_ngcontent-%COMP%] {\n padding: 6px 8px;\n}\n\n.custom-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.send-button[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-radius: 4px;\n padding: 8px 16px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n font-family: inherit;\n}\n\n.send-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.send-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.add-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n\n\n.remove-button[_ngcontent-%COMP%], \n.delete-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: var(--mj-status-error);\n padding: 4px 8px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover, \n.delete-button[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n color: var(--mj-color-error-600);\n}\n\n\n\n.copy-button-in-bubble[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n padding: 6px;\n font-size: 14px;\n color: var(--mj-border-strong);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0;\n z-index: 10; \n\n}\n\n.message-content[_ngcontent-%COMP%]:hover .copy-button-in-bubble[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.08);\n color: var(--mj-text-muted);\n}\n\n.copy-button-in-bubble[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.model-settings[_ngcontent-%COMP%] {\n padding: 16px;\n}\n\n.setting-group[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.setting-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n}\n\n.model-selector[_ngcontent-%COMP%], \n.vendor-selector[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.temperature-slider[_ngcontent-%COMP%] {\n width: 100%;\n margin-top: 8px;\n}\n\n.max-tokens-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.setting-help[_ngcontent-%COMP%] {\n margin-top: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n cursor: pointer;\n}\n\n.skip-validation-checkbox[_ngcontent-%COMP%] {\n margin-right: 8px;\n cursor: pointer;\n width: 16px;\n height: 16px;\n}\n\n\n\n.harness-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.agent-info[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.agent-details[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.agent-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n color: var(--mj-brand-primary);\n}\n\n.agent-details[_ngcontent-%COMP%] .entity-logo[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n object-fit: cover;\n border-radius: 8px;\n}\n\n.agent-details[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.agent-details[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n\n.harness-body[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n\n\n.chat-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n height: 100%;\n min-height: 0; \n\n}\n\n\n\n.messages-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n.messages-container[_ngcontent-%COMP%] mj-empty-state[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-in;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.message-user[_ngcontent-%COMP%] {\n margin-left: auto;\n max-width: 70%;\n}\n\n.message-assistant[_ngcontent-%COMP%] {\n margin-right: auto;\n max-width: 70%;\n}\n\n.message-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 13px;\n}\n\n.message-role[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.message-role[_ngcontent-%COMP%] .message-role-logo[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n object-fit: cover;\n border-radius: 3px;\n display: inline-block;\n vertical-align: middle;\n}\n\n.message-user[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.message-time[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.execution-time[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.raw-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n margin-left: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n}\n\n.raw-toggle[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.05);\n color: var(--mj-text-secondary);\n}\n\n.raw-toggle[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n\n.message-user[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface));\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.message.streaming[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.streaming-content[_ngcontent-%COMP%] {\n display: inline;\n}\n\n.streaming-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.streaming-wrapper[_ngcontent-%COMP%] .cursor[_ngcontent-%COMP%] {\n display: inline;\n margin-left: 2px;\n}\n\n.cursor[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_blink 1s infinite;\n font-weight: 100;\n color: var(--mj-text-secondary);\n}\n\n@keyframes _ngcontent-%COMP%_blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n.error-details[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n border-radius: 6px;\n color: var(--mj-color-error-600);\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.payload-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.payload-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\n.payload-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.payload-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.payload-content[_ngcontent-%COMP%] {\n max-height: 250px;\n overflow: auto;\n background: var(--mj-bg-surface-card);\n}\n\n.payload-content[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n background: transparent;\n}\n\n.payload-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.payload-toggle[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.payload-toggle[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.payload-section.collapsed[_ngcontent-%COMP%] .payload-header[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n\n\n.save-dialog[_ngcontent-%COMP%], \n.confirm-dialog[_ngcontent-%COMP%] {\n .dialog-content {\n padding: 20px;\n\n p {\n margin: 0 0 16px 0;\n color: var(--mj-text-primary);\n font-size: 14px;\n line-height: 1.5;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .full-width {\n width: 100%;\n }\n\n input.k-textbox {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n\n &:focus {\n outline: none;\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--mj-status-error) 25%, transparent);\n }\n }\n }\n}\n\n\n\n.markdown-content[_ngcontent-%COMP%] {\n line-height: 1.6;\n word-wrap: break-word;\n overflow-wrap: break-word;\n max-width: 100%;\n}\n\n\n\n.inline-json-editor[_ngcontent-%COMP%] {\n margin: 8px 0;\n\n .json-editor-container {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n max-height: 400px;\n\n pre {\n margin: 0;\n padding: 12px;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n height: 100%;\n background: transparent;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n }\n}\n\n.markdown-paragraph[_ngcontent-%COMP%] {\n margin: 8px 0;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.markdown-h1[_ngcontent-%COMP%] {\n font-size: 1.5em;\n font-weight: 600;\n margin: 16px 0 8px 0;\n color: var(--mj-text-primary);\n border-bottom: 2px solid var(--mj-bg-surface-sunken);\n padding-bottom: 4px;\n}\n\n.markdown-h2[_ngcontent-%COMP%] {\n font-size: 1.3em;\n font-weight: 600;\n margin: 14px 0 6px 0;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n padding-bottom: 2px;\n}\n\n.markdown-h3[_ngcontent-%COMP%] {\n font-size: 1.1em;\n font-weight: 600;\n margin: 12px 0 4px 0;\n color: var(--mj-text-primary);\n}\n\n.code-block[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n padding: 16px;\n margin: 12px 0;\n overflow-x: auto;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre;\n word-wrap: normal;\n max-width: 100%;\n}\n\n.code-block[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre;\n word-wrap: normal;\n}\n\n.language-json[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.inline-code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 0.9em;\n color: var(--mj-status-error);\n white-space: nowrap;\n}\n\n.markdown-list[_ngcontent-%COMP%] {\n margin: 8px 0;\n padding-left: 24px;\n}\n\n.markdown-list[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin: 4px 0;\n line-height: 1.5;\n}\n\n.markdown-link[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: none;\n}\n\n\n\n.message-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n padding: 12px 40px 12px 16px; \n\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n position: relative;\n overflow-wrap: break-word;\n hyphens: auto;\n max-width: 100%;\n overflow-x: hidden;\n}\n\n\n\n.json-content-wrapper[_ngcontent-%COMP%] {\n margin: 8px 0;\n}\n\n.json-main-content[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n.json-toggle-button[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.json-toggle-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.json-toggle-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n margin: 8px 0 0 0;\n font-size: 12px;\n max-height: 300px;\n overflow-y: auto;\n}\n\n\n\n@media (max-width: 768px) {\n .json-raw-section[_ngcontent-%COMP%] .code-block[_ngcontent-%COMP%] {\n font-size: 11px;\n max-height: 200px;\n }\n}\n\n\n\n.json-raw-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n}\n\n\n\n.input-area[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0; \n\n margin-top: auto; \n\n}\n\n.input-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n}\n\n.rerun-mode-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 8px;\n gap: 16px;\n}\n\n.rerun-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.rerun-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.rerun-message[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-family: 'Fira Code', 'Consolas', monospace;\n}\n\n.rerun-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 100px;\n justify-content: center;\n}\n\n.rerun-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.rerun-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.reset-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 120px;\n justify-content: center;\n background-color: var(--mj-text-muted);\n}\n\n.reset-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: var(--mj-text-secondary);\n}\n\n.reset-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.message-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.message-input[_ngcontent-%COMP%] textarea[_ngcontent-%COMP%] {\n resize: none;\n font-size: 14px;\n}\n\n.send-button[_ngcontent-%COMP%] {\n margin-bottom: 1px;\n}\n\n\n\n.sidebar[_ngcontent-%COMP%] {\n width: 100%; \n\n background: var(--mj-bg-surface);\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n\n\n.sidebar-tabs[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.tab-button[_ngcontent-%COMP%] {\n flex: 1;\n padding: 12px 8px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.tab-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.tab-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tab-button[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: var(--mj-text-muted);\n color: var(--mj-text-inverse);\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n margin-left: 4px;\n}\n\n.tab-button.active[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.tab-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n\n\n.sidebar-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n width: 100%; \n\n}\n\n.tab-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%; \n\n box-sizing: border-box; \n\n}\n\n.tab-header[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.icon-only[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.tab-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.tab-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] {\n align-self: flex-start;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n.tab-header[_ngcontent-%COMP%] .custom-button.small[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n\n\n.variables-list[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n width: 100%;\n}\n\n.variable-item[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n align-items: center;\n width: 100%;\n}\n\n.variable-name[_ngcontent-%COMP%] {\n width: 30%; \n\n min-width: 100px;\n}\n\n.variable-type[_ngcontent-%COMP%] {\n width: 25%; \n\n min-width: 80px;\n}\n\n.variable-value[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0; \n\n}\n\n.remove-button[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.add-variable-button[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.saved-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.saved-item[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 12px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.saved-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.saved-item.current[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.saved-info[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.saved-info[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.saved-date[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n@media (max-width: 1200px) {\n .sidebar[_ngcontent-%COMP%] {\n width: 320px;\n }\n}\n\n@media (max-width: 992px) {\n .message-user[_ngcontent-%COMP%], \n .message-assistant[_ngcontent-%COMP%] {\n max-width: 85%;\n }\n\n .sidebar[_ngcontent-%COMP%] {\n width: 280px;\n }\n}\n\n\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n\n\n .ai-agent-test-harness .k-dialog-wrapper {\n border-radius: 8px;\n overflow: hidden;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-inverse);\n}\n\n .ai-agent-test-harness .k-dialog-title {\n font-weight: 600;\n}\n\n .ai-agent-test-harness .k-dialog-titlebar-actions .k-button {\n color: var(--mj-text-inverse);\n}\n\n .ai-agent-test-harness .k-dialog-content {\n padding: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n\n\n\n.advanced-params-panel[_ngcontent-%COMP%] {\n margin-top: 24px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n}\n\n.advanced-params-panel[_ngcontent-%COMP%] .k-expander-title {\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.advanced-settings[_ngcontent-%COMP%] {\n padding: 16px;\n}\n\n.advanced-param-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.advanced-param-switch[_ngcontent-%COMP%] {\n margin-top: 8px;\n}\n\n\n\n.format-selector[_ngcontent-%COMP%] {\n width: 100%;\n}"] }); }
3848
3840
  }
3849
3841
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AITestHarnessComponent, [{
3850
3842
  type: Component,
3851
3843
  args: [{ standalone: false, selector: 'mj-ai-test-harness', template: "@if (isVisible) {\n <div class=\"harness-container\">\n <!-- Header -->\n <div class=\"harness-header\">\n @if (entity) {\n <div class=\"agent-info\">\n <div class=\"agent-details\">\n @if (hasEntityLogo()) {\n <img [src]=\"getEntityLogoURL()\" [alt]=\"getEntityName() + ' logo'\" class=\"entity-logo\">\n } @else {\n <i [class]=\"getEntityIconClass()\"></i>\n }\n <div>\n <h3>{{ getEntityName() }}</h3>\n @if (entity.Description) {\n <p>{{ entity.Description }}</p>\n }\n </div>\n </div>\n <div class=\"header-actions\">\n <button\n class=\"custom-button\"\n (click)=\"clearConversation()\"\n [disabled]=\"isExecuting || conversationMessages.length === 0\"\n title=\"Clear conversation\">\n <i class=\"fa-solid fa-broom\"></i>\n Clear\n </button>\n <button\n class=\"custom-button\"\n (click)=\"saveConversation()\"\n [disabled]=\"conversationMessages.length === 0\"\n title=\"Save conversation\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n <button\n class=\"custom-button\"\n (click)=\"exportConversation()\"\n [disabled]=\"conversationMessages.length === 0\"\n title=\"Export conversation\">\n <i class=\"fa-solid fa-download\"></i>\n Export\n </button>\n <button\n class=\"custom-button\"\n (click)=\"importConversation()\"\n title=\"Import conversation\">\n <i class=\"fa-solid fa-upload\"></i>\n Import\n </button>\n <input\n #fileInput\n type=\"file\"\n accept=\".json\"\n style=\"display: none\"\n (change)=\"onFileSelected($event)\">\n <button\n class=\"custom-button icon-only\"\n (click)=\"toggleSidebar()\"\n title=\"Toggle sidebar\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"!showSidebar\" [class.fa-chevron-left]=\"showSidebar\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n <!-- Main Content Area with Splitter -->\n <div class=\"harness-body\">\n @if (showSidebar) {\n <as-split\n direction=\"horizontal\"\n style=\"height: 100%; width: 100%;\">\n <!-- Chat Area (Left Pane) -->\n <as-split-area\n [size]=\"70\">\n <div class=\"chat-area\">\n <!-- Messages Container -->\n <div class=\"messages-container\" #messagesContainer>\n @if (conversationMessages.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-comments\"\n Title=\"Start a conversation\"\n Message=\"Send a message to begin testing the AI agent\" />\n }\n @for (message of conversationMessages; track message.id) {\n <div [ngClass]=\"getMessageClass(message)\">\n <div class=\"message-header\">\n <span class=\"message-role\">\n @if (message.role === 'user') {\n <i class=\"fa-solid fa-user\"></i> You\n } @else {\n @if (hasEntityLogo()) {\n <img [src]=\"getEntityLogoURL()\" [alt]=\"getEntityName() + ' logo'\" class=\"message-role-logo\">\n } @else {\n <i [class]=\"getEntityIconClass()\"></i>\n }\n {{ getEntityName() || 'Assistant' }}\n }\n </span>\n <span class=\"message-time\">{{ formatTimestamp(message.timestamp) }}</span>\n @if (message.isStreaming && message.elapsedTime !== undefined) {\n <span class=\"execution-time streaming\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> {{ formatElapsedTime(message.elapsedTime) }}\n </span>\n } @else if (message.executionTime) {\n <span class=\"execution-time\" [title]=\"getExecutionSummary(message)\">{{ formatExecutionTime(message.executionTime) }}</span>\n }\n @if (showRawToggle(message)) {\n <button class=\"raw-toggle\" (click)=\"showRawJsonDialog(message)\" title=\"View raw JSON response\">\n <i class=\"fa-solid fa-code\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\" [innerHTML]=\"getFormattedStreamingContent(message)\"></span>\n <span class=\"cursor\">|</span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n @if (hasPayload(message.payload) && mode === 'agent' && message.role === 'assistant') {\n <div class=\"payload-section\" [class.collapsed]=\"message.payloadCollapsed\">\n <div class=\"payload-header\" (click)=\"togglePayloadCollapse(message)\">\n <span class=\"payload-label\">\n <i class=\"fa-solid fa-code\"></i> Payload\n </span>\n <button class=\"payload-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!message.payloadCollapsed\" [class.fa-chevron-right]=\"message.payloadCollapsed\"></i>\n </button>\n </div>\n @if (!message.payloadCollapsed) {\n <div class=\"payload-content\">\n <mj-code-editor\n [ngModel]=\"formatJson(message.payload)\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n <!-- Input Area -->\n <div class=\"input-area\">\n @if (originalPromptRunId && conversationMessages.length > 0) {\n <!-- Re-run mode - show loaded message -->\n <div class=\"rerun-mode-container\">\n <div class=\"rerun-message\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n <span>Messages from Prompt Run <strong>{{ originalPromptRunId.substring(0, 8) }}</strong> loaded above</span>\n </div>\n <div class=\"rerun-buttons\">\n @if (!hasExecutedRerun) {\n <!-- Show Re-Run button if we haven't executed yet -->\n <button\n class=\"send-button rerun-button\"\n (click)=\"executeRerun()\"\n [disabled]=\"isExecuting\"\n title=\"Re-run with loaded messages\">\n @if (isExecuting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Running...</span>\n } @else {\n <i class=\"fa-solid fa-play\"></i>\n <span>Re-Run</span>\n }\n </button>\n } @else {\n <!-- Show only Reset button after execution -->\n <button\n class=\"send-button reset-button\"\n (click)=\"resetToOriginalMessages()\"\n [disabled]=\"isExecuting\"\n title=\"Reset conversation messages to the original state from the prompt run. Model settings and parameters will be preserved.\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n <span>Reset Messages</span>\n </button>\n }\n </div>\n </div>\n } @else {\n <!-- Normal mode - show text input -->\n <div class=\"input-container\">\n <textarea\n #messageInput\n class=\"mj-textarea message-input\"\n [(ngModel)]=\"currentUserMessage\"\n [rows]=\"3\"\n placeholder=\"Type your message here... (Press Enter to send, Shift+Enter for new line)\"\n (keypress)=\"handleKeyPress($event)\"\n [disabled]=\"isExecuting\"></textarea>\n <button\n class=\"send-button\"\n (click)=\"sendMessage()\"\n [disabled]=\"isExecuting || !currentUserMessage.trim()\"\n title=\"Send message\">\n @if (isExecuting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n }\n </button>\n </div>\n }\n </div>\n </div>\n </as-split-area>\n <!-- Sidebar (Right Pane) -->\n <as-split-area\n [size]=\"30\">\n <div class=\"sidebar\">\n <!-- Tab Navigation -->\n <div class=\"sidebar-tabs\">\n @if (mode === 'agent') {\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'agentVariables'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'agentVariables'\"\n (click)=\"selectTab('agentVariables')\">\n <i class=\"fa-solid fa-code\"></i>\n Agent Variables\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'executionMonitor'\"\n (click)=\"selectTab('executionMonitor')\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n Execution Monitor\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'agentSettings'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'agentSettings'\"\n (click)=\"selectTab('agentSettings')\">\n <i class=\"fa-solid fa-sliders\"></i>\n Settings\n </button>\n } @else {\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'templateVariables'\"\n (click)=\"selectTab('templateVariables')\">\n <i class=\"fa-solid fa-code\"></i>\n Template Variables\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'modelSettings'\"\n (click)=\"selectTab('modelSettings')\">\n <i class=\"fa-solid fa-sliders\"></i>\n Model Settings\n </button>\n }\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'savedConversations'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'savedConversations'\"\n (click)=\"selectTab('savedConversations')\">\n <i class=\"fa-solid fa-history\"></i>\n Saved\n @if (savedConversations.length > 0) {\n <span class=\"badge\">{{ savedConversations.length }}</span>\n }\n </button>\n </div>\n <!-- Tab Content -->\n <div class=\"sidebar-content\">\n <!-- Agent Variables Tab (Unified) -->\n @if (activeTab === 'agentVariables') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Agent Variables</h4>\n <p>Variables available during agent execution and template rendering</p>\n </div>\n <div class=\"variables-list\">\n @if (agentVariables.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-code\"\n Title=\"No variables defined\"\n Message=\"Click &quot;Add Variable&quot; to get started.\"\n Size=\"compact\" />\n }\n @for (variable of agentVariables; track $index) {\n <div class=\"variable-item\">\n <input type=\"text\"\n class=\"mj-input variable-name\"\n [(ngModel)]=\"variable.name\"\n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\" />\n <mj-dropdown\n [(ngModel)]=\"variable.type\"\n [Data]=\"[\n {text: 'String', value: 'string'},\n {text: 'Number', value: 'number'},\n {text: 'Boolean', value: 'boolean'},\n {text: 'Object', value: 'object'}\n ]\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [Disabled]=\"isExecuting\"\n class=\"variable-type\">\n </mj-dropdown>\n <input type=\"text\"\n class=\"mj-input variable-value\"\n [(ngModel)]=\"variable.value\"\n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\" />\n <button\n class=\"remove-button\"\n (click)=\"removeAgentVariable($index)\"\n [disabled]=\"isExecuting\"\n title=\"Remove variable\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n </div>\n <button\n class=\"add-button\"\n (click)=\"addAgentVariable()\"\n [disabled]=\"isExecuting\">\n <i class=\"fa-solid fa-plus\"></i> Add Variable\n </button>\n </div>\n }\n <!-- Execution Monitor Tab -->\n @if (activeTab === 'executionMonitor') {\n <div class=\"tab-content\" style=\"padding: 0; height: 100%;\">\n <mj-agent-execution-monitor\n [mode]=\"executionMonitorMode\"\n [agentRun]=\"currentAgentRun\"\n [liveSteps]=\"liveAgentSteps\"\n [autoExpand]=\"true\"\n (viewRunClick)=\"navigateToAgentRun($event)\"\n [runId]=\"getLastRunId()\"\n [runType]=\"mode\">\n </mj-agent-execution-monitor>\n </div>\n }\n <!-- Agent Settings Tab -->\n @if (activeTab === 'agentSettings') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Agent Settings</h4>\n <p>Configure agent execution parameters</p>\n </div>\n <div class=\"model-settings\">\n <div class=\"setting-group\">\n <label>AI Configuration</label>\n <mj-dropdown\n [(ngModel)]=\"agentConfigurationId\"\n [Data]=\"availableConfigurations\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n Placeholder=\"Select a configuration...\"\n class=\"configuration-selector\">\n </mj-dropdown>\n <div class=\"setting-help\">\n @if (agentConfigurationId) {\n @for (config of availableConfigurations; track config.ID) {\n @if (IsConfigMatchById(config, agentConfigurationId) && config.Description) {\n {{ config.Description }}\n }\n }\n } @else {\n Using default configuration\n }\n </div>\n </div>\n </div>\n </div>\n }\n <!-- Template Variables Tab (Prompt Mode) -->\n @if (activeTab === 'templateVariables') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Template Variables</h4>\n <p>Variables for prompt template rendering</p>\n </div>\n <div class=\"variables-list\">\n @for (variable of templateVariables; track $index) {\n <div class=\"variable-item\">\n <input type=\"text\"\n class=\"mj-input variable-name\"\n [(ngModel)]=\"variable.name\"\n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\" />\n <mj-dropdown\n [(ngModel)]=\"variable.type\"\n [Data]=\"[\n {text: 'String', value: 'string'},\n {text: 'Number', value: 'number'},\n {text: 'Boolean', value: 'boolean'},\n {text: 'Object', value: 'object'}\n ]\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [Disabled]=\"isExecuting\"\n class=\"variable-type\">\n </mj-dropdown>\n <input type=\"text\"\n class=\"mj-input variable-value\"\n [(ngModel)]=\"variable.value\"\n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\" />\n <button\n class=\"remove-button\"\n (click)=\"removeTemplateVariable($index)\"\n title=\"Remove variable\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n </div>\n <button\n class=\"add-button\"\n (click)=\"addTemplateVariable()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Variable\n </button>\n </div>\n }\n <!-- Model Settings Tab (Prompt Mode) -->\n @if (activeTab === 'modelSettings') {\n <div class=\"tab-content\" style=\"overflow-y: auto;\">\n <div class=\"tab-header\">\n <h4>Model Settings</h4>\n <p>Configure AI model parameters</p>\n <button class=\"custom-button icon-only\" (click)=\"resetToPromptDefaults()\" title=\"Reset to Prompt Settings\">\n <i class=\"fa-solid fa-undo\"></i>\n </button>\n </div>\n <div class=\"model-settings\">\n <div class=\"setting-group\">\n <label>AI Model</label>\n <mj-dropdown\n [(ngModel)]=\"selectedModelId\"\n (ngModelChange)=\"onModelSelectionChange()\"\n [Data]=\"availableModels\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n Placeholder=\"Select a model...\"\n class=\"model-selector\">\n </mj-dropdown>\n </div>\n <div class=\"setting-group\">\n <label>AI Vendor</label>\n <mj-dropdown\n [(ngModel)]=\"selectedVendorId\"\n [Data]=\"availableVendors\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n [Disabled]=\"availableVendors.length <= 1 || !selectedModelId\"\n Placeholder=\"Select a vendor...\"\n class=\"vendor-selector\">\n </mj-dropdown>\n <div class=\"setting-help\">\n @if (!selectedModelId) {\n Using default vendor for the default model\n } @else if (availableVendors.length <= 1) {\n Only one vendor available for this model\n } @else {\n Select the inference provider for this model\n }\n </div>\n </div>\n <div class=\"setting-group\">\n <label>AI Configuration</label>\n <mj-dropdown\n [(ngModel)]=\"selectedConfigurationId\"\n [Data]=\"availableConfigurations\"\n TextField=\"Name\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n Placeholder=\"Select a configuration...\"\n class=\"configuration-selector\">\n </mj-dropdown>\n <div class=\"setting-help\">\n @if (selectedConfigurationId) {\n @for (config of availableConfigurations; track config.ID) {\n @if (IsConfigMatchById(config, selectedConfigurationId) && config.Description) {\n {{ config.Description }}\n }\n }\n } @else {\n Using default configuration\n }\n </div>\n </div>\n <div class=\"setting-group\">\n <label>Response Format</label>\n <mj-dropdown\n [(ngModel)]=\"selectedResponseFormat\"\n [Data]=\"responseFormatOptions\"\n TextField=\"text\"\n ValueField=\"value\"\n Placeholder=\"Select format...\"\n class=\"format-selector\">\n </mj-dropdown>\n <div class=\"setting-help\">\n Expected format for AI response (defaults to prompt setting)\n </div>\n </div>\n <div class=\"setting-group\">\n <label>Max Tokens</label>\n <mj-numeric-input\n [(ngModel)]=\"maxTokens\"\n [Min]=\"100\"\n [Max]=\"8000\"\n [Step]=\"100\"\n Placeholder=\"Max tokens...\"\n class=\"max-tokens-input\">\n </mj-numeric-input>\n <div class=\"setting-help\">\n Maximum length of generated response\n </div>\n </div>\n <div class=\"setting-group\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\"\n [(ngModel)]=\"skipValidation\"\n class=\"skip-validation-checkbox\">\n Skip Validation\n </label>\n <div class=\"setting-help\">\n Skip output validation during testing\n </div>\n </div>\n <!-- Advanced Parameters Expansion Panel -->\n <mj-accordion-panel\n [Title]=\"'Advanced Parameters'\"\n [Expanded]=\"advancedParamsExpanded\"\n class=\"advanced-params-panel\">\n <div class=\"advanced-settings\">\n <div class=\"setting-group\">\n <label title=\"Controls randomness: 0 = more focused and deterministic, 2 = more random and creative\">\n Temperature\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.temperature\"\n [Min]=\"0\"\n [Max]=\"2\"\n [Step]=\"0.1\"\n [Format]=\"'n1'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Nucleus sampling: only consider tokens with cumulative probability up to this value. 1 = consider all tokens\">\n Top P\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.topP\"\n [Min]=\"0\"\n [Max]=\"1\"\n [Step]=\"0.01\"\n [Format]=\"'n2'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Only sample from the top K tokens. Lower values reduce randomness\">\n Top K\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.topK\"\n [Min]=\"1\"\n [Max]=\"100\"\n [Step]=\"1\"\n [Format]=\"'n0'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Minimum probability for token selection. Filters out low-probability tokens\">\n Min P\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.minP\"\n [Min]=\"0\"\n [Max]=\"1\"\n [Step]=\"0.01\"\n [Format]=\"'n2'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Penalizes tokens based on their frequency in the text. Positive values reduce repetition\">\n Frequency Penalty\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.frequencyPenalty\"\n [Min]=\"-2\"\n [Max]=\"2\"\n [Step]=\"0.1\"\n [Format]=\"'n1'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Penalizes tokens that have appeared in the text. Positive values increase topic diversity\">\n Presence Penalty\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.presencePenalty\"\n [Min]=\"-2\"\n [Max]=\"2\"\n [Step]=\"0.1\"\n [Format]=\"'n1'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Random seed for deterministic generation. Same seed produces same output\">\n Seed\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.seed\"\n [Format]=\"'n0'\"\n Placeholder=\"None\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n <div class=\"setting-group\">\n <label title=\"Sequences that will stop generation when encountered. Enter comma-separated values\">\n Stop Sequences\n </label>\n <textarea\n class=\"mj-textarea advanced-param-input\"\n [(ngModel)]=\"stopSequencesText\"\n (ngModelChange)=\"updateStopSequences()\"\n [rows]=\"2\"\n placeholder=\"Enter comma-separated sequences\"></textarea>\n <div class=\"setting-help\">\n Separate multiple sequences with commas\n </div>\n </div>\n <div class=\"setting-group\">\n <label title=\"Include log probabilities of the output tokens in the response\">\n Include Log Probs\n </label>\n <mj-switch\n [(ngModel)]=\"advancedParams.includeLogProbs\"\n class=\"advanced-param-switch\">\n </mj-switch>\n </div>\n @if (advancedParams.includeLogProbs) {\n <div class=\"setting-group\">\n <label title=\"Number of top log probabilities to include for each token\">\n Top Log Probs\n </label>\n <mj-numeric-input\n [(ngModel)]=\"advancedParams.topLogProbs\"\n [Min]=\"2\"\n [Max]=\"20\"\n [Step]=\"1\"\n [Format]=\"'n0'\"\n Placeholder=\"2\"\n class=\"advanced-param-input\">\n </mj-numeric-input>\n </div>\n }\n </div>\n </mj-accordion-panel>\n </div>\n </div>\n }\n <!-- Saved Conversations Tab -->\n @if (activeTab === 'savedConversations') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Saved Conversations</h4>\n <p>Previously saved test sessions</p>\n @if (currentConversationId) {\n <button class=\"custom-button small primary\" (click)=\"newConversation()\" title=\"Start a new conversation\">\n <i class=\"fa-solid fa-plus\"></i>\n New\n </button>\n }\n </div>\n <div class=\"saved-list\">\n @if (savedConversations.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-folder-open\"\n Title=\"No saved conversations\"\n Size=\"compact\" />\n }\n @for (conv of savedConversations; track conv.id) {\n <div class=\"saved-item\"\n [class.current]=\"conv.id === currentConversationId\"\n (click)=\"loadConversation(conv)\">\n <div class=\"saved-info\">\n <h5>{{ conv.name }}</h5>\n <p>{{ conv.messages.length }} messages</p>\n <span class=\"saved-date\">{{ conv.updatedAt | date:'short' }}</span>\n </div>\n <button\n class=\"delete-button\"\n (click)=\"deleteConversation(conv, $event)\"\n title=\"Delete conversation\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </as-split-area>\n </as-split>\n } @else {\n <!-- No sidebar - full width chat -->\n <div class=\"chat-area\">\n <!-- Messages Container -->\n <div class=\"messages-container\" #messagesContainer>\n @if (conversationMessages.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-comments\"\n Title=\"Start a conversation\"\n Message=\"Send a message to begin testing the AI agent\" />\n }\n @for (message of conversationMessages; track message.id) {\n <div [ngClass]=\"getMessageClass(message)\">\n <div class=\"message-header\">\n <span class=\"message-role\">\n @if (message.role === 'user') {\n <i class=\"fa-solid fa-user\"></i> You\n } @else {\n <i class=\"fa-solid fa-robot\"></i> {{ getEntityName() || 'Assistant' }}\n }\n </span>\n <span class=\"message-time\">{{ formatTimestamp(message.timestamp) }}</span>\n @if (message.isStreaming && message.elapsedTime !== undefined) {\n <span class=\"execution-time streaming\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> {{ formatElapsedTime(message.elapsedTime) }}\n </span>\n } @else if (message.executionTime) {\n <span class=\"execution-time\" [title]=\"getExecutionSummary(message)\">{{ formatExecutionTime(message.executionTime) }}</span>\n }\n @if (showRawToggle(message)) {\n <button class=\"raw-toggle\" (click)=\"showRawJsonDialog(message)\" title=\"View raw JSON response\">\n <i class=\"fa-solid fa-code\"></i>\n </button>\n }\n @if (message.executionData && mode === 'agent' && message.role === 'assistant') {\n <button class=\"execution-history-toggle\" (click)=\"showMessageExecutionHistory(message)\" title=\"View execution details\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </button>\n }\n @if (message.agentRunId && mode === 'agent' && message.role === 'assistant') {\n <button class=\"execution-history-toggle\" (click)=\"navigateToAgentRun({runId: message.agentRunId, runType: 'agent'})\" title=\"View full run details\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\">{{ message.streamingContent }}<span class=\"cursor\">|</span></span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n @if (hasPayload(message.payload) && mode === 'agent' && message.role === 'assistant') {\n <div class=\"payload-section\" [class.collapsed]=\"message.payloadCollapsed\">\n <div class=\"payload-header\" (click)=\"togglePayloadCollapse(message)\">\n <span class=\"payload-label\">\n <i class=\"fa-solid fa-code\"></i> Payload\n </span>\n <button class=\"payload-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!message.payloadCollapsed\" [class.fa-chevron-right]=\"message.payloadCollapsed\"></i>\n </button>\n </div>\n @if (!message.payloadCollapsed) {\n <div class=\"payload-content\">\n <pre>{{ formatJson(message.payload) }}</pre>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n <!-- Input Area -->\n <div class=\"input-area\">\n <div class=\"input-container\">\n <textarea\n #messageInput\n class=\"mj-textarea message-input\"\n [(ngModel)]=\"currentUserMessage\"\n [rows]=\"3\"\n placeholder=\"Type your message here... (Press Enter to send, Shift+Enter for new line)\"\n (keypress)=\"handleKeyPress($event)\"\n [disabled]=\"isExecuting\"></textarea>\n <button\n class=\"send-button\"\n (click)=\"sendMessage()\"\n [disabled]=\"isExecuting || !currentUserMessage.trim()\"\n title=\"Send message\">\n @if (isExecuting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-paper-plane\"></i>\n }\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n<!-- Save Conversation Dialog -->\n@if (showSaveDialog) {\n <mj-dialog\n [Visible]=\"true\"\n [Width]=\"400\"\n (Close)=\"cancelSaveDialog()\"\n class=\"save-dialog\">\n <mj-dialog-titlebar>Save Conversation</mj-dialog-titlebar>\n <div class=\"dialog-content\">\n <p>Enter a name for this conversation:</p>\n <input\n #saveDialogInput\n type=\"text\"\n (keyup)=\"updateTempConversation()\"\n placeholder=\"Conversation name\"\n class=\"mj-input full-width\" />\n </div>\n <mj-dialog-actions>\n <button mjButton (click)=\"cancelSaveDialog()\">Cancel</button>\n <button mjButton\n variant=\"primary\"\n (click)=\"confirmSaveConversation()\"\n [disabled]=\"tempConversationName === ''\">\n Save\n </button>\n </mj-dialog-actions>\n </mj-dialog>\n}\n\n<!-- Load Confirmation Dialog -->\n@if (showLoadConfirmDialog) {\n <mj-dialog\n [Visible]=\"true\"\n [Width]=\"400\"\n (Close)=\"cancelLoadConversation()\"\n class=\"confirm-dialog\">\n <mj-dialog-titlebar>Replace Current Conversation?</mj-dialog-titlebar>\n <div class=\"dialog-content\">\n <p>Loading this conversation will replace the current one. Any unsaved changes will be lost.</p>\n <p>Do you want to continue?</p>\n </div>\n <mj-dialog-actions>\n <button mjButton (click)=\"cancelLoadConversation()\">Cancel</button>\n <button mjButton\n variant=\"primary\"\n (click)=\"confirmLoadConversation()\">\n Load Conversation\n </button>\n </mj-dialog-actions>\n </mj-dialog>\n}\n\n<!-- JSON Viewer Window -->\n@if (showJsonWindow) {\n <mj-window\n [Visible]=\"true\"\n Title=\"Raw JSON Response\"\n [Width]=\"900\"\n [Height]=\"700\"\n [MinWidth]=\"600\"\n [MinHeight]=\"400\"\n [Draggable]=\"true\"\n [Resizable]=\"true\"\n (Close)=\"closeJsonWindow()\">\n <mj-json-viewer-window [jsonContent]=\"currentJsonContent\"></mj-json-viewer-window>\n </mj-window>\n}\n\n", styles: ["/* Container Styles */\n.harness-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-card);\n}\n\n/* Custom Button Styles */\n.custom-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.custom-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.custom-button:active:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.custom-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.custom-button.icon-only {\n padding: 6px 8px;\n}\n\n.custom-button i {\n font-size: 14px;\n}\n\n/* Send Button - Primary Style */\n.send-button {\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-radius: 4px;\n padding: 8px 16px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n font-family: inherit;\n}\n\n.send-button:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button:active:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.send-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.send-button i {\n font-size: 16px;\n}\n\n/* Add Button */\n.add-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.add-button:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n/* Remove/Delete Buttons */\n.remove-button,\n.delete-button {\n background: transparent;\n border: none;\n color: var(--mj-status-error);\n padding: 4px 8px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.remove-button:hover,\n.delete-button:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n color: var(--mj-color-error-600);\n}\n\n/* Copy Button in Message Bubble */\n.copy-button-in-bubble {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n padding: 6px;\n font-size: 14px;\n color: var(--mj-border-strong);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0;\n z-index: 10; /* Ensure it's above content */\n}\n\n.message-content:hover .copy-button-in-bubble {\n opacity: 1;\n}\n\n.copy-button-in-bubble:hover {\n background: rgba(0, 0, 0, 0.08);\n color: var(--mj-text-muted);\n}\n\n.copy-button-in-bubble i {\n font-size: 14px;\n}\n\n/* Model Settings Styles (Prompt Mode) */\n.model-settings {\n padding: 16px;\n}\n\n.setting-group {\n margin-bottom: 24px;\n}\n\n.setting-group label {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n}\n\n.model-selector,\n.vendor-selector {\n width: 100%;\n}\n\n.temperature-slider {\n width: 100%;\n margin-top: 8px;\n}\n\n.max-tokens-input {\n width: 100%;\n}\n\n.setting-help {\n margin-top: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Checkbox Styles */\n.checkbox-label {\n display: flex;\n align-items: center;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 14px;\n cursor: pointer;\n}\n\n.skip-validation-checkbox {\n margin-right: 8px;\n cursor: pointer;\n width: 16px;\n height: 16px;\n}\n\n/* Header Styles */\n.harness-header {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.agent-info {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.agent-details {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.agent-details i {\n font-size: 28px;\n color: var(--mj-brand-primary);\n}\n\n.agent-details .entity-logo {\n width: 40px;\n height: 40px;\n object-fit: cover;\n border-radius: 8px;\n}\n\n.agent-details h3 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.agent-details p {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n/* Body Layout */\n.harness-body {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Chat Area */\n.chat-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n height: 100%;\n min-height: 0; /* Important for flexbox children */\n}\n\n/* Messages Container */\n.messages-container {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n.messages-container mj-empty-state {\n height: 100%;\n}\n\n/* Message Styles */\n.message {\n margin-bottom: 20px;\n animation: fadeIn 0.3s ease-in;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.message-user {\n margin-left: auto;\n max-width: 70%;\n}\n\n.message-assistant {\n margin-right: auto;\n max-width: 70%;\n}\n\n.message-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 13px;\n}\n\n.message-role {\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role i {\n font-size: 14px;\n}\n\n.message-role .message-role-logo {\n width: 16px;\n height: 16px;\n object-fit: cover;\n border-radius: 3px;\n display: inline-block;\n vertical-align: middle;\n}\n\n.message-user .message-role {\n color: var(--mj-brand-primary);\n}\n\n.message-assistant .message-role {\n color: var(--mj-brand-primary);\n}\n\n.message-time {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.execution-time {\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.raw-toggle {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n margin-left: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n}\n\n.raw-toggle:hover {\n background: rgba(0, 0, 0, 0.05);\n color: var(--mj-text-secondary);\n}\n\n.raw-toggle i {\n font-size: 12px;\n}\n\n/* Message content styles are now defined above in enhanced content formatting section */\n\n.message-user .message-content {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface));\n}\n\n.message-assistant .message-content {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.message.streaming .message-content {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--mj-bg-surface));\n}\n\n.streaming-content {\n display: inline;\n}\n\n.streaming-wrapper {\n position: relative;\n}\n\n.streaming-wrapper .cursor {\n display: inline;\n margin-left: 2px;\n}\n\n.cursor {\n animation: blink 1s infinite;\n font-weight: 100;\n color: var(--mj-text-secondary);\n}\n\n@keyframes blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n.error-details {\n margin-top: 8px;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n border-radius: 6px;\n color: var(--mj-color-error-600);\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details i {\n color: var(--mj-status-error);\n}\n\n/* Payload Section Styles */\n.payload-section {\n margin-top: 12px;\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.payload-header {\n background: var(--mj-bg-surface-card);\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\n.payload-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.payload-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label i {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.payload-content {\n max-height: 250px;\n overflow: auto;\n background: var(--mj-bg-surface-card);\n}\n\n.payload-content pre {\n margin: 0;\n padding: 12px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n background: transparent;\n}\n\n.payload-toggle {\n background: transparent;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: color 0.2s;\n}\n\n.payload-toggle:hover {\n color: var(--mj-text-secondary);\n}\n\n.payload-toggle i {\n font-size: 12px;\n}\n\n.payload-section.collapsed .payload-header {\n border-bottom: none;\n}\n\n/* Dialog styles */\n.save-dialog,\n.confirm-dialog {\n .dialog-content {\n padding: 20px;\n\n p {\n margin: 0 0 16px 0;\n color: var(--mj-text-primary);\n font-size: 14px;\n line-height: 1.5;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .full-width {\n width: 100%;\n }\n\n input.k-textbox {\n padding: 8px 12px;\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n\n &:focus {\n outline: none;\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--mj-status-error) 25%, transparent);\n }\n }\n }\n}\n\n/* Enhanced content formatting styles */\n.markdown-content {\n line-height: 1.6;\n word-wrap: break-word;\n overflow-wrap: break-word;\n max-width: 100%;\n}\n\n/* Inline JSON editor styles */\n.inline-json-editor {\n margin: 8px 0;\n\n .json-editor-container {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n max-height: 400px;\n\n pre {\n margin: 0;\n padding: 12px;\n font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n height: 100%;\n background: transparent;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n }\n}\n\n.markdown-paragraph {\n margin: 8px 0;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.markdown-h1 {\n font-size: 1.5em;\n font-weight: 600;\n margin: 16px 0 8px 0;\n color: var(--mj-text-primary);\n border-bottom: 2px solid var(--mj-bg-surface-sunken);\n padding-bottom: 4px;\n}\n\n.markdown-h2 {\n font-size: 1.3em;\n font-weight: 600;\n margin: 14px 0 6px 0;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n padding-bottom: 2px;\n}\n\n.markdown-h3 {\n font-size: 1.1em;\n font-weight: 600;\n margin: 12px 0 4px 0;\n color: var(--mj-text-primary);\n}\n\n.code-block {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-bg-surface-sunken);\n border-radius: 6px;\n padding: 16px;\n margin: 12px 0;\n overflow-x: auto;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-primary);\n white-space: pre;\n word-wrap: normal;\n max-width: 100%;\n}\n\n.code-block code {\n background: none;\n border: none;\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre;\n word-wrap: normal;\n}\n\n.language-json {\n color: var(--mj-status-error);\n}\n\n.inline-code {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;\n font-size: 0.9em;\n color: var(--mj-status-error);\n white-space: nowrap;\n}\n\n.markdown-list {\n margin: 8px 0;\n padding-left: 24px;\n}\n\n.markdown-list li {\n margin: 4px 0;\n line-height: 1.5;\n}\n\n.markdown-link {\n color: var(--mj-brand-primary);\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: none;\n}\n\n/* Ensure proper text wrapping in message content */\n.message-content {\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n padding: 12px 40px 12px 16px; /* Extra right padding for copy button */\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n position: relative;\n overflow-wrap: break-word;\n hyphens: auto;\n max-width: 100%;\n overflow-x: hidden;\n}\n\n/* Enhanced JSON content display */\n.json-content-wrapper {\n margin: 8px 0;\n}\n\n.json-main-content {\n margin-bottom: 12px;\n}\n\n.json-raw-section {\n margin-top: 12px;\n}\n\n.json-toggle-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n}\n\n.json-toggle-button:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n}\n\n.json-toggle-button i {\n font-size: 12px;\n}\n\n/* Compact code block for JSON in collapsible sections */\n.json-raw-section .code-block {\n margin: 8px 0 0 0;\n font-size: 12px;\n max-height: 300px;\n overflow-y: auto;\n}\n\n/* Better mobile responsiveness for JSON content */\n@media (max-width: 768px) {\n .json-raw-section .code-block {\n font-size: 11px;\n max-height: 200px;\n }\n}\n\n/* JSON raw section styling - simplified since we use code editor in dialog */\n.json-raw-section {\n margin-top: 12px;\n}\n\n/* Input Area */\n.input-area {\n padding: 16px;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0; /* Prevent input area from shrinking */\n margin-top: auto; /* Push to bottom */\n}\n\n.input-container {\n display: flex;\n gap: 12px;\n align-items: center;\n}\n\n.rerun-mode-container {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 8px;\n gap: 16px;\n}\n\n.rerun-message {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.rerun-message i {\n font-size: 16px;\n}\n\n.rerun-message strong {\n font-family: 'Fira Code', 'Consolas', monospace;\n}\n\n.rerun-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 100px;\n justify-content: center;\n}\n\n.rerun-button span {\n font-weight: 500;\n}\n\n.rerun-buttons {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.reset-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n min-width: 120px;\n justify-content: center;\n background-color: var(--mj-text-muted);\n}\n\n.reset-button:hover:not(:disabled) {\n background-color: var(--mj-text-secondary);\n}\n\n.reset-button span {\n font-weight: 500;\n}\n\n.message-input {\n flex: 1;\n}\n\n.message-input textarea {\n resize: none;\n font-size: 14px;\n}\n\n.send-button {\n margin-bottom: 1px;\n}\n\n/* Sidebar */\n.sidebar {\n width: 100%; /* Changed from fixed 360px to 100% */\n background: var(--mj-bg-surface);\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n/* Sidebar Tabs */\n.sidebar-tabs {\n display: flex;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.tab-button {\n flex: 1;\n padding: 12px 8px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.tab-button:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.tab-button.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.tab-button i {\n font-size: 14px;\n}\n\n.tab-button .badge {\n background: var(--mj-text-muted);\n color: var(--mj-text-inverse);\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n margin-left: 4px;\n}\n\n.tab-button.active .badge {\n background: var(--mj-brand-primary);\n}\n\n.tab-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* Sidebar Content */\n.sidebar-content {\n flex: 1;\n overflow-y: auto;\n width: 100%; /* Ensure content takes full width */\n}\n\n.tab-content {\n padding: 20px;\n width: 100%; /* Ensure content takes full width */\n box-sizing: border-box; /* Include padding in width calculation */\n}\n\n.tab-header {\n margin-bottom: 20px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n position: relative;\n}\n\n.tab-header .custom-button.icon-only {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.tab-header h4 {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.tab-header p {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.tab-header .custom-button.small {\n align-self: flex-start;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n.tab-header .custom-button.small i {\n margin-right: 4px;\n}\n\n/* Variables */\n.variables-list {\n margin-bottom: 16px;\n width: 100%;\n}\n\n.variable-item {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n align-items: center;\n width: 100%;\n}\n\n.variable-name {\n width: 30%; /* Changed from fixed width to percentage */\n min-width: 100px;\n}\n\n.variable-type {\n width: 25%; /* Changed from fixed width to percentage */\n min-width: 80px;\n}\n\n.variable-value {\n flex: 1;\n min-width: 0; /* Allow flex item to shrink below content size */\n}\n\n.remove-button {\n width: 32px;\n height: 32px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.add-variable-button {\n width: 100%;\n}\n\n/* Saved Conversations */\n.saved-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.saved-item {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 12px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.saved-item:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.saved-item.current {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.saved-info h5 {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.saved-info p {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.saved-date {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* Responsive adjustments */\n@media (max-width: 1200px) {\n .sidebar {\n width: 320px;\n }\n}\n\n@media (max-width: 992px) {\n .message-user,\n .message-assistant {\n max-width: 85%;\n }\n\n .sidebar {\n width: 280px;\n }\n}\n\n/* Custom scrollbar */\n.messages-container::-webkit-scrollbar,\n.sidebar-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.messages-container::-webkit-scrollbar-track,\n.sidebar-content::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.messages-container::-webkit-scrollbar-thumb,\n.sidebar-content::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n.messages-container::-webkit-scrollbar-thumb:hover,\n.sidebar-content::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* Dialog customization */\n::ng-deep .ai-agent-test-harness .k-dialog-wrapper {\n border-radius: 8px;\n overflow: hidden;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-titlebar {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-inverse);\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-title {\n font-weight: 600;\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-titlebar-actions .k-button {\n color: var(--mj-text-inverse);\n}\n\n::ng-deep .ai-agent-test-harness .k-dialog-content {\n padding: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* JSON Dialog Styles - removed since we're using WindowService */\n\n/* Advanced Parameters Styles */\n.advanced-params-panel {\n margin-top: 24px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n}\n\n.advanced-params-panel ::ng-deep .k-expander-title {\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.advanced-settings {\n padding: 16px;\n}\n\n.advanced-param-input {\n width: 100%;\n}\n\n.advanced-param-switch {\n margin-top: 8px;\n}\n\n/* Format selector dropdown */\n.format-selector {\n width: 100%;\n}\n"] }]
3852
- }], () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }], { mode: [{
3844
+ }], () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i2.MJConfirmService }], { mode: [{
3853
3845
  type: Input
3854
3846
  }], entity: [{
3855
3847
  type: Input
@@ -3880,5 +3872,5 @@ export class AITestHarnessComponent extends BaseAngularComponent {
3880
3872
  type: ViewChild,
3881
3873
  args: ['saveDialogInput']
3882
3874
  }] }); })();
3883
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 154 }); })();
3875
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 155 }); })();
3884
3876
  //# sourceMappingURL=ai-test-harness.component.js.map