@memberjunction/ng-ai-test-harness 2.55.0 → 2.57.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.
Files changed (49) hide show
  1. package/dist/lib/agent-execution-monitor.component.d.ts +9 -0
  2. package/dist/lib/agent-execution-monitor.component.d.ts.map +1 -1
  3. package/dist/lib/agent-execution-monitor.component.js +68 -10
  4. package/dist/lib/agent-execution-monitor.component.js.map +1 -1
  5. package/dist/lib/agent-execution-node.component.d.ts +1 -0
  6. package/dist/lib/agent-execution-node.component.d.ts.map +1 -1
  7. package/dist/lib/agent-execution-node.component.js +88 -39
  8. package/dist/lib/agent-execution-node.component.js.map +1 -1
  9. package/dist/lib/ai-test-harness-dialog.service.d.ts +7 -14
  10. package/dist/lib/ai-test-harness-dialog.service.d.ts.map +1 -1
  11. package/dist/lib/ai-test-harness-dialog.service.js +21 -95
  12. package/dist/lib/ai-test-harness-dialog.service.js.map +1 -1
  13. package/dist/lib/ai-test-harness-window.component.d.ts +37 -0
  14. package/dist/lib/ai-test-harness-window.component.d.ts.map +1 -0
  15. package/dist/lib/ai-test-harness-window.component.js +171 -0
  16. package/dist/lib/ai-test-harness-window.component.js.map +1 -0
  17. package/dist/lib/ai-test-harness.component.d.ts +26 -1
  18. package/dist/lib/ai-test-harness.component.d.ts.map +1 -1
  19. package/dist/lib/ai-test-harness.component.js +303 -223
  20. package/dist/lib/ai-test-harness.component.js.map +1 -1
  21. package/dist/lib/test-harness-custom-window.component.d.ts +78 -0
  22. package/dist/lib/test-harness-custom-window.component.d.ts.map +1 -0
  23. package/dist/lib/test-harness-custom-window.component.js +528 -0
  24. package/dist/lib/test-harness-custom-window.component.js.map +1 -0
  25. package/dist/lib/test-harness-window-manager.service.d.ts +59 -0
  26. package/dist/lib/test-harness-window-manager.service.d.ts.map +1 -0
  27. package/dist/lib/test-harness-window-manager.service.js +163 -0
  28. package/dist/lib/test-harness-window-manager.service.js.map +1 -0
  29. package/dist/lib/test-harness-window.service.d.ts +73 -0
  30. package/dist/lib/test-harness-window.service.d.ts.map +1 -0
  31. package/dist/lib/test-harness-window.service.js +164 -0
  32. package/dist/lib/test-harness-window.service.js.map +1 -0
  33. package/dist/lib/window-dock.service.d.ts +32 -0
  34. package/dist/lib/window-dock.service.d.ts.map +1 -0
  35. package/dist/lib/window-dock.service.js +125 -0
  36. package/dist/lib/window-dock.service.js.map +1 -0
  37. package/dist/module.d.ts +19 -17
  38. package/dist/module.d.ts.map +1 -1
  39. package/dist/module.js +23 -4
  40. package/dist/module.js.map +1 -1
  41. package/dist/public-api.d.ts +6 -1
  42. package/dist/public-api.d.ts.map +1 -1
  43. package/dist/public-api.js +6 -1
  44. package/dist/public-api.js.map +1 -1
  45. package/package.json +8 -8
  46. package/dist/lib/test-harness-dialog.service.d.ts +0 -151
  47. package/dist/lib/test-harness-dialog.service.d.ts.map +0 -1
  48. package/dist/lib/test-harness-dialog.service.js +0 -234
  49. package/dist/lib/test-harness-dialog.service.js.map +0 -1
@@ -26,7 +26,19 @@ const _c5 = () => ({ text: "Number", value: "number" });
26
26
  const _c6 = () => ({ text: "Boolean", value: "boolean" });
27
27
  const _c7 = () => ({ text: "Object", value: "object" });
28
28
  const _c8 = (a0, a1, a2, a3) => [a0, a1, a2, a3];
29
- function AITestHarnessComponent_div_0_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
29
+ function AITestHarnessComponent_div_0_Conditional_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
30
+ i0.ɵɵelement(0, "img", 14);
31
+ } if (rf & 2) {
32
+ const ctx_r1 = i0.ɵɵnextContext(3);
33
+ i0.ɵɵproperty("src", ctx_r1.getEntityLogoURL(), i0.ɵɵsanitizeUrl)("alt", ctx_r1.getEntityName() + " logo");
34
+ } }
35
+ function AITestHarnessComponent_div_0_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
36
+ i0.ɵɵelement(0, "i");
37
+ } if (rf & 2) {
38
+ const ctx_r1 = i0.ɵɵnextContext(3);
39
+ i0.ɵɵclassMap(ctx_r1.getEntityIconClass());
40
+ } }
41
+ function AITestHarnessComponent_div_0_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
30
42
  i0.ɵɵelementStart(0, "p");
31
43
  i0.ɵɵtext(1);
32
44
  i0.ɵɵelementEnd();
@@ -38,47 +50,47 @@ function AITestHarnessComponent_div_0_Conditional_2_Conditional_6_Template(rf, c
38
50
  function AITestHarnessComponent_div_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
39
51
  const _r1 = i0.ɵɵgetCurrentView();
40
52
  i0.ɵɵelementStart(0, "div", 9)(1, "div", 13);
41
- i0.ɵɵelement(2, "i", 14);
42
- i0.ɵɵelementStart(3, "div")(4, "h3");
43
- i0.ɵɵtext(5);
53
+ i0.ɵɵtemplate(2, AITestHarnessComponent_div_0_Conditional_2_Conditional_2_Template, 1, 2, "img", 14)(3, AITestHarnessComponent_div_0_Conditional_2_Conditional_3_Template, 1, 2, "i", 15);
54
+ i0.ɵɵelementStart(4, "div")(5, "h3");
55
+ i0.ɵɵtext(6);
44
56
  i0.ɵɵelementEnd();
45
- i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_2_Conditional_6_Template, 2, 1, "p");
57
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_2_Conditional_7_Template, 2, 1, "p");
46
58
  i0.ɵɵelementEnd()();
47
- i0.ɵɵelementStart(7, "div", 15)(8, "button", 16);
48
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearConversation()); });
49
- i0.ɵɵelement(9, "i", 17);
50
- i0.ɵɵtext(10, " Clear ");
51
- i0.ɵɵelementEnd();
52
- i0.ɵɵelementStart(11, "button", 18);
53
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.saveConversation()); });
54
- i0.ɵɵelement(12, "i", 19);
55
- i0.ɵɵtext(13, " Save ");
56
- i0.ɵɵelementEnd();
57
- i0.ɵɵelementStart(14, "button", 20);
58
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.exportConversation()); });
59
- i0.ɵɵelement(15, "i", 21);
60
- i0.ɵɵtext(16, " Export ");
61
- i0.ɵɵelementEnd();
62
- i0.ɵɵelementStart(17, "button", 22);
63
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.importConversation()); });
64
- i0.ɵɵelement(18, "i", 23);
65
- i0.ɵɵtext(19, " Import ");
66
- i0.ɵɵelementEnd();
67
- i0.ɵɵelementStart(20, "input", 24, 0);
68
- i0.ɵɵlistener("change", function AITestHarnessComponent_div_0_Conditional_2_Template_input_change_20_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onFileSelected($event)); });
69
- i0.ɵɵelementEnd();
70
- i0.ɵɵelementStart(22, "button", 25);
71
- i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_22_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleSidebar()); });
72
- i0.ɵɵelement(23, "i", 14);
59
+ i0.ɵɵelementStart(8, "div", 16)(9, "button", 17);
60
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearConversation()); });
61
+ i0.ɵɵelement(10, "i", 18);
62
+ i0.ɵɵtext(11, " Clear ");
63
+ i0.ɵɵelementEnd();
64
+ i0.ɵɵelementStart(12, "button", 19);
65
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.saveConversation()); });
66
+ i0.ɵɵelement(13, "i", 20);
67
+ i0.ɵɵtext(14, " Save ");
68
+ i0.ɵɵelementEnd();
69
+ i0.ɵɵelementStart(15, "button", 21);
70
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.exportConversation()); });
71
+ i0.ɵɵelement(16, "i", 22);
72
+ i0.ɵɵtext(17, " Export ");
73
+ i0.ɵɵelementEnd();
74
+ i0.ɵɵelementStart(18, "button", 23);
75
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.importConversation()); });
76
+ i0.ɵɵelement(19, "i", 24);
77
+ i0.ɵɵtext(20, " Import ");
78
+ i0.ɵɵelementEnd();
79
+ i0.ɵɵelementStart(21, "input", 25, 0);
80
+ i0.ɵɵlistener("change", function AITestHarnessComponent_div_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)); });
81
+ i0.ɵɵelementEnd();
82
+ i0.ɵɵelementStart(23, "button", 26);
83
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_2_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleSidebar()); });
84
+ i0.ɵɵelement(24, "i", 27);
73
85
  i0.ɵɵelementEnd()()();
74
86
  } if (rf & 2) {
75
87
  const ctx_r1 = i0.ɵɵnextContext(2);
76
88
  i0.ɵɵadvance(2);
77
- i0.ɵɵclassProp("fa-robot", ctx_r1.mode === "agent")("fa-comment-dots", ctx_r1.mode === "prompt");
78
- i0.ɵɵadvance(3);
89
+ i0.ɵɵconditional(ctx_r1.hasEntityLogo() ? 2 : 3);
90
+ i0.ɵɵadvance(4);
79
91
  i0.ɵɵtextInterpolate(ctx_r1.getEntityName());
80
92
  i0.ɵɵadvance();
81
- i0.ɵɵconditional(ctx_r1.entity.Description ? 6 : -1);
93
+ i0.ɵɵconditional(ctx_r1.entity.Description ? 7 : -1);
82
94
  i0.ɵɵadvance(2);
83
95
  i0.ɵɵproperty("disabled", ctx_r1.isExecuting || ctx_r1.conversationMessages.length === 0);
84
96
  i0.ɵɵadvance(3);
@@ -89,8 +101,8 @@ function AITestHarnessComponent_div_0_Conditional_2_Template(rf, ctx) { if (rf &
89
101
  i0.ɵɵclassProp("fa-chevron-right", !ctx_r1.showSidebar)("fa-chevron-left", ctx_r1.showSidebar);
90
102
  } }
91
103
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
92
- i0.ɵɵelementStart(0, "div", 28);
93
- i0.ɵɵelement(1, "i", 46);
104
+ i0.ɵɵelementStart(0, "div", 30);
105
+ i0.ɵɵelement(1, "i", 48);
94
106
  i0.ɵɵelementStart(2, "h4");
95
107
  i0.ɵɵtext(3, "Start a conversation");
96
108
  i0.ɵɵelementEnd();
@@ -99,20 +111,33 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template(rf, c
99
111
  i0.ɵɵelementEnd()();
100
112
  } }
101
113
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
102
- i0.ɵɵelement(0, "i", 60);
114
+ i0.ɵɵelement(0, "i", 62);
103
115
  i0.ɵɵtext(1, " You ");
104
116
  } }
117
+ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵelement(0, "img", 63);
119
+ } if (rf & 2) {
120
+ const ctx_r1 = i0.ɵɵnextContext(5);
121
+ i0.ɵɵproperty("src", ctx_r1.getEntityLogoURL(), i0.ɵɵsanitizeUrl)("alt", ctx_r1.getEntityName() + " logo");
122
+ } }
123
+ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
124
+ i0.ɵɵelement(0, "i");
125
+ } if (rf & 2) {
126
+ const ctx_r1 = i0.ɵɵnextContext(5);
127
+ i0.ɵɵclassMap(ctx_r1.getEntityIconClass());
128
+ } }
105
129
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
106
- i0.ɵɵelement(0, "i", 61);
107
- i0.ɵɵtext(1);
130
+ i0.ɵɵtemplate(0, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Conditional_0_Template, 1, 2, "img", 63)(1, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Conditional_1_Template, 1, 2, "i", 15);
131
+ i0.ɵɵtext(2);
108
132
  } if (rf & 2) {
109
133
  const ctx_r1 = i0.ɵɵnextContext(4);
110
- i0.ɵɵadvance();
134
+ i0.ɵɵconditional(ctx_r1.hasEntityLogo() ? 0 : 1);
135
+ i0.ɵɵadvance(2);
111
136
  i0.ɵɵtextInterpolate1(" ", ctx_r1.getEntityName() || "Assistant", " ");
112
137
  } }
113
138
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template(rf, ctx) { if (rf & 1) {
114
- i0.ɵɵelementStart(0, "span", 50);
115
- i0.ɵɵelement(1, "i", 34);
139
+ i0.ɵɵelementStart(0, "span", 52);
140
+ i0.ɵɵelement(1, "i", 36);
116
141
  i0.ɵɵtext(2);
117
142
  i0.ɵɵelementEnd();
118
143
  } if (rf & 2) {
@@ -122,7 +147,7 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template
122
147
  i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r5.elapsedTime), " ");
123
148
  } }
124
149
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template(rf, ctx) { if (rf & 1) {
125
- i0.ɵɵelementStart(0, "span", 51);
150
+ i0.ɵɵelementStart(0, "span", 53);
126
151
  i0.ɵɵtext(1);
127
152
  i0.ɵɵelementEnd();
128
153
  } if (rf & 2) {
@@ -134,15 +159,15 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template
134
159
  } }
135
160
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template(rf, ctx) { if (rf & 1) {
136
161
  const _r6 = i0.ɵɵgetCurrentView();
137
- i0.ɵɵelementStart(0, "button", 62);
162
+ i0.ɵɵelementStart(0, "button", 64);
138
163
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const message_r5 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showRawJsonDialog(message_r5)); });
139
- i0.ɵɵelement(1, "i", 63);
164
+ i0.ɵɵelement(1, "i", 65);
140
165
  i0.ɵɵelementEnd();
141
166
  } }
142
167
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Template(rf, ctx) { if (rf & 1) {
143
- i0.ɵɵelementStart(0, "div", 56);
144
- i0.ɵɵelement(1, "span", 64);
145
- i0.ɵɵelementStart(2, "span", 65);
168
+ i0.ɵɵelementStart(0, "div", 58);
169
+ i0.ɵɵelement(1, "span", 66);
170
+ i0.ɵɵelementStart(2, "span", 67);
146
171
  i0.ɵɵtext(3, "|");
147
172
  i0.ɵɵelementEnd()();
148
173
  } if (rf & 2) {
@@ -152,15 +177,15 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Templat
152
177
  i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedStreamingContent(message_r5), i0.ɵɵsanitizeHtml);
153
178
  } }
154
179
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_14_Template(rf, ctx) { if (rf & 1) {
155
- i0.ɵɵelement(0, "div", 57);
180
+ i0.ɵɵelement(0, "div", 59);
156
181
  } if (rf & 2) {
157
182
  const message_r5 = i0.ɵɵnextContext().$implicit;
158
183
  const ctx_r1 = i0.ɵɵnextContext(3);
159
184
  i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r5), i0.ɵɵsanitizeHtml);
160
185
  } }
161
186
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Template(rf, ctx) { if (rf & 1) {
162
- i0.ɵɵelementStart(0, "div", 58);
163
- i0.ɵɵelement(1, "i", 66);
187
+ i0.ɵɵelementStart(0, "div", 60);
188
+ i0.ɵɵelement(1, "i", 68);
164
189
  i0.ɵɵtext(2);
165
190
  i0.ɵɵelementEnd();
166
191
  } if (rf & 2) {
@@ -169,8 +194,8 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Templat
169
194
  i0.ɵɵtextInterpolate1(" ", message_r5.error, " ");
170
195
  } }
171
196
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Conditional_7_Template(rf, ctx) { if (rf & 1) {
172
- i0.ɵɵelementStart(0, "div", 71);
173
- i0.ɵɵelement(1, "mj-code-editor", 72);
197
+ i0.ɵɵelementStart(0, "div", 73);
198
+ i0.ɵɵelement(1, "mj-code-editor", 74);
174
199
  i0.ɵɵelementEnd();
175
200
  } if (rf & 2) {
176
201
  const message_r5 = i0.ɵɵnextContext(2).$implicit;
@@ -180,16 +205,16 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Conditi
180
205
  } }
181
206
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Template(rf, ctx) { if (rf & 1) {
182
207
  const _r7 = i0.ɵɵgetCurrentView();
183
- i0.ɵɵelementStart(0, "div", 67)(1, "div", 68);
208
+ i0.ɵɵelementStart(0, "div", 69)(1, "div", 70);
184
209
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r7); const message_r5 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.togglePayloadCollapse(message_r5)); });
185
- i0.ɵɵelementStart(2, "span", 69);
186
- i0.ɵɵelement(3, "i", 63);
210
+ i0.ɵɵelementStart(2, "span", 71);
211
+ i0.ɵɵelement(3, "i", 65);
187
212
  i0.ɵɵtext(4, " Payload ");
188
213
  i0.ɵɵelementEnd();
189
- i0.ɵɵelementStart(5, "button", 70);
190
- i0.ɵɵelement(6, "i", 14);
214
+ i0.ɵɵelementStart(5, "button", 72);
215
+ i0.ɵɵelement(6, "i", 27);
191
216
  i0.ɵɵelementEnd()();
192
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Conditional_7_Template, 2, 3, "div", 71);
217
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Conditional_7_Template, 2, 3, "div", 73);
193
218
  i0.ɵɵelementEnd();
194
219
  } if (rf & 2) {
195
220
  const message_r5 = i0.ɵɵnextContext().$implicit;
@@ -201,19 +226,19 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Templat
201
226
  } }
202
227
  function AITestHarnessComponent_div_0_Conditional_4_For_7_Template(rf, ctx) { if (rf & 1) {
203
228
  const _r4 = i0.ɵɵgetCurrentView();
204
- i0.ɵɵelementStart(0, "div", 29)(1, "div", 47)(2, "span", 48);
205
- i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Template, 2, 1);
229
+ i0.ɵɵelementStart(0, "div", 31)(1, "div", 49)(2, "span", 50);
230
+ i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_4_Template, 3, 2);
206
231
  i0.ɵɵelementEnd();
207
- i0.ɵɵelementStart(5, "span", 49);
232
+ i0.ɵɵelementStart(5, "span", 51);
208
233
  i0.ɵɵtext(6);
209
234
  i0.ɵɵelementEnd();
210
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template, 3, 1, "span", 50)(8, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template, 2, 2, "span", 51)(9, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template, 2, 0, "button", 52);
235
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_7_Template, 3, 1, "span", 52)(8, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_8_Template, 2, 2, "span", 53)(9, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_9_Template, 2, 0, "button", 54);
211
236
  i0.ɵɵelementEnd();
212
- i0.ɵɵelementStart(10, "div", 53)(11, "button", 54);
237
+ i0.ɵɵelementStart(10, "div", 55)(11, "button", 56);
213
238
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_For_7_Template_button_click_11_listener() { const message_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.copyMessage(message_r5)); });
214
- i0.ɵɵelement(12, "i", 55);
239
+ i0.ɵɵelement(12, "i", 57);
215
240
  i0.ɵɵelementEnd();
216
- i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Template, 4, 1, "div", 56)(14, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_14_Template, 1, 1, "div", 57)(15, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Template, 3, 1, "div", 58)(16, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Template, 8, 7, "div", 59);
241
+ i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_13_Template, 4, 1, "div", 58)(14, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_14_Template, 1, 1, "div", 59)(15, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_15_Template, 3, 1, "div", 60)(16, AITestHarnessComponent_div_0_Conditional_4_For_7_Conditional_16_Template, 8, 7, "div", 61);
217
242
  i0.ɵɵelementEnd()();
218
243
  } if (rf & 2) {
219
244
  const message_r5 = ctx.$implicit;
@@ -232,24 +257,24 @@ function AITestHarnessComponent_div_0_Conditional_4_For_7_Template(rf, ctx) { if
232
257
  i0.ɵɵadvance(2);
233
258
  i0.ɵɵconditional(message_r5.error ? 15 : -1);
234
259
  i0.ɵɵadvance();
235
- i0.ɵɵconditional(message_r5.payload && ctx_r1.mode === "agent" && message_r5.role === "assistant" ? 16 : -1);
260
+ i0.ɵɵconditional(ctx_r1.hasPayload(message_r5.payload) && ctx_r1.mode === "agent" && message_r5.role === "assistant" ? 16 : -1);
236
261
  } }
237
262
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_13_Template(rf, ctx) { if (rf & 1) {
238
- i0.ɵɵelement(0, "i", 34);
263
+ i0.ɵɵelement(0, "i", 36);
239
264
  } }
240
265
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_14_Template(rf, ctx) { if (rf & 1) {
241
- i0.ɵɵelement(0, "i", 35);
266
+ i0.ɵɵelement(0, "i", 37);
242
267
  } }
243
268
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template(rf, ctx) { if (rf & 1) {
244
269
  const _r8 = i0.ɵɵgetCurrentView();
245
- i0.ɵɵelementStart(0, "button", 39);
270
+ i0.ɵɵelementStart(0, "button", 41);
246
271
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("agentVariables")); });
247
- i0.ɵɵelement(1, "i", 63);
272
+ i0.ɵɵelement(1, "i", 65);
248
273
  i0.ɵɵtext(2, " Agent Variables ");
249
274
  i0.ɵɵelementEnd();
250
- i0.ɵɵelementStart(3, "button", 73);
275
+ i0.ɵɵelementStart(3, "button", 75);
251
276
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("executionMonitor")); });
252
- i0.ɵɵelement(4, "i", 74);
277
+ i0.ɵɵelement(4, "i", 76);
253
278
  i0.ɵɵtext(5, " Execution Monitor ");
254
279
  i0.ɵɵelementEnd();
255
280
  } if (rf & 2) {
@@ -261,14 +286,14 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template(rf,
261
286
  } }
262
287
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template(rf, ctx) { if (rf & 1) {
263
288
  const _r9 = i0.ɵɵgetCurrentView();
264
- i0.ɵɵelementStart(0, "button", 73);
289
+ i0.ɵɵelementStart(0, "button", 75);
265
290
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("templateVariables")); });
266
- i0.ɵɵelement(1, "i", 63);
291
+ i0.ɵɵelement(1, "i", 65);
267
292
  i0.ɵɵtext(2, " Template Variables ");
268
293
  i0.ɵɵelementEnd();
269
- i0.ɵɵelementStart(3, "button", 73);
294
+ i0.ɵɵelementStart(3, "button", 75);
270
295
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("modelSettings")); });
271
- i0.ɵɵelement(4, "i", 75);
296
+ i0.ɵɵelement(4, "i", 77);
272
297
  i0.ɵɵtext(5, " Model Settings ");
273
298
  i0.ɵɵelementEnd();
274
299
  } if (rf & 2) {
@@ -278,7 +303,7 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template(rf,
278
303
  i0.ɵɵclassProp("active", ctx_r1.activeTab === "modelSettings");
279
304
  } }
280
305
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template(rf, ctx) { if (rf & 1) {
281
- i0.ɵɵelementStart(0, "span", 41);
306
+ i0.ɵɵelementStart(0, "span", 43);
282
307
  i0.ɵɵtext(1);
283
308
  i0.ɵɵelementEnd();
284
309
  } if (rf & 2) {
@@ -287,24 +312,24 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template(rf,
287
312
  i0.ɵɵtextInterpolate(ctx_r1.savedConversations.length);
288
313
  } }
289
314
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Conditional_7_Template(rf, ctx) { if (rf & 1) {
290
- i0.ɵɵelementStart(0, "div", 78)(1, "p");
315
+ i0.ɵɵelementStart(0, "div", 80)(1, "p");
291
316
  i0.ɵɵtext(2, "No variables defined. Click \"Add Variable\" to get started.");
292
317
  i0.ɵɵelementEnd()();
293
318
  } }
294
319
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template(rf, ctx) { if (rf & 1) {
295
320
  const _r11 = i0.ɵɵgetCurrentView();
296
- i0.ɵɵelementStart(0, "div", 79)(1, "kendo-textbox", 82);
321
+ i0.ɵɵelementStart(0, "div", 81)(1, "kendo-textbox", 84);
297
322
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_textbox_ngModelChange_1_listener($event) { const variable_r12 = i0.ɵɵrestoreView(_r11).$implicit; i0.ɵɵtwoWayBindingSet(variable_r12.name, $event) || (variable_r12.name = $event); return i0.ɵɵresetView($event); });
298
323
  i0.ɵɵelementEnd();
299
- i0.ɵɵelementStart(2, "kendo-dropdownlist", 83);
324
+ i0.ɵɵelementStart(2, "kendo-dropdownlist", 85);
300
325
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { const variable_r12 = i0.ɵɵrestoreView(_r11).$implicit; i0.ɵɵtwoWayBindingSet(variable_r12.type, $event) || (variable_r12.type = $event); return i0.ɵɵresetView($event); });
301
326
  i0.ɵɵelementEnd();
302
- i0.ɵɵelementStart(3, "kendo-textbox", 84);
327
+ i0.ɵɵelementStart(3, "kendo-textbox", 86);
303
328
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_kendo_textbox_ngModelChange_3_listener($event) { const variable_r12 = i0.ɵɵrestoreView(_r11).$implicit; i0.ɵɵtwoWayBindingSet(variable_r12.value, $event) || (variable_r12.value = $event); return i0.ɵɵresetView($event); });
304
329
  i0.ɵɵelementEnd();
305
- i0.ɵɵelementStart(4, "button", 85);
330
+ i0.ɵɵelementStart(4, "button", 87);
306
331
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template_button_click_4_listener() { const $index_r13 = i0.ɵɵrestoreView(_r11).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeAgentVariable($index_r13)); });
307
- i0.ɵɵelement(5, "i", 86);
332
+ i0.ɵɵelement(5, "i", 88);
308
333
  i0.ɵɵelementEnd()();
309
334
  } if (rf & 2) {
310
335
  const variable_r12 = ctx.$implicit;
@@ -323,19 +348,19 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Templat
323
348
  } }
324
349
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template(rf, ctx) { if (rf & 1) {
325
350
  const _r10 = i0.ɵɵgetCurrentView();
326
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 76)(2, "h4");
351
+ i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
327
352
  i0.ɵɵtext(3, "Agent Variables");
328
353
  i0.ɵɵelementEnd();
329
354
  i0.ɵɵelementStart(4, "p");
330
355
  i0.ɵɵtext(5, "Variables available during agent execution and template rendering");
331
356
  i0.ɵɵelementEnd()();
332
- i0.ɵɵelementStart(6, "div", 77);
333
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Conditional_7_Template, 3, 0, "div", 78);
334
- i0.ɵɵrepeaterCreate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template, 6, 19, "div", 79, i0.ɵɵrepeaterTrackByIndex);
357
+ i0.ɵɵelementStart(6, "div", 79);
358
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Conditional_7_Template, 3, 0, "div", 80);
359
+ i0.ɵɵrepeaterCreate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_For_9_Template, 6, 19, "div", 81, i0.ɵɵrepeaterTrackByIndex);
335
360
  i0.ɵɵelementEnd();
336
- i0.ɵɵelementStart(10, "button", 80);
361
+ i0.ɵɵelementStart(10, "button", 82);
337
362
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.addAgentVariable()); });
338
- i0.ɵɵelement(11, "i", 81);
363
+ i0.ɵɵelement(11, "i", 83);
339
364
  i0.ɵɵtext(12, " Add Variable ");
340
365
  i0.ɵɵelementEnd()();
341
366
  } if (rf & 2) {
@@ -349,7 +374,7 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template(rf,
349
374
  } }
350
375
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template(rf, ctx) { if (rf & 1) {
351
376
  const _r14 = i0.ɵɵgetCurrentView();
352
- i0.ɵɵelementStart(0, "div", 44)(1, "mj-agent-execution-monitor", 87);
377
+ i0.ɵɵelementStart(0, "div", 46)(1, "mj-agent-execution-monitor", 89);
353
378
  i0.ɵɵlistener("viewRunClick", function AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template_mj_agent_execution_monitor_viewRunClick_1_listener($event) { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.navigateToRun($event)); });
354
379
  i0.ɵɵelementEnd()();
355
380
  } if (rf & 2) {
@@ -359,18 +384,18 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template(rf,
359
384
  } }
360
385
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template(rf, ctx) { if (rf & 1) {
361
386
  const _r16 = i0.ɵɵgetCurrentView();
362
- i0.ɵɵelementStart(0, "div", 79)(1, "kendo-textbox", 82);
387
+ i0.ɵɵelementStart(0, "div", 81)(1, "kendo-textbox", 84);
363
388
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_textbox_ngModelChange_1_listener($event) { const variable_r17 = i0.ɵɵrestoreView(_r16).$implicit; i0.ɵɵtwoWayBindingSet(variable_r17.name, $event) || (variable_r17.name = $event); return i0.ɵɵresetView($event); });
364
389
  i0.ɵɵelementEnd();
365
- i0.ɵɵelementStart(2, "kendo-dropdownlist", 83);
390
+ i0.ɵɵelementStart(2, "kendo-dropdownlist", 85);
366
391
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { const variable_r17 = i0.ɵɵrestoreView(_r16).$implicit; i0.ɵɵtwoWayBindingSet(variable_r17.type, $event) || (variable_r17.type = $event); return i0.ɵɵresetView($event); });
367
392
  i0.ɵɵelementEnd();
368
- i0.ɵɵelementStart(3, "kendo-textbox", 84);
393
+ i0.ɵɵelementStart(3, "kendo-textbox", 86);
369
394
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_kendo_textbox_ngModelChange_3_listener($event) { const variable_r17 = i0.ɵɵrestoreView(_r16).$implicit; i0.ɵɵtwoWayBindingSet(variable_r17.value, $event) || (variable_r17.value = $event); return i0.ɵɵresetView($event); });
370
395
  i0.ɵɵelementEnd();
371
- i0.ɵɵelementStart(4, "button", 89);
396
+ i0.ɵɵelementStart(4, "button", 91);
372
397
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template_button_click_4_listener() { const $index_r18 = i0.ɵɵrestoreView(_r16).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeTemplateVariable($index_r18)); });
373
- i0.ɵɵelement(5, "i", 86);
398
+ i0.ɵɵelement(5, "i", 88);
374
399
  i0.ɵɵelementEnd()();
375
400
  } if (rf & 2) {
376
401
  const variable_r17 = ctx.$implicit;
@@ -387,18 +412,18 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Templat
387
412
  } }
388
413
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf, ctx) { if (rf & 1) {
389
414
  const _r15 = i0.ɵɵgetCurrentView();
390
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 76)(2, "h4");
415
+ i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
391
416
  i0.ɵɵtext(3, "Template Variables");
392
417
  i0.ɵɵelementEnd();
393
418
  i0.ɵɵelementStart(4, "p");
394
419
  i0.ɵɵtext(5, "Variables for prompt template rendering");
395
420
  i0.ɵɵelementEnd()();
396
- i0.ɵɵelementStart(6, "div", 77);
397
- i0.ɵɵrepeaterCreate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template, 6, 18, "div", 79, i0.ɵɵrepeaterTrackByIndex);
421
+ i0.ɵɵelementStart(6, "div", 79);
422
+ i0.ɵɵrepeaterCreate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template, 6, 18, "div", 81, i0.ɵɵrepeaterTrackByIndex);
398
423
  i0.ɵɵelementEnd();
399
- i0.ɵɵelementStart(9, "button", 88);
424
+ i0.ɵɵelementStart(9, "button", 90);
400
425
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.addTemplateVariable()); });
401
- i0.ɵɵelement(10, "i", 81);
426
+ i0.ɵɵelement(10, "i", 83);
402
427
  i0.ɵɵtext(11, " Add Variable ");
403
428
  i0.ɵɵelementEnd()();
404
429
  } if (rf & 2) {
@@ -417,10 +442,10 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_2
417
442
  } }
418
443
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template(rf, ctx) { if (rf & 1) {
419
444
  const _r20 = i0.ɵɵgetCurrentView();
420
- i0.ɵɵelementStart(0, "div", 93)(1, "label", 116);
445
+ i0.ɵɵelementStart(0, "div", 95)(1, "label", 118);
421
446
  i0.ɵɵtext(2, " Top Log Probs ");
422
447
  i0.ɵɵelementEnd();
423
- i0.ɵɵelementStart(3, "kendo-numerictextbox", 117);
448
+ i0.ɵɵelementStart(3, "kendo-numerictextbox", 119);
424
449
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template_kendo_numerictextbox_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topLogProbs, $event) || (ctx_r1.advancedParams.topLogProbs = $event); return i0.ɵɵresetView($event); });
425
450
  i0.ɵɵelementEnd()();
426
451
  } if (rf & 2) {
@@ -431,119 +456,119 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_7
431
456
  } }
432
457
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf, ctx) { if (rf & 1) {
433
458
  const _r19 = i0.ɵɵgetCurrentView();
434
- i0.ɵɵelementStart(0, "div", 45)(1, "div", 76)(2, "h4");
459
+ i0.ɵɵelementStart(0, "div", 47)(1, "div", 78)(2, "h4");
435
460
  i0.ɵɵtext(3, "Model Settings");
436
461
  i0.ɵɵelementEnd();
437
462
  i0.ɵɵelementStart(4, "p");
438
463
  i0.ɵɵtext(5, "Configure AI model parameters");
439
464
  i0.ɵɵelementEnd();
440
- i0.ɵɵelementStart(6, "button", 90);
465
+ i0.ɵɵelementStart(6, "button", 92);
441
466
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.resetToPromptDefaults()); });
442
- i0.ɵɵelement(7, "i", 91);
467
+ i0.ɵɵelement(7, "i", 93);
443
468
  i0.ɵɵelementEnd()();
444
- i0.ɵɵelementStart(8, "div", 92)(9, "div", 93)(10, "label");
469
+ i0.ɵɵelementStart(8, "div", 94)(9, "div", 95)(10, "label");
445
470
  i0.ɵɵtext(11, "AI Model");
446
471
  i0.ɵɵelementEnd();
447
- i0.ɵɵelementStart(12, "kendo-dropdownlist", 94);
472
+ i0.ɵɵelementStart(12, "kendo-dropdownlist", 96);
448
473
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedModelId, $event) || (ctx_r1.selectedModelId = $event); return i0.ɵɵresetView($event); });
449
474
  i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_12_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onModelSelectionChange()); });
450
475
  i0.ɵɵelementEnd()();
451
- i0.ɵɵelementStart(13, "div", 93)(14, "label");
476
+ i0.ɵɵelementStart(13, "div", 95)(14, "label");
452
477
  i0.ɵɵtext(15, "AI Vendor");
453
478
  i0.ɵɵelementEnd();
454
- i0.ɵɵelementStart(16, "kendo-dropdownlist", 95);
479
+ i0.ɵɵelementStart(16, "kendo-dropdownlist", 97);
455
480
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedVendorId, $event) || (ctx_r1.selectedVendorId = $event); return i0.ɵɵresetView($event); });
456
481
  i0.ɵɵelementEnd();
457
- i0.ɵɵelementStart(17, "div", 96);
482
+ i0.ɵɵelementStart(17, "div", 98);
458
483
  i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_18_Template, 1, 0)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_19_Template, 1, 0)(20, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_20_Template, 1, 0);
459
484
  i0.ɵɵelementEnd()();
460
- i0.ɵɵelementStart(21, "div", 93)(22, "label");
485
+ i0.ɵɵelementStart(21, "div", 95)(22, "label");
461
486
  i0.ɵɵtext(23, "Response Format");
462
487
  i0.ɵɵelementEnd();
463
- i0.ɵɵelementStart(24, "kendo-dropdownlist", 97);
488
+ i0.ɵɵelementStart(24, "kendo-dropdownlist", 99);
464
489
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_dropdownlist_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedResponseFormat, $event) || (ctx_r1.selectedResponseFormat = $event); return i0.ɵɵresetView($event); });
465
490
  i0.ɵɵelementEnd();
466
- i0.ɵɵelementStart(25, "div", 96);
491
+ i0.ɵɵelementStart(25, "div", 98);
467
492
  i0.ɵɵtext(26, " Expected format for AI response (defaults to prompt setting) ");
468
493
  i0.ɵɵelementEnd()();
469
- i0.ɵɵelementStart(27, "div", 93)(28, "label");
494
+ i0.ɵɵelementStart(27, "div", 95)(28, "label");
470
495
  i0.ɵɵtext(29, "Max Tokens");
471
496
  i0.ɵɵelementEnd();
472
- i0.ɵɵelementStart(30, "kendo-numerictextbox", 98);
497
+ i0.ɵɵelementStart(30, "kendo-numerictextbox", 100);
473
498
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_30_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.maxTokens, $event) || (ctx_r1.maxTokens = $event); return i0.ɵɵresetView($event); });
474
499
  i0.ɵɵelementEnd();
475
- i0.ɵɵelementStart(31, "div", 96);
500
+ i0.ɵɵelementStart(31, "div", 98);
476
501
  i0.ɵɵtext(32, " Maximum length of generated response ");
477
502
  i0.ɵɵelementEnd()();
478
- i0.ɵɵelementStart(33, "div", 93)(34, "label", 99)(35, "input", 100);
503
+ i0.ɵɵelementStart(33, "div", 95)(34, "label", 101)(35, "input", 102);
479
504
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_input_ngModelChange_35_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.skipValidation, $event) || (ctx_r1.skipValidation = $event); return i0.ɵɵresetView($event); });
480
505
  i0.ɵɵelementEnd();
481
506
  i0.ɵɵtext(36, " Skip Validation ");
482
507
  i0.ɵɵelementEnd();
483
- i0.ɵɵelementStart(37, "div", 96);
508
+ i0.ɵɵelementStart(37, "div", 98);
484
509
  i0.ɵɵtext(38, " Skip output validation during testing ");
485
510
  i0.ɵɵelementEnd()();
486
- i0.ɵɵelementStart(39, "kendo-expansionpanel", 101);
511
+ i0.ɵɵelementStart(39, "kendo-expansionpanel", 103);
487
512
  i0.ɵɵlistener("action", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_expansionpanel_action_39_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleAdvancedParams()); });
488
- i0.ɵɵelementStart(40, "div", 102)(41, "div", 93)(42, "label", 103);
513
+ i0.ɵɵelementStart(40, "div", 104)(41, "div", 95)(42, "label", 105);
489
514
  i0.ɵɵtext(43, " Temperature ");
490
515
  i0.ɵɵelementEnd();
491
- i0.ɵɵelementStart(44, "kendo-numerictextbox", 104);
516
+ i0.ɵɵelementStart(44, "kendo-numerictextbox", 106);
492
517
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_44_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.temperature, $event) || (ctx_r1.advancedParams.temperature = $event); return i0.ɵɵresetView($event); });
493
518
  i0.ɵɵelementEnd()();
494
- i0.ɵɵelementStart(45, "div", 93)(46, "label", 105);
519
+ i0.ɵɵelementStart(45, "div", 95)(46, "label", 107);
495
520
  i0.ɵɵtext(47, " Top P ");
496
521
  i0.ɵɵelementEnd();
497
- i0.ɵɵelementStart(48, "kendo-numerictextbox", 104);
522
+ i0.ɵɵelementStart(48, "kendo-numerictextbox", 106);
498
523
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_48_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topP, $event) || (ctx_r1.advancedParams.topP = $event); return i0.ɵɵresetView($event); });
499
524
  i0.ɵɵelementEnd()();
500
- i0.ɵɵelementStart(49, "div", 93)(50, "label", 106);
525
+ i0.ɵɵelementStart(49, "div", 95)(50, "label", 108);
501
526
  i0.ɵɵtext(51, " Top K ");
502
527
  i0.ɵɵelementEnd();
503
- i0.ɵɵelementStart(52, "kendo-numerictextbox", 104);
528
+ i0.ɵɵelementStart(52, "kendo-numerictextbox", 106);
504
529
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_52_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topK, $event) || (ctx_r1.advancedParams.topK = $event); return i0.ɵɵresetView($event); });
505
530
  i0.ɵɵelementEnd()();
506
- i0.ɵɵelementStart(53, "div", 93)(54, "label", 107);
531
+ i0.ɵɵelementStart(53, "div", 95)(54, "label", 109);
507
532
  i0.ɵɵtext(55, " Min P ");
508
533
  i0.ɵɵelementEnd();
509
- i0.ɵɵelementStart(56, "kendo-numerictextbox", 104);
534
+ i0.ɵɵelementStart(56, "kendo-numerictextbox", 106);
510
535
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_56_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.minP, $event) || (ctx_r1.advancedParams.minP = $event); return i0.ɵɵresetView($event); });
511
536
  i0.ɵɵelementEnd()();
512
- i0.ɵɵelementStart(57, "div", 93)(58, "label", 108);
537
+ i0.ɵɵelementStart(57, "div", 95)(58, "label", 110);
513
538
  i0.ɵɵtext(59, " Frequency Penalty ");
514
539
  i0.ɵɵelementEnd();
515
- i0.ɵɵelementStart(60, "kendo-numerictextbox", 104);
540
+ i0.ɵɵelementStart(60, "kendo-numerictextbox", 106);
516
541
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_60_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.frequencyPenalty, $event) || (ctx_r1.advancedParams.frequencyPenalty = $event); return i0.ɵɵresetView($event); });
517
542
  i0.ɵɵelementEnd()();
518
- i0.ɵɵelementStart(61, "div", 93)(62, "label", 109);
543
+ i0.ɵɵelementStart(61, "div", 95)(62, "label", 111);
519
544
  i0.ɵɵtext(63, " Presence Penalty ");
520
545
  i0.ɵɵelementEnd();
521
- i0.ɵɵelementStart(64, "kendo-numerictextbox", 104);
546
+ i0.ɵɵelementStart(64, "kendo-numerictextbox", 106);
522
547
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_64_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.presencePenalty, $event) || (ctx_r1.advancedParams.presencePenalty = $event); return i0.ɵɵresetView($event); });
523
548
  i0.ɵɵelementEnd()();
524
- i0.ɵɵelementStart(65, "div", 93)(66, "label", 110);
549
+ i0.ɵɵelementStart(65, "div", 95)(66, "label", 112);
525
550
  i0.ɵɵtext(67, " Seed ");
526
551
  i0.ɵɵelementEnd();
527
- i0.ɵɵelementStart(68, "kendo-numerictextbox", 111);
552
+ i0.ɵɵelementStart(68, "kendo-numerictextbox", 113);
528
553
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_numerictextbox_ngModelChange_68_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.seed, $event) || (ctx_r1.advancedParams.seed = $event); return i0.ɵɵresetView($event); });
529
554
  i0.ɵɵelementEnd()();
530
- i0.ɵɵelementStart(69, "div", 93)(70, "label", 112);
555
+ i0.ɵɵelementStart(69, "div", 95)(70, "label", 114);
531
556
  i0.ɵɵtext(71, " Stop Sequences ");
532
557
  i0.ɵɵelementEnd();
533
- i0.ɵɵelementStart(72, "kendo-textarea", 113);
558
+ i0.ɵɵelementStart(72, "kendo-textarea", 115);
534
559
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_textarea_ngModelChange_72_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.stopSequencesText, $event) || (ctx_r1.stopSequencesText = $event); return i0.ɵɵresetView($event); });
535
560
  i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_textarea_ngModelChange_72_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.updateStopSequences()); });
536
561
  i0.ɵɵelementEnd();
537
- i0.ɵɵelementStart(73, "div", 96);
562
+ i0.ɵɵelementStart(73, "div", 98);
538
563
  i0.ɵɵtext(74, " Separate multiple sequences with commas ");
539
564
  i0.ɵɵelementEnd()();
540
- i0.ɵɵelementStart(75, "div", 93)(76, "label", 114);
565
+ i0.ɵɵelementStart(75, "div", 95)(76, "label", 116);
541
566
  i0.ɵɵtext(77, " Include Log Probs ");
542
567
  i0.ɵɵelementEnd();
543
- i0.ɵɵelementStart(78, "kendo-switch", 115);
568
+ i0.ɵɵelementStart(78, "kendo-switch", 117);
544
569
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_kendo_switch_ngModelChange_78_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.includeLogProbs, $event) || (ctx_r1.advancedParams.includeLogProbs = $event); return i0.ɵɵresetView($event); });
545
570
  i0.ɵɵelementEnd()();
546
- i0.ɵɵtemplate(79, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template, 4, 5, "div", 93);
571
+ i0.ɵɵtemplate(79, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template, 4, 5, "div", 95);
547
572
  i0.ɵɵelementEnd()()()();
548
573
  } if (rf & 2) {
549
574
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -596,36 +621,36 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf,
596
621
  } }
597
622
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template(rf, ctx) { if (rf & 1) {
598
623
  const _r21 = i0.ɵɵgetCurrentView();
599
- i0.ɵɵelementStart(0, "button", 122);
624
+ i0.ɵɵelementStart(0, "button", 124);
600
625
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.newConversation()); });
601
- i0.ɵɵelement(1, "i", 81);
626
+ i0.ɵɵelement(1, "i", 83);
602
627
  i0.ɵɵtext(2, " New ");
603
628
  i0.ɵɵelementEnd();
604
629
  } }
605
630
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template(rf, ctx) { if (rf & 1) {
606
- i0.ɵɵelementStart(0, "div", 120);
607
- i0.ɵɵelement(1, "i", 123);
631
+ i0.ɵɵelementStart(0, "div", 122);
632
+ i0.ɵɵelement(1, "i", 125);
608
633
  i0.ɵɵelementStart(2, "p");
609
634
  i0.ɵɵtext(3, "No saved conversations");
610
635
  i0.ɵɵelementEnd()();
611
636
  } }
612
637
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template(rf, ctx) { if (rf & 1) {
613
638
  const _r22 = i0.ɵɵgetCurrentView();
614
- i0.ɵɵelementStart(0, "div", 124);
639
+ i0.ɵɵelementStart(0, "div", 126);
615
640
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template_div_click_0_listener() { const conv_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.loadConversation(conv_r23)); });
616
- i0.ɵɵelementStart(1, "div", 125)(2, "h5");
641
+ i0.ɵɵelementStart(1, "div", 127)(2, "h5");
617
642
  i0.ɵɵtext(3);
618
643
  i0.ɵɵelementEnd();
619
644
  i0.ɵɵelementStart(4, "p");
620
645
  i0.ɵɵtext(5);
621
646
  i0.ɵɵelementEnd();
622
- i0.ɵɵelementStart(6, "span", 126);
647
+ i0.ɵɵelementStart(6, "span", 128);
623
648
  i0.ɵɵtext(7);
624
649
  i0.ɵɵpipe(8, "date");
625
650
  i0.ɵɵelementEnd()();
626
- i0.ɵɵelementStart(9, "button", 127);
651
+ i0.ɵɵelementStart(9, "button", 129);
627
652
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template_button_click_9_listener($event) { const conv_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.deleteConversation(conv_r23, $event)); });
628
- i0.ɵɵelement(10, "i", 128);
653
+ i0.ɵɵelement(10, "i", 130);
629
654
  i0.ɵɵelementEnd()();
630
655
  } if (rf & 2) {
631
656
  const conv_r23 = ctx.$implicit;
@@ -639,17 +664,17 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Templa
639
664
  i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(8, 5, conv_r23.updatedAt, "short"));
640
665
  } }
641
666
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template(rf, ctx) { if (rf & 1) {
642
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 76)(2, "h4");
667
+ i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
643
668
  i0.ɵɵtext(3, "Saved Conversations");
644
669
  i0.ɵɵelementEnd();
645
670
  i0.ɵɵelementStart(4, "p");
646
671
  i0.ɵɵtext(5, "Previously saved test sessions");
647
672
  i0.ɵɵelementEnd();
648
- i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template, 3, 0, "button", 118);
673
+ i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template, 3, 0, "button", 120);
649
674
  i0.ɵɵelementEnd();
650
- i0.ɵɵelementStart(7, "div", 119);
651
- i0.ɵɵtemplate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template, 4, 0, "div", 120);
652
- i0.ɵɵrepeaterCreate(9, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template, 11, 8, "div", 121, _forTrack0);
675
+ i0.ɵɵelementStart(7, "div", 121);
676
+ i0.ɵɵtemplate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template, 4, 0, "div", 122);
677
+ i0.ɵɵrepeaterCreate(9, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template, 11, 8, "div", 123, _forTrack0);
653
678
  i0.ɵɵelementEnd()();
654
679
  } if (rf & 2) {
655
680
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -662,28 +687,28 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template(rf,
662
687
  } }
663
688
  function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
664
689
  const _r3 = i0.ɵɵgetCurrentView();
665
- i0.ɵɵelementStart(0, "kendo-splitter", 11)(1, "kendo-splitter-pane", 26)(2, "div", 12)(3, "div", 27, 1);
666
- i0.ɵɵtemplate(5, AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template, 6, 0, "div", 28);
667
- i0.ɵɵrepeaterCreate(6, AITestHarnessComponent_div_0_Conditional_4_For_7_Template, 17, 8, "div", 29, _forTrack0);
690
+ i0.ɵɵelementStart(0, "kendo-splitter", 11)(1, "kendo-splitter-pane", 28)(2, "div", 12)(3, "div", 29, 1);
691
+ i0.ɵɵtemplate(5, AITestHarnessComponent_div_0_Conditional_4_Conditional_5_Template, 6, 0, "div", 30);
692
+ i0.ɵɵrepeaterCreate(6, AITestHarnessComponent_div_0_Conditional_4_For_7_Template, 17, 8, "div", 31, _forTrack0);
668
693
  i0.ɵɵelementEnd();
669
- i0.ɵɵelementStart(8, "div", 30)(9, "div", 31)(10, "kendo-textarea", 32, 2);
694
+ i0.ɵɵelementStart(8, "div", 32)(9, "div", 33)(10, "kendo-textarea", 34, 2);
670
695
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Template_kendo_textarea_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
671
696
  i0.ɵɵlistener("keypress", function AITestHarnessComponent_div_0_Conditional_4_Template_kendo_textarea_keypress_10_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
672
697
  i0.ɵɵelementEnd();
673
- i0.ɵɵelementStart(12, "button", 33);
698
+ i0.ɵɵelementStart(12, "button", 35);
674
699
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
675
- i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_Conditional_13_Template, 1, 0, "i", 34)(14, AITestHarnessComponent_div_0_Conditional_4_Conditional_14_Template, 1, 0, "i", 35);
700
+ i0.ɵɵtemplate(13, AITestHarnessComponent_div_0_Conditional_4_Conditional_13_Template, 1, 0, "i", 36)(14, AITestHarnessComponent_div_0_Conditional_4_Conditional_14_Template, 1, 0, "i", 37);
676
701
  i0.ɵɵelementEnd()()()()();
677
- i0.ɵɵelementStart(15, "kendo-splitter-pane", 36)(16, "div", 37)(17, "div", 38);
702
+ i0.ɵɵelementStart(15, "kendo-splitter-pane", 38)(16, "div", 39)(17, "div", 40);
678
703
  i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template, 6, 5)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template, 6, 4);
679
- i0.ɵɵelementStart(20, "button", 39);
704
+ i0.ɵɵelementStart(20, "button", 41);
680
705
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.selectTab("savedConversations")); });
681
- i0.ɵɵelement(21, "i", 40);
706
+ i0.ɵɵelement(21, "i", 42);
682
707
  i0.ɵɵtext(22, " Saved ");
683
- i0.ɵɵtemplate(23, AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template, 2, 1, "span", 41);
708
+ i0.ɵɵtemplate(23, AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template, 2, 1, "span", 43);
684
709
  i0.ɵɵelementEnd()();
685
- i0.ɵɵelementStart(24, "div", 42);
686
- i0.ɵɵtemplate(25, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template, 13, 2, "div", 43)(26, AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template, 2, 5, "div", 44)(27, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template, 12, 0, "div", 43)(28, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template, 80, 52, "div", 45)(29, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template, 11, 2, "div", 43);
710
+ i0.ɵɵelementStart(24, "div", 44);
711
+ i0.ɵɵtemplate(25, AITestHarnessComponent_div_0_Conditional_4_Conditional_25_Template, 13, 2, "div", 45)(26, AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template, 2, 5, "div", 46)(27, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template, 12, 0, "div", 45)(28, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template, 80, 52, "div", 47)(29, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template, 11, 2, "div", 45);
687
712
  i0.ɵɵelementEnd()()()();
688
713
  } if (rf & 2) {
689
714
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -721,8 +746,8 @@ function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf &
721
746
  i0.ɵɵconditional(ctx_r1.activeTab === "savedConversations" ? 29 : -1);
722
747
  } }
723
748
  function AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
724
- i0.ɵɵelementStart(0, "div", 28);
725
- i0.ɵɵelement(1, "i", 46);
749
+ i0.ɵɵelementStart(0, "div", 30);
750
+ i0.ɵɵelement(1, "i", 48);
726
751
  i0.ɵɵelementStart(2, "h4");
727
752
  i0.ɵɵtext(3, "Start a conversation");
728
753
  i0.ɵɵelementEnd();
@@ -731,11 +756,11 @@ function AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template(rf, c
731
756
  i0.ɵɵelementEnd()();
732
757
  } }
733
758
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
734
- i0.ɵɵelement(0, "i", 60);
759
+ i0.ɵɵelement(0, "i", 62);
735
760
  i0.ɵɵtext(1, " You ");
736
761
  } }
737
762
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
738
- i0.ɵɵelement(0, "i", 61);
763
+ i0.ɵɵelement(0, "i", 133);
739
764
  i0.ɵɵtext(1);
740
765
  } if (rf & 2) {
741
766
  const ctx_r1 = i0.ɵɵnextContext(4);
@@ -743,8 +768,8 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template
743
768
  i0.ɵɵtextInterpolate1(" ", ctx_r1.getEntityName() || "Assistant", " ");
744
769
  } }
745
770
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template(rf, ctx) { if (rf & 1) {
746
- i0.ɵɵelementStart(0, "span", 50);
747
- i0.ɵɵelement(1, "i", 34);
771
+ i0.ɵɵelementStart(0, "span", 52);
772
+ i0.ɵɵelement(1, "i", 36);
748
773
  i0.ɵɵtext(2);
749
774
  i0.ɵɵelementEnd();
750
775
  } if (rf & 2) {
@@ -754,7 +779,7 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template
754
779
  i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r26.elapsedTime), " ");
755
780
  } }
756
781
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template(rf, ctx) { if (rf & 1) {
757
- i0.ɵɵelementStart(0, "span", 51);
782
+ i0.ɵɵelementStart(0, "span", 53);
758
783
  i0.ɵɵtext(1);
759
784
  i0.ɵɵelementEnd();
760
785
  } if (rf & 2) {
@@ -766,29 +791,29 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template
766
791
  } }
767
792
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template(rf, ctx) { if (rf & 1) {
768
793
  const _r27 = i0.ɵɵgetCurrentView();
769
- i0.ɵɵelementStart(0, "button", 62);
794
+ i0.ɵɵelementStart(0, "button", 64);
770
795
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r27); const message_r26 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showRawJsonDialog(message_r26)); });
771
- i0.ɵɵelement(1, "i", 63);
796
+ i0.ɵɵelement(1, "i", 65);
772
797
  i0.ɵɵelementEnd();
773
798
  } }
774
799
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template(rf, ctx) { if (rf & 1) {
775
800
  const _r28 = i0.ɵɵgetCurrentView();
776
- i0.ɵɵelementStart(0, "button", 131);
801
+ i0.ɵɵelementStart(0, "button", 134);
777
802
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r28); const message_r26 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showMessageExecutionHistory(message_r26)); });
778
- i0.ɵɵelement(1, "i", 74);
803
+ i0.ɵɵelement(1, "i", 76);
779
804
  i0.ɵɵelementEnd();
780
805
  } }
781
806
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
782
807
  const _r29 = i0.ɵɵgetCurrentView();
783
- i0.ɵɵelementStart(0, "button", 132);
808
+ i0.ɵɵelementStart(0, "button", 135);
784
809
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r29); const message_r26 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.navigateToAgentRun(message_r26.agentRunId)); });
785
- i0.ɵɵelement(1, "i", 133);
810
+ i0.ɵɵelement(1, "i", 136);
786
811
  i0.ɵɵelementEnd();
787
812
  } }
788
813
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template(rf, ctx) { if (rf & 1) {
789
- i0.ɵɵelementStart(0, "div", 56)(1, "span", 134);
814
+ i0.ɵɵelementStart(0, "div", 58)(1, "span", 137);
790
815
  i0.ɵɵtext(2);
791
- i0.ɵɵelementStart(3, "span", 65);
816
+ i0.ɵɵelementStart(3, "span", 67);
792
817
  i0.ɵɵtext(4, "|");
793
818
  i0.ɵɵelementEnd()()();
794
819
  } if (rf & 2) {
@@ -797,15 +822,15 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Templat
797
822
  i0.ɵɵtextInterpolate(message_r26.streamingContent);
798
823
  } }
799
824
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template(rf, ctx) { if (rf & 1) {
800
- i0.ɵɵelement(0, "div", 57);
825
+ i0.ɵɵelement(0, "div", 59);
801
826
  } if (rf & 2) {
802
827
  const message_r26 = i0.ɵɵnextContext().$implicit;
803
828
  const ctx_r1 = i0.ɵɵnextContext(3);
804
829
  i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r26), i0.ɵɵsanitizeHtml);
805
830
  } }
806
831
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Template(rf, ctx) { if (rf & 1) {
807
- i0.ɵɵelementStart(0, "div", 58);
808
- i0.ɵɵelement(1, "i", 66);
832
+ i0.ɵɵelementStart(0, "div", 60);
833
+ i0.ɵɵelement(1, "i", 68);
809
834
  i0.ɵɵtext(2);
810
835
  i0.ɵɵelementEnd();
811
836
  } if (rf & 2) {
@@ -814,7 +839,7 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Templat
814
839
  i0.ɵɵtextInterpolate1(" ", message_r26.error, " ");
815
840
  } }
816
841
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template(rf, ctx) { if (rf & 1) {
817
- i0.ɵɵelementStart(0, "div", 71)(1, "pre");
842
+ i0.ɵɵelementStart(0, "div", 73)(1, "pre");
818
843
  i0.ɵɵtext(2);
819
844
  i0.ɵɵelementEnd()();
820
845
  } if (rf & 2) {
@@ -825,16 +850,16 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditi
825
850
  } }
826
851
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template(rf, ctx) { if (rf & 1) {
827
852
  const _r30 = i0.ɵɵgetCurrentView();
828
- i0.ɵɵelementStart(0, "div", 67)(1, "div", 68);
853
+ i0.ɵɵelementStart(0, "div", 69)(1, "div", 70);
829
854
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r30); const message_r26 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.togglePayloadCollapse(message_r26)); });
830
- i0.ɵɵelementStart(2, "span", 69);
831
- i0.ɵɵelement(3, "i", 63);
855
+ i0.ɵɵelementStart(2, "span", 71);
856
+ i0.ɵɵelement(3, "i", 65);
832
857
  i0.ɵɵtext(4, " Payload ");
833
858
  i0.ɵɵelementEnd();
834
- i0.ɵɵelementStart(5, "button", 70);
835
- i0.ɵɵelement(6, "i", 14);
859
+ i0.ɵɵelementStart(5, "button", 72);
860
+ i0.ɵɵelement(6, "i", 27);
836
861
  i0.ɵɵelementEnd()();
837
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template, 3, 1, "div", 71);
862
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template, 3, 1, "div", 73);
838
863
  i0.ɵɵelementEnd();
839
864
  } if (rf & 2) {
840
865
  const message_r26 = i0.ɵɵnextContext().$implicit;
@@ -846,19 +871,19 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Templat
846
871
  } }
847
872
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Template(rf, ctx) { if (rf & 1) {
848
873
  const _r25 = i0.ɵɵgetCurrentView();
849
- i0.ɵɵelementStart(0, "div", 29)(1, "div", 47)(2, "span", 48);
874
+ i0.ɵɵelementStart(0, "div", 31)(1, "div", 49)(2, "span", 50);
850
875
  i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_3_Template, 2, 0)(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template, 2, 1);
851
876
  i0.ɵɵelementEnd();
852
- i0.ɵɵelementStart(5, "span", 49);
877
+ i0.ɵɵelementStart(5, "span", 51);
853
878
  i0.ɵɵtext(6);
854
879
  i0.ɵɵelementEnd();
855
- i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template, 3, 1, "span", 50)(8, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template, 2, 2, "span", 51)(9, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template, 2, 0, "button", 52)(10, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template, 2, 0, "button", 129)(11, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template, 2, 0, "button", 130);
880
+ i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template, 3, 1, "span", 52)(8, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template, 2, 2, "span", 53)(9, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template, 2, 0, "button", 54)(10, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template, 2, 0, "button", 131)(11, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template, 2, 0, "button", 132);
856
881
  i0.ɵɵelementEnd();
857
- i0.ɵɵelementStart(12, "div", 53)(13, "button", 54);
882
+ i0.ɵɵelementStart(12, "div", 55)(13, "button", 56);
858
883
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Template_button_click_13_listener() { const message_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.copyMessage(message_r26)); });
859
- i0.ɵɵelement(14, "i", 55);
884
+ i0.ɵɵelement(14, "i", 57);
860
885
  i0.ɵɵelementEnd();
861
- i0.ɵɵtemplate(15, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template, 5, 1, "div", 56)(16, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template, 1, 1, "div", 57)(17, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Template, 3, 1, "div", 58)(18, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template, 8, 7, "div", 59);
886
+ i0.ɵɵtemplate(15, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template, 5, 1, "div", 58)(16, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template, 1, 1, "div", 59)(17, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Template, 3, 1, "div", 60)(18, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template, 8, 7, "div", 61);
862
887
  i0.ɵɵelementEnd()();
863
888
  } if (rf & 2) {
864
889
  const message_r26 = ctx.$implicit;
@@ -881,27 +906,27 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Template(rf, ctx) { if
881
906
  i0.ɵɵadvance(2);
882
907
  i0.ɵɵconditional(message_r26.error ? 17 : -1);
883
908
  i0.ɵɵadvance();
884
- i0.ɵɵconditional(message_r26.payload && ctx_r1.mode === "agent" && message_r26.role === "assistant" ? 18 : -1);
909
+ i0.ɵɵconditional(ctx_r1.hasPayload(message_r26.payload) && ctx_r1.mode === "agent" && message_r26.role === "assistant" ? 18 : -1);
885
910
  } }
886
911
  function AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
887
- i0.ɵɵelement(0, "i", 34);
912
+ i0.ɵɵelement(0, "i", 36);
888
913
  } }
889
914
  function AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template(rf, ctx) { if (rf & 1) {
890
- i0.ɵɵelement(0, "i", 35);
915
+ i0.ɵɵelement(0, "i", 37);
891
916
  } }
892
917
  function AITestHarnessComponent_div_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
893
918
  const _r24 = i0.ɵɵgetCurrentView();
894
- i0.ɵɵelementStart(0, "div", 12)(1, "div", 27, 1);
895
- i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template, 6, 0, "div", 28);
896
- i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Template, 19, 10, "div", 29, _forTrack0);
919
+ i0.ɵɵelementStart(0, "div", 12)(1, "div", 29, 1);
920
+ i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template, 6, 0, "div", 30);
921
+ i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Template, 19, 10, "div", 31, _forTrack0);
897
922
  i0.ɵɵelementEnd();
898
- i0.ɵɵelementStart(6, "div", 30)(7, "div", 31)(8, "kendo-textarea", 32, 2);
923
+ i0.ɵɵelementStart(6, "div", 32)(7, "div", 33)(8, "kendo-textarea", 34, 2);
899
924
  i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
900
925
  i0.ɵɵlistener("keypress", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_keypress_8_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
901
926
  i0.ɵɵelementEnd();
902
- i0.ɵɵelementStart(10, "button", 33);
927
+ i0.ɵɵelementStart(10, "button", 35);
903
928
  i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
904
- i0.ɵɵtemplate(11, AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template, 1, 0, "i", 34)(12, AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template, 1, 0, "i", 35);
929
+ i0.ɵɵtemplate(11, AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template, 1, 0, "i", 36)(12, AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template, 1, 0, "i", 37);
905
930
  i0.ɵɵelementEnd()()()();
906
931
  } if (rf & 2) {
907
932
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -919,7 +944,7 @@ function AITestHarnessComponent_div_0_Conditional_5_Template(rf, ctx) { if (rf &
919
944
  } }
920
945
  function AITestHarnessComponent_div_0_Template(rf, ctx) { if (rf & 1) {
921
946
  i0.ɵɵelementStart(0, "div", 7)(1, "div", 8);
922
- i0.ɵɵtemplate(2, AITestHarnessComponent_div_0_Conditional_2_Template, 24, 13, "div", 9);
947
+ i0.ɵɵtemplate(2, AITestHarnessComponent_div_0_Conditional_2_Template, 25, 10, "div", 9);
923
948
  i0.ɵɵelementEnd();
924
949
  i0.ɵɵelementStart(3, "div", 10);
925
950
  i0.ɵɵtemplate(4, AITestHarnessComponent_div_0_Conditional_4_Template, 30, 23, "kendo-splitter", 11)(5, AITestHarnessComponent_div_0_Conditional_5_Template, 13, 6, "div", 12);
@@ -933,19 +958,19 @@ function AITestHarnessComponent_div_0_Template(rf, ctx) { if (rf & 1) {
933
958
  } }
934
959
  function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
935
960
  const _r31 = i0.ɵɵgetCurrentView();
936
- i0.ɵɵelementStart(0, "kendo-dialog", 135);
961
+ i0.ɵɵelementStart(0, "kendo-dialog", 138);
937
962
  i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_1_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
938
- i0.ɵɵelementStart(1, "div", 136)(2, "p");
963
+ i0.ɵɵelementStart(1, "div", 139)(2, "p");
939
964
  i0.ɵɵtext(3, "Enter a name for this conversation:");
940
965
  i0.ɵɵelementEnd();
941
- i0.ɵɵelementStart(4, "input", 137, 3);
966
+ i0.ɵɵelementStart(4, "input", 140, 3);
942
967
  i0.ɵɵlistener("keyup", function AITestHarnessComponent_Conditional_1_Template_input_keyup_4_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateTempConversation()); });
943
968
  i0.ɵɵelementEnd()();
944
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 138);
969
+ i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 141);
945
970
  i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
946
971
  i0.ɵɵtext(8, "Cancel");
947
972
  i0.ɵɵelementEnd();
948
- i0.ɵɵelementStart(9, "button", 139);
973
+ i0.ɵɵelementStart(9, "button", 142);
949
974
  i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmSaveConversation()); });
950
975
  i0.ɵɵtext(10, " Save ");
951
976
  i0.ɵɵelementEnd()()();
@@ -957,19 +982,19 @@ function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
957
982
  } }
958
983
  function AITestHarnessComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
959
984
  const _r32 = i0.ɵɵgetCurrentView();
960
- i0.ɵɵelementStart(0, "kendo-dialog", 140);
985
+ i0.ɵɵelementStart(0, "kendo-dialog", 143);
961
986
  i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_2_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
962
- i0.ɵɵelementStart(1, "div", 136)(2, "p");
987
+ i0.ɵɵelementStart(1, "div", 139)(2, "p");
963
988
  i0.ɵɵtext(3, "Loading this conversation will replace the current one. Any unsaved changes will be lost.");
964
989
  i0.ɵɵelementEnd();
965
990
  i0.ɵɵelementStart(4, "p");
966
991
  i0.ɵɵtext(5, "Do you want to continue?");
967
992
  i0.ɵɵelementEnd()();
968
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 138);
993
+ i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 141);
969
994
  i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
970
995
  i0.ɵɵtext(8, "Cancel");
971
996
  i0.ɵɵelementEnd();
972
- i0.ɵɵelementStart(9, "button", 141);
997
+ i0.ɵɵelementStart(9, "button", 144);
973
998
  i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmLoadConversation()); });
974
999
  i0.ɵɵtext(10, " Load Conversation ");
975
1000
  i0.ɵɵelementEnd()()();
@@ -1033,6 +1058,10 @@ export class AITestHarnessComponent {
1033
1058
  this._isVisible = false;
1034
1059
  /** Event emitted when the visibility state changes, allowing parent components to react */
1035
1060
  this.visibilityChange = new EventEmitter();
1061
+ /**
1062
+ * Emitted when the user navigates to view a run (agent or prompt)
1063
+ */
1064
+ this.runOpened = new EventEmitter();
1036
1065
  // === Conversation State ===
1037
1066
  /** Complete array of all messages in the current conversation session */
1038
1067
  this.conversationMessages = [];
@@ -2048,8 +2077,8 @@ export class AITestHarnessComponent {
2048
2077
  }));
2049
2078
  // Execute the prompt using RunAIPrompt
2050
2079
  const query = `
2051
- mutation RunAIPrompt($promptId: String!, $data: String, $modelId: String, $vendorId: String, $configurationId: String, $skipValidation: Boolean, $templateData: String, $responseFormat: String, $temperature: Float, $topP: Float, $topK: Int, $minP: Float, $frequencyPenalty: Float, $presencePenalty: Float, $seed: Int, $stopSequences: [String!], $includeLogProbs: Boolean, $topLogProbs: Int, $messages: String) {
2052
- RunAIPrompt(promptId: $promptId, data: $data, modelId: $modelId, vendorId: $vendorId, configurationId: $configurationId, skipValidation: $skipValidation, templateData: $templateData, responseFormat: $responseFormat, temperature: $temperature, topP: $topP, topK: $topK, minP: $minP, frequencyPenalty: $frequencyPenalty, presencePenalty: $presencePenalty, seed: $seed, stopSequences: $stopSequences, includeLogProbs: $includeLogProbs, topLogProbs: $topLogProbs, messages: $messages) {
2080
+ mutation RunAIPrompt($promptId: String!, $data: String, $overrideModelId: String, $overrideVendorId: String, $configurationId: String, $skipValidation: Boolean, $templateData: String, $responseFormat: String, $temperature: Float, $topP: Float, $topK: Int, $minP: Float, $frequencyPenalty: Float, $presencePenalty: Float, $seed: Int, $stopSequences: [String!], $includeLogProbs: Boolean, $topLogProbs: Int, $messages: String) {
2081
+ RunAIPrompt(promptId: $promptId, data: $data, overrideModelId: $overrideModelId, overrideVendorId: $overrideVendorId, configurationId: $configurationId, skipValidation: $skipValidation, templateData: $templateData, responseFormat: $responseFormat, temperature: $temperature, topP: $topP, topK: $topK, minP: $minP, frequencyPenalty: $frequencyPenalty, presencePenalty: $presencePenalty, seed: $seed, stopSequences: $stopSequences, includeLogProbs: $includeLogProbs, topLogProbs: $topLogProbs, messages: $messages) {
2053
2082
  success
2054
2083
  output
2055
2084
  parsedResult
@@ -2066,8 +2095,8 @@ export class AITestHarnessComponent {
2066
2095
  const variables = {
2067
2096
  promptId: this.entity.ID,
2068
2097
  data: JSON.stringify(dataContext),
2069
- modelId: this.selectedModelId || undefined,
2070
- vendorId: this.selectedVendorId || undefined,
2098
+ overrideModelId: this.selectedModelId || undefined,
2099
+ overrideVendorId: this.selectedVendorId || undefined,
2071
2100
  configurationId: undefined, // Use default configuration
2072
2101
  skipValidation: this.skipValidation,
2073
2102
  templateData: null, // Additional template context if needed
@@ -2871,6 +2900,8 @@ export class AITestHarnessComponent {
2871
2900
  else {
2872
2901
  SharedService.Instance.OpenEntityRecord('MJ: AI Prompt Runs', CompositeKey.FromID(event.runId));
2873
2902
  }
2903
+ // Emit event so parent window can minimize
2904
+ this.runOpened.emit(event);
2874
2905
  }
2875
2906
  /**
2876
2907
  * Copies the message content to clipboard.
@@ -2933,6 +2964,21 @@ export class AITestHarnessComponent {
2933
2964
  return typeof content === 'string' ? content : JSON.stringify(content);
2934
2965
  }
2935
2966
  }
2967
+ /**
2968
+ * Checks if the payload should be displayed (not null, undefined, or empty object)
2969
+ * @param payload - The payload to check
2970
+ * @returns true if the payload has content, false otherwise
2971
+ */
2972
+ hasPayload(payload) {
2973
+ if (!payload) {
2974
+ return false;
2975
+ }
2976
+ // Check if it's an empty object
2977
+ if (typeof payload === 'object' && Object.keys(payload).length === 0) {
2978
+ return false;
2979
+ }
2980
+ return true;
2981
+ }
2936
2982
  /**
2937
2983
  * Toggles the collapsed state of a message's payload section
2938
2984
  * @param message - The message to toggle payload visibility for
@@ -3298,6 +3344,38 @@ export class AITestHarnessComponent {
3298
3344
  return '';
3299
3345
  return this.entity.Name || 'Untitled';
3300
3346
  }
3347
+ /**
3348
+ * Gets the icon class for the current entity
3349
+ */
3350
+ getEntityIconClass() {
3351
+ if (!this.entity) {
3352
+ return this.mode === 'agent' ? 'fa-solid fa-robot' : 'fa-solid fa-comment-dots';
3353
+ }
3354
+ if (this.isAgentEntity(this.entity)) {
3355
+ // Agent entity - check for IconClass
3356
+ return this.entity.IconClass || 'fa-solid fa-robot';
3357
+ }
3358
+ // Prompt entity - use default prompt icon
3359
+ return 'fa-solid fa-comment-dots';
3360
+ }
3361
+ /**
3362
+ * Checks if the entity has a logo URL
3363
+ */
3364
+ hasEntityLogo() {
3365
+ if (!this.entity || !this.isAgentEntity(this.entity)) {
3366
+ return false;
3367
+ }
3368
+ return !!this.entity.LogoURL;
3369
+ }
3370
+ /**
3371
+ * Gets the logo URL for the entity (agent only)
3372
+ */
3373
+ getEntityLogoURL() {
3374
+ if (!this.entity || !this.isAgentEntity(this.entity)) {
3375
+ return '';
3376
+ }
3377
+ return this.entity.LogoURL || '';
3378
+ }
3301
3379
  /**
3302
3380
  * Updates stop sequences from the textarea input
3303
3381
  */
@@ -3340,7 +3418,7 @@ export class AITestHarnessComponent {
3340
3418
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.fileInput = _t.first);
3341
3419
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageInput = _t.first);
3342
3420
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.saveDialogInput = _t.first);
3343
- } }, inputs: { mode: "mode", entity: "entity", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange" }, features: [i0.ɵɵNgOnChangesFeature], decls: 3, vars: 3, consts: [["fileInput", ""], ["messagesContainer", ""], ["messageInput", ""], ["saveDialogInput", ""], ["class", "harness-container", "kendoWindowContainer", "", 4, "ngIf"], [1, "save-dialog", 3, "title", "width"], [1, "confirm-dialog", 3, "title", "width"], ["kendoWindowContainer", "", 1, "harness-container"], [1, "harness-header"], [1, "agent-info"], [1, "harness-body"], ["orientation", "horizontal", 2, "height", "100%", "width", "100%"], [1, "chat-area"], [1, "agent-details"], [1, "fa-solid"], [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"], [3, "collapsible", "resizable", "min"], [1, "messages-container"], [1, "empty-state"], [3, "ngClass"], [1, "input-area"], [1, "input-container"], ["placeholder", "Type your message here... (Press Enter to send, Shift+Enter for new line)", 1, "message-input", 3, "ngModelChange", "keypress", "ngModel", "rows", "disabled"], ["title", "Send message", 1, "send-button", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-paper-plane"], [3, "collapsible", "resizable", "size", "min"], [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, "fa-solid", "fa-robot"], ["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, "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"], ["placeholder", "Variable name", 1, "variable-name", 3, "ngModelChange", "ngModel", "disabled"], ["textField", "text", "valueField", "value", 1, "variable-type", 3, "ngModelChange", "ngModel", "data", "valuePrimitive", "disabled"], [1, "variable-value", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], ["title", "Remove variable", 1, "remove-button", 3, "click", "disabled"], [1, "fa-solid", "fa-times"], [3, "viewRunClick", "mode", "executionData", "autoExpand", "runId", "runType"], [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"], [1, "model-settings"], [1, "setting-group"], ["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"], [1, "setting-help"], ["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"], ["title", "Advanced Parameters", 1, "advanced-params-panel", 3, "action", "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, "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"], ["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", "title", "width"], [1, "dialog-content"], ["type", "text", "placeholder", "Conversation name", 1, "k-textbox", "k-input", "k-input-md", "k-rounded-md", "k-input-solid", "full-width", 3, "keyup"], ["kendoButton", "", 3, "click"], ["kendoButton", "", 3, "click", "primary", "disabled"], [1, "confirm-dialog", 3, "close", "title", "width"], ["kendoButton", "", 3, "click", "primary"]], template: function AITestHarnessComponent_Template(rf, ctx) { if (rf & 1) {
3421
+ } }, inputs: { mode: "mode", entity: "entity", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange", runOpened: "runOpened" }, features: [i0.ɵɵNgOnChangesFeature], decls: 3, vars: 3, consts: [["fileInput", ""], ["messagesContainer", ""], ["messageInput", ""], ["saveDialogInput", ""], ["class", "harness-container", "kendoWindowContainer", "", 4, "ngIf"], [1, "save-dialog", 3, "title", "width"], [1, "confirm-dialog", 3, "title", "width"], ["kendoWindowContainer", "", 1, "harness-container"], [1, "harness-header"], [1, "agent-info"], [1, "harness-body"], ["orientation", "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, "collapsible", "resizable", "min"], [1, "messages-container"], [1, "empty-state"], [3, "ngClass"], [1, "input-area"], [1, "input-container"], ["placeholder", "Type your message here... (Press Enter to send, Shift+Enter for new line)", 1, "message-input", 3, "ngModelChange", "keypress", "ngModel", "rows", "disabled"], ["title", "Send message", 1, "send-button", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-paper-plane"], [3, "collapsible", "resizable", "size", "min"], [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"], ["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, "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"], ["placeholder", "Variable name", 1, "variable-name", 3, "ngModelChange", "ngModel", "disabled"], ["textField", "text", "valueField", "value", 1, "variable-type", 3, "ngModelChange", "ngModel", "data", "valuePrimitive", "disabled"], [1, "variable-value", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], ["title", "Remove variable", 1, "remove-button", 3, "click", "disabled"], [1, "fa-solid", "fa-times"], [3, "viewRunClick", "mode", "executionData", "autoExpand", "runId", "runType"], [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"], [1, "model-settings"], [1, "setting-group"], ["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"], [1, "setting-help"], ["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"], ["title", "Advanced Parameters", 1, "advanced-params-panel", 3, "action", "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, "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", "title", "width"], [1, "dialog-content"], ["type", "text", "placeholder", "Conversation name", 1, "k-textbox", "k-input", "k-input-md", "k-rounded-md", "k-input-solid", "full-width", 3, "keyup"], ["kendoButton", "", 3, "click"], ["kendoButton", "", 3, "click", "primary", "disabled"], [1, "confirm-dialog", 3, "close", "title", "width"], ["kendoButton", "", 3, "click", "primary"]], template: function AITestHarnessComponent_Template(rf, ctx) { if (rf & 1) {
3344
3422
  i0.ɵɵtemplate(0, AITestHarnessComponent_div_0_Template, 6, 2, "div", 4)(1, AITestHarnessComponent_Conditional_1_Template, 11, 4, "kendo-dialog", 5)(2, AITestHarnessComponent_Conditional_2_Template, 11, 3, "kendo-dialog", 6);
3345
3423
  } if (rf & 2) {
3346
3424
  i0.ɵɵproperty("ngIf", ctx.isVisible);
@@ -3348,11 +3426,11 @@ export class AITestHarnessComponent {
3348
3426
  i0.ɵɵconditional(ctx.showSaveDialog ? 1 : -1);
3349
3427
  i0.ɵɵadvance();
3350
3428
  i0.ɵɵconditional(ctx.showLoadConfirmDialog ? 2 : -1);
3351
- } }, dependencies: [i4.NgClass, i4.NgIf, i5.CheckboxControlValueAccessor, i5.NgControlStatus, i5.NgModel, i6.ButtonComponent, i2.DialogComponent, i2.DialogActionsComponent, i2.WindowContainerDirective, i7.DropDownListComponent, i8.TextAreaComponent, i8.TextBoxComponent, i8.SwitchComponent, i8.NumericTextBoxComponent, 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: #f8f9fa;\n}\n\n\n\n.custom-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\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: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\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: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\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: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\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: #0d6efd;\n color: white;\n}\n\n\n\n.remove-button[_ngcontent-%COMP%], \n.delete-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: #dc3545;\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: rgba(220, 53, 69, 0.1);\n color: #bd2130;\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: #adb5bd;\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: #6c757d;\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: #495057;\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: #6c757d;\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: #495057;\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: white;\n border-bottom: 1px solid #dee2e6;\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: #17a2b8;\n}\n\n.agent-details[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.agent-details[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\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: white;\n border-right: 1px solid #dee2e6;\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: #6c757d;\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: #495057;\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-user[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: #6f42c1;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: #17a2b8;\n}\n\n.message-time[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time[_ngcontent-%COMP%] {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming[_ngcontent-%COMP%] {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\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: #495057;\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: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\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: #495057;\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: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\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: #dc3545;\n}\n\n\n\n.payload-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n overflow: hidden;\n background: #ffffff;\n}\n\n.payload-header[_ngcontent-%COMP%] {\n background: #f8f9fa;\n padding: 8px 12px;\n border-bottom: 1px solid #e9ecef;\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: #e9ecef;\n}\n\n.payload-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 12px;\n}\n\n.payload-content[_ngcontent-%COMP%] {\n max-height: 250px;\n overflow: auto;\n background: #f8f9fa;\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: #212529;\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: #6c757d;\n transition: color 0.2s;\n}\n\n.payload-toggle[_ngcontent-%COMP%]:hover {\n color: #495057;\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: #333;\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 #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\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: #f8f9fa;\n border: 1px solid #e0e0e0;\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: #333;\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: #212529;\n border-bottom: 2px solid #e9ecef;\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: #212529;\n border-bottom: 1px solid #e9ecef;\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: #212529;\n}\n\n.code-block[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\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: #212529;\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: #d73e48;\n}\n\n.inline-code[_ngcontent-%COMP%] {\n background: #f1f3f4;\n border: 1px solid #dadce0;\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: #d73e48;\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: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link[_ngcontent-%COMP%]:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n\n\n.message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\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: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\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: white;\n border-top: 1px solid #dee2e6;\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.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: white;\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: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\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: #6c757d;\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: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\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: #6c757d;\n color: white;\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: #0d6efd;\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: #212529;\n}\n\n.tab-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\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: #6c757d;\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: #6c757d;\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 #dee2e6;\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: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current[_ngcontent-%COMP%] {\n background: #e7f3ff;\n border-color: #0d6efd;\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: #212529;\n}\n\n.saved-info[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6c757d;\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: #f1f1f1;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #c1c1c1;\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: #a1a1a1;\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: #343a40;\n color: white;\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: white;\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 #dee2e6;\n border-radius: 4px;\n}\n\n.advanced-params-panel[_ngcontent-%COMP%] .k-expander-title {\n font-weight: 600;\n color: #495057;\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}"] }); }
3429
+ } }, dependencies: [i4.NgClass, i4.NgIf, i5.CheckboxControlValueAccessor, i5.NgControlStatus, i5.NgModel, i6.ButtonComponent, i2.DialogComponent, i2.DialogActionsComponent, i2.WindowContainerDirective, i7.DropDownListComponent, i8.TextAreaComponent, i8.TextBoxComponent, i8.SwitchComponent, i8.NumericTextBoxComponent, 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: #f8f9fa;\n}\n\n\n\n.custom-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\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: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\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: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button[_ngcontent-%COMP%]:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\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: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\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: #0d6efd;\n color: white;\n}\n\n\n\n.remove-button[_ngcontent-%COMP%], \n.delete-button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n color: #dc3545;\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: rgba(220, 53, 69, 0.1);\n color: #bd2130;\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: #adb5bd;\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: #6c757d;\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: #495057;\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: #6c757d;\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: #495057;\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: white;\n border-bottom: 1px solid #dee2e6;\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: #17a2b8;\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: #212529;\n}\n\n.agent-details[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\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: white;\n border-right: 1px solid #dee2e6;\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: #6c757d;\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: #495057;\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: #6f42c1;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-role[_ngcontent-%COMP%] {\n color: #17a2b8;\n}\n\n.message-time[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time[_ngcontent-%COMP%] {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming[_ngcontent-%COMP%] {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\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: #495057;\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: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming[_ngcontent-%COMP%] .message-content[_ngcontent-%COMP%] {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\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: #495057;\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: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\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: #dc3545;\n}\n\n\n\n.payload-section[_ngcontent-%COMP%] {\n margin-top: 12px;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n overflow: hidden;\n background: #ffffff;\n}\n\n.payload-header[_ngcontent-%COMP%] {\n background: #f8f9fa;\n padding: 8px 12px;\n border-bottom: 1px solid #e9ecef;\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: #e9ecef;\n}\n\n.payload-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 12px;\n}\n\n.payload-content[_ngcontent-%COMP%] {\n max-height: 250px;\n overflow: auto;\n background: #f8f9fa;\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: #212529;\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: #6c757d;\n transition: color 0.2s;\n}\n\n.payload-toggle[_ngcontent-%COMP%]:hover {\n color: #495057;\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: #333;\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 #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\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: #f8f9fa;\n border: 1px solid #e0e0e0;\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: #333;\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: #212529;\n border-bottom: 2px solid #e9ecef;\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: #212529;\n border-bottom: 1px solid #e9ecef;\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: #212529;\n}\n\n.code-block[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\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: #212529;\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: #d73e48;\n}\n\n.inline-code[_ngcontent-%COMP%] {\n background: #f1f3f4;\n border: 1px solid #dadce0;\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: #d73e48;\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: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link[_ngcontent-%COMP%]:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n\n\n.message-content[_ngcontent-%COMP%] {\n background: #f8f9fa;\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: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\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: white;\n border-top: 1px solid #dee2e6;\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.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: white;\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: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\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: #6c757d;\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: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\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: #6c757d;\n color: white;\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: #0d6efd;\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: #212529;\n}\n\n.tab-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\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: #6c757d;\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: #6c757d;\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 #dee2e6;\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: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current[_ngcontent-%COMP%] {\n background: #e7f3ff;\n border-color: #0d6efd;\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: #212529;\n}\n\n.saved-info[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6c757d;\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: #f1f1f1;\n}\n\n.messages-container[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.sidebar-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #c1c1c1;\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: #a1a1a1;\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: #343a40;\n color: white;\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: white;\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 #dee2e6;\n border-radius: 4px;\n}\n\n.advanced-params-panel[_ngcontent-%COMP%] .k-expander-title {\n font-weight: 600;\n color: #495057;\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}"] }); }
3352
3430
  }
3353
3431
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AITestHarnessComponent, [{
3354
3432
  type: Component,
3355
- args: [{ selector: 'mj-ai-test-harness', template: "<div class=\"harness-container\" *ngIf=\"isVisible\" kendoWindowContainer>\n <!-- Header -->\n <div class=\"harness-header\">\n @if (entity) {\n <div class=\"agent-info\">\n <div class=\"agent-details\">\n <i class=\"fa-solid\" [class.fa-robot]=\"mode === 'agent'\" [class.fa-comment-dots]=\"mode === 'prompt'\"></i>\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\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 \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\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 </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 (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\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 </kendo-splitter-pane>\n \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 } @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\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 \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 \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 \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 \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 \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 \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\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 [executionData]=\"currentExecutionData\"\n [autoExpand]=\"true\"\n [runId]=\"getLastRunId()\"\n [runType]=\"mode\"\n (viewRunClick)=\"navigateToRun($event)\">\n </mj-agent-execution-monitor>\n </div>\n }\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 \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 \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 \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 \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 \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\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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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\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 \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 \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\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(message.agentRunId)\" 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 (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\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 <!-- 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: #f8f9fa;\n}\n\n/* Custom Button Styles */\n.custom-button {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\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: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\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: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\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: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\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: #0d6efd;\n color: white;\n}\n\n/* Remove/Delete Buttons */\n.remove-button,\n.delete-button {\n background: transparent;\n border: none;\n color: #dc3545;\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: rgba(220, 53, 69, 0.1);\n color: #bd2130;\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: #adb5bd;\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: #6c757d;\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: #495057;\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: #6c757d;\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: #495057;\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: white;\n border-bottom: 1px solid #dee2e6;\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: #17a2b8;\n}\n\n.agent-details h3 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.agent-details p {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\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: white;\n border-right: 1px solid #dee2e6;\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: #6c757d;\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: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.message-role i {\n font-size: 14px;\n}\n\n.message-user .message-role {\n color: #6f42c1;\n}\n\n.message-assistant .message-role {\n color: #17a2b8;\n}\n\n.message-time {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\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: #495057;\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: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant .message-content {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming .message-content {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\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: #495057;\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: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details i {\n color: #dc3545;\n}\n\n/* Payload Section Styles */\n.payload-section {\n margin-top: 12px;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n overflow: hidden;\n background: #ffffff;\n}\n\n.payload-header {\n background: #f8f9fa;\n padding: 8px 12px;\n border-bottom: 1px solid #e9ecef;\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: #e9ecef;\n}\n\n.payload-label {\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label i {\n color: #6c757d;\n font-size: 12px;\n}\n\n.payload-content {\n max-height: 250px;\n overflow: auto;\n background: #f8f9fa;\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: #212529;\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: #6c757d;\n transition: color 0.2s;\n}\n\n.payload-toggle:hover {\n color: #495057;\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: #333;\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 #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\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: #f8f9fa;\n border: 1px solid #e0e0e0;\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: #333;\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: #212529;\n border-bottom: 2px solid #e9ecef;\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: #212529;\n border-bottom: 1px solid #e9ecef;\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: #212529;\n}\n\n.code-block {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\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: #212529;\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: #d73e48;\n}\n\n.inline-code {\n background: #f1f3f4;\n border: 1px solid #dadce0;\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: #d73e48;\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: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n/* Ensure proper text wrapping in message content */\n.message-content {\n background: #f8f9fa;\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: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\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: white;\n border-top: 1px solid #dee2e6;\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.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: white;\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: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\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: #6c757d;\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: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\n}\n\n.tab-button i {\n font-size: 14px;\n}\n\n.tab-button .badge {\n background: #6c757d;\n color: white;\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: #0d6efd;\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: #212529;\n}\n\n.tab-header p {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\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: #6c757d;\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: #6c757d;\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 #dee2e6;\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: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current {\n background: #e7f3ff;\n border-color: #0d6efd;\n}\n\n.saved-info h5 {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: #212529;\n}\n\n.saved-info p {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date {\n font-size: 11px;\n color: #6c757d;\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: #f1f1f1;\n}\n\n.messages-container::-webkit-scrollbar-thumb,\n.sidebar-content::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 4px;\n}\n\n.messages-container::-webkit-scrollbar-thumb:hover,\n.sidebar-content::-webkit-scrollbar-thumb:hover {\n background: #a1a1a1;\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: #343a40;\n color: white;\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: white;\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 #dee2e6;\n border-radius: 4px;\n}\n\n.advanced-params-panel ::ng-deep .k-expander-title {\n font-weight: 600;\n color: #495057;\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}"] }]
3433
+ args: [{ selector: 'mj-ai-test-harness', template: "<div class=\"harness-container\" *ngIf=\"isVisible\" 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\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 \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\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\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 </kendo-splitter-pane>\n \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 } @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\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 \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 \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 \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 \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 \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 \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\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 [executionData]=\"currentExecutionData\"\n [autoExpand]=\"true\"\n [runId]=\"getLastRunId()\"\n [runType]=\"mode\"\n (viewRunClick)=\"navigateToRun($event)\">\n </mj-agent-execution-monitor>\n </div>\n }\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 \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 \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 \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 \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 \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\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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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 \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\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 \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 \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\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(message.agentRunId)\" 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\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 <!-- 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: #f8f9fa;\n}\n\n/* Custom Button Styles */\n.custom-button {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\n}\n\n.custom-button:active:not(:disabled) {\n background: #e9ecef;\n border-color: #adb5bd;\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: #0d6efd;\n border: 1px solid #0d6efd;\n color: white;\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: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.send-button:active:not(:disabled) {\n background: #0a58ca;\n border-color: #0a58ca;\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: white;\n border: 1px solid #0d6efd;\n color: #0d6efd;\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: #0d6efd;\n color: white;\n}\n\n/* Remove/Delete Buttons */\n.remove-button,\n.delete-button {\n background: transparent;\n border: none;\n color: #dc3545;\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: rgba(220, 53, 69, 0.1);\n color: #bd2130;\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: #adb5bd;\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: #6c757d;\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: #495057;\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: #6c757d;\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: #495057;\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: white;\n border-bottom: 1px solid #dee2e6;\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: #17a2b8;\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: #212529;\n}\n\n.agent-details p {\n margin: 4px 0 0 0;\n font-size: 14px;\n color: #6c757d;\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: white;\n border-right: 1px solid #dee2e6;\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: #6c757d;\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: #495057;\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: #6f42c1;\n}\n\n.message-assistant .message-role {\n color: #17a2b8;\n}\n\n.message-time {\n color: #6c757d;\n font-size: 12px;\n}\n\n.execution-time {\n background: #e9ecef;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n color: #495057;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.execution-time.streaming {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n}\n\n.raw-toggle {\n background: transparent;\n border: none;\n padding: 4px 8px;\n font-size: 12px;\n color: #6c757d;\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: #495057;\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: #e7f3ff;\n border: 1px solid #b8daff;\n}\n\n.message-assistant .message-content {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n}\n\n.message.streaming .message-content {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\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: #495057;\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: #f8d7da;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.error-details i {\n color: #dc3545;\n}\n\n/* Payload Section Styles */\n.payload-section {\n margin-top: 12px;\n border: 1px solid #e9ecef;\n border-radius: 6px;\n overflow: hidden;\n background: #ffffff;\n}\n\n.payload-header {\n background: #f8f9fa;\n padding: 8px 12px;\n border-bottom: 1px solid #e9ecef;\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: #e9ecef;\n}\n\n.payload-label {\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.payload-label i {\n color: #6c757d;\n font-size: 12px;\n}\n\n.payload-content {\n max-height: 250px;\n overflow: auto;\n background: #f8f9fa;\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: #212529;\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: #6c757d;\n transition: color 0.2s;\n}\n\n.payload-toggle:hover {\n color: #495057;\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: #333;\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 #dee2e6;\n border-radius: 4px;\n \n &:focus {\n outline: none;\n border-color: #ff6358;\n box-shadow: 0 0 0 0.25rem rgba(255, 99, 88, 0.25);\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: #f8f9fa;\n border: 1px solid #e0e0e0;\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: #333;\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: #212529;\n border-bottom: 2px solid #e9ecef;\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: #212529;\n border-bottom: 1px solid #e9ecef;\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: #212529;\n}\n\n.code-block {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\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: #212529;\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: #d73e48;\n}\n\n.inline-code {\n background: #f1f3f4;\n border: 1px solid #dadce0;\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: #d73e48;\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: #0d6efd;\n text-decoration: underline;\n transition: color 0.2s;\n}\n\n.markdown-link:hover {\n color: #0a58ca;\n text-decoration: none;\n}\n\n/* Ensure proper text wrapping in message content */\n.message-content {\n background: #f8f9fa;\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: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n color: #495057;\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: #f8f9fa;\n border-color: #adb5bd;\n color: #212529;\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: white;\n border-top: 1px solid #dee2e6;\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.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: white;\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: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\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: #6c757d;\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: #e9ecef;\n color: #495057;\n}\n\n.tab-button.active {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n background: white;\n}\n\n.tab-button i {\n font-size: 14px;\n}\n\n.tab-button .badge {\n background: #6c757d;\n color: white;\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: #0d6efd;\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: #212529;\n}\n\n.tab-header p {\n margin: 0;\n font-size: 13px;\n color: #6c757d;\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: #6c757d;\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: #6c757d;\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 #dee2e6;\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: #f8f9fa;\n border-color: #adb5bd;\n}\n\n.saved-item.current {\n background: #e7f3ff;\n border-color: #0d6efd;\n}\n\n.saved-info h5 {\n margin: 0 0 4px 0;\n font-size: 14px;\n font-weight: 600;\n color: #212529;\n}\n\n.saved-info p {\n margin: 0 0 4px 0;\n font-size: 12px;\n color: #6c757d;\n}\n\n.saved-date {\n font-size: 11px;\n color: #6c757d;\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: #f1f1f1;\n}\n\n.messages-container::-webkit-scrollbar-thumb,\n.sidebar-content::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 4px;\n}\n\n.messages-container::-webkit-scrollbar-thumb:hover,\n.sidebar-content::-webkit-scrollbar-thumb:hover {\n background: #a1a1a1;\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: #343a40;\n color: white;\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: white;\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 #dee2e6;\n border-radius: 4px;\n}\n\n.advanced-params-panel ::ng-deep .k-expander-title {\n font-weight: 600;\n color: #495057;\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}"] }]
3356
3434
  }], () => [{ type: i1.DomSanitizer }, { type: i2.WindowService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i3.Router }], { mode: [{
3357
3435
  type: Input
3358
3436
  }], entity: [{
@@ -3363,6 +3441,8 @@ export class AITestHarnessComponent {
3363
3441
  type: Input
3364
3442
  }], visibilityChange: [{
3365
3443
  type: Output
3444
+ }], runOpened: [{
3445
+ type: Output
3366
3446
  }], messagesContainer: [{
3367
3447
  type: ViewChild,
3368
3448
  args: ['messagesContainer']