@memberjunction/ng-ai-test-harness 2.69.1 → 2.71.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.
@@ -22,6 +22,7 @@ const _c1 = ["fileInput"];
22
22
  const _c2 = ["messageInput"];
23
23
  const _c3 = ["saveDialogInput"];
24
24
  const _forTrack0 = ($index, $item) => $item.id;
25
+ const _forTrack1 = ($index, $item) => $item.ID;
25
26
  const _c4 = () => ({ text: "String", value: "string" });
26
27
  const _c5 = () => ({ text: "Number", value: "number" });
27
28
  const _c6 = () => ({ text: "Boolean", value: "boolean" });
@@ -278,12 +279,20 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template(rf,
278
279
  i0.ɵɵelement(4, "i", 76);
279
280
  i0.ɵɵtext(5, " Execution Monitor ");
280
281
  i0.ɵɵelementEnd();
282
+ i0.ɵɵelementStart(6, "button", 41);
283
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectTab("agentSettings")); });
284
+ i0.ɵɵelement(7, "i", 77);
285
+ i0.ɵɵtext(8, " Settings ");
286
+ i0.ɵɵelementEnd();
281
287
  } if (rf & 2) {
282
288
  const ctx_r1 = i0.ɵɵnextContext(3);
283
289
  i0.ɵɵclassProp("active", ctx_r1.activeTab === "agentVariables");
284
290
  i0.ɵɵproperty("disabled", ctx_r1.executionMonitorMode === "live" && ctx_r1.activeTab !== "agentVariables");
285
291
  i0.ɵɵadvance(3);
286
292
  i0.ɵɵclassProp("active", ctx_r1.activeTab === "executionMonitor");
293
+ i0.ɵɵadvance(3);
294
+ i0.ɵɵclassProp("active", ctx_r1.activeTab === "agentSettings");
295
+ i0.ɵɵproperty("disabled", ctx_r1.executionMonitorMode === "live" && ctx_r1.activeTab !== "agentSettings");
287
296
  } }
288
297
  function AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template(rf, ctx) { if (rf & 1) {
289
298
  const _r9 = i0.ɵɵgetCurrentView();
@@ -383,36 +392,83 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_26_Template(rf,
383
392
  i0.ɵɵadvance();
384
393
  i0.ɵɵproperty("mode", ctx_r1.executionMonitorMode)("agentRun", ctx_r1.currentAgentRun)("liveSteps", ctx_r1.liveAgentSteps)("autoExpand", true)("runId", ctx_r1.getLastRunId())("runType", ctx_r1.mode);
385
394
  } }
386
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template(rf, ctx) { if (rf & 1) {
387
- const _r16 = i0.ɵɵgetCurrentView();
395
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_For_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
396
+ i0.ɵɵtext(0);
397
+ } if (rf & 2) {
398
+ const config_r16 = i0.ɵɵnextContext().$implicit;
399
+ i0.ɵɵtextInterpolate1(" ", config_r16.Description, " ");
400
+ } }
401
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_For_1_Template(rf, ctx) { if (rf & 1) {
402
+ i0.ɵɵtemplate(0, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_For_1_Conditional_0_Template, 1, 1);
403
+ } if (rf & 2) {
404
+ const config_r16 = ctx.$implicit;
405
+ const ctx_r1 = i0.ɵɵnextContext(5);
406
+ i0.ɵɵconditional(config_r16.ID === ctx_r1.agentConfigurationId && config_r16.Description ? 0 : -1);
407
+ } }
408
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_Template(rf, ctx) { if (rf & 1) {
409
+ i0.ɵɵrepeaterCreate(0, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_For_1_Template, 1, 1, null, null, _forTrack1);
410
+ } if (rf & 2) {
411
+ const ctx_r1 = i0.ɵɵnextContext(4);
412
+ i0.ɵɵrepeater(ctx_r1.availableConfigurations);
413
+ } }
414
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_13_Template(rf, ctx) { if (rf & 1) {
415
+ i0.ɵɵtext(0, " Using default configuration ");
416
+ } }
417
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf, ctx) { if (rf & 1) {
418
+ const _r15 = i0.ɵɵgetCurrentView();
419
+ i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
420
+ i0.ɵɵtext(3, "Agent Settings");
421
+ i0.ɵɵelementEnd();
422
+ i0.ɵɵelementStart(4, "p");
423
+ i0.ɵɵtext(5, "Configure agent execution parameters");
424
+ i0.ɵɵelementEnd()();
425
+ i0.ɵɵelementStart(6, "div", 90)(7, "div", 91)(8, "label");
426
+ i0.ɵɵtext(9, "AI Configuration");
427
+ i0.ɵɵelementEnd();
428
+ i0.ɵɵelementStart(10, "kendo-dropdownlist", 92);
429
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template_kendo_dropdownlist_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.agentConfigurationId, $event) || (ctx_r1.agentConfigurationId = $event); return i0.ɵɵresetView($event); });
430
+ i0.ɵɵelementEnd();
431
+ i0.ɵɵelementStart(11, "div", 93);
432
+ i0.ɵɵtemplate(12, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_12_Template, 2, 0)(13, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Conditional_13_Template, 1, 0);
433
+ i0.ɵɵelementEnd()()()();
434
+ } if (rf & 2) {
435
+ const ctx_r1 = i0.ɵɵnextContext(3);
436
+ i0.ɵɵadvance(10);
437
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.agentConfigurationId);
438
+ i0.ɵɵproperty("data", ctx_r1.availableConfigurations)("valuePrimitive", true);
439
+ i0.ɵɵadvance(2);
440
+ i0.ɵɵconditional(ctx_r1.agentConfigurationId ? 12 : 13);
441
+ } }
442
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template(rf, ctx) { if (rf & 1) {
443
+ const _r18 = i0.ɵɵgetCurrentView();
388
444
  i0.ɵɵelementStart(0, "div", 81)(1, "kendo-textbox", 84);
389
- 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); });
445
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template_kendo_textbox_ngModelChange_1_listener($event) { const variable_r19 = i0.ɵɵrestoreView(_r18).$implicit; i0.ɵɵtwoWayBindingSet(variable_r19.name, $event) || (variable_r19.name = $event); return i0.ɵɵresetView($event); });
390
446
  i0.ɵɵelementEnd();
391
447
  i0.ɵɵelementStart(2, "kendo-dropdownlist", 85);
392
- 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); });
448
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { const variable_r19 = i0.ɵɵrestoreView(_r18).$implicit; i0.ɵɵtwoWayBindingSet(variable_r19.type, $event) || (variable_r19.type = $event); return i0.ɵɵresetView($event); });
393
449
  i0.ɵɵelementEnd();
394
450
  i0.ɵɵelementStart(3, "kendo-textbox", 86);
395
- 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); });
451
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template_kendo_textbox_ngModelChange_3_listener($event) { const variable_r19 = i0.ɵɵrestoreView(_r18).$implicit; i0.ɵɵtwoWayBindingSet(variable_r19.value, $event) || (variable_r19.value = $event); return i0.ɵɵresetView($event); });
396
452
  i0.ɵɵelementEnd();
397
- i0.ɵɵelementStart(4, "button", 91);
398
- 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)); });
453
+ i0.ɵɵelementStart(4, "button", 95);
454
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template_button_click_4_listener() { const $index_r20 = i0.ɵɵrestoreView(_r18).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.removeTemplateVariable($index_r20)); });
399
455
  i0.ɵɵelement(5, "i", 88);
400
456
  i0.ɵɵelementEnd()();
401
457
  } if (rf & 2) {
402
- const variable_r17 = ctx.$implicit;
458
+ const variable_r19 = ctx.$implicit;
403
459
  const ctx_r1 = i0.ɵɵnextContext(4);
404
460
  i0.ɵɵadvance();
405
- i0.ɵɵtwoWayProperty("ngModel", variable_r17.name);
461
+ i0.ɵɵtwoWayProperty("ngModel", variable_r19.name);
406
462
  i0.ɵɵproperty("disabled", ctx_r1.isExecuting);
407
463
  i0.ɵɵadvance();
408
- i0.ɵɵtwoWayProperty("ngModel", variable_r17.type);
464
+ i0.ɵɵtwoWayProperty("ngModel", variable_r19.type);
409
465
  i0.ɵɵproperty("data", i0.ɵɵpureFunction4(13, _c8, i0.ɵɵpureFunction0(9, _c4), i0.ɵɵpureFunction0(10, _c5), i0.ɵɵpureFunction0(11, _c6), i0.ɵɵpureFunction0(12, _c7)))("valuePrimitive", true)("disabled", ctx_r1.isExecuting);
410
466
  i0.ɵɵadvance();
411
- i0.ɵɵtwoWayProperty("ngModel", variable_r17.value);
412
- i0.ɵɵproperty("placeholder", variable_r17.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
467
+ i0.ɵɵtwoWayProperty("ngModel", variable_r19.value);
468
+ i0.ɵɵproperty("placeholder", variable_r19.type === "object" ? "JSON value" : "Value")("disabled", ctx_r1.isExecuting);
413
469
  } }
414
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf, ctx) { if (rf & 1) {
415
- const _r15 = i0.ɵɵgetCurrentView();
470
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf, ctx) { if (rf & 1) {
471
+ const _r17 = i0.ɵɵgetCurrentView();
416
472
  i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
417
473
  i0.ɵɵtext(3, "Template Variables");
418
474
  i0.ɵɵelementEnd();
@@ -420,10 +476,10 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf,
420
476
  i0.ɵɵtext(5, "Variables for prompt template rendering");
421
477
  i0.ɵɵelementEnd()();
422
478
  i0.ɵɵelementStart(6, "div", 79);
423
- i0.ɵɵrepeaterCreate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_For_8_Template, 6, 18, "div", 81, i0.ɵɵrepeaterTrackByIndex);
479
+ i0.ɵɵrepeaterCreate(7, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_For_8_Template, 6, 18, "div", 81, i0.ɵɵrepeaterTrackByIndex);
424
480
  i0.ɵɵelementEnd();
425
- i0.ɵɵelementStart(9, "button", 90);
426
- 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()); });
481
+ i0.ɵɵelementStart(9, "button", 94);
482
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.addTemplateVariable()); });
427
483
  i0.ɵɵelement(10, "i", 83);
428
484
  i0.ɵɵtext(11, " Add Variable ");
429
485
  i0.ɵɵelementEnd()();
@@ -432,22 +488,44 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template(rf,
432
488
  i0.ɵɵadvance(7);
433
489
  i0.ɵɵrepeater(ctx_r1.templateVariables);
434
490
  } }
435
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_18_Template(rf, ctx) { if (rf & 1) {
491
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_18_Template(rf, ctx) { if (rf & 1) {
436
492
  i0.ɵɵtext(0, " Using default vendor for the default model ");
437
493
  } }
438
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_19_Template(rf, ctx) { if (rf & 1) {
494
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_19_Template(rf, ctx) { if (rf & 1) {
439
495
  i0.ɵɵtext(0, " Only one vendor available for this model ");
440
496
  } }
441
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_20_Template(rf, ctx) { if (rf & 1) {
497
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_20_Template(rf, ctx) { if (rf & 1) {
442
498
  i0.ɵɵtext(0, " Select the inference provider for this model ");
443
499
  } }
444
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template(rf, ctx) { if (rf & 1) {
445
- const _r20 = i0.ɵɵgetCurrentView();
446
- i0.ɵɵelementStart(0, "div", 95)(1, "label", 118);
500
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_For_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
501
+ i0.ɵɵtext(0);
502
+ } if (rf & 2) {
503
+ const config_r22 = i0.ɵɵnextContext().$implicit;
504
+ i0.ɵɵtextInterpolate1(" ", config_r22.Description, " ");
505
+ } }
506
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_For_1_Template(rf, ctx) { if (rf & 1) {
507
+ i0.ɵɵtemplate(0, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_For_1_Conditional_0_Template, 1, 1);
508
+ } if (rf & 2) {
509
+ const config_r22 = ctx.$implicit;
510
+ const ctx_r1 = i0.ɵɵnextContext(5);
511
+ i0.ɵɵconditional(config_r22.ID === ctx_r1.selectedConfigurationId && config_r22.Description ? 0 : -1);
512
+ } }
513
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_Template(rf, ctx) { if (rf & 1) {
514
+ i0.ɵɵrepeaterCreate(0, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_For_1_Template, 1, 1, null, null, _forTrack1);
515
+ } if (rf & 2) {
516
+ const ctx_r1 = i0.ɵɵnextContext(4);
517
+ i0.ɵɵrepeater(ctx_r1.availableConfigurations);
518
+ } }
519
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_27_Template(rf, ctx) { if (rf & 1) {
520
+ i0.ɵɵtext(0, " Using default configuration ");
521
+ } }
522
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_86_Template(rf, ctx) { if (rf & 1) {
523
+ const _r23 = i0.ɵɵgetCurrentView();
524
+ i0.ɵɵelementStart(0, "div", 91)(1, "label", 119);
447
525
  i0.ɵɵtext(2, " Top Log Probs ");
448
526
  i0.ɵɵelementEnd();
449
- i0.ɵɵelementStart(3, "kendo-numerictextbox", 119);
450
- 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); });
527
+ i0.ɵɵelementStart(3, "kendo-numerictextbox", 120);
528
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_86_Template_kendo_numerictextbox_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topLogProbs, $event) || (ctx_r1.advancedParams.topLogProbs = $event); return i0.ɵɵresetView($event); });
451
529
  i0.ɵɵelementEnd()();
452
530
  } if (rf & 2) {
453
531
  const ctx_r1 = i0.ɵɵnextContext(4);
@@ -455,121 +533,130 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_7
455
533
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.topLogProbs);
456
534
  i0.ɵɵproperty("min", 2)("max", 20)("step", 1)("format", "n0");
457
535
  } }
458
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf, ctx) { if (rf & 1) {
459
- const _r19 = i0.ɵɵgetCurrentView();
536
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template(rf, ctx) { if (rf & 1) {
537
+ const _r21 = i0.ɵɵgetCurrentView();
460
538
  i0.ɵɵelementStart(0, "div", 47)(1, "div", 78)(2, "h4");
461
539
  i0.ɵɵtext(3, "Model Settings");
462
540
  i0.ɵɵelementEnd();
463
541
  i0.ɵɵelementStart(4, "p");
464
542
  i0.ɵɵtext(5, "Configure AI model parameters");
465
543
  i0.ɵɵelementEnd();
466
- i0.ɵɵelementStart(6, "button", 92);
467
- 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()); });
468
- i0.ɵɵelement(7, "i", 93);
544
+ i0.ɵɵelementStart(6, "button", 96);
545
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.resetToPromptDefaults()); });
546
+ i0.ɵɵelement(7, "i", 97);
469
547
  i0.ɵɵelementEnd()();
470
- i0.ɵɵelementStart(8, "div", 94)(9, "div", 95)(10, "label");
548
+ i0.ɵɵelementStart(8, "div", 90)(9, "div", 91)(10, "label");
471
549
  i0.ɵɵtext(11, "AI Model");
472
550
  i0.ɵɵelementEnd();
473
- i0.ɵɵelementStart(12, "kendo-dropdownlist", 96);
474
- 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); });
475
- 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()); });
551
+ i0.ɵɵelementStart(12, "kendo-dropdownlist", 98);
552
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_dropdownlist_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedModelId, $event) || (ctx_r1.selectedModelId = $event); return i0.ɵɵresetView($event); });
553
+ i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_dropdownlist_ngModelChange_12_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onModelSelectionChange()); });
476
554
  i0.ɵɵelementEnd()();
477
- i0.ɵɵelementStart(13, "div", 95)(14, "label");
555
+ i0.ɵɵelementStart(13, "div", 91)(14, "label");
478
556
  i0.ɵɵtext(15, "AI Vendor");
479
557
  i0.ɵɵelementEnd();
480
- i0.ɵɵelementStart(16, "kendo-dropdownlist", 97);
481
- 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); });
558
+ i0.ɵɵelementStart(16, "kendo-dropdownlist", 99);
559
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_dropdownlist_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedVendorId, $event) || (ctx_r1.selectedVendorId = $event); return i0.ɵɵresetView($event); });
560
+ i0.ɵɵelementEnd();
561
+ i0.ɵɵelementStart(17, "div", 93);
562
+ i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_18_Template, 1, 0)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_19_Template, 1, 0)(20, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_20_Template, 1, 0);
563
+ i0.ɵɵelementEnd()();
564
+ i0.ɵɵelementStart(21, "div", 91)(22, "label");
565
+ i0.ɵɵtext(23, "AI Configuration");
566
+ i0.ɵɵelementEnd();
567
+ i0.ɵɵelementStart(24, "kendo-dropdownlist", 92);
568
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_dropdownlist_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedConfigurationId, $event) || (ctx_r1.selectedConfigurationId = $event); return i0.ɵɵresetView($event); });
482
569
  i0.ɵɵelementEnd();
483
- i0.ɵɵelementStart(17, "div", 98);
484
- 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);
570
+ i0.ɵɵelementStart(25, "div", 93);
571
+ i0.ɵɵtemplate(26, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_26_Template, 2, 0)(27, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_27_Template, 1, 0);
485
572
  i0.ɵɵelementEnd()();
486
- i0.ɵɵelementStart(21, "div", 95)(22, "label");
487
- i0.ɵɵtext(23, "Response Format");
573
+ i0.ɵɵelementStart(28, "div", 91)(29, "label");
574
+ i0.ɵɵtext(30, "Response Format");
488
575
  i0.ɵɵelementEnd();
489
- i0.ɵɵelementStart(24, "kendo-dropdownlist", 99);
490
- 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); });
576
+ i0.ɵɵelementStart(31, "kendo-dropdownlist", 100);
577
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_dropdownlist_ngModelChange_31_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedResponseFormat, $event) || (ctx_r1.selectedResponseFormat = $event); return i0.ɵɵresetView($event); });
491
578
  i0.ɵɵelementEnd();
492
- i0.ɵɵelementStart(25, "div", 98);
493
- i0.ɵɵtext(26, " Expected format for AI response (defaults to prompt setting) ");
579
+ i0.ɵɵelementStart(32, "div", 93);
580
+ i0.ɵɵtext(33, " Expected format for AI response (defaults to prompt setting) ");
494
581
  i0.ɵɵelementEnd()();
495
- i0.ɵɵelementStart(27, "div", 95)(28, "label");
496
- i0.ɵɵtext(29, "Max Tokens");
582
+ i0.ɵɵelementStart(34, "div", 91)(35, "label");
583
+ i0.ɵɵtext(36, "Max Tokens");
497
584
  i0.ɵɵelementEnd();
498
- i0.ɵɵelementStart(30, "kendo-numerictextbox", 100);
499
- 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); });
585
+ i0.ɵɵelementStart(37, "kendo-numerictextbox", 101);
586
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.maxTokens, $event) || (ctx_r1.maxTokens = $event); return i0.ɵɵresetView($event); });
500
587
  i0.ɵɵelementEnd();
501
- i0.ɵɵelementStart(31, "div", 98);
502
- i0.ɵɵtext(32, " Maximum length of generated response ");
588
+ i0.ɵɵelementStart(38, "div", 93);
589
+ i0.ɵɵtext(39, " Maximum length of generated response ");
503
590
  i0.ɵɵelementEnd()();
504
- i0.ɵɵelementStart(33, "div", 95)(34, "label", 101)(35, "input", 102);
505
- 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); });
591
+ i0.ɵɵelementStart(40, "div", 91)(41, "label", 102)(42, "input", 103);
592
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_input_ngModelChange_42_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.skipValidation, $event) || (ctx_r1.skipValidation = $event); return i0.ɵɵresetView($event); });
506
593
  i0.ɵɵelementEnd();
507
- i0.ɵɵtext(36, " Skip Validation ");
594
+ i0.ɵɵtext(43, " Skip Validation ");
508
595
  i0.ɵɵelementEnd();
509
- i0.ɵɵelementStart(37, "div", 98);
510
- i0.ɵɵtext(38, " Skip output validation during testing ");
596
+ i0.ɵɵelementStart(44, "div", 93);
597
+ i0.ɵɵtext(45, " Skip output validation during testing ");
511
598
  i0.ɵɵelementEnd()();
512
- i0.ɵɵelementStart(39, "kendo-expansionpanel", 103);
513
- 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()); });
514
- i0.ɵɵelementStart(40, "div", 104)(41, "div", 95)(42, "label", 105);
515
- i0.ɵɵtext(43, " Temperature ");
599
+ i0.ɵɵelementStart(46, "kendo-expansionpanel", 104);
600
+ i0.ɵɵlistener("action", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_expansionpanel_action_46_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleAdvancedParams()); });
601
+ i0.ɵɵelementStart(47, "div", 105)(48, "div", 91)(49, "label", 106);
602
+ i0.ɵɵtext(50, " Temperature ");
516
603
  i0.ɵɵelementEnd();
517
- i0.ɵɵelementStart(44, "kendo-numerictextbox", 106);
518
- 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); });
604
+ i0.ɵɵelementStart(51, "kendo-numerictextbox", 107);
605
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_51_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.temperature, $event) || (ctx_r1.advancedParams.temperature = $event); return i0.ɵɵresetView($event); });
519
606
  i0.ɵɵelementEnd()();
520
- i0.ɵɵelementStart(45, "div", 95)(46, "label", 107);
521
- i0.ɵɵtext(47, " Top P ");
607
+ i0.ɵɵelementStart(52, "div", 91)(53, "label", 108);
608
+ i0.ɵɵtext(54, " Top P ");
522
609
  i0.ɵɵelementEnd();
523
- i0.ɵɵelementStart(48, "kendo-numerictextbox", 106);
524
- 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); });
610
+ i0.ɵɵelementStart(55, "kendo-numerictextbox", 107);
611
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_55_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topP, $event) || (ctx_r1.advancedParams.topP = $event); return i0.ɵɵresetView($event); });
525
612
  i0.ɵɵelementEnd()();
526
- i0.ɵɵelementStart(49, "div", 95)(50, "label", 108);
527
- i0.ɵɵtext(51, " Top K ");
613
+ i0.ɵɵelementStart(56, "div", 91)(57, "label", 109);
614
+ i0.ɵɵtext(58, " Top K ");
528
615
  i0.ɵɵelementEnd();
529
- i0.ɵɵelementStart(52, "kendo-numerictextbox", 106);
530
- 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); });
616
+ i0.ɵɵelementStart(59, "kendo-numerictextbox", 107);
617
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_59_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.topK, $event) || (ctx_r1.advancedParams.topK = $event); return i0.ɵɵresetView($event); });
531
618
  i0.ɵɵelementEnd()();
532
- i0.ɵɵelementStart(53, "div", 95)(54, "label", 109);
533
- i0.ɵɵtext(55, " Min P ");
619
+ i0.ɵɵelementStart(60, "div", 91)(61, "label", 110);
620
+ i0.ɵɵtext(62, " Min P ");
534
621
  i0.ɵɵelementEnd();
535
- i0.ɵɵelementStart(56, "kendo-numerictextbox", 106);
536
- 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); });
622
+ i0.ɵɵelementStart(63, "kendo-numerictextbox", 107);
623
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_63_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.minP, $event) || (ctx_r1.advancedParams.minP = $event); return i0.ɵɵresetView($event); });
537
624
  i0.ɵɵelementEnd()();
538
- i0.ɵɵelementStart(57, "div", 95)(58, "label", 110);
539
- i0.ɵɵtext(59, " Frequency Penalty ");
625
+ i0.ɵɵelementStart(64, "div", 91)(65, "label", 111);
626
+ i0.ɵɵtext(66, " Frequency Penalty ");
540
627
  i0.ɵɵelementEnd();
541
- i0.ɵɵelementStart(60, "kendo-numerictextbox", 106);
542
- 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); });
628
+ i0.ɵɵelementStart(67, "kendo-numerictextbox", 107);
629
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_67_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.frequencyPenalty, $event) || (ctx_r1.advancedParams.frequencyPenalty = $event); return i0.ɵɵresetView($event); });
543
630
  i0.ɵɵelementEnd()();
544
- i0.ɵɵelementStart(61, "div", 95)(62, "label", 111);
545
- i0.ɵɵtext(63, " Presence Penalty ");
631
+ i0.ɵɵelementStart(68, "div", 91)(69, "label", 112);
632
+ i0.ɵɵtext(70, " Presence Penalty ");
546
633
  i0.ɵɵelementEnd();
547
- i0.ɵɵelementStart(64, "kendo-numerictextbox", 106);
548
- 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); });
634
+ i0.ɵɵelementStart(71, "kendo-numerictextbox", 107);
635
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.presencePenalty, $event) || (ctx_r1.advancedParams.presencePenalty = $event); return i0.ɵɵresetView($event); });
549
636
  i0.ɵɵelementEnd()();
550
- i0.ɵɵelementStart(65, "div", 95)(66, "label", 112);
551
- i0.ɵɵtext(67, " Seed ");
637
+ i0.ɵɵelementStart(72, "div", 91)(73, "label", 113);
638
+ i0.ɵɵtext(74, " Seed ");
552
639
  i0.ɵɵelementEnd();
553
- i0.ɵɵelementStart(68, "kendo-numerictextbox", 113);
554
- 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); });
640
+ i0.ɵɵelementStart(75, "kendo-numerictextbox", 114);
641
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_numerictextbox_ngModelChange_75_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.seed, $event) || (ctx_r1.advancedParams.seed = $event); return i0.ɵɵresetView($event); });
555
642
  i0.ɵɵelementEnd()();
556
- i0.ɵɵelementStart(69, "div", 95)(70, "label", 114);
557
- i0.ɵɵtext(71, " Stop Sequences ");
643
+ i0.ɵɵelementStart(76, "div", 91)(77, "label", 115);
644
+ i0.ɵɵtext(78, " Stop Sequences ");
558
645
  i0.ɵɵelementEnd();
559
- i0.ɵɵelementStart(72, "kendo-textarea", 115);
560
- 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); });
561
- 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()); });
646
+ i0.ɵɵelementStart(79, "kendo-textarea", 116);
647
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_textarea_ngModelChange_79_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.stopSequencesText, $event) || (ctx_r1.stopSequencesText = $event); return i0.ɵɵresetView($event); });
648
+ i0.ɵɵlistener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_textarea_ngModelChange_79_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.updateStopSequences()); });
562
649
  i0.ɵɵelementEnd();
563
- i0.ɵɵelementStart(73, "div", 98);
564
- i0.ɵɵtext(74, " Separate multiple sequences with commas ");
650
+ i0.ɵɵelementStart(80, "div", 93);
651
+ i0.ɵɵtext(81, " Separate multiple sequences with commas ");
565
652
  i0.ɵɵelementEnd()();
566
- i0.ɵɵelementStart(75, "div", 95)(76, "label", 116);
567
- i0.ɵɵtext(77, " Include Log Probs ");
653
+ i0.ɵɵelementStart(82, "div", 91)(83, "label", 117);
654
+ i0.ɵɵtext(84, " Include Log Probs ");
568
655
  i0.ɵɵelementEnd();
569
- i0.ɵɵelementStart(78, "kendo-switch", 117);
570
- 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); });
656
+ i0.ɵɵelementStart(85, "kendo-switch", 118);
657
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template_kendo_switch_ngModelChange_85_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.advancedParams.includeLogProbs, $event) || (ctx_r1.advancedParams.includeLogProbs = $event); return i0.ɵɵresetView($event); });
571
658
  i0.ɵɵelementEnd()();
572
- i0.ɵɵtemplate(79, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Conditional_79_Template, 4, 5, "div", 95);
659
+ i0.ɵɵtemplate(86, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_86_Template, 4, 5, "div", 91);
573
660
  i0.ɵɵelementEnd()()()();
574
661
  } if (rf & 2) {
575
662
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -582,6 +669,11 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf,
582
669
  i0.ɵɵadvance(2);
583
670
  i0.ɵɵconditional(!ctx_r1.selectedModelId ? 18 : ctx_r1.availableVendors.length <= 1 ? 19 : 20);
584
671
  i0.ɵɵadvance(6);
672
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedConfigurationId);
673
+ i0.ɵɵproperty("data", ctx_r1.availableConfigurations)("valuePrimitive", true);
674
+ i0.ɵɵadvance(2);
675
+ i0.ɵɵconditional(ctx_r1.selectedConfigurationId ? 26 : 27);
676
+ i0.ɵɵadvance(5);
585
677
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedResponseFormat);
586
678
  i0.ɵɵproperty("data", ctx_r1.responseFormatOptions);
587
679
  i0.ɵɵadvance(6);
@@ -618,64 +710,64 @@ function AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template(rf,
618
710
  i0.ɵɵadvance(6);
619
711
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.advancedParams.includeLogProbs);
620
712
  i0.ɵɵadvance();
621
- i0.ɵɵconditional(ctx_r1.advancedParams.includeLogProbs ? 79 : -1);
713
+ i0.ɵɵconditional(ctx_r1.advancedParams.includeLogProbs ? 86 : -1);
622
714
  } }
623
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template(rf, ctx) { if (rf & 1) {
624
- const _r21 = i0.ɵɵgetCurrentView();
625
- i0.ɵɵelementStart(0, "button", 124);
626
- 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()); });
715
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Conditional_6_Template(rf, ctx) { if (rf & 1) {
716
+ const _r24 = i0.ɵɵgetCurrentView();
717
+ i0.ɵɵelementStart(0, "button", 125);
718
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.newConversation()); });
627
719
  i0.ɵɵelement(1, "i", 83);
628
720
  i0.ɵɵtext(2, " New ");
629
721
  i0.ɵɵelementEnd();
630
722
  } }
631
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template(rf, ctx) { if (rf & 1) {
632
- i0.ɵɵelementStart(0, "div", 122);
633
- i0.ɵɵelement(1, "i", 125);
723
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Conditional_8_Template(rf, ctx) { if (rf & 1) {
724
+ i0.ɵɵelementStart(0, "div", 123);
725
+ i0.ɵɵelement(1, "i", 126);
634
726
  i0.ɵɵelementStart(2, "p");
635
727
  i0.ɵɵtext(3, "No saved conversations");
636
728
  i0.ɵɵelementEnd()();
637
729
  } }
638
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template(rf, ctx) { if (rf & 1) {
639
- const _r22 = i0.ɵɵgetCurrentView();
640
- i0.ɵɵelementStart(0, "div", 126);
641
- 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)); });
642
- i0.ɵɵelementStart(1, "div", 127)(2, "h5");
730
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_For_10_Template(rf, ctx) { if (rf & 1) {
731
+ const _r25 = i0.ɵɵgetCurrentView();
732
+ i0.ɵɵelementStart(0, "div", 127);
733
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_For_10_Template_div_click_0_listener() { const conv_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.loadConversation(conv_r26)); });
734
+ i0.ɵɵelementStart(1, "div", 128)(2, "h5");
643
735
  i0.ɵɵtext(3);
644
736
  i0.ɵɵelementEnd();
645
737
  i0.ɵɵelementStart(4, "p");
646
738
  i0.ɵɵtext(5);
647
739
  i0.ɵɵelementEnd();
648
- i0.ɵɵelementStart(6, "span", 128);
740
+ i0.ɵɵelementStart(6, "span", 129);
649
741
  i0.ɵɵtext(7);
650
742
  i0.ɵɵpipe(8, "date");
651
743
  i0.ɵɵelementEnd()();
652
- i0.ɵɵelementStart(9, "button", 129);
653
- 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)); });
654
- i0.ɵɵelement(10, "i", 130);
744
+ i0.ɵɵelementStart(9, "button", 130);
745
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_For_10_Template_button_click_9_listener($event) { const conv_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.deleteConversation(conv_r26, $event)); });
746
+ i0.ɵɵelement(10, "i", 131);
655
747
  i0.ɵɵelementEnd()();
656
748
  } if (rf & 2) {
657
- const conv_r23 = ctx.$implicit;
749
+ const conv_r26 = ctx.$implicit;
658
750
  const ctx_r1 = i0.ɵɵnextContext(4);
659
- i0.ɵɵclassProp("current", conv_r23.id === ctx_r1.currentConversationId);
751
+ i0.ɵɵclassProp("current", conv_r26.id === ctx_r1.currentConversationId);
660
752
  i0.ɵɵadvance(3);
661
- i0.ɵɵtextInterpolate(conv_r23.name);
753
+ i0.ɵɵtextInterpolate(conv_r26.name);
662
754
  i0.ɵɵadvance(2);
663
- i0.ɵɵtextInterpolate1("", conv_r23.messages.length, " messages");
755
+ i0.ɵɵtextInterpolate1("", conv_r26.messages.length, " messages");
664
756
  i0.ɵɵadvance(2);
665
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(8, 5, conv_r23.updatedAt, "short"));
757
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(8, 5, conv_r26.updatedAt, "short"));
666
758
  } }
667
- function AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template(rf, ctx) { if (rf & 1) {
759
+ function AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Template(rf, ctx) { if (rf & 1) {
668
760
  i0.ɵɵelementStart(0, "div", 45)(1, "div", 78)(2, "h4");
669
761
  i0.ɵɵtext(3, "Saved Conversations");
670
762
  i0.ɵɵelementEnd();
671
763
  i0.ɵɵelementStart(4, "p");
672
764
  i0.ɵɵtext(5, "Previously saved test sessions");
673
765
  i0.ɵɵelementEnd();
674
- i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_6_Template, 3, 0, "button", 120);
766
+ i0.ɵɵtemplate(6, AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Conditional_6_Template, 3, 0, "button", 121);
675
767
  i0.ɵɵelementEnd();
676
- i0.ɵɵelementStart(7, "div", 121);
677
- i0.ɵɵtemplate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Conditional_8_Template, 4, 0, "div", 122);
678
- i0.ɵɵrepeaterCreate(9, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_For_10_Template, 11, 8, "div", 123, _forTrack0);
768
+ i0.ɵɵelementStart(7, "div", 122);
769
+ i0.ɵɵtemplate(8, AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Conditional_8_Template, 4, 0, "div", 123);
770
+ i0.ɵɵrepeaterCreate(9, AITestHarnessComponent_div_0_Conditional_4_Conditional_30_For_10_Template, 11, 8, "div", 124, _forTrack0);
679
771
  i0.ɵɵelementEnd()();
680
772
  } if (rf & 2) {
681
773
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -701,7 +793,7 @@ function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf &
701
793
  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);
702
794
  i0.ɵɵelementEnd()()()()();
703
795
  i0.ɵɵelementStart(15, "kendo-splitter-pane", 38)(16, "div", 39)(17, "div", 40);
704
- i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template, 6, 5)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template, 6, 4);
796
+ i0.ɵɵtemplate(18, AITestHarnessComponent_div_0_Conditional_4_Conditional_18_Template, 9, 8)(19, AITestHarnessComponent_div_0_Conditional_4_Conditional_19_Template, 6, 4);
705
797
  i0.ɵɵelementStart(20, "button", 41);
706
798
  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")); });
707
799
  i0.ɵɵelement(21, "i", 42);
@@ -709,7 +801,7 @@ function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf &
709
801
  i0.ɵɵtemplate(23, AITestHarnessComponent_div_0_Conditional_4_Conditional_23_Template, 2, 1, "span", 43);
710
802
  i0.ɵɵelementEnd()();
711
803
  i0.ɵɵelementStart(24, "div", 44);
712
- 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, 6, "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);
804
+ 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, 6, "div", 46)(27, AITestHarnessComponent_div_0_Conditional_4_Conditional_27_Template, 14, 4, "div", 45)(28, AITestHarnessComponent_div_0_Conditional_4_Conditional_28_Template, 12, 0, "div", 45)(29, AITestHarnessComponent_div_0_Conditional_4_Conditional_29_Template, 87, 56, "div", 47)(30, AITestHarnessComponent_div_0_Conditional_4_Conditional_30_Template, 11, 2, "div", 45);
713
805
  i0.ɵɵelementEnd()()()();
714
806
  } if (rf & 2) {
715
807
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -740,11 +832,13 @@ function AITestHarnessComponent_div_0_Conditional_4_Template(rf, ctx) { if (rf &
740
832
  i0.ɵɵadvance();
741
833
  i0.ɵɵconditional(ctx_r1.activeTab === "executionMonitor" ? 26 : -1);
742
834
  i0.ɵɵadvance();
743
- i0.ɵɵconditional(ctx_r1.activeTab === "templateVariables" ? 27 : -1);
835
+ i0.ɵɵconditional(ctx_r1.activeTab === "agentSettings" ? 27 : -1);
836
+ i0.ɵɵadvance();
837
+ i0.ɵɵconditional(ctx_r1.activeTab === "templateVariables" ? 28 : -1);
744
838
  i0.ɵɵadvance();
745
- i0.ɵɵconditional(ctx_r1.activeTab === "modelSettings" ? 28 : -1);
839
+ i0.ɵɵconditional(ctx_r1.activeTab === "modelSettings" ? 29 : -1);
746
840
  i0.ɵɵadvance();
747
- i0.ɵɵconditional(ctx_r1.activeTab === "savedConversations" ? 29 : -1);
841
+ i0.ɵɵconditional(ctx_r1.activeTab === "savedConversations" ? 30 : -1);
748
842
  } }
749
843
  function AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
750
844
  i0.ɵɵelementStart(0, "div", 30);
@@ -761,7 +855,7 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_3_Template
761
855
  i0.ɵɵtext(1, " You ");
762
856
  } }
763
857
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
764
- i0.ɵɵelement(0, "i", 133);
858
+ i0.ɵɵelement(0, "i", 134);
765
859
  i0.ɵɵtext(1);
766
860
  } if (rf & 2) {
767
861
  const ctx_r1 = i0.ɵɵnextContext(4);
@@ -774,60 +868,60 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_7_Template
774
868
  i0.ɵɵtext(2);
775
869
  i0.ɵɵelementEnd();
776
870
  } if (rf & 2) {
777
- const message_r26 = i0.ɵɵnextContext().$implicit;
871
+ const message_r29 = i0.ɵɵnextContext().$implicit;
778
872
  const ctx_r1 = i0.ɵɵnextContext(3);
779
873
  i0.ɵɵadvance(2);
780
- i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r26.elapsedTime), " ");
874
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatElapsedTime(message_r29.elapsedTime), " ");
781
875
  } }
782
876
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_8_Template(rf, ctx) { if (rf & 1) {
783
877
  i0.ɵɵelementStart(0, "span", 53);
784
878
  i0.ɵɵtext(1);
785
879
  i0.ɵɵelementEnd();
786
880
  } if (rf & 2) {
787
- const message_r26 = i0.ɵɵnextContext().$implicit;
881
+ const message_r29 = i0.ɵɵnextContext().$implicit;
788
882
  const ctx_r1 = i0.ɵɵnextContext(3);
789
- i0.ɵɵproperty("title", ctx_r1.getExecutionSummary(message_r26));
883
+ i0.ɵɵproperty("title", ctx_r1.getExecutionSummary(message_r29));
790
884
  i0.ɵɵadvance();
791
- i0.ɵɵtextInterpolate(ctx_r1.formatExecutionTime(message_r26.executionTime));
885
+ i0.ɵɵtextInterpolate(ctx_r1.formatExecutionTime(message_r29.executionTime));
792
886
  } }
793
887
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template(rf, ctx) { if (rf & 1) {
794
- const _r27 = i0.ɵɵgetCurrentView();
888
+ const _r30 = i0.ɵɵgetCurrentView();
795
889
  i0.ɵɵelementStart(0, "button", 64);
796
- 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)); });
890
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r30); const message_r29 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showRawJsonDialog(message_r29)); });
797
891
  i0.ɵɵelement(1, "i", 65);
798
892
  i0.ɵɵelementEnd();
799
893
  } }
800
894
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template(rf, ctx) { if (rf & 1) {
801
- const _r28 = i0.ɵɵgetCurrentView();
802
- i0.ɵɵelementStart(0, "button", 134);
803
- 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)); });
895
+ const _r31 = i0.ɵɵgetCurrentView();
896
+ i0.ɵɵelementStart(0, "button", 135);
897
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r31); const message_r29 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showMessageExecutionHistory(message_r29)); });
804
898
  i0.ɵɵelement(1, "i", 76);
805
899
  i0.ɵɵelementEnd();
806
900
  } }
807
901
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
808
- const _r29 = i0.ɵɵgetCurrentView();
809
- i0.ɵɵelementStart(0, "button", 135);
810
- 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({ runId: message_r26.agentRunId, runType: "agent" })); });
811
- i0.ɵɵelement(1, "i", 136);
902
+ const _r32 = i0.ɵɵgetCurrentView();
903
+ i0.ɵɵelementStart(0, "button", 136);
904
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r32); const message_r29 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.navigateToAgentRun({ runId: message_r29.agentRunId, runType: "agent" })); });
905
+ i0.ɵɵelement(1, "i", 137);
812
906
  i0.ɵɵelementEnd();
813
907
  } }
814
908
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_15_Template(rf, ctx) { if (rf & 1) {
815
- i0.ɵɵelementStart(0, "div", 58)(1, "span", 137);
909
+ i0.ɵɵelementStart(0, "div", 58)(1, "span", 138);
816
910
  i0.ɵɵtext(2);
817
911
  i0.ɵɵelementStart(3, "span", 67);
818
912
  i0.ɵɵtext(4, "|");
819
913
  i0.ɵɵelementEnd()()();
820
914
  } if (rf & 2) {
821
- const message_r26 = i0.ɵɵnextContext().$implicit;
915
+ const message_r29 = i0.ɵɵnextContext().$implicit;
822
916
  i0.ɵɵadvance(2);
823
- i0.ɵɵtextInterpolate(message_r26.streamingContent);
917
+ i0.ɵɵtextInterpolate(message_r29.streamingContent);
824
918
  } }
825
919
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_16_Template(rf, ctx) { if (rf & 1) {
826
920
  i0.ɵɵelement(0, "div", 59);
827
921
  } if (rf & 2) {
828
- const message_r26 = i0.ɵɵnextContext().$implicit;
922
+ const message_r29 = i0.ɵɵnextContext().$implicit;
829
923
  const ctx_r1 = i0.ɵɵnextContext(3);
830
- i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r26), i0.ɵɵsanitizeHtml);
924
+ i0.ɵɵproperty("innerHTML", ctx_r1.getFormattedContent(message_r29), i0.ɵɵsanitizeHtml);
831
925
  } }
832
926
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Template(rf, ctx) { if (rf & 1) {
833
927
  i0.ɵɵelementStart(0, "div", 60);
@@ -835,24 +929,24 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_17_Templat
835
929
  i0.ɵɵtext(2);
836
930
  i0.ɵɵelementEnd();
837
931
  } if (rf & 2) {
838
- const message_r26 = i0.ɵɵnextContext().$implicit;
932
+ const message_r29 = i0.ɵɵnextContext().$implicit;
839
933
  i0.ɵɵadvance(2);
840
- i0.ɵɵtextInterpolate1(" ", message_r26.error, " ");
934
+ i0.ɵɵtextInterpolate1(" ", message_r29.error, " ");
841
935
  } }
842
936
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template(rf, ctx) { if (rf & 1) {
843
937
  i0.ɵɵelementStart(0, "div", 73)(1, "pre");
844
938
  i0.ɵɵtext(2);
845
939
  i0.ɵɵelementEnd()();
846
940
  } if (rf & 2) {
847
- const message_r26 = i0.ɵɵnextContext(2).$implicit;
941
+ const message_r29 = i0.ɵɵnextContext(2).$implicit;
848
942
  const ctx_r1 = i0.ɵɵnextContext(3);
849
943
  i0.ɵɵadvance(2);
850
- i0.ɵɵtextInterpolate(ctx_r1.formatJson(message_r26.payload));
944
+ i0.ɵɵtextInterpolate(ctx_r1.formatJson(message_r29.payload));
851
945
  } }
852
946
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template(rf, ctx) { if (rf & 1) {
853
- const _r30 = i0.ɵɵgetCurrentView();
947
+ const _r33 = i0.ɵɵgetCurrentView();
854
948
  i0.ɵɵelementStart(0, "div", 69)(1, "div", 70);
855
- 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)); });
949
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r33); const message_r29 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.togglePayloadCollapse(message_r29)); });
856
950
  i0.ɵɵelementStart(2, "span", 71);
857
951
  i0.ɵɵelement(3, "i", 65);
858
952
  i0.ɵɵtext(4, " Payload ");
@@ -863,51 +957,51 @@ function AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Templat
863
957
  i0.ɵɵtemplate(7, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_18_Conditional_7_Template, 3, 1, "div", 73);
864
958
  i0.ɵɵelementEnd();
865
959
  } if (rf & 2) {
866
- const message_r26 = i0.ɵɵnextContext().$implicit;
867
- i0.ɵɵclassProp("collapsed", message_r26.payloadCollapsed);
960
+ const message_r29 = i0.ɵɵnextContext().$implicit;
961
+ i0.ɵɵclassProp("collapsed", message_r29.payloadCollapsed);
868
962
  i0.ɵɵadvance(6);
869
- i0.ɵɵclassProp("fa-chevron-down", !message_r26.payloadCollapsed)("fa-chevron-right", message_r26.payloadCollapsed);
963
+ i0.ɵɵclassProp("fa-chevron-down", !message_r29.payloadCollapsed)("fa-chevron-right", message_r29.payloadCollapsed);
870
964
  i0.ɵɵadvance();
871
- i0.ɵɵconditional(!message_r26.payloadCollapsed ? 7 : -1);
965
+ i0.ɵɵconditional(!message_r29.payloadCollapsed ? 7 : -1);
872
966
  } }
873
967
  function AITestHarnessComponent_div_0_Conditional_5_For_5_Template(rf, ctx) { if (rf & 1) {
874
- const _r25 = i0.ɵɵgetCurrentView();
968
+ const _r28 = i0.ɵɵgetCurrentView();
875
969
  i0.ɵɵelementStart(0, "div", 31)(1, "div", 49)(2, "span", 50);
876
970
  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);
877
971
  i0.ɵɵelementEnd();
878
972
  i0.ɵɵelementStart(5, "span", 51);
879
973
  i0.ɵɵtext(6);
880
974
  i0.ɵɵelementEnd();
881
- 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);
975
+ 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", 132)(11, AITestHarnessComponent_div_0_Conditional_5_For_5_Conditional_11_Template, 2, 0, "button", 133);
882
976
  i0.ɵɵelementEnd();
883
977
  i0.ɵɵelementStart(12, "div", 55)(13, "button", 56);
884
- 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)); });
978
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_For_5_Template_button_click_13_listener() { const message_r29 = i0.ɵɵrestoreView(_r28).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.copyMessage(message_r29)); });
885
979
  i0.ɵɵelement(14, "i", 57);
886
980
  i0.ɵɵelementEnd();
887
981
  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);
888
982
  i0.ɵɵelementEnd()();
889
983
  } if (rf & 2) {
890
- const message_r26 = ctx.$implicit;
984
+ const message_r29 = ctx.$implicit;
891
985
  const ctx_r1 = i0.ɵɵnextContext(3);
892
- i0.ɵɵproperty("ngClass", ctx_r1.getMessageClass(message_r26));
986
+ i0.ɵɵproperty("ngClass", ctx_r1.getMessageClass(message_r29));
893
987
  i0.ɵɵadvance(3);
894
- i0.ɵɵconditional(message_r26.role === "user" ? 3 : 4);
988
+ i0.ɵɵconditional(message_r29.role === "user" ? 3 : 4);
895
989
  i0.ɵɵadvance(3);
896
- i0.ɵɵtextInterpolate(ctx_r1.formatTimestamp(message_r26.timestamp));
990
+ i0.ɵɵtextInterpolate(ctx_r1.formatTimestamp(message_r29.timestamp));
897
991
  i0.ɵɵadvance();
898
- i0.ɵɵconditional(message_r26.isStreaming && message_r26.elapsedTime !== undefined ? 7 : message_r26.executionTime ? 8 : -1);
992
+ i0.ɵɵconditional(message_r29.isStreaming && message_r29.elapsedTime !== undefined ? 7 : message_r29.executionTime ? 8 : -1);
899
993
  i0.ɵɵadvance(2);
900
- i0.ɵɵconditional(ctx_r1.showRawToggle(message_r26) ? 9 : -1);
994
+ i0.ɵɵconditional(ctx_r1.showRawToggle(message_r29) ? 9 : -1);
901
995
  i0.ɵɵadvance();
902
- i0.ɵɵconditional(message_r26.executionData && ctx_r1.mode === "agent" && message_r26.role === "assistant" ? 10 : -1);
996
+ i0.ɵɵconditional(message_r29.executionData && ctx_r1.mode === "agent" && message_r29.role === "assistant" ? 10 : -1);
903
997
  i0.ɵɵadvance();
904
- i0.ɵɵconditional(message_r26.agentRunId && ctx_r1.mode === "agent" && message_r26.role === "assistant" ? 11 : -1);
998
+ i0.ɵɵconditional(message_r29.agentRunId && ctx_r1.mode === "agent" && message_r29.role === "assistant" ? 11 : -1);
905
999
  i0.ɵɵadvance(4);
906
- i0.ɵɵconditional(message_r26.isStreaming ? 15 : 16);
1000
+ i0.ɵɵconditional(message_r29.isStreaming ? 15 : 16);
907
1001
  i0.ɵɵadvance(2);
908
- i0.ɵɵconditional(message_r26.error ? 17 : -1);
1002
+ i0.ɵɵconditional(message_r29.error ? 17 : -1);
909
1003
  i0.ɵɵadvance();
910
- i0.ɵɵconditional(ctx_r1.hasPayload(message_r26.payload) && ctx_r1.mode === "agent" && message_r26.role === "assistant" ? 18 : -1);
1004
+ i0.ɵɵconditional(ctx_r1.hasPayload(message_r29.payload) && ctx_r1.mode === "agent" && message_r29.role === "assistant" ? 18 : -1);
911
1005
  } }
912
1006
  function AITestHarnessComponent_div_0_Conditional_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
913
1007
  i0.ɵɵelement(0, "i", 36);
@@ -916,17 +1010,17 @@ function AITestHarnessComponent_div_0_Conditional_5_Conditional_12_Template(rf,
916
1010
  i0.ɵɵelement(0, "i", 37);
917
1011
  } }
918
1012
  function AITestHarnessComponent_div_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
919
- const _r24 = i0.ɵɵgetCurrentView();
1013
+ const _r27 = i0.ɵɵgetCurrentView();
920
1014
  i0.ɵɵelementStart(0, "div", 12)(1, "div", 29, 1);
921
1015
  i0.ɵɵtemplate(3, AITestHarnessComponent_div_0_Conditional_5_Conditional_3_Template, 6, 0, "div", 30);
922
1016
  i0.ɵɵrepeaterCreate(4, AITestHarnessComponent_div_0_Conditional_5_For_5_Template, 19, 10, "div", 31, _forTrack0);
923
1017
  i0.ɵɵelementEnd();
924
1018
  i0.ɵɵelementStart(6, "div", 32)(7, "div", 33)(8, "kendo-textarea", 34, 2);
925
- 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); });
926
- 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)); });
1019
+ i0.ɵɵtwoWayListener("ngModelChange", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.currentUserMessage, $event) || (ctx_r1.currentUserMessage = $event); return i0.ɵɵresetView($event); });
1020
+ i0.ɵɵlistener("keypress", function AITestHarnessComponent_div_0_Conditional_5_Template_kendo_textarea_keypress_8_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.handleKeyPress($event)); });
927
1021
  i0.ɵɵelementEnd();
928
1022
  i0.ɵɵelementStart(10, "button", 35);
929
- 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()); });
1023
+ i0.ɵɵlistener("click", function AITestHarnessComponent_div_0_Conditional_5_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.sendMessage()); });
930
1024
  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);
931
1025
  i0.ɵɵelementEnd()()()();
932
1026
  } if (rf & 2) {
@@ -948,7 +1042,7 @@ function AITestHarnessComponent_div_0_Template(rf, ctx) { if (rf & 1) {
948
1042
  i0.ɵɵtemplate(2, AITestHarnessComponent_div_0_Conditional_2_Template, 25, 10, "div", 9);
949
1043
  i0.ɵɵelementEnd();
950
1044
  i0.ɵɵelementStart(3, "div", 10);
951
- 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);
1045
+ i0.ɵɵtemplate(4, AITestHarnessComponent_div_0_Conditional_4_Template, 31, 24, "kendo-splitter", 11)(5, AITestHarnessComponent_div_0_Conditional_5_Template, 13, 6, "div", 12);
952
1046
  i0.ɵɵelementEnd()();
953
1047
  } if (rf & 2) {
954
1048
  const ctx_r1 = i0.ɵɵnextContext();
@@ -958,21 +1052,21 @@ function AITestHarnessComponent_div_0_Template(rf, ctx) { if (rf & 1) {
958
1052
  i0.ɵɵconditional(ctx_r1.showSidebar ? 4 : 5);
959
1053
  } }
960
1054
  function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
961
- const _r31 = i0.ɵɵgetCurrentView();
962
- i0.ɵɵelementStart(0, "kendo-dialog", 138);
963
- 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()); });
964
- i0.ɵɵelementStart(1, "div", 139)(2, "p");
1055
+ const _r34 = i0.ɵɵgetCurrentView();
1056
+ i0.ɵɵelementStart(0, "kendo-dialog", 139);
1057
+ i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_1_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
1058
+ i0.ɵɵelementStart(1, "div", 140)(2, "p");
965
1059
  i0.ɵɵtext(3, "Enter a name for this conversation:");
966
1060
  i0.ɵɵelementEnd();
967
- i0.ɵɵelementStart(4, "input", 140, 3);
968
- 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()); });
1061
+ i0.ɵɵelementStart(4, "input", 141, 3);
1062
+ i0.ɵɵlistener("keyup", function AITestHarnessComponent_Conditional_1_Template_input_keyup_4_listener() { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateTempConversation()); });
969
1063
  i0.ɵɵelementEnd()();
970
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 141);
971
- 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()); });
1064
+ i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 142);
1065
+ i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelSaveDialog()); });
972
1066
  i0.ɵɵtext(8, "Cancel");
973
1067
  i0.ɵɵelementEnd();
974
- i0.ɵɵelementStart(9, "button", 142);
975
- 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()); });
1068
+ i0.ɵɵelementStart(9, "button", 143);
1069
+ i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_1_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmSaveConversation()); });
976
1070
  i0.ɵɵtext(10, " Save ");
977
1071
  i0.ɵɵelementEnd()()();
978
1072
  } if (rf & 2) {
@@ -982,21 +1076,21 @@ function AITestHarnessComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
982
1076
  i0.ɵɵproperty("primary", true)("disabled", ctx_r1.tempConversationName === "");
983
1077
  } }
984
1078
  function AITestHarnessComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
985
- const _r32 = i0.ɵɵgetCurrentView();
986
- i0.ɵɵelementStart(0, "kendo-dialog", 143);
987
- 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()); });
988
- i0.ɵɵelementStart(1, "div", 139)(2, "p");
1079
+ const _r35 = i0.ɵɵgetCurrentView();
1080
+ i0.ɵɵelementStart(0, "kendo-dialog", 144);
1081
+ i0.ɵɵlistener("close", function AITestHarnessComponent_Conditional_2_Template_kendo_dialog_close_0_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
1082
+ i0.ɵɵelementStart(1, "div", 140)(2, "p");
989
1083
  i0.ɵɵtext(3, "Loading this conversation will replace the current one. Any unsaved changes will be lost.");
990
1084
  i0.ɵɵelementEnd();
991
1085
  i0.ɵɵelementStart(4, "p");
992
1086
  i0.ɵɵtext(5, "Do you want to continue?");
993
1087
  i0.ɵɵelementEnd()();
994
- i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 141);
995
- 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()); });
1088
+ i0.ɵɵelementStart(6, "kendo-dialog-actions")(7, "button", 142);
1089
+ i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelLoadConversation()); });
996
1090
  i0.ɵɵtext(8, "Cancel");
997
1091
  i0.ɵɵelementEnd();
998
- i0.ɵɵelementStart(9, "button", 144);
999
- 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()); });
1092
+ i0.ɵɵelementStart(9, "button", 145);
1093
+ i0.ɵɵlistener("click", function AITestHarnessComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmLoadConversation()); });
1000
1094
  i0.ɵɵtext(10, " Load Conversation ");
1001
1095
  i0.ɵɵelementEnd()()();
1002
1096
  } if (rf & 2) {
@@ -1086,12 +1180,18 @@ export class AITestHarnessComponent {
1086
1180
  this.selectedVendorId = '';
1087
1181
  /** Available AI vendors for the selected model */
1088
1182
  this.availableVendors = [];
1183
+ /** Selected AI configuration for prompt execution */
1184
+ this.selectedConfigurationId = '';
1185
+ /** Available AI configurations */
1186
+ this.availableConfigurations = [];
1089
1187
  /** Default model for the prompt (cached for display) */
1090
1188
  this.defaultModelName = '';
1091
1189
  /** Maximum tokens for prompt execution */
1092
1190
  this.maxTokens = null;
1093
1191
  /** Whether to skip validation when running prompts */
1094
1192
  this.skipValidation = false;
1193
+ /** Selected AI configuration for agent execution */
1194
+ this.agentConfigurationId = '';
1095
1195
  /** Advanced LLM Parameters */
1096
1196
  this.advancedParams = {
1097
1197
  temperature: null,
@@ -1215,6 +1315,8 @@ export class AITestHarnessComponent {
1215
1315
  this.loadSavedConversations();
1216
1316
  this.subscribeToEvents();
1217
1317
  this.resetHarness();
1318
+ // Load configurations for both modes
1319
+ this.loadAvailableConfigurations();
1218
1320
  // Load models if in prompt mode
1219
1321
  if (this.mode === 'prompt') {
1220
1322
  this.loadAvailableModels();
@@ -1503,6 +1605,37 @@ export class AITestHarnessComponent {
1503
1605
  this.availableVendors = [];
1504
1606
  }
1505
1607
  }
1608
+ /**
1609
+ * Loads available AI configurations from the database
1610
+ * Only configurations with 'Active' or 'Preview' status are shown
1611
+ */
1612
+ async loadAvailableConfigurations() {
1613
+ try {
1614
+ const rv = new RunView();
1615
+ const result = await rv.RunView({
1616
+ EntityName: 'MJ: AI Configurations',
1617
+ ExtraFilter: `Status IN ('Active', 'Preview')`,
1618
+ OrderBy: 'IsDefault DESC, Name',
1619
+ ResultType: 'entity_object'
1620
+ });
1621
+ if (result.Success && result.Results) {
1622
+ this.availableConfigurations = result.Results;
1623
+ // Auto-select the default configuration if one exists
1624
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1625
+ if (defaultConfig) {
1626
+ this.selectedConfigurationId = defaultConfig.ID;
1627
+ }
1628
+ }
1629
+ else {
1630
+ console.error('Failed to load AI configurations:', result.ErrorMessage);
1631
+ this.availableConfigurations = [];
1632
+ }
1633
+ }
1634
+ catch (error) {
1635
+ console.error('Error loading AI configurations:', error);
1636
+ this.availableConfigurations = [];
1637
+ }
1638
+ }
1506
1639
  /**
1507
1640
  * Handles model selection change and loads available vendors for the selected model
1508
1641
  */
@@ -1673,6 +1806,14 @@ export class AITestHarnessComponent {
1673
1806
  this.maxTokens = null;
1674
1807
  // Reset skip validation
1675
1808
  this.skipValidation = false;
1809
+ // Reset configuration to default
1810
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1811
+ if (defaultConfig) {
1812
+ this.selectedConfigurationId = defaultConfig.ID;
1813
+ }
1814
+ else {
1815
+ this.selectedConfigurationId = '';
1816
+ }
1676
1817
  // Reset advanced parameters
1677
1818
  this.advancedParams = {
1678
1819
  temperature: null,
@@ -1734,6 +1875,11 @@ export class AITestHarnessComponent {
1734
1875
  this.stopSequencesText = '';
1735
1876
  this.advancedParamsExpanded = false;
1736
1877
  this.skipValidation = false;
1878
+ // Reset agent configuration to default
1879
+ if (this.mode === 'agent') {
1880
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1881
+ this.agentConfigurationId = defaultConfig?.ID || '';
1882
+ }
1737
1883
  }
1738
1884
  /**
1739
1885
  * Starts a new conversation
@@ -1981,8 +2127,8 @@ export class AITestHarnessComponent {
1981
2127
  const sessionId = dataProvider.sessionId;
1982
2128
  // Execute the agent
1983
2129
  const query = `
1984
- mutation RunAIAgent($agentId: String!, $messages: String!, $sessionId: String!, $data: String, $templateData: String, $lastRunId: String, $autoPopulateLastRunPayload: Boolean) {
1985
- RunAIAgent(agentId: $agentId, messages: $messages, sessionId: $sessionId, data: $data, templateData: $templateData, lastRunId: $lastRunId, autoPopulateLastRunPayload: $autoPopulateLastRunPayload) {
2130
+ mutation RunAIAgent($agentId: String!, $messages: String!, $sessionId: String!, $data: String, $templateData: String, $lastRunId: String, $autoPopulateLastRunPayload: Boolean, $configurationId: String) {
2131
+ RunAIAgent(agentId: $agentId, messages: $messages, sessionId: $sessionId, data: $data, templateData: $templateData, lastRunId: $lastRunId, autoPopulateLastRunPayload: $autoPopulateLastRunPayload, configurationId: $configurationId) {
1986
2132
  success
1987
2133
  errorMessage
1988
2134
  executionTimeMs
@@ -1997,7 +2143,8 @@ export class AITestHarnessComponent {
1997
2143
  data: Object.keys(dataContext).length > 0 ? JSON.stringify(dataContext) : null,
1998
2144
  templateData: Object.keys(templateData).length > 0 ? JSON.stringify(templateData) : null,
1999
2145
  lastRunId: this.lastAgentRunId,
2000
- autoPopulateLastRunPayload: this.lastAgentRunId ? true : false
2146
+ autoPopulateLastRunPayload: this.lastAgentRunId ? true : false,
2147
+ configurationId: this.agentConfigurationId || undefined
2001
2148
  };
2002
2149
  // Start typing animation while we wait for the first real stream
2003
2150
  this.startTypingAnimation(assistantMessage);
@@ -2208,7 +2355,7 @@ export class AITestHarnessComponent {
2208
2355
  data: JSON.stringify(dataContext),
2209
2356
  overrideModelId: this.selectedModelId || undefined,
2210
2357
  overrideVendorId: this.selectedVendorId || undefined,
2211
- configurationId: undefined, // Use default configuration
2358
+ configurationId: this.selectedConfigurationId || undefined,
2212
2359
  skipValidation: this.skipValidation,
2213
2360
  templateData: null, // Additional template context if needed
2214
2361
  responseFormat: this.selectedResponseFormat?.value,
@@ -2534,7 +2681,9 @@ export class AITestHarnessComponent {
2534
2681
  advancedParams: this.mode === 'prompt' ? this.advancedParams : undefined,
2535
2682
  selectedModelId: this.mode === 'prompt' ? this.selectedModelId : undefined,
2536
2683
  selectedVendorId: this.mode === 'prompt' ? this.selectedVendorId : undefined,
2684
+ selectedConfigurationId: this.mode === 'prompt' ? this.selectedConfigurationId : undefined,
2537
2685
  skipValidation: this.mode === 'prompt' ? this.skipValidation : undefined,
2686
+ agentConfigurationId: this.mode === 'agent' ? this.agentConfigurationId : undefined,
2538
2687
  createdAt: new Date(),
2539
2688
  updatedAt: new Date()
2540
2689
  };
@@ -2599,12 +2748,14 @@ export class AITestHarnessComponent {
2599
2748
  this.savedConversations[index].dataContext = this.buildDataContext();
2600
2749
  if (this.mode === 'agent') {
2601
2750
  this.savedConversations[index].templateData = this.buildTemplateData();
2751
+ this.savedConversations[index].agentConfigurationId = this.agentConfigurationId;
2602
2752
  }
2603
2753
  else {
2604
2754
  this.savedConversations[index].templateVariables = this.buildTemplateVariables();
2605
2755
  this.savedConversations[index].advancedParams = this.advancedParams;
2606
2756
  this.savedConversations[index].selectedModelId = this.selectedModelId;
2607
2757
  this.savedConversations[index].selectedVendorId = this.selectedVendorId;
2758
+ this.savedConversations[index].selectedConfigurationId = this.selectedConfigurationId;
2608
2759
  this.savedConversations[index].skipValidation = this.skipValidation;
2609
2760
  }
2610
2761
  this.savedConversations[index].updatedAt = new Date();
@@ -2661,6 +2812,12 @@ export class AITestHarnessComponent {
2661
2812
  typeof value === 'object' ? 'object' : 'string'
2662
2813
  });
2663
2814
  }
2815
+ // Restore configuration for agent mode
2816
+ if (this.mode === 'agent') {
2817
+ if (conversation.agentConfigurationId !== undefined) {
2818
+ this.agentConfigurationId = conversation.agentConfigurationId;
2819
+ }
2820
+ }
2664
2821
  // Restore template variables for prompt mode
2665
2822
  if (this.mode === 'prompt') {
2666
2823
  this.templateVariables = [];
@@ -2696,6 +2853,10 @@ export class AITestHarnessComponent {
2696
2853
  if (conversation.selectedVendorId !== undefined && !this.selectedModelId) {
2697
2854
  this.selectedVendorId = conversation.selectedVendorId;
2698
2855
  }
2856
+ // Restore configuration selection
2857
+ if (conversation.selectedConfigurationId !== undefined) {
2858
+ this.selectedConfigurationId = conversation.selectedConfigurationId;
2859
+ }
2699
2860
  // Restore skip validation setting
2700
2861
  if (conversation.skipValidation !== undefined) {
2701
2862
  this.skipValidation = conversation.skipValidation;
@@ -2752,12 +2913,16 @@ export class AITestHarnessComponent {
2752
2913
  // Add mode-specific data
2753
2914
  if (this.mode === 'agent') {
2754
2915
  exportData.templateData = this.buildTemplateData();
2916
+ exportData.agentSettings = {
2917
+ configurationId: this.agentConfigurationId
2918
+ };
2755
2919
  }
2756
2920
  else {
2757
2921
  exportData.templateVariables = this.buildTemplateVariables();
2758
2922
  exportData.modelSettings = {
2759
2923
  modelId: this.selectedModelId,
2760
2924
  vendorId: this.selectedVendorId,
2925
+ configurationId: this.selectedConfigurationId,
2761
2926
  maxTokens: this.maxTokens,
2762
2927
  skipValidation: this.skipValidation
2763
2928
  };
@@ -2812,6 +2977,40 @@ export class AITestHarnessComponent {
2812
2977
  this.advancedParams = { ...this.advancedParams, ...data.advancedParams };
2813
2978
  this.stopSequencesText = this.advancedParams.stopSequences?.join(', ') || '';
2814
2979
  }
2980
+ // Import agent settings if in agent mode
2981
+ if (this.mode === 'agent' && data.agentSettings) {
2982
+ if (data.agentSettings.configurationId !== undefined) {
2983
+ this.agentConfigurationId = data.agentSettings.configurationId;
2984
+ }
2985
+ }
2986
+ // Import model settings if in prompt mode
2987
+ if (this.mode === 'prompt' && data.modelSettings) {
2988
+ if (data.modelSettings.modelId !== undefined) {
2989
+ this.selectedModelId = data.modelSettings.modelId;
2990
+ // Trigger vendor loading if model is selected
2991
+ if (this.selectedModelId) {
2992
+ this.onModelSelectionChange();
2993
+ // After vendors load, restore vendor selection
2994
+ setTimeout(() => {
2995
+ if (data.modelSettings.vendorId !== undefined) {
2996
+ this.selectedVendorId = data.modelSettings.vendorId;
2997
+ }
2998
+ }, 100);
2999
+ }
3000
+ }
3001
+ if (data.modelSettings.vendorId !== undefined && !this.selectedModelId) {
3002
+ this.selectedVendorId = data.modelSettings.vendorId;
3003
+ }
3004
+ if (data.modelSettings.configurationId !== undefined) {
3005
+ this.selectedConfigurationId = data.modelSettings.configurationId;
3006
+ }
3007
+ if (data.modelSettings.maxTokens !== undefined) {
3008
+ this.maxTokens = data.modelSettings.maxTokens;
3009
+ }
3010
+ if (data.modelSettings.skipValidation !== undefined) {
3011
+ this.skipValidation = data.modelSettings.skipValidation;
3012
+ }
3013
+ }
2815
3014
  this.currentConversationId = null;
2816
3015
  this.scrollNeeded = true;
2817
3016
  MJNotificationService.Instance.CreateSimpleNotification('Conversation imported successfully', 'success', 3000);
@@ -3520,7 +3719,7 @@ export class AITestHarnessComponent {
3520
3719
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.fileInput = _t.first);
3521
3720
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageInput = _t.first);
3522
3721
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.saveDialogInput = _t.first);
3523
- } }, inputs: { mode: "mode", entity: "entity", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange", runOpened: "runOpened", minimizeRequested: "minimizeRequested" }, 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", "agentRun", "liveSteps", "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) {
3722
+ } }, inputs: { mode: "mode", entity: "entity", aiAgent: "aiAgent", isVisible: "isVisible" }, outputs: { visibilityChange: "visibilityChange", runOpened: "runOpened", minimizeRequested: "minimizeRequested" }, 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", "agentRun", "liveSteps", "autoExpand", "runId", "runType"], [1, "model-settings"], [1, "setting-group"], ["textField", "Name", "valueField", "ID", "placeholder", "Select a configuration...", 1, "configuration-selector", 3, "ngModelChange", "ngModel", "data", "valuePrimitive"], [1, "setting-help"], [1, "add-button", 3, "click"], ["title", "Remove variable", 1, "remove-button", 3, "click"], ["title", "Reset to Prompt Settings", 1, "custom-button", "icon-only", 3, "click"], [1, "fa-solid", "fa-undo"], ["textField", "Name", "valueField", "ID", "placeholder", "Select a model...", 1, "model-selector", 3, "ngModelChange", "ngModel", "data", "valuePrimitive"], ["textField", "Name", "valueField", "ID", "placeholder", "Select a vendor...", 1, "vendor-selector", 3, "ngModelChange", "ngModel", "data", "valuePrimitive", "disabled"], ["textField", "text", "valueField", "value", "placeholder", "Select format...", 1, "format-selector", 3, "ngModelChange", "ngModel", "data"], ["placeholder", "Max tokens...", 1, "max-tokens-input", 3, "ngModelChange", "ngModel", "min", "max", "step"], [1, "checkbox-label"], ["type", "checkbox", 1, "skip-validation-checkbox", 3, "ngModelChange", "ngModel"], ["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) {
3524
3723
  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);
3525
3724
  } if (rf & 2) {
3526
3725
  i0.ɵɵproperty("ngIf", ctx.isVisible);
@@ -3532,7 +3731,7 @@ export class AITestHarnessComponent {
3532
3731
  }
3533
3732
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AITestHarnessComponent, [{
3534
3733
  type: Component,
3535
- 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 [agentRun]=\"currentAgentRun\"\n [liveSteps]=\"liveAgentSteps\"\n [autoExpand]=\"true\"\n (viewRunClick)=\"navigateToAgentRun($event)\"\n [runId]=\"getLastRunId()\"\n [runType]=\"mode\">\n </mj-agent-execution-monitor>\n </div>\n }\n\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({runId: message.agentRunId, runType: 'agent'})\" title=\"View full run details\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\">{{ message.streamingContent }}<span class=\"cursor\">|</span></span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n @if (hasPayload(message.payload) && mode === 'agent' && message.role === 'assistant') {\n <div class=\"payload-section\" [class.collapsed]=\"message.payloadCollapsed\">\n <div class=\"payload-header\" (click)=\"togglePayloadCollapse(message)\">\n <span class=\"payload-label\">\n <i class=\"fa-solid fa-code\"></i> Payload\n </span>\n <button class=\"payload-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!message.payloadCollapsed\" [class.fa-chevron-right]=\"message.payloadCollapsed\"></i>\n </button>\n </div>\n @if (!message.payloadCollapsed) {\n <div class=\"payload-content\">\n <pre>{{ formatJson(message.payload) }}</pre>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\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}"] }]
3734
+ 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 <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'agentSettings'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'agentSettings'\"\n (click)=\"selectTab('agentSettings')\">\n <i class=\"fa-solid fa-sliders\"></i>\n Settings\n </button>\n } @else {\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'templateVariables'\"\n (click)=\"selectTab('templateVariables')\">\n <i class=\"fa-solid fa-code\"></i>\n Template Variables\n </button>\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'modelSettings'\"\n (click)=\"selectTab('modelSettings')\">\n <i class=\"fa-solid fa-sliders\"></i>\n Model Settings\n </button>\n }\n <button \n class=\"tab-button\"\n [class.active]=\"activeTab === 'savedConversations'\"\n [disabled]=\"executionMonitorMode === 'live' && activeTab !== 'savedConversations'\"\n (click)=\"selectTab('savedConversations')\">\n <i class=\"fa-solid fa-history\"></i>\n Saved\n @if (savedConversations.length > 0) {\n <span class=\"badge\">{{ savedConversations.length }}</span>\n }\n </button>\n </div>\n\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 [agentRun]=\"currentAgentRun\"\n [liveSteps]=\"liveAgentSteps\"\n [autoExpand]=\"true\"\n (viewRunClick)=\"navigateToAgentRun($event)\"\n [runId]=\"getLastRunId()\"\n [runType]=\"mode\">\n </mj-agent-execution-monitor>\n </div>\n }\n\n <!-- Agent Settings Tab -->\n @if (activeTab === 'agentSettings') {\n <div class=\"tab-content\">\n <div class=\"tab-header\">\n <h4>Agent Settings</h4>\n <p>Configure agent execution parameters</p>\n </div>\n \n <div class=\"model-settings\">\n <div class=\"setting-group\">\n <label>AI Configuration</label>\n <kendo-dropdownlist \n [(ngModel)]=\"agentConfigurationId\"\n [data]=\"availableConfigurations\"\n textField=\"Name\"\n valueField=\"ID\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select a configuration...\"\n class=\"configuration-selector\">\n </kendo-dropdownlist>\n <div class=\"setting-help\">\n @if (agentConfigurationId) {\n @for (config of availableConfigurations; track config.ID) {\n @if (config.ID === agentConfigurationId && config.Description) {\n {{ config.Description }}\n }\n }\n } @else {\n Using default configuration\n }\n </div>\n </div>\n </div>\n </div>\n }\n\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>AI Configuration</label>\n <kendo-dropdownlist \n [(ngModel)]=\"selectedConfigurationId\"\n [data]=\"availableConfigurations\"\n textField=\"Name\"\n valueField=\"ID\"\n [valuePrimitive]=\"true\"\n placeholder=\"Select a configuration...\"\n class=\"configuration-selector\">\n </kendo-dropdownlist>\n <div class=\"setting-help\">\n @if (selectedConfigurationId) {\n @for (config of availableConfigurations; track config.ID) {\n @if (config.ID === selectedConfigurationId && config.Description) {\n {{ config.Description }}\n }\n }\n } @else {\n Using default configuration\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({runId: message.agentRunId, runType: 'agent'})\" title=\"View full run details\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n </div>\n <div class=\"message-content\">\n <button class=\"copy-button-in-bubble\" (click)=\"copyMessage(message)\" title=\"Copy message\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (message.isStreaming) {\n <div class=\"streaming-wrapper\">\n <span class=\"streaming-content\">{{ message.streamingContent }}<span class=\"cursor\">|</span></span>\n </div>\n } @else {\n <div [innerHTML]=\"getFormattedContent(message)\"></div>\n }\n @if (message.error) {\n <div class=\"error-details\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ message.error }}\n </div>\n }\n @if (hasPayload(message.payload) && mode === 'agent' && message.role === 'assistant') {\n <div class=\"payload-section\" [class.collapsed]=\"message.payloadCollapsed\">\n <div class=\"payload-header\" (click)=\"togglePayloadCollapse(message)\">\n <span class=\"payload-label\">\n <i class=\"fa-solid fa-code\"></i> Payload\n </span>\n <button class=\"payload-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!message.payloadCollapsed\" [class.fa-chevron-right]=\"message.payloadCollapsed\"></i>\n </button>\n </div>\n @if (!message.payloadCollapsed) {\n <div class=\"payload-content\">\n <pre>{{ formatJson(message.payload) }}</pre>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\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}"] }]
3536
3735
  }], () => [{ type: i1.DomSanitizer }, { type: i2.WindowService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i3.Router }], { mode: [{
3537
3736
  type: Input
3538
3737
  }], entity: [{
@@ -3560,5 +3759,5 @@ export class AITestHarnessComponent {
3560
3759
  type: ViewChild,
3561
3760
  args: ['saveDialogInput']
3562
3761
  }] }); })();
3563
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 151 }); })();
3762
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 155 }); })();
3564
3763
  //# sourceMappingURL=ai-test-harness.component.js.map