@memberjunction/ng-ai-test-harness 5.22.0 → 5.23.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.
- package/dist/__tests__/services.test.js +0 -14
- package/dist/__tests__/services.test.js.map +1 -1
- package/dist/lib/ai-test-harness.component.d.ts +6 -9
- package/dist/lib/ai-test-harness.component.d.ts.map +1 -1
- package/dist/lib/ai-test-harness.component.js +186 -214
- package/dist/lib/ai-test-harness.component.js.map +1 -1
- package/dist/lib/json-viewer-window.component.js +2 -2
- package/dist/lib/json-viewer-window.component.js.map +1 -1
- package/dist/lib/test-harness-custom-window.component.d.ts +40 -44
- package/dist/lib/test-harness-custom-window.component.d.ts.map +1 -1
- package/dist/lib/test-harness-custom-window.component.js +210 -325
- package/dist/lib/test-harness-custom-window.component.js.map +1 -1
- package/dist/lib/test-harness-window-manager.service.js +11 -11
- package/dist/lib/test-harness-window-manager.service.js.map +1 -1
- package/dist/lib/test-harness-window.service.d.ts +5 -59
- package/dist/lib/test-harness-window.service.d.ts.map +1 -1
- package/dist/lib/test-harness-window.service.js +6 -159
- package/dist/lib/test-harness-window.service.js.map +1 -1
- package/dist/module.d.ts +6 -13
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +38 -46
- package/dist/module.js.map +1 -1
- package/package.json +15 -23
|
@@ -7,16 +7,14 @@ import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
|
7
7
|
import { ParseJSONRecursive, UUIDsEqual } from '@memberjunction/global';
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
import * as i1 from "@angular/platform-browser";
|
|
10
|
-
import * as i2 from "@
|
|
11
|
-
import * as i3 from "@angular/
|
|
12
|
-
import * as i4 from "@angular/
|
|
13
|
-
import * as i5 from "@
|
|
14
|
-
import * as i6 from "
|
|
15
|
-
import * as i7 from "@
|
|
16
|
-
import * as i8 from "
|
|
17
|
-
import * as i9 from "
|
|
18
|
-
import * as i10 from "@memberjunction/ng-code-editor";
|
|
19
|
-
import * as i11 from "./agent-execution-monitor.component";
|
|
10
|
+
import * as i2 from "@angular/router";
|
|
11
|
+
import * as i3 from "@angular/common";
|
|
12
|
+
import * as i4 from "@angular/forms";
|
|
13
|
+
import * as i5 from "@memberjunction/ng-ui-components";
|
|
14
|
+
import * as i6 from "angular-split";
|
|
15
|
+
import * as i7 from "@memberjunction/ng-code-editor";
|
|
16
|
+
import * as i8 from "./json-viewer-window.component";
|
|
17
|
+
import * as i9 from "./agent-execution-monitor.component";
|
|
20
18
|
const _c0 = ["messagesContainer"];
|
|
21
19
|
const _c1 = ["fileInput"];
|
|
22
20
|
const _c2 = ["messageInput"];
|
|
@@ -29,7 +27,7 @@ const _c8 = (a0, a1, a2, a3) => [a0, a1, a2, a3];
|
|
|
29
27
|
const _forTrack0 = ($index, $item) => $item.id;
|
|
30
28
|
const _forTrack1 = ($index, $item) => $item.ID;
|
|
31
29
|
function AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
-
i0.ɵɵelement(0, "img",
|
|
30
|
+
i0.ɵɵelement(0, "img", 14);
|
|
33
31
|
} if (rf & 2) {
|
|
34
32
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
35
33
|
i0.ɵɵproperty("src", ctx_r1.getEntityLogoURL(), i0.ɵɵsanitizeUrl)("alt", ctx_r1.getEntityName() + " logo");
|
|
@@ -51,39 +49,39 @@ function AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_7_Templa
|
|
|
51
49
|
} }
|
|
52
50
|
function AITestHarnessComponent_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
53
51
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
54
|
-
i0.ɵɵelementStart(0, "div",
|
|
55
|
-
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_2_Template, 1, 2, "img",
|
|
52
|
+
i0.ɵɵelementStart(0, "div", 9)(1, "div", 13);
|
|
53
|
+
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_2_Template, 1, 2, "img", 14)(3, AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_3_Template, 1, 2, "i", 15);
|
|
56
54
|
i0.ɵɵelementStart(4, "div")(5, "h3");
|
|
57
55
|
i0.ɵɵtext(6);
|
|
58
56
|
i0.ɵɵelementEnd();
|
|
59
57
|
i0.ɵɵconditionalCreate(7, AITestHarnessComponent_Conditional_0_Conditional_2_Conditional_7_Template, 2, 1, "p");
|
|
60
58
|
i0.ɵɵelementEnd()();
|
|
61
|
-
i0.ɵɵelementStart(8, "div",
|
|
59
|
+
i0.ɵɵelementStart(8, "div", 16)(9, "button", 17);
|
|
62
60
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearConversation()); });
|
|
63
|
-
i0.ɵɵelement(10, "i",
|
|
61
|
+
i0.ɵɵelement(10, "i", 18);
|
|
64
62
|
i0.ɵɵtext(11, " Clear ");
|
|
65
63
|
i0.ɵɵelementEnd();
|
|
66
|
-
i0.ɵɵelementStart(12, "button",
|
|
64
|
+
i0.ɵɵelementStart(12, "button", 19);
|
|
67
65
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.saveConversation()); });
|
|
68
|
-
i0.ɵɵelement(13, "i",
|
|
66
|
+
i0.ɵɵelement(13, "i", 20);
|
|
69
67
|
i0.ɵɵtext(14, " Save ");
|
|
70
68
|
i0.ɵɵelementEnd();
|
|
71
|
-
i0.ɵɵelementStart(15, "button",
|
|
69
|
+
i0.ɵɵelementStart(15, "button", 21);
|
|
72
70
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.exportConversation()); });
|
|
73
|
-
i0.ɵɵelement(16, "i",
|
|
71
|
+
i0.ɵɵelement(16, "i", 22);
|
|
74
72
|
i0.ɵɵtext(17, " Export ");
|
|
75
73
|
i0.ɵɵelementEnd();
|
|
76
|
-
i0.ɵɵelementStart(18, "button",
|
|
74
|
+
i0.ɵɵelementStart(18, "button", 23);
|
|
77
75
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.importConversation()); });
|
|
78
|
-
i0.ɵɵelement(19, "i",
|
|
76
|
+
i0.ɵɵelement(19, "i", 24);
|
|
79
77
|
i0.ɵɵtext(20, " Import ");
|
|
80
78
|
i0.ɵɵelementEnd();
|
|
81
|
-
i0.ɵɵelementStart(21, "input",
|
|
79
|
+
i0.ɵɵelementStart(21, "input", 25, 0);
|
|
82
80
|
i0.ɵɵlistener("change", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_input_change_21_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onFileSelected($event)); });
|
|
83
81
|
i0.ɵɵelementEnd();
|
|
84
|
-
i0.ɵɵelementStart(23, "button",
|
|
82
|
+
i0.ɵɵelementStart(23, "button", 26);
|
|
85
83
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_2_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleSidebar()); });
|
|
86
|
-
i0.ɵɵelement(24, "i",
|
|
84
|
+
i0.ɵɵelement(24, "i", 27);
|
|
87
85
|
i0.ɵɵelementEnd()()();
|
|
88
86
|
} if (rf & 2) {
|
|
89
87
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -103,7 +101,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_2_Template(rf, ctx) {
|
|
|
103
101
|
i0.ɵɵclassProp("fa-chevron-right", !ctx_r1.showSidebar)("fa-chevron-left", ctx_r1.showSidebar);
|
|
104
102
|
} }
|
|
105
103
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
106
|
-
i0.ɵɵelementStart(0, "div",
|
|
104
|
+
i0.ɵɵelementStart(0, "div", 30);
|
|
107
105
|
i0.ɵɵelement(1, "i", 44);
|
|
108
106
|
i0.ɵɵelementStart(2, "h4");
|
|
109
107
|
i0.ɵɵtext(3, "Start a conversation");
|
|
@@ -129,7 +127,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_
|
|
|
129
127
|
i0.ɵɵclassMap(ctx_r1.getEntityIconClass());
|
|
130
128
|
} }
|
|
131
129
|
function AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
-
i0.ɵɵconditionalCreate(0, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Conditional_0_Template, 1, 2, "img", 59)(1, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Conditional_1_Template, 1, 2, "i",
|
|
130
|
+
i0.ɵɵconditionalCreate(0, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Conditional_0_Template, 1, 2, "img", 59)(1, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Conditional_1_Template, 1, 2, "i", 15);
|
|
133
131
|
i0.ɵɵtext(2);
|
|
134
132
|
} if (rf & 2) {
|
|
135
133
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
@@ -214,7 +212,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_16
|
|
|
214
212
|
i0.ɵɵtext(4, " Payload ");
|
|
215
213
|
i0.ɵɵelementEnd();
|
|
216
214
|
i0.ɵɵelementStart(5, "button", 69);
|
|
217
|
-
i0.ɵɵelement(6, "i",
|
|
215
|
+
i0.ɵɵelement(6, "i", 27);
|
|
218
216
|
i0.ɵɵelementEnd()();
|
|
219
217
|
i0.ɵɵconditionalCreate(7, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_16_Conditional_7_Template, 2, 3, "div", 70);
|
|
220
218
|
i0.ɵɵelementEnd();
|
|
@@ -228,7 +226,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_16
|
|
|
228
226
|
} }
|
|
229
227
|
function AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Template(rf, ctx) { if (rf & 1) {
|
|
230
228
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
231
|
-
i0.ɵɵelementStart(0, "div",
|
|
229
|
+
i0.ɵɵelementStart(0, "div", 31)(1, "div", 45)(2, "span", 46);
|
|
232
230
|
i0.ɵɵconditionalCreate(3, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Conditional_4_Template, 3, 2);
|
|
233
231
|
i0.ɵɵelementEnd();
|
|
234
232
|
i0.ɵɵelementStart(5, "span", 47);
|
|
@@ -301,7 +299,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_9_Condit
|
|
|
301
299
|
i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
|
|
302
300
|
} }
|
|
303
301
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
304
|
-
i0.ɵɵelementStart(0, "div",
|
|
302
|
+
i0.ɵɵelementStart(0, "div", 33)(1, "div", 72);
|
|
305
303
|
i0.ɵɵelement(2, "i", 73);
|
|
306
304
|
i0.ɵɵelementStart(3, "span");
|
|
307
305
|
i0.ɵɵtext(4, "Messages from Prompt Run ");
|
|
@@ -328,9 +326,9 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Condi
|
|
|
328
326
|
} }
|
|
329
327
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
330
328
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
331
|
-
i0.ɵɵelementStart(0, "div",
|
|
332
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
333
|
-
i0.ɵɵlistener("keypress", function
|
|
329
|
+
i0.ɵɵelementStart(0, "div", 34)(1, "textarea", 81, 2);
|
|
330
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Template_textarea_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
|
|
331
|
+
i0.ɵɵlistener("keypress", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Template_textarea_keypress_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
|
|
334
332
|
i0.ɵɵelementEnd();
|
|
335
333
|
i0.ɵɵelementStart(3, "button", 82);
|
|
336
334
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
|
|
@@ -407,14 +405,14 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_Condi
|
|
|
407
405
|
} }
|
|
408
406
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9_Template(rf, ctx) { if (rf & 1) {
|
|
409
407
|
const _r14 = i0.ɵɵgetCurrentView();
|
|
410
|
-
i0.ɵɵelementStart(0, "div", 90)(1, "
|
|
411
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
408
|
+
i0.ɵɵelementStart(0, "div", 90)(1, "input", 93);
|
|
409
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9_Template_input_ngModelChange_1_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.name, $event) || (variable_r15.name = $event); return i0.ɵɵresetView($event); });
|
|
412
410
|
i0.ɵɵelementEnd();
|
|
413
|
-
i0.ɵɵelementStart(2, "
|
|
414
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
411
|
+
i0.ɵɵelementStart(2, "mj-dropdown", 94);
|
|
412
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9_Template_mj_dropdown_ngModelChange_2_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.type, $event) || (variable_r15.type = $event); return i0.ɵɵresetView($event); });
|
|
415
413
|
i0.ɵɵelementEnd();
|
|
416
|
-
i0.ɵɵelementStart(3, "
|
|
417
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
414
|
+
i0.ɵɵelementStart(3, "input", 95);
|
|
415
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9_Template_input_ngModelChange_3_listener($event) { const variable_r15 = i0.ɵɵrestoreView(_r14).$implicit; i0.ɵɵtwoWayBindingSet(variable_r15.value, $event) || (variable_r15.value = $event); return i0.ɵɵresetView($event); });
|
|
418
416
|
i0.ɵɵelementEnd();
|
|
419
417
|
i0.ɵɵelementStart(4, "button", 96);
|
|
420
418
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9_Template_button_click_4_listener() { const $index_r16 = i0.ɵɵrestoreView(_r14).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeAgentVariable($index_r16)); });
|
|
@@ -428,7 +426,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_21_For_9
|
|
|
428
426
|
i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
|
|
429
427
|
i0.ɵɵadvance();
|
|
430
428
|
i0.ɵɵtwoWayProperty("ngModel", variable_r15.type);
|
|
431
|
-
i0.ɵɵproperty("
|
|
429
|
+
i0.ɵɵproperty("Data", i0.ɵɵpureFunction4(14, _c8, i0.ɵɵpureFunction0(10, _c4), i0.ɵɵpureFunction0(11, _c5), i0.ɵɵpureFunction0(12, _c6), i0.ɵɵpureFunction0(13, _c7)))("ValuePrimitive", true)("Disabled", ctx_r1.isExecuting);
|
|
432
430
|
i0.ɵɵadvance();
|
|
433
431
|
i0.ɵɵtwoWayProperty("ngModel", variable_r15.value);
|
|
434
432
|
i0.ɵɵproperty("placeholder", variable_r15.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
|
|
@@ -504,8 +502,8 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Templ
|
|
|
504
502
|
i0.ɵɵelementStart(6, "div", 99)(7, "div", 100)(8, "label");
|
|
505
503
|
i0.ɵɵtext(9, "AI Configuration");
|
|
506
504
|
i0.ɵɵelementEnd();
|
|
507
|
-
i0.ɵɵelementStart(10, "
|
|
508
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
505
|
+
i0.ɵɵelementStart(10, "mj-dropdown", 101);
|
|
506
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Template_mj_dropdown_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.agentConfigurationId, $event) || (ctx_r1.agentConfigurationId = $event); return i0.ɵɵresetView($event); });
|
|
509
507
|
i0.ɵɵelementEnd();
|
|
510
508
|
i0.ɵɵelementStart(11, "div", 102);
|
|
511
509
|
i0.ɵɵconditionalCreate(12, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Conditional_12_Template, 2, 0)(13, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Conditional_13_Template, 1, 0);
|
|
@@ -514,20 +512,20 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Templ
|
|
|
514
512
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
515
513
|
i0.ɵɵadvance(10);
|
|
516
514
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.agentConfigurationId);
|
|
517
|
-
i0.ɵɵproperty("
|
|
515
|
+
i0.ɵɵproperty("Data", ctx_r1.availableConfigurations)("ValuePrimitive", true);
|
|
518
516
|
i0.ɵɵadvance(2);
|
|
519
517
|
i0.ɵɵconditional(ctx_r1.agentConfigurationId ? 12 : 13);
|
|
520
518
|
} }
|
|
521
519
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
522
520
|
const _r21 = i0.ɵɵgetCurrentView();
|
|
523
|
-
i0.ɵɵelementStart(0, "div", 90)(1, "
|
|
524
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
521
|
+
i0.ɵɵelementStart(0, "div", 90)(1, "input", 93);
|
|
522
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8_Template_input_ngModelChange_1_listener($event) { const variable_r22 = i0.ɵɵrestoreView(_r21).$implicit; i0.ɵɵtwoWayBindingSet(variable_r22.name, $event) || (variable_r22.name = $event); return i0.ɵɵresetView($event); });
|
|
525
523
|
i0.ɵɵelementEnd();
|
|
526
|
-
i0.ɵɵelementStart(2, "
|
|
527
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
524
|
+
i0.ɵɵelementStart(2, "mj-dropdown", 94);
|
|
525
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8_Template_mj_dropdown_ngModelChange_2_listener($event) { const variable_r22 = i0.ɵɵrestoreView(_r21).$implicit; i0.ɵɵtwoWayBindingSet(variable_r22.type, $event) || (variable_r22.type = $event); return i0.ɵɵresetView($event); });
|
|
528
526
|
i0.ɵɵelementEnd();
|
|
529
|
-
i0.ɵɵelementStart(3, "
|
|
530
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
527
|
+
i0.ɵɵelementStart(3, "input", 95);
|
|
528
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8_Template_input_ngModelChange_3_listener($event) { const variable_r22 = i0.ɵɵrestoreView(_r21).$implicit; i0.ɵɵtwoWayBindingSet(variable_r22.value, $event) || (variable_r22.value = $event); return i0.ɵɵresetView($event); });
|
|
531
529
|
i0.ɵɵelementEnd();
|
|
532
530
|
i0.ɵɵelementStart(4, "button", 104);
|
|
533
531
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8_Template_button_click_4_listener() { const $index_r23 = i0.ɵɵrestoreView(_r21).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeTemplateVariable($index_r23)); });
|
|
@@ -541,7 +539,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_For_8
|
|
|
541
539
|
i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
|
|
542
540
|
i0.ɵɵadvance();
|
|
543
541
|
i0.ɵɵtwoWayProperty("ngModel", variable_r22.type);
|
|
544
|
-
i0.ɵɵproperty("
|
|
542
|
+
i0.ɵɵproperty("Data", i0.ɵɵpureFunction4(13, _c8, i0.ɵɵpureFunction0(9, _c4), i0.ɵɵpureFunction0(10, _c5), i0.ɵɵpureFunction0(11, _c6), i0.ɵɵpureFunction0(12, _c7)))("ValuePrimitive", true)("Disabled", ctx_r1.isExecuting);
|
|
545
543
|
i0.ɵɵadvance();
|
|
546
544
|
i0.ɵɵtwoWayProperty("ngModel", variable_r22.value);
|
|
547
545
|
i0.ɵɵproperty("placeholder", variable_r22.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
|
|
@@ -603,14 +601,14 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Condi
|
|
|
603
601
|
i0.ɵɵelementStart(0, "div", 100)(1, "label", 128);
|
|
604
602
|
i0.ɵɵtext(2, " Top Log Probs ");
|
|
605
603
|
i0.ɵɵelementEnd();
|
|
606
|
-
i0.ɵɵelementStart(3, "
|
|
607
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
604
|
+
i0.ɵɵelementStart(3, "mj-numeric-input", 129);
|
|
605
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_86_Template_mj_numeric_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topLogProbs, $event) || (ctx_r1.advancedParams.topLogProbs = $event); return i0.ɵɵresetView($event); });
|
|
608
606
|
i0.ɵɵelementEnd()();
|
|
609
607
|
} if (rf & 2) {
|
|
610
608
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
611
609
|
i0.ɵɵadvance(3);
|
|
612
610
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.topLogProbs);
|
|
613
|
-
i0.ɵɵproperty("
|
|
611
|
+
i0.ɵɵproperty("Min", 2)("Max", 20)("Step", 1)("Format", "n0");
|
|
614
612
|
} }
|
|
615
613
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
616
614
|
const _r24 = i0.ɵɵgetCurrentView();
|
|
@@ -627,15 +625,15 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
627
625
|
i0.ɵɵelementStart(8, "div", 99)(9, "div", 100)(10, "label");
|
|
628
626
|
i0.ɵɵtext(11, "AI Model");
|
|
629
627
|
i0.ɵɵelementEnd();
|
|
630
|
-
i0.ɵɵelementStart(12, "
|
|
631
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
632
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
628
|
+
i0.ɵɵelementStart(12, "mj-dropdown", 107);
|
|
629
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_dropdown_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedModelId, $event) || (ctx_r1.selectedModelId = $event); return i0.ɵɵresetView($event); });
|
|
630
|
+
i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_dropdown_ngModelChange_12_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onModelSelectionChange()); });
|
|
633
631
|
i0.ɵɵelementEnd()();
|
|
634
632
|
i0.ɵɵelementStart(13, "div", 100)(14, "label");
|
|
635
633
|
i0.ɵɵtext(15, "AI Vendor");
|
|
636
634
|
i0.ɵɵelementEnd();
|
|
637
|
-
i0.ɵɵelementStart(16, "
|
|
638
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
635
|
+
i0.ɵɵelementStart(16, "mj-dropdown", 108);
|
|
636
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_dropdown_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedVendorId, $event) || (ctx_r1.selectedVendorId = $event); return i0.ɵɵresetView($event); });
|
|
639
637
|
i0.ɵɵelementEnd();
|
|
640
638
|
i0.ɵɵelementStart(17, "div", 102);
|
|
641
639
|
i0.ɵɵconditionalCreate(18, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_18_Template, 1, 0)(19, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_19_Template, 1, 0)(20, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_20_Template, 1, 0);
|
|
@@ -643,8 +641,8 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
643
641
|
i0.ɵɵelementStart(21, "div", 100)(22, "label");
|
|
644
642
|
i0.ɵɵtext(23, "AI Configuration");
|
|
645
643
|
i0.ɵɵelementEnd();
|
|
646
|
-
i0.ɵɵelementStart(24, "
|
|
647
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
644
|
+
i0.ɵɵelementStart(24, "mj-dropdown", 101);
|
|
645
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_dropdown_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedConfigurationId, $event) || (ctx_r1.selectedConfigurationId = $event); return i0.ɵɵresetView($event); });
|
|
648
646
|
i0.ɵɵelementEnd();
|
|
649
647
|
i0.ɵɵelementStart(25, "div", 102);
|
|
650
648
|
i0.ɵɵconditionalCreate(26, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_26_Template, 2, 0)(27, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_27_Template, 1, 0);
|
|
@@ -652,8 +650,8 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
652
650
|
i0.ɵɵelementStart(28, "div", 100)(29, "label");
|
|
653
651
|
i0.ɵɵtext(30, "Response Format");
|
|
654
652
|
i0.ɵɵelementEnd();
|
|
655
|
-
i0.ɵɵelementStart(31, "
|
|
656
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
653
|
+
i0.ɵɵelementStart(31, "mj-dropdown", 109);
|
|
654
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_dropdown_ngModelChange_31_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedResponseFormat, $event) || (ctx_r1.selectedResponseFormat = $event); return i0.ɵɵresetView($event); });
|
|
657
655
|
i0.ɵɵelementEnd();
|
|
658
656
|
i0.ɵɵelementStart(32, "div", 102);
|
|
659
657
|
i0.ɵɵtext(33, " Expected format for AI response (defaults to prompt setting) ");
|
|
@@ -661,8 +659,8 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
661
659
|
i0.ɵɵelementStart(34, "div", 100)(35, "label");
|
|
662
660
|
i0.ɵɵtext(36, "Max Tokens");
|
|
663
661
|
i0.ɵɵelementEnd();
|
|
664
|
-
i0.ɵɵelementStart(37, "
|
|
665
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
662
|
+
i0.ɵɵelementStart(37, "mj-numeric-input", 110);
|
|
663
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.maxTokens, $event) || (ctx_r1.maxTokens = $event); return i0.ɵɵresetView($event); });
|
|
666
664
|
i0.ɵɵelementEnd();
|
|
667
665
|
i0.ɵɵelementStart(38, "div", 102);
|
|
668
666
|
i0.ɵɵtext(39, " Maximum length of generated response ");
|
|
@@ -675,56 +673,54 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
675
673
|
i0.ɵɵelementStart(44, "div", 102);
|
|
676
674
|
i0.ɵɵtext(45, " Skip output validation during testing ");
|
|
677
675
|
i0.ɵɵelementEnd()();
|
|
678
|
-
i0.ɵɵelementStart(46, "
|
|
679
|
-
i0.ɵɵlistener("action", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_kendo_expansionpanel_action_46_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleAdvancedParams()); });
|
|
680
|
-
i0.ɵɵelementStart(47, "div", 114)(48, "div", 100)(49, "label", 115);
|
|
676
|
+
i0.ɵɵelementStart(46, "mj-accordion-panel", 113)(47, "div", 114)(48, "div", 100)(49, "label", 115);
|
|
681
677
|
i0.ɵɵtext(50, " Temperature ");
|
|
682
678
|
i0.ɵɵelementEnd();
|
|
683
|
-
i0.ɵɵelementStart(51, "
|
|
684
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
679
|
+
i0.ɵɵelementStart(51, "mj-numeric-input", 116);
|
|
680
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_51_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.temperature, $event) || (ctx_r1.advancedParams.temperature = $event); return i0.ɵɵresetView($event); });
|
|
685
681
|
i0.ɵɵelementEnd()();
|
|
686
682
|
i0.ɵɵelementStart(52, "div", 100)(53, "label", 117);
|
|
687
683
|
i0.ɵɵtext(54, " Top P ");
|
|
688
684
|
i0.ɵɵelementEnd();
|
|
689
|
-
i0.ɵɵelementStart(55, "
|
|
690
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
685
|
+
i0.ɵɵelementStart(55, "mj-numeric-input", 116);
|
|
686
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_55_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topP, $event) || (ctx_r1.advancedParams.topP = $event); return i0.ɵɵresetView($event); });
|
|
691
687
|
i0.ɵɵelementEnd()();
|
|
692
688
|
i0.ɵɵelementStart(56, "div", 100)(57, "label", 118);
|
|
693
689
|
i0.ɵɵtext(58, " Top K ");
|
|
694
690
|
i0.ɵɵelementEnd();
|
|
695
|
-
i0.ɵɵelementStart(59, "
|
|
696
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
691
|
+
i0.ɵɵelementStart(59, "mj-numeric-input", 116);
|
|
692
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_59_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topK, $event) || (ctx_r1.advancedParams.topK = $event); return i0.ɵɵresetView($event); });
|
|
697
693
|
i0.ɵɵelementEnd()();
|
|
698
694
|
i0.ɵɵelementStart(60, "div", 100)(61, "label", 119);
|
|
699
695
|
i0.ɵɵtext(62, " Min P ");
|
|
700
696
|
i0.ɵɵelementEnd();
|
|
701
|
-
i0.ɵɵelementStart(63, "
|
|
702
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
697
|
+
i0.ɵɵelementStart(63, "mj-numeric-input", 116);
|
|
698
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_63_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.minP, $event) || (ctx_r1.advancedParams.minP = $event); return i0.ɵɵresetView($event); });
|
|
703
699
|
i0.ɵɵelementEnd()();
|
|
704
700
|
i0.ɵɵelementStart(64, "div", 100)(65, "label", 120);
|
|
705
701
|
i0.ɵɵtext(66, " Frequency Penalty ");
|
|
706
702
|
i0.ɵɵelementEnd();
|
|
707
|
-
i0.ɵɵelementStart(67, "
|
|
708
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
703
|
+
i0.ɵɵelementStart(67, "mj-numeric-input", 116);
|
|
704
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_67_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.frequencyPenalty, $event) || (ctx_r1.advancedParams.frequencyPenalty = $event); return i0.ɵɵresetView($event); });
|
|
709
705
|
i0.ɵɵelementEnd()();
|
|
710
706
|
i0.ɵɵelementStart(68, "div", 100)(69, "label", 121);
|
|
711
707
|
i0.ɵɵtext(70, " Presence Penalty ");
|
|
712
708
|
i0.ɵɵelementEnd();
|
|
713
|
-
i0.ɵɵelementStart(71, "
|
|
714
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
709
|
+
i0.ɵɵelementStart(71, "mj-numeric-input", 116);
|
|
710
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.presencePenalty, $event) || (ctx_r1.advancedParams.presencePenalty = $event); return i0.ɵɵresetView($event); });
|
|
715
711
|
i0.ɵɵelementEnd()();
|
|
716
712
|
i0.ɵɵelementStart(72, "div", 100)(73, "label", 122);
|
|
717
713
|
i0.ɵɵtext(74, " Seed ");
|
|
718
714
|
i0.ɵɵelementEnd();
|
|
719
|
-
i0.ɵɵelementStart(75, "
|
|
720
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
715
|
+
i0.ɵɵelementStart(75, "mj-numeric-input", 123);
|
|
716
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_numeric_input_ngModelChange_75_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.seed, $event) || (ctx_r1.advancedParams.seed = $event); return i0.ɵɵresetView($event); });
|
|
721
717
|
i0.ɵɵelementEnd()();
|
|
722
718
|
i0.ɵɵelementStart(76, "div", 100)(77, "label", 124);
|
|
723
719
|
i0.ɵɵtext(78, " Stop Sequences ");
|
|
724
720
|
i0.ɵɵelementEnd();
|
|
725
|
-
i0.ɵɵelementStart(79, "
|
|
726
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
727
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
721
|
+
i0.ɵɵelementStart(79, "textarea", 125);
|
|
722
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_textarea_ngModelChange_79_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.stopSequencesText, $event) || (ctx_r1.stopSequencesText = $event); return i0.ɵɵresetView($event); });
|
|
723
|
+
i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_textarea_ngModelChange_79_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.updateStopSequences()); });
|
|
728
724
|
i0.ɵɵelementEnd();
|
|
729
725
|
i0.ɵɵelementStart(80, "div", 102);
|
|
730
726
|
i0.ɵɵtext(81, " Separate multiple sequences with commas ");
|
|
@@ -732,8 +728,8 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
732
728
|
i0.ɵɵelementStart(82, "div", 100)(83, "label", 126);
|
|
733
729
|
i0.ɵɵtext(84, " Include Log Probs ");
|
|
734
730
|
i0.ɵɵelementEnd();
|
|
735
|
-
i0.ɵɵelementStart(85, "
|
|
736
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
731
|
+
i0.ɵɵelementStart(85, "mj-switch", 127);
|
|
732
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template_mj_switch_ngModelChange_85_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.includeLogProbs, $event) || (ctx_r1.advancedParams.includeLogProbs = $event); return i0.ɵɵresetView($event); });
|
|
737
733
|
i0.ɵɵelementEnd()();
|
|
738
734
|
i0.ɵɵconditionalCreate(86, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Conditional_86_Template, 4, 5, "div", 100);
|
|
739
735
|
i0.ɵɵelementEnd()()()();
|
|
@@ -741,48 +737,48 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Templ
|
|
|
741
737
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
742
738
|
i0.ɵɵadvance(12);
|
|
743
739
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedModelId);
|
|
744
|
-
i0.ɵɵproperty("
|
|
740
|
+
i0.ɵɵproperty("Data", ctx_r1.availableModels)("ValuePrimitive", true);
|
|
745
741
|
i0.ɵɵadvance(4);
|
|
746
742
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedVendorId);
|
|
747
|
-
i0.ɵɵproperty("
|
|
743
|
+
i0.ɵɵproperty("Data", ctx_r1.availableVendors)("ValuePrimitive", true)("Disabled", ctx_r1.availableVendors.length <= 1 || !ctx_r1.selectedModelId);
|
|
748
744
|
i0.ɵɵadvance(2);
|
|
749
745
|
i0.ɵɵconditional(!ctx_r1.selectedModelId ? 18 : ctx_r1.availableVendors.length <= 1 ? 19 : 20);
|
|
750
746
|
i0.ɵɵadvance(6);
|
|
751
747
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedConfigurationId);
|
|
752
|
-
i0.ɵɵproperty("
|
|
748
|
+
i0.ɵɵproperty("Data", ctx_r1.availableConfigurations)("ValuePrimitive", true);
|
|
753
749
|
i0.ɵɵadvance(2);
|
|
754
750
|
i0.ɵɵconditional(ctx_r1.selectedConfigurationId ? 26 : 27);
|
|
755
751
|
i0.ɵɵadvance(5);
|
|
756
752
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedResponseFormat);
|
|
757
|
-
i0.ɵɵproperty("
|
|
753
|
+
i0.ɵɵproperty("Data", ctx_r1.responseFormatOptions);
|
|
758
754
|
i0.ɵɵadvance(6);
|
|
759
755
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.maxTokens);
|
|
760
|
-
i0.ɵɵproperty("
|
|
756
|
+
i0.ɵɵproperty("Min", 100)("Max", 8000)("Step", 100);
|
|
761
757
|
i0.ɵɵadvance(5);
|
|
762
758
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.skipValidation);
|
|
763
759
|
i0.ɵɵadvance(4);
|
|
764
|
-
i0.ɵɵproperty("
|
|
760
|
+
i0.ɵɵproperty("Title", "Advanced Parameters")("Expanded", ctx_r1.advancedParamsExpanded);
|
|
765
761
|
i0.ɵɵadvance(5);
|
|
766
762
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.temperature);
|
|
767
|
-
i0.ɵɵproperty("
|
|
763
|
+
i0.ɵɵproperty("Min", 0)("Max", 2)("Step", 0.1)("Format", "n1");
|
|
768
764
|
i0.ɵɵadvance(4);
|
|
769
765
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.topP);
|
|
770
|
-
i0.ɵɵproperty("
|
|
766
|
+
i0.ɵɵproperty("Min", 0)("Max", 1)("Step", 0.01)("Format", "n2");
|
|
771
767
|
i0.ɵɵadvance(4);
|
|
772
768
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.topK);
|
|
773
|
-
i0.ɵɵproperty("
|
|
769
|
+
i0.ɵɵproperty("Min", 1)("Max", 100)("Step", 1)("Format", "n0");
|
|
774
770
|
i0.ɵɵadvance(4);
|
|
775
771
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.minP);
|
|
776
|
-
i0.ɵɵproperty("
|
|
772
|
+
i0.ɵɵproperty("Min", 0)("Max", 1)("Step", 0.01)("Format", "n2");
|
|
777
773
|
i0.ɵɵadvance(4);
|
|
778
774
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.frequencyPenalty);
|
|
779
|
-
i0.ɵɵproperty("
|
|
775
|
+
i0.ɵɵproperty("Min", -2)("Max", 2)("Step", 0.1)("Format", "n1");
|
|
780
776
|
i0.ɵɵadvance(4);
|
|
781
777
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.presencePenalty);
|
|
782
|
-
i0.ɵɵproperty("
|
|
778
|
+
i0.ɵɵproperty("Min", -2)("Max", 2)("Step", 0.1)("Format", "n1");
|
|
783
779
|
i0.ɵɵadvance(4);
|
|
784
780
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.seed);
|
|
785
|
-
i0.ɵɵproperty("
|
|
781
|
+
i0.ɵɵproperty("Format", "n0");
|
|
786
782
|
i0.ɵɵadvance(4);
|
|
787
783
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.stopSequencesText);
|
|
788
784
|
i0.ɵɵproperty("rows", 2);
|
|
@@ -859,14 +855,14 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_26_Templ
|
|
|
859
855
|
} }
|
|
860
856
|
function AITestHarnessComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
861
857
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
862
|
-
i0.ɵɵelementStart(0, "
|
|
863
|
-
i0.ɵɵconditionalCreate(5, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_5_Template, 6, 0, "div",
|
|
864
|
-
i0.ɵɵrepeaterCreate(6, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Template, 17, 8, "div",
|
|
858
|
+
i0.ɵɵelementStart(0, "as-split", 11)(1, "as-split-area", 28)(2, "div", 12)(3, "div", 29, 1);
|
|
859
|
+
i0.ɵɵconditionalCreate(5, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_5_Template, 6, 0, "div", 30);
|
|
860
|
+
i0.ɵɵrepeaterCreate(6, AITestHarnessComponent_Conditional_0_Conditional_4_For_7_Template, 17, 8, "div", 31, _forTrack0);
|
|
865
861
|
i0.ɵɵelementEnd();
|
|
866
|
-
i0.ɵɵelementStart(8, "div",
|
|
867
|
-
i0.ɵɵconditionalCreate(9, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_9_Template, 11, 2, "div",
|
|
862
|
+
i0.ɵɵelementStart(8, "div", 32);
|
|
863
|
+
i0.ɵɵconditionalCreate(9, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_9_Template, 11, 2, "div", 33)(10, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_10_Template, 6, 5, "div", 34);
|
|
868
864
|
i0.ɵɵelementEnd()()();
|
|
869
|
-
i0.ɵɵelementStart(11, "
|
|
865
|
+
i0.ɵɵelementStart(11, "as-split-area", 28)(12, "div", 35)(13, "div", 36);
|
|
870
866
|
i0.ɵɵconditionalCreate(14, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_14_Template, 9, 8)(15, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_15_Template, 6, 4);
|
|
871
867
|
i0.ɵɵelementStart(16, "button", 37);
|
|
872
868
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_4_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.selectTab("savedConversations")); });
|
|
@@ -879,13 +875,13 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Template(rf, ctx) {
|
|
|
879
875
|
i0.ɵɵconditionalCreate(22, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_22_Template, 2, 6, "div", 42);
|
|
880
876
|
i0.ɵɵconditionalCreate(23, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_23_Template, 14, 4, "div", 41);
|
|
881
877
|
i0.ɵɵconditionalCreate(24, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_24_Template, 12, 0, "div", 41);
|
|
882
|
-
i0.ɵɵconditionalCreate(25, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template, 87,
|
|
878
|
+
i0.ɵɵconditionalCreate(25, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_25_Template, 87, 57, "div", 43);
|
|
883
879
|
i0.ɵɵconditionalCreate(26, AITestHarnessComponent_Conditional_0_Conditional_4_Conditional_26_Template, 11, 2, "div", 41);
|
|
884
880
|
i0.ɵɵelementEnd()()()();
|
|
885
881
|
} if (rf & 2) {
|
|
886
882
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
887
883
|
i0.ɵɵadvance();
|
|
888
|
-
i0.ɵɵproperty("
|
|
884
|
+
i0.ɵɵproperty("size", 70);
|
|
889
885
|
i0.ɵɵadvance(4);
|
|
890
886
|
i0.ɵɵconditional(ctx_r1.conversationMessages.length === 0 ? 5 : -1);
|
|
891
887
|
i0.ɵɵadvance();
|
|
@@ -893,7 +889,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Template(rf, ctx) {
|
|
|
893
889
|
i0.ɵɵadvance(3);
|
|
894
890
|
i0.ɵɵconditional(ctx_r1.originalPromptRunId && ctx_r1.conversationMessages.length > 0 ? 9 : 10);
|
|
895
891
|
i0.ɵɵadvance(2);
|
|
896
|
-
i0.ɵɵproperty("
|
|
892
|
+
i0.ɵɵproperty("size", 30);
|
|
897
893
|
i0.ɵɵadvance(3);
|
|
898
894
|
i0.ɵɵconditional(ctx_r1.mode === "agent" ? 14 : 15);
|
|
899
895
|
i0.ɵɵadvance(2);
|
|
@@ -915,7 +911,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_4_Template(rf, ctx) {
|
|
|
915
911
|
i0.ɵɵconditional(ctx_r1.activeTab === "savedConversations" ? 26 : -1);
|
|
916
912
|
} }
|
|
917
913
|
function AITestHarnessComponent_Conditional_0_Conditional_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
918
|
-
i0.ɵɵelementStart(0, "div",
|
|
914
|
+
i0.ɵɵelementStart(0, "div", 30);
|
|
919
915
|
i0.ɵɵelement(1, "i", 44);
|
|
920
916
|
i0.ɵɵelementStart(2, "h4");
|
|
921
917
|
i0.ɵɵtext(3, "Start a conversation");
|
|
@@ -1026,7 +1022,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Conditional_18
|
|
|
1026
1022
|
i0.ɵɵtext(4, " Payload ");
|
|
1027
1023
|
i0.ɵɵelementEnd();
|
|
1028
1024
|
i0.ɵɵelementStart(5, "button", 69);
|
|
1029
|
-
i0.ɵɵelement(6, "i",
|
|
1025
|
+
i0.ɵɵelement(6, "i", 27);
|
|
1030
1026
|
i0.ɵɵelementEnd()();
|
|
1031
1027
|
i0.ɵɵconditionalCreate(7, AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template, 3, 1, "div", 70);
|
|
1032
1028
|
i0.ɵɵelementEnd();
|
|
@@ -1040,7 +1036,7 @@ function AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Conditional_18
|
|
|
1040
1036
|
} }
|
|
1041
1037
|
function AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
1042
1038
|
const _r31 = i0.ɵɵgetCurrentView();
|
|
1043
|
-
i0.ɵɵelementStart(0, "div",
|
|
1039
|
+
i0.ɵɵelementStart(0, "div", 31)(1, "div", 45)(2, "span", 46);
|
|
1044
1040
|
i0.ɵɵconditionalCreate(3, AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Conditional_4_Template, 2, 1);
|
|
1045
1041
|
i0.ɵɵelementEnd();
|
|
1046
1042
|
i0.ɵɵelementStart(5, "span", 47);
|
|
@@ -1090,13 +1086,13 @@ function AITestHarnessComponent_Conditional_0_Conditional_5_Conditional_12_Templ
|
|
|
1090
1086
|
} }
|
|
1091
1087
|
function AITestHarnessComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
1092
1088
|
const _r30 = i0.ɵɵgetCurrentView();
|
|
1093
|
-
i0.ɵɵelementStart(0, "div",
|
|
1094
|
-
i0.ɵɵconditionalCreate(3, AITestHarnessComponent_Conditional_0_Conditional_5_Conditional_3_Template, 6, 0, "div",
|
|
1095
|
-
i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Template, 19, 10, "div",
|
|
1089
|
+
i0.ɵɵelementStart(0, "div", 12)(1, "div", 29, 1);
|
|
1090
|
+
i0.ɵɵconditionalCreate(3, AITestHarnessComponent_Conditional_0_Conditional_5_Conditional_3_Template, 6, 0, "div", 30);
|
|
1091
|
+
i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_Conditional_0_Conditional_5_For_5_Template, 19, 10, "div", 31, _forTrack0);
|
|
1096
1092
|
i0.ɵɵelementEnd();
|
|
1097
|
-
i0.ɵɵelementStart(6, "div",
|
|
1098
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
1099
|
-
i0.ɵɵlistener("keypress", function
|
|
1093
|
+
i0.ɵɵelementStart(6, "div", 32)(7, "div", 34)(8, "textarea", 81, 2);
|
|
1094
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_Conditional_0_Conditional_5_Template_textarea_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
|
|
1095
|
+
i0.ɵɵlistener("keypress", function AITestHarnessComponent_Conditional_0_Conditional_5_Template_textarea_keypress_8_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
|
|
1100
1096
|
i0.ɵɵelementEnd();
|
|
1101
1097
|
i0.ɵɵelementStart(10, "button", 82);
|
|
1102
1098
|
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_0_Conditional_5_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r30); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
|
|
@@ -1117,11 +1113,11 @@ function AITestHarnessComponent_Conditional_0_Conditional_5_Template(rf, ctx) {
|
|
|
1117
1113
|
i0.ɵɵconditional(ctx_r1.isExecuting ? 11 : 12);
|
|
1118
1114
|
} }
|
|
1119
1115
|
function AITestHarnessComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
1120
|
-
i0.ɵɵelementStart(0, "div", 4)(1, "div",
|
|
1121
|
-
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_0_Conditional_2_Template, 25, 10, "div",
|
|
1116
|
+
i0.ɵɵelementStart(0, "div", 4)(1, "div", 8);
|
|
1117
|
+
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_0_Conditional_2_Template, 25, 10, "div", 9);
|
|
1122
1118
|
i0.ɵɵelementEnd();
|
|
1123
|
-
i0.ɵɵelementStart(3, "div",
|
|
1124
|
-
i0.ɵɵconditionalCreate(4, AITestHarnessComponent_Conditional_0_Conditional_4_Template, 27,
|
|
1119
|
+
i0.ɵɵelementStart(3, "div", 10);
|
|
1120
|
+
i0.ɵɵconditionalCreate(4, AITestHarnessComponent_Conditional_0_Conditional_4_Template, 27, 15, "as-split", 11)(5, AITestHarnessComponent_Conditional_0_Conditional_5_Template, 13, 6, "div", 12);
|
|
1125
1121
|
i0.ɵɵelementEnd()();
|
|
1126
1122
|
} if (rf & 2) {
|
|
1127
1123
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -1132,50 +1128,66 @@ function AITestHarnessComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
1132
1128
|
} }
|
|
1133
1129
|
function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
1134
1130
|
const _r37 = i0.ɵɵgetCurrentView();
|
|
1135
|
-
i0.ɵɵelementStart(0, "
|
|
1136
|
-
i0.ɵɵlistener("
|
|
1137
|
-
i0.ɵɵelementStart(1, "
|
|
1138
|
-
i0.ɵɵtext(
|
|
1131
|
+
i0.ɵɵelementStart(0, "mj-dialog", 148);
|
|
1132
|
+
i0.ɵɵlistener("Close", function AITestHarnessComponent_Conditional_1_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(_r37); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
|
|
1133
|
+
i0.ɵɵelementStart(1, "mj-dialog-titlebar");
|
|
1134
|
+
i0.ɵɵtext(2, "Save Conversation");
|
|
1139
1135
|
i0.ɵɵelementEnd();
|
|
1140
|
-
i0.ɵɵelementStart(
|
|
1141
|
-
i0.ɵɵ
|
|
1136
|
+
i0.ɵɵelementStart(3, "div", 149)(4, "p");
|
|
1137
|
+
i0.ɵɵtext(5, "Enter a name for this conversation:");
|
|
1138
|
+
i0.ɵɵelementEnd();
|
|
1139
|
+
i0.ɵɵelementStart(6, "input", 150, 3);
|
|
1140
|
+
i0.ɵɵlistener("keyup", function AITestHarnessComponent_Conditional_1_Template_input_keyup_6_listener() { i0.ɵɵrestoreView(_r37); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateTempConversation()); });
|
|
1142
1141
|
i0.ɵɵelementEnd()();
|
|
1143
|
-
i0.ɵɵelementStart(
|
|
1144
|
-
i0.ɵɵlistener("click", function
|
|
1145
|
-
i0.ɵɵtext(
|
|
1142
|
+
i0.ɵɵelementStart(8, "mj-dialog-actions")(9, "button", 151);
|
|
1143
|
+
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r37); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
|
|
1144
|
+
i0.ɵɵtext(10, "Cancel");
|
|
1146
1145
|
i0.ɵɵelementEnd();
|
|
1147
|
-
i0.ɵɵelementStart(
|
|
1148
|
-
i0.ɵɵlistener("click", function
|
|
1149
|
-
i0.ɵɵtext(
|
|
1146
|
+
i0.ɵɵelementStart(11, "button", 152);
|
|
1147
|
+
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r37); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmSaveConversation()); });
|
|
1148
|
+
i0.ɵɵtext(12, " Save ");
|
|
1150
1149
|
i0.ɵɵelementEnd()()();
|
|
1151
1150
|
} if (rf & 2) {
|
|
1152
1151
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
1153
|
-
i0.ɵɵproperty("
|
|
1154
|
-
i0.ɵɵadvance(
|
|
1155
|
-
i0.ɵɵproperty("
|
|
1152
|
+
i0.ɵɵproperty("Visible", true)("Width", 400);
|
|
1153
|
+
i0.ɵɵadvance(11);
|
|
1154
|
+
i0.ɵɵproperty("disabled", ctx_r1.tempConversationName === "");
|
|
1156
1155
|
} }
|
|
1157
1156
|
function AITestHarnessComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
1158
1157
|
const _r38 = i0.ɵɵgetCurrentView();
|
|
1159
|
-
i0.ɵɵelementStart(0, "
|
|
1160
|
-
i0.ɵɵlistener("
|
|
1161
|
-
i0.ɵɵelementStart(1, "
|
|
1162
|
-
i0.ɵɵtext(
|
|
1158
|
+
i0.ɵɵelementStart(0, "mj-dialog", 153);
|
|
1159
|
+
i0.ɵɵlistener("Close", function AITestHarnessComponent_Conditional_2_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(_r38); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
|
|
1160
|
+
i0.ɵɵelementStart(1, "mj-dialog-titlebar");
|
|
1161
|
+
i0.ɵɵtext(2, "Replace Current Conversation?");
|
|
1163
1162
|
i0.ɵɵelementEnd();
|
|
1164
|
-
i0.ɵɵelementStart(4, "p");
|
|
1165
|
-
i0.ɵɵtext(5, "
|
|
1163
|
+
i0.ɵɵelementStart(3, "div", 149)(4, "p");
|
|
1164
|
+
i0.ɵɵtext(5, "Loading this conversation will replace the current one. Any unsaved changes will be lost.");
|
|
1165
|
+
i0.ɵɵelementEnd();
|
|
1166
|
+
i0.ɵɵelementStart(6, "p");
|
|
1167
|
+
i0.ɵɵtext(7, "Do you want to continue?");
|
|
1166
1168
|
i0.ɵɵelementEnd()();
|
|
1167
|
-
i0.ɵɵelementStart(
|
|
1168
|
-
i0.ɵɵlistener("click", function
|
|
1169
|
-
i0.ɵɵtext(
|
|
1169
|
+
i0.ɵɵelementStart(8, "mj-dialog-actions")(9, "button", 151);
|
|
1170
|
+
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r38); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
|
|
1171
|
+
i0.ɵɵtext(10, "Cancel");
|
|
1170
1172
|
i0.ɵɵelementEnd();
|
|
1171
|
-
i0.ɵɵelementStart(
|
|
1172
|
-
i0.ɵɵlistener("click", function
|
|
1173
|
-
i0.ɵɵtext(
|
|
1173
|
+
i0.ɵɵelementStart(11, "button", 154);
|
|
1174
|
+
i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r38); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmLoadConversation()); });
|
|
1175
|
+
i0.ɵɵtext(12, " Load Conversation ");
|
|
1174
1176
|
i0.ɵɵelementEnd()()();
|
|
1175
1177
|
} if (rf & 2) {
|
|
1176
|
-
i0.ɵɵproperty("
|
|
1177
|
-
|
|
1178
|
-
|
|
1178
|
+
i0.ɵɵproperty("Visible", true)("Width", 400);
|
|
1179
|
+
} }
|
|
1180
|
+
function AITestHarnessComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
1181
|
+
const _r39 = i0.ɵɵgetCurrentView();
|
|
1182
|
+
i0.ɵɵelementStart(0, "mj-window", 155);
|
|
1183
|
+
i0.ɵɵlistener("Close", function AITestHarnessComponent_Conditional_3_Template_mj_window_Close_0_listener() { i0.ɵɵrestoreView(_r39); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeJsonWindow()); });
|
|
1184
|
+
i0.ɵɵelement(1, "mj-json-viewer-window", 156);
|
|
1185
|
+
i0.ɵɵelementEnd();
|
|
1186
|
+
} if (rf & 2) {
|
|
1187
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
1188
|
+
i0.ɵɵproperty("Visible", true)("Width", 900)("Height", 700)("MinWidth", 600)("MinHeight", 400)("Draggable", true)("Resizable", true);
|
|
1189
|
+
i0.ɵɵadvance();
|
|
1190
|
+
i0.ɵɵproperty("jsonContent", ctx_r1.currentJsonContent);
|
|
1179
1191
|
} }
|
|
1180
1192
|
/**
|
|
1181
1193
|
* Comprehensive test harness component for AI Agent development and testing.
|
|
@@ -1215,14 +1227,10 @@ export class AITestHarnessComponent {
|
|
|
1215
1227
|
/**
|
|
1216
1228
|
* Creates a new AI Test Harness component instance.
|
|
1217
1229
|
* @param sanitizer - Angular DomSanitizer for safe HTML rendering of formatted content
|
|
1218
|
-
* @param windowService - Kendo WindowService for creating modal windows
|
|
1219
|
-
* @param viewContainerRef - Angular ViewContainerRef for window positioning
|
|
1220
1230
|
* @param cdr - Angular ChangeDetectorRef for managing change detection
|
|
1221
1231
|
*/
|
|
1222
|
-
constructor(sanitizer,
|
|
1232
|
+
constructor(sanitizer, cdr, router) {
|
|
1223
1233
|
this.sanitizer = sanitizer;
|
|
1224
|
-
this.windowService = windowService;
|
|
1225
|
-
this.viewContainerRef = viewContainerRef;
|
|
1226
1234
|
this.cdr = cdr;
|
|
1227
1235
|
this.router = router;
|
|
1228
1236
|
/** The mode of operation - either 'agent' or 'prompt' */
|
|
@@ -1321,8 +1329,8 @@ export class AITestHarnessComponent {
|
|
|
1321
1329
|
this.showJsonDialog = false;
|
|
1322
1330
|
/** Current JSON content to display in the dialog */
|
|
1323
1331
|
this.currentJsonContent = '';
|
|
1324
|
-
/**
|
|
1325
|
-
this.
|
|
1332
|
+
/** Whether the JSON viewer window is visible */
|
|
1333
|
+
this.showJsonWindow = false;
|
|
1326
1334
|
// === Execution Monitor Properties ===
|
|
1327
1335
|
/** Mode for the execution monitor component */
|
|
1328
1336
|
this.executionMonitorMode = 'historical';
|
|
@@ -1474,7 +1482,7 @@ export class AITestHarnessComponent {
|
|
|
1474
1482
|
if (this.isVisible && !this._hasFocused && this.messageInput) {
|
|
1475
1483
|
this._hasFocused = true;
|
|
1476
1484
|
Promise.resolve().then(() => {
|
|
1477
|
-
this.messageInput?.focus();
|
|
1485
|
+
this.messageInput?.nativeElement?.focus();
|
|
1478
1486
|
});
|
|
1479
1487
|
}
|
|
1480
1488
|
}
|
|
@@ -3181,62 +3189,27 @@ export class AITestHarnessComponent {
|
|
|
3181
3189
|
*/
|
|
3182
3190
|
showRawJsonDialog(message) {
|
|
3183
3191
|
if (message.rawContent) {
|
|
3184
|
-
// Close any existing window
|
|
3185
|
-
if (this.jsonWindowRef) {
|
|
3186
|
-
this.jsonWindowRef.close();
|
|
3187
|
-
}
|
|
3188
3192
|
try {
|
|
3189
|
-
// Try to parse and format the JSON
|
|
3190
3193
|
const parsed = JSON.parse(message.rawContent);
|
|
3191
|
-
// If this is an agent result with execution tree, enhance the display
|
|
3192
3194
|
if (parsed.agentRunID) {
|
|
3193
|
-
|
|
3194
|
-
const enhancedParsed = {
|
|
3195
|
-
...parsed,
|
|
3196
|
-
_agentRunID: parsed.agentRunID
|
|
3197
|
-
};
|
|
3195
|
+
const enhancedParsed = { ...parsed, _agentRunID: parsed.agentRunID };
|
|
3198
3196
|
this.currentJsonContent = this.formatJson(enhancedParsed);
|
|
3199
3197
|
}
|
|
3200
3198
|
else {
|
|
3201
|
-
// Apply recursive JSON parsing
|
|
3202
3199
|
this.currentJsonContent = this.formatJson(parsed);
|
|
3203
3200
|
}
|
|
3204
3201
|
}
|
|
3205
3202
|
catch {
|
|
3206
|
-
// If not valid JSON, show as-is
|
|
3207
3203
|
this.currentJsonContent = message.rawContent;
|
|
3208
3204
|
}
|
|
3209
|
-
|
|
3210
|
-
import('./json-viewer-window.component').then(({ JsonViewerWindowComponent }) => {
|
|
3211
|
-
// Create the window using WindowService
|
|
3212
|
-
// Calculate center position accounting for scroll
|
|
3213
|
-
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
3214
|
-
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
3215
|
-
const centerTop = Math.max(50, (window.innerHeight - 700) / 2 + scrollTop);
|
|
3216
|
-
const centerLeft = Math.max(50, (window.innerWidth - 900) / 2 + scrollLeft);
|
|
3217
|
-
this.jsonWindowRef = this.windowService.open({
|
|
3218
|
-
title: 'Raw JSON Response',
|
|
3219
|
-
content: JsonViewerWindowComponent,
|
|
3220
|
-
width: 900,
|
|
3221
|
-
height: 700,
|
|
3222
|
-
minWidth: 600,
|
|
3223
|
-
minHeight: 400,
|
|
3224
|
-
resizable: true,
|
|
3225
|
-
draggable: true,
|
|
3226
|
-
top: centerTop,
|
|
3227
|
-
left: centerLeft
|
|
3228
|
-
});
|
|
3229
|
-
// Pass the JSON content to the component
|
|
3230
|
-
const windowContent = this.jsonWindowRef.content.instance;
|
|
3231
|
-
windowContent.jsonContent = this.currentJsonContent;
|
|
3232
|
-
// Handle window close
|
|
3233
|
-
this.jsonWindowRef.result.subscribe((result) => {
|
|
3234
|
-
this.jsonWindowRef = null;
|
|
3235
|
-
this.currentJsonContent = '';
|
|
3236
|
-
});
|
|
3237
|
-
});
|
|
3205
|
+
this.showJsonWindow = true;
|
|
3238
3206
|
}
|
|
3239
3207
|
}
|
|
3208
|
+
/** Closes the JSON viewer window */
|
|
3209
|
+
closeJsonWindow() {
|
|
3210
|
+
this.showJsonWindow = false;
|
|
3211
|
+
this.currentJsonContent = '';
|
|
3212
|
+
}
|
|
3240
3213
|
/**
|
|
3241
3214
|
* Get the last run ID from conversation messages
|
|
3242
3215
|
*/
|
|
@@ -3293,7 +3266,7 @@ export class AITestHarnessComponent {
|
|
|
3293
3266
|
focusMessageInput() {
|
|
3294
3267
|
if (this.messageInput) {
|
|
3295
3268
|
setTimeout(() => {
|
|
3296
|
-
this.messageInput.focus();
|
|
3269
|
+
this.messageInput.nativeElement.focus();
|
|
3297
3270
|
}, 100);
|
|
3298
3271
|
}
|
|
3299
3272
|
}
|
|
@@ -3542,11 +3515,7 @@ export class AITestHarnessComponent {
|
|
|
3542
3515
|
* Closes the JSON dialog
|
|
3543
3516
|
*/
|
|
3544
3517
|
closeJsonDialog() {
|
|
3545
|
-
|
|
3546
|
-
this.jsonWindowRef.close();
|
|
3547
|
-
this.jsonWindowRef = null;
|
|
3548
|
-
}
|
|
3549
|
-
this.showJsonDialog = false;
|
|
3518
|
+
this.showJsonWindow = false;
|
|
3550
3519
|
this.currentJsonContent = '';
|
|
3551
3520
|
}
|
|
3552
3521
|
/**
|
|
@@ -3873,7 +3842,7 @@ export class AITestHarnessComponent {
|
|
|
3873
3842
|
IsConfigMatchById(config, id) {
|
|
3874
3843
|
return UUIDsEqual(config.ID, id);
|
|
3875
3844
|
}
|
|
3876
|
-
static { this.ɵfac = function AITestHarnessComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AITestHarnessComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(
|
|
3845
|
+
static { this.ɵfac = function AITestHarnessComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AITestHarnessComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.Router)); }; }
|
|
3877
3846
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AITestHarnessComponent, selectors: [["mj-ai-test-harness"]], viewQuery: function AITestHarnessComponent_Query(rf, ctx) { if (rf & 1) {
|
|
3878
3847
|
i0.ɵɵviewQuery(_c0, 5)(_c1, 5)(_c2, 5)(_c3, 5);
|
|
3879
3848
|
} if (rf & 2) {
|
|
@@ -3882,22 +3851,25 @@ export class AITestHarnessComponent {
|
|
|
3882
3851
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.fileInput = _t.first);
|
|
3883
3852
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageInput = _t.first);
|
|
3884
3853
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.saveDialogInput = _t.first);
|
|
3885
|
-
} }, inputs: { mode: "mode", entity: "entity", originalPromptRunId: "originalPromptRunId", systemPromptOverride: "systemPromptOverride", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange", runOpened: "runOpened", minimizeRequested: "minimizeRequested" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls:
|
|
3854
|
+
} }, inputs: { mode: "mode", entity: "entity", originalPromptRunId: "originalPromptRunId", systemPromptOverride: "systemPromptOverride", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange", runOpened: "runOpened", minimizeRequested: "minimizeRequested" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 4, consts: [["fileInput", ""], ["messagesContainer", ""], ["messageInput", ""], ["saveDialogInput", ""], [1, "harness-container"], [1, "save-dialog", 3, "Visible", "Width"], [1, "confirm-dialog", 3, "Visible", "Width"], ["Title", "Raw JSON Response", 3, "Visible", "Width", "Height", "MinWidth", "MinHeight", "Draggable", "Resizable"], [1, "harness-header"], [1, "agent-info"], [1, "harness-body"], ["direction", "horizontal", 2, "height", "100%", "width", "100%"], [1, "chat-area"], [1, "agent-details"], [1, "entity-logo", 3, "src", "alt"], [3, "class"], [1, "header-actions"], ["title", "Clear conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-broom"], ["title", "Save conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-save"], ["title", "Export conversation", 1, "custom-button", 3, "click", "disabled"], [1, "fa-solid", "fa-download"], ["title", "Import conversation", 1, "custom-button", 3, "click"], [1, "fa-solid", "fa-upload"], ["type", "file", "accept", ".json", 2, "display", "none", 3, "change"], ["title", "Toggle sidebar", 1, "custom-button", "icon-only", 3, "click"], [1, "fa-solid"], [3, "size"], [1, "messages-container"], [1, "empty-state"], [3, "ngClass"], [1, "input-area"], [1, "rerun-mode-container"], [1, "input-container"], [1, "sidebar"], [1, "sidebar-tabs"], [1, "tab-button", 3, "click", "disabled"], [1, "fa-solid", "fa-history"], [1, "badge"], [1, "sidebar-content"], [1, "tab-content"], [1, "tab-content", 2, "padding", "0", "height", "100%"], [1, "tab-content", 2, "overflow-y", "auto"], [1, "fa-solid", "fa-comments"], [1, "message-header"], [1, "message-role"], [1, "message-time"], [1, "execution-time", "streaming"], [1, "execution-time", 3, "title"], ["title", "View raw JSON response", 1, "raw-toggle"], [1, "message-content"], ["title", "Copy message", 1, "copy-button-in-bubble", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "streaming-wrapper"], [3, "innerHTML"], [1, "error-details"], [1, "payload-section", 3, "collapsed"], [1, "fa-solid", "fa-user"], [1, "message-role-logo", 3, "src", "alt"], [1, "fa-solid", "fa-spinner", "fa-spin"], ["title", "View raw JSON response", 1, "raw-toggle", 3, "click"], [1, "fa-solid", "fa-code"], [1, "streaming-content", 3, "innerHTML"], [1, "cursor"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "payload-section"], [1, "payload-header", 3, "click"], [1, "payload-label"], ["type", "button", 1, "payload-toggle"], [1, "payload-content"], [2, "height", "300px", "width", "100%", 3, "ngModel", "language", "readonly"], [1, "rerun-message"], [1, "fa-solid", "fa-rotate-right"], [1, "rerun-buttons"], ["title", "Re-run with loaded messages", 1, "send-button", "rerun-button", 3, "disabled"], ["title", "Reset conversation messages to the original state from the prompt run. Model settings and parameters will be preserved.", 1, "send-button", "reset-button", 3, "disabled"], ["title", "Re-run with loaded messages", 1, "send-button", "rerun-button", 3, "click", "disabled"], [1, "fa-solid", "fa-play"], ["title", "Reset conversation messages to the original state from the prompt run. Model settings and parameters will be preserved.", 1, "send-button", "reset-button", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], ["placeholder", "Type your message here... (Press Enter to send, Shift+Enter for new line)", 1, "mj-textarea", "message-input", 3, "ngModelChange", "keypress", "ngModel", "rows", "disabled"], ["title", "Send message", 1, "send-button", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], [1, "tab-button", 3, "click"], [1, "fa-solid", "fa-diagram-project"], [1, "fa-solid", "fa-sliders"], [1, "tab-header"], [1, "variables-list"], [1, "empty-variables"], [1, "variable-item"], [1, "add-button", 3, "click", "disabled"], [1, "fa-solid", "fa-plus"], ["type", "text", "placeholder", "Variable name", 1, "mj-input", "variable-name", 3, "ngModelChange", "ngModel", "disabled"], ["TextField", "text", "ValueField", "value", 1, "variable-type", 3, "ngModelChange", "ngModel", "Data", "ValuePrimitive", "Disabled"], ["type", "text", 1, "mj-input", "variable-value", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], ["title", "Remove variable", 1, "remove-button", 3, "click", "disabled"], [1, "fa-solid", "fa-times"], [3, "viewRunClick", "mode", "agentRun", "liveSteps", "autoExpand", "runId", "runType"], [1, "model-settings"], [1, "setting-group"], ["TextField", "Name", "ValueField", "ID", "Placeholder", "Select a configuration...", 1, "configuration-selector", 3, "ngModelChange", "ngModel", "Data", "ValuePrimitive"], [1, "setting-help"], [1, "add-button", 3, "click"], ["title", "Remove variable", 1, "remove-button", 3, "click"], ["title", "Reset to Prompt Settings", 1, "custom-button", "icon-only", 3, "click"], [1, "fa-solid", "fa-undo"], ["TextField", "Name", "ValueField", "ID", "Placeholder", "Select a model...", 1, "model-selector", 3, "ngModelChange", "ngModel", "Data", "ValuePrimitive"], ["TextField", "Name", "ValueField", "ID", "Placeholder", "Select a vendor...", 1, "vendor-selector", 3, "ngModelChange", "ngModel", "Data", "ValuePrimitive", "Disabled"], ["TextField", "text", "ValueField", "value", "Placeholder", "Select format...", 1, "format-selector", 3, "ngModelChange", "ngModel", "Data"], ["Placeholder", "Max tokens...", 1, "max-tokens-input", 3, "ngModelChange", "ngModel", "Min", "Max", "Step"], [1, "checkbox-label"], ["type", "checkbox", 1, "skip-validation-checkbox", 3, "ngModelChange", "ngModel"], [1, "advanced-params-panel", 3, "Title", "Expanded"], [1, "advanced-settings"], ["title", "Controls randomness: 0 = more focused and deterministic, 2 = more random and creative"], ["Placeholder", "None", 1, "advanced-param-input", 3, "ngModelChange", "ngModel", "Min", "Max", "Step", "Format"], ["title", "Nucleus sampling: only consider tokens with cumulative probability up to this value. 1 = consider all tokens"], ["title", "Only sample from the top K tokens. Lower values reduce randomness"], ["title", "Minimum probability for token selection. Filters out low-probability tokens"], ["title", "Penalizes tokens based on their frequency in the text. Positive values reduce repetition"], ["title", "Penalizes tokens that have appeared in the text. Positive values increase topic diversity"], ["title", "Random seed for deterministic generation. Same seed produces same output"], ["Placeholder", "None", 1, "advanced-param-input", 3, "ngModelChange", "ngModel", "Format"], ["title", "Sequences that will stop generation when encountered. Enter comma-separated values"], ["placeholder", "Enter comma-separated sequences", 1, "mj-textarea", "advanced-param-input", 3, "ngModelChange", "ngModel", "rows"], ["title", "Include log probabilities of the output tokens in the response"], [1, "advanced-param-switch", 3, "ngModelChange", "ngModel"], ["title", "Number of top log probabilities to include for each token"], ["Placeholder", "2", 1, "advanced-param-input", 3, "ngModelChange", "ngModel", "Min", "Max", "Step", "Format"], ["title", "Start a new conversation", 1, "custom-button", "small", "primary"], [1, "saved-list"], [1, "empty-saved"], [1, "saved-item", 3, "current"], ["title", "Start a new conversation", 1, "custom-button", "small", "primary", 3, "click"], [1, "fa-solid", "fa-folder-open"], [1, "saved-item", 3, "click"], [1, "saved-info"], [1, "saved-date"], ["title", "Delete conversation", 1, "delete-button", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "View execution details", 1, "execution-history-toggle"], ["title", "View full run details", 1, "execution-history-toggle"], [1, "fa-solid", "fa-robot"], ["title", "View execution details", 1, "execution-history-toggle", 3, "click"], ["title", "View full run details", 1, "execution-history-toggle", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "streaming-content"], [1, "save-dialog", 3, "Close", "Visible", "Width"], [1, "dialog-content"], ["type", "text", "placeholder", "Conversation name", 1, "mj-input", "full-width", 3, "keyup"], ["mjButton", "", 3, "click"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], [1, "confirm-dialog", 3, "Close", "Visible", "Width"], ["mjButton", "", "variant", "primary", 3, "click"], ["Title", "Raw JSON Response", 3, "Close", "Visible", "Width", "Height", "MinWidth", "MinHeight", "Draggable", "Resizable"], [3, "jsonContent"]], template: function AITestHarnessComponent_Template(rf, ctx) { if (rf & 1) {
|
|
3886
3855
|
i0.ɵɵconditionalCreate(0, AITestHarnessComponent_Conditional_0_Template, 6, 2, "div", 4);
|
|
3887
|
-
i0.ɵɵconditionalCreate(1, AITestHarnessComponent_Conditional_1_Template,
|
|
3888
|
-
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_2_Template,
|
|
3856
|
+
i0.ɵɵconditionalCreate(1, AITestHarnessComponent_Conditional_1_Template, 13, 3, "mj-dialog", 5);
|
|
3857
|
+
i0.ɵɵconditionalCreate(2, AITestHarnessComponent_Conditional_2_Template, 13, 2, "mj-dialog", 6);
|
|
3858
|
+
i0.ɵɵconditionalCreate(3, AITestHarnessComponent_Conditional_3_Template, 2, 8, "mj-window", 7);
|
|
3889
3859
|
} if (rf & 2) {
|
|
3890
3860
|
i0.ɵɵconditional(ctx.isVisible ? 0 : -1);
|
|
3891
3861
|
i0.ɵɵadvance();
|
|
3892
3862
|
i0.ɵɵconditional(ctx.showSaveDialog ? 1 : -1);
|
|
3893
3863
|
i0.ɵɵadvance();
|
|
3894
3864
|
i0.ɵɵconditional(ctx.showLoadConfirmDialog ? 2 : -1);
|
|
3895
|
-
} }, dependencies: [i4.NgClass, i5.CheckboxControlValueAccessor, i5.NgControlStatus, i5.NgModel, i6.ButtonComponent, i2.DialogComponent, i2.DialogActionsComponent, i2.WindowContainerDirective, i7.DropDownListComponent, i8.TextBoxComponent, i8.NumericTextBoxComponent, i8.TextAreaComponent, i8.SwitchComponent, i9.ExpansionPanelComponent, i9.SplitterComponent, i9.SplitterPaneComponent, i10.CodeEditorComponent, i11.AgentExecutionMonitorComponent, i4.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.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\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.harness-body[_ngcontent-%COMP%] kendo-splitter[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n.harness-body[_ngcontent-%COMP%] kendo-splitter-pane[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n overflow: hidden;\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.empty-variables[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n\n\n.saved-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-saved[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\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}"] }); }
|
|
3865
|
+
i0.ɵɵadvance();
|
|
3866
|
+
i0.ɵɵconditional(ctx.showJsonWindow ? 3 : -1);
|
|
3867
|
+
} }, dependencies: [i3.NgClass, i4.DefaultValueAccessor, i4.CheckboxControlValueAccessor, i4.NgControlStatus, i4.NgModel, i5.MJWindowComponent, i5.MJButtonDirective, i5.MJDropdownComponent, i5.MJNumericInputComponent, i5.MJSwitchComponent, i5.MJAccordionPanelComponent, i5.MJDialogComponent, i5.MJDialogTitlebarComponent, i5.MJDialogActionsComponent, i6.SplitComponent, i6.SplitAreaComponent, i7.CodeEditorComponent, i8.JsonViewerWindowComponent, i9.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.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\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.empty-variables[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n\n\n.saved-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-saved[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\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}"] }); }
|
|
3896
3868
|
}
|
|
3897
3869
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AITestHarnessComponent, [{
|
|
3898
3870
|
type: Component,
|
|
3899
|
-
args: [{ standalone: false, selector: 'mj-ai-test-harness', template: "@if (isVisible) {\n <div class=\"harness-container\" kendoWindowContainer>\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 <kendo-splitter\n orientation=\"horizontal\"\n style=\"height: 100%; width: 100%;\">\n <!-- Chat Area (Left Pane) -->\n <kendo-splitter-pane\n [collapsible]=\"false\"\n [resizable]=\"true\"\n [min]=\"'400px'\">\n <div class=\"chat-area\">\n <!-- Messages Container -->\n <div class=\"messages-container\" #messagesContainer>\n @if (conversationMessages.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\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 <kendo-textarea\n #messageInput\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\"\n class=\"message-input\">\n </kendo-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 </kendo-splitter-pane>\n <!-- Sidebar (Right Pane) -->\n <kendo-splitter-pane\n [collapsible]=\"false\"\n [resizable]=\"true\"\n [size]=\"'30%'\"\n [min]=\"'300px'\">\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 <div class=\"empty-variables\">\n <p>No variables defined. Click \"Add Variable\" to get started.</p>\n </div>\n }\n @for (variable of agentVariables; track $index) {\n <div class=\"variable-item\">\n <kendo-textbox\n [(ngModel)]=\"variable.name\"\n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\"\n class=\"variable-name\">\n </kendo-textbox>\n <kendo-dropdownlist\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 </kendo-dropdownlist>\n <kendo-textbox\n [(ngModel)]=\"variable.value\"\n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\"\n class=\"variable-value\">\n </kendo-textbox>\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 <kendo-dropdownlist\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 </kendo-dropdownlist>\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 <kendo-textbox\n [(ngModel)]=\"variable.name\"\n placeholder=\"Variable name\"\n [disabled]=\"isExecuting\"\n class=\"variable-name\">\n </kendo-textbox>\n <kendo-dropdownlist\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 </kendo-dropdownlist>\n <kendo-textbox\n [(ngModel)]=\"variable.value\"\n [placeholder]=\"variable.type === 'object' ? 'JSON value' : 'Value'\"\n [disabled]=\"isExecuting\"\n class=\"variable-value\">\n </kendo-textbox>\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 <kendo-dropdownlist\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 </kendo-dropdownlist>\n </div>\n <div class=\"setting-group\">\n <label>AI Vendor</label>\n <kendo-dropdownlist\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 </kendo-dropdownlist>\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 <kendo-dropdownlist\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 </kendo-dropdownlist>\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 <kendo-dropdownlist\n [(ngModel)]=\"selectedResponseFormat\"\n [data]=\"responseFormatOptions\"\n textField=\"text\"\n valueField=\"value\"\n placeholder=\"Select format...\"\n class=\"format-selector\">\n </kendo-dropdownlist>\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 <kendo-numerictextbox\n [(ngModel)]=\"maxTokens\"\n [min]=\"100\"\n [max]=\"8000\"\n [step]=\"100\"\n placeholder=\"Max tokens...\"\n class=\"max-tokens-input\">\n </kendo-numerictextbox>\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 <kendo-expansionpanel\n [expanded]=\"advancedParamsExpanded\"\n (action)=\"toggleAdvancedParams()\"\n title=\"Advanced Parameters\"\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\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 </kendo-numerictextbox>\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 <kendo-numerictextbox\n [(ngModel)]=\"advancedParams.seed\"\n [format]=\"'n0'\"\n placeholder=\"None\"\n class=\"advanced-param-input\">\n </kendo-numerictextbox>\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 <kendo-textarea\n [(ngModel)]=\"stopSequencesText\"\n (ngModelChange)=\"updateStopSequences()\"\n [rows]=\"2\"\n placeholder=\"Enter comma-separated sequences\"\n class=\"advanced-param-input\">\n </kendo-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 <kendo-switch\n [(ngModel)]=\"advancedParams.includeLogProbs\"\n class=\"advanced-param-switch\">\n </kendo-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 <kendo-numerictextbox\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 </kendo-numerictextbox>\n </div>\n }\n </div>\n </kendo-expansionpanel>\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 <div class=\"empty-saved\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <p>No saved conversations</p>\n </div>\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 </kendo-splitter-pane>\n </kendo-splitter>\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 <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\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 <kendo-textarea\n #messageInput\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\"\n class=\"message-input\">\n </kendo-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 <kendo-dialog\n [title]=\"'Save Conversation'\"\n [width]=\"400\"\n (close)=\"cancelSaveDialog()\"\n class=\"save-dialog\">\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=\"k-textbox k-input k-input-md k-rounded-md k-input-solid full-width\" />\n </div>\n <kendo-dialog-actions>\n <button kendoButton (click)=\"cancelSaveDialog()\">Cancel</button>\n <button kendoButton\n [primary]=\"true\"\n (click)=\"confirmSaveConversation()\"\n [disabled]=\"tempConversationName === ''\">\n Save\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\n}\n\n<!-- Load Confirmation Dialog -->\n@if (showLoadConfirmDialog) {\n <kendo-dialog\n [title]=\"'Replace Current Conversation?'\"\n [width]=\"400\"\n (close)=\"cancelLoadConversation()\"\n class=\"confirm-dialog\">\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 <kendo-dialog-actions>\n <button kendoButton (click)=\"cancelLoadConversation()\">Cancel</button>\n <button kendoButton\n [primary]=\"true\"\n (click)=\"confirmLoadConversation()\">\n Load Conversation\n </button>\n </kendo-dialog-actions>\n </kendo-dialog>\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.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\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/* Kendo Splitter Specific Styles */\n.harness-body kendo-splitter {\n height: 100%;\n}\n\n.harness-body kendo-splitter-pane {\n display: flex;\n flex-direction: column;\n overflow: hidden;\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.empty-variables {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n/* Saved Conversations */\n.saved-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-saved i {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\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"] }]
|
|
3900
|
-
}], () => [{ type: i1.DomSanitizer }, { type:
|
|
3871
|
+
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 <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\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 <div class=\"empty-variables\">\n <p>No variables defined. Click \"Add Variable\" to get started.</p>\n </div>\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 <div class=\"empty-saved\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <p>No saved conversations</p>\n </div>\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 <div class=\"empty-state\">\n <i class=\"fa-solid fa-comments\"></i>\n <h4>Start a conversation</h4>\n <p>Send a message to begin testing the AI agent</p>\n </div>\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.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 500;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\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.empty-variables {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n/* Saved Conversations */\n.saved-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-saved {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-saved i {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\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"] }]
|
|
3872
|
+
}], () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i2.Router }], { mode: [{
|
|
3901
3873
|
type: Input
|
|
3902
3874
|
}], entity: [{
|
|
3903
3875
|
type: Input
|
|
@@ -3928,5 +3900,5 @@ export class AITestHarnessComponent {
|
|
|
3928
3900
|
type: ViewChild,
|
|
3929
3901
|
args: ['saveDialogInput']
|
|
3930
3902
|
}] }); })();
|
|
3931
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber:
|
|
3903
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 154 }); })();
|
|
3932
3904
|
//# sourceMappingURL=ai-test-harness.component.js.map
|