@memberjunction/ng-ai-test-harness 2.112.0 → 2.113.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.
@@ -1,5 +1,5 @@
1
- import { Component, Input, Output, EventEmitter, ViewChild, SecurityContext, } from '@angular/core';
2
- import { Metadata, RunView, CompositeKey } from '@memberjunction/global';
1
+ import { Component, Input, Output, EventEmitter, ViewChild, SecurityContext } from '@angular/core';
2
+ import { Metadata, RunView, CompositeKey } from '@memberjunction/core';
3
3
  import { MJNotificationService } from '@memberjunction/ng-notifications';
4
4
  import { SharedService } from '@memberjunction/ng-shared';
5
5
  import { Subject } from 'rxjs';
@@ -1277,7 +1277,7 @@ export class AITestHarnessComponent {
1277
1277
  seed: null,
1278
1278
  stopSequences: [],
1279
1279
  includeLogProbs: false,
1280
- topLogProbs: 2,
1280
+ topLogProbs: 2
1281
1281
  };
1282
1282
  /** Raw stop sequences input for textarea */
1283
1283
  this.stopSequencesText = '';
@@ -1291,7 +1291,7 @@ export class AITestHarnessComponent {
1291
1291
  { text: 'Text', value: 'Text' },
1292
1292
  { text: 'Markdown', value: 'Markdown' },
1293
1293
  { text: 'JSON', value: 'JSON' },
1294
- { text: 'Model Specific', value: 'ModelSpecific' },
1294
+ { text: 'Model Specific', value: 'ModelSpecific' }
1295
1295
  ];
1296
1296
  /** Selected response format for prompt execution */
1297
1297
  this.selectedResponseFormat = this.responseFormatOptions[0];
@@ -1477,7 +1477,7 @@ export class AITestHarnessComponent {
1477
1477
  const serializedAgentRun = message.data.agentRun;
1478
1478
  // Update streaming message content if available
1479
1479
  if (message.data.progress?.message) {
1480
- const streamingMessage = this.conversationMessages.find((m) => m.isStreaming);
1480
+ const streamingMessage = this.conversationMessages.find(m => m.isStreaming);
1481
1481
  if (streamingMessage) {
1482
1482
  // Clear any typing animation interval
1483
1483
  const typingInterval = streamingMessage._typingInterval;
@@ -1499,7 +1499,7 @@ export class AITestHarnessComponent {
1499
1499
  // Load the serialized data into our entity
1500
1500
  await this.currentAgentRun.LoadFromData(serializedAgentRun);
1501
1501
  // Update assistant message with agent run ID if available
1502
- const streamingMessage = this.conversationMessages.find((m) => m.isStreaming);
1502
+ const streamingMessage = this.conversationMessages.find(m => m.isStreaming);
1503
1503
  if (streamingMessage && this.currentAgentRun.ID) {
1504
1504
  streamingMessage.agentRunId = this.currentAgentRun.ID;
1505
1505
  }
@@ -1512,19 +1512,19 @@ export class AITestHarnessComponent {
1512
1512
  status: this.currentAgentRun.Status,
1513
1513
  stepCount: this.currentAgentRun.Steps?.length || 0,
1514
1514
  executionMonitorMode: this.executionMonitorMode,
1515
- steps: this.currentAgentRun.Steps?.map((s) => ({
1515
+ steps: this.currentAgentRun.Steps?.map(s => ({
1516
1516
  id: s.ID,
1517
1517
  type: s.StepType,
1518
1518
  status: s.Status,
1519
1519
  hasSubAgentRun: !!s.SubAgentRun,
1520
- subStepCount: s.SubAgentRun?.Steps?.length || 0,
1521
- })),
1520
+ subStepCount: s.SubAgentRun?.Steps?.length || 0
1521
+ }))
1522
1522
  });
1523
1523
  // Force change detection
1524
1524
  this.cdr.detectChanges();
1525
1525
  }
1526
1526
  else if (message?.type === 'StreamingContent' && message.data?.streaming) {
1527
- const streamingMessage = this.conversationMessages.find((m) => m.isStreaming);
1527
+ const streamingMessage = this.conversationMessages.find(m => m.isStreaming);
1528
1528
  if (streamingMessage) {
1529
1529
  // Append streaming content
1530
1530
  if (!streamingMessage.streamingContent) {
@@ -1555,15 +1555,15 @@ export class AITestHarnessComponent {
1555
1555
  if (this.entity && 'AIModelTypeID' in this.entity) {
1556
1556
  const prompt = this.entity;
1557
1557
  if (prompt.AIModelTypeID) {
1558
- filteredModels = AIEngineBase.Instance.Models.filter((model) => model.AIModelTypeID === prompt.AIModelTypeID && model.IsActive);
1558
+ filteredModels = AIEngineBase.Instance.Models.filter(model => model.AIModelTypeID === prompt.AIModelTypeID && model.IsActive);
1559
1559
  }
1560
1560
  else {
1561
1561
  // No model type restriction, show all active models
1562
- filteredModels = AIEngineBase.Instance.Models.filter((model) => model.IsActive);
1562
+ filteredModels = AIEngineBase.Instance.Models.filter(model => model.IsActive);
1563
1563
  }
1564
1564
  // Set default response format from prompt with slight delay for Kendo dropdown
1565
1565
  setTimeout(() => {
1566
- const format = this.responseFormatOptions.find((f) => f.value.trim().toLowerCase() === prompt.ResponseFormat.trim().toLowerCase());
1566
+ const format = this.responseFormatOptions.find(f => f.value.trim().toLowerCase() === prompt.ResponseFormat.trim().toLowerCase());
1567
1567
  if (format) {
1568
1568
  this.selectedResponseFormat = format;
1569
1569
  }
@@ -1574,7 +1574,7 @@ export class AITestHarnessComponent {
1574
1574
  }
1575
1575
  else {
1576
1576
  // Not a prompt entity, show all active models
1577
- filteredModels = AIEngineBase.Instance.Models.filter((model) => model.IsActive);
1577
+ filteredModels = AIEngineBase.Instance.Models.filter(model => model.IsActive);
1578
1578
  }
1579
1579
  // Sort models by name
1580
1580
  filteredModels.sort((a, b) => a.Name.localeCompare(b.Name));
@@ -1586,7 +1586,7 @@ export class AITestHarnessComponent {
1586
1586
  // Add a blank option at the beginning with the default model name
1587
1587
  this.availableModels = [
1588
1588
  { ID: '', Name: this.defaultModelName ? `-- Default: ${this.defaultModelName} --` : '-- Use Default Model --' },
1589
- ...filteredModels,
1589
+ ...filteredModels
1590
1590
  ];
1591
1591
  // Don't auto-select a model - let the dropdown show the blank option
1592
1592
  this.selectedModelId = '';
@@ -1605,14 +1605,15 @@ export class AITestHarnessComponent {
1605
1605
  async getDefaultModelName(prompt) {
1606
1606
  try {
1607
1607
  // Get prompt-specific model associations
1608
- const promptModels = AIEngineBase.Instance.PromptModels.filter((pm) => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview'));
1608
+ const promptModels = AIEngineBase.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
1609
+ (pm.Status === 'Active' || pm.Status === 'Preview'));
1609
1610
  let defaultModel = null;
1610
1611
  if (promptModels.length > 0) {
1611
1612
  // Sort by priority (higher priority first)
1612
1613
  promptModels.sort((a, b) => (b.Priority || 0) - (a.Priority || 0));
1613
1614
  // Find the first active model
1614
1615
  for (const pm of promptModels) {
1615
- const model = AIEngineBase.Instance.Models.find((m) => m.ID === pm.ModelID && m.IsActive);
1616
+ const model = AIEngineBase.Instance.Models.find(m => m.ID === pm.ModelID && m.IsActive);
1616
1617
  if (model) {
1617
1618
  defaultModel = model;
1618
1619
  break;
@@ -1621,7 +1622,8 @@ export class AITestHarnessComponent {
1621
1622
  }
1622
1623
  // If no prompt-specific model, use selection strategy
1623
1624
  if (!defaultModel) {
1624
- const candidates = AIEngineBase.Instance.Models.filter((m) => m.IsActive && (!prompt.AIModelTypeID || m.AIModelTypeID === prompt.AIModelTypeID));
1625
+ const candidates = AIEngineBase.Instance.Models.filter(m => m.IsActive &&
1626
+ (!prompt.AIModelTypeID || m.AIModelTypeID === prompt.AIModelTypeID));
1625
1627
  if (candidates.length > 0) {
1626
1628
  // Apply selection strategy
1627
1629
  if (prompt.SelectionStrategy === 'ByPower') {
@@ -1658,16 +1660,18 @@ export class AITestHarnessComponent {
1658
1660
  return;
1659
1661
  }
1660
1662
  // Get vendors that offer this model - same logic as loadVendorsForModel
1661
- const modelVendors = AIEngineBase.Instance.ModelVendors.filter((mv) => mv.ModelID === this.defaultModel.ID && mv.Status === 'Active' && mv.Type?.trim().toLowerCase() === 'inference provider');
1663
+ const modelVendors = AIEngineBase.Instance.ModelVendors.filter(mv => mv.ModelID === this.defaultModel.ID &&
1664
+ mv.Status === 'Active' &&
1665
+ mv.Type?.trim().toLowerCase() === 'inference provider');
1662
1666
  // Map to vendor objects with priority from ModelVendor
1663
1667
  const vendorObjects = [];
1664
1668
  for (const mv of modelVendors) {
1665
- const vendor = AIEngineBase.Instance.Vendors.find((v) => v.ID === mv.VendorID);
1669
+ const vendor = AIEngineBase.Instance.Vendors.find(v => v.ID === mv.VendorID);
1666
1670
  if (vendor) {
1667
1671
  vendorObjects.push({
1668
1672
  ID: vendor.ID,
1669
1673
  Name: vendor.Name,
1670
- Priority: mv.Priority || 999, // Use ModelVendor priority
1674
+ Priority: mv.Priority || 999 // Use ModelVendor priority
1671
1675
  });
1672
1676
  }
1673
1677
  }
@@ -1695,12 +1699,12 @@ export class AITestHarnessComponent {
1695
1699
  EntityName: 'MJ: AI Configurations',
1696
1700
  ExtraFilter: `Status IN ('Active', 'Preview')`,
1697
1701
  OrderBy: 'IsDefault DESC, Name',
1698
- ResultType: 'entity_object',
1702
+ ResultType: 'entity_object'
1699
1703
  });
1700
1704
  if (result.Success && result.Results) {
1701
1705
  this.availableConfigurations = result.Results;
1702
1706
  // Auto-select the default configuration if one exists
1703
- const defaultConfig = this.availableConfigurations.find((c) => c.IsDefault);
1707
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1704
1708
  if (defaultConfig) {
1705
1709
  this.selectedConfigurationId = defaultConfig.ID;
1706
1710
  }
@@ -1746,17 +1750,19 @@ export class AITestHarnessComponent {
1746
1750
  return;
1747
1751
  }
1748
1752
  // Get model-specific vendors
1749
- const modelVendors = AIEngineBase.Instance.ModelVendors.filter((mv) => mv.ModelID === this.selectedModelId && mv.Status === 'Active' && mv.Type?.trim().toLowerCase() === 'inference provider');
1753
+ const modelVendors = AIEngineBase.Instance.ModelVendors.filter(mv => mv.ModelID === this.selectedModelId &&
1754
+ mv.Status === 'Active' &&
1755
+ mv.Type?.trim().toLowerCase() === 'inference provider');
1750
1756
  // Map to vendor objects with priority from ModelVendor
1751
1757
  const vendorObjects = [];
1752
1758
  for (const mv of modelVendors) {
1753
- const vendor = AIEngineBase.Instance.Vendors.find((v) => v.ID === mv.VendorID);
1759
+ const vendor = AIEngineBase.Instance.Vendors.find(v => v.ID === mv.VendorID);
1754
1760
  if (vendor) {
1755
1761
  // For now, include all vendors. TODO: Filter by vendor type when available
1756
1762
  vendorObjects.push({
1757
1763
  ID: vendor.ID,
1758
1764
  Name: vendor.Name,
1759
- Priority: mv.Priority || 999, // Use ModelVendor priority
1765
+ Priority: mv.Priority || 999 // Use ModelVendor priority
1760
1766
  });
1761
1767
  }
1762
1768
  }
@@ -1795,9 +1801,7 @@ export class AITestHarnessComponent {
1795
1801
  this.advancedParams.seed = prompt.Seed;
1796
1802
  if (prompt.StopSequences) {
1797
1803
  this.stopSequencesText = prompt.StopSequences;
1798
- this.advancedParams.stopSequences = prompt.StopSequences.split(',')
1799
- .map((s) => s.trim())
1800
- .filter((s) => s.length > 0);
1804
+ this.advancedParams.stopSequences = prompt.StopSequences.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
1801
1805
  }
1802
1806
  if (prompt.IncludeLogProbs != null)
1803
1807
  this.advancedParams.includeLogProbs = prompt.IncludeLogProbs;
@@ -1821,7 +1825,7 @@ export class AITestHarnessComponent {
1821
1825
  EntityName: 'Template Params',
1822
1826
  ExtraFilter: `TemplateID='${prompt.TemplateID}'`,
1823
1827
  OrderBy: 'Name ASC',
1824
- ResultType: 'entity_object',
1828
+ ResultType: 'entity_object'
1825
1829
  });
1826
1830
  if (result.Success && result.Results && result.Results.length > 0) {
1827
1831
  // Clear existing template variables
@@ -1831,7 +1835,7 @@ export class AITestHarnessComponent {
1831
1835
  this.templateVariables.push({
1832
1836
  name: param.Name,
1833
1837
  value: param.DefaultValue || '',
1834
- type: this.getVariableTypeFromParamType(param.Type),
1838
+ type: this.getVariableTypeFromParamType(param.Type)
1835
1839
  });
1836
1840
  }
1837
1841
  // If no parameters found, add one empty variable to start
@@ -1879,14 +1883,14 @@ export class AITestHarnessComponent {
1879
1883
  // Reset vendor - will be loaded by loadDefaultVendor
1880
1884
  this.selectedVendorId = '';
1881
1885
  // Reset response format to prompt's setting
1882
- const format = this.responseFormatOptions.find((f) => f.value.trim().toLowerCase() === prompt.ResponseFormat.trim().toLowerCase());
1886
+ const format = this.responseFormatOptions.find(f => f.value.trim().toLowerCase() === prompt.ResponseFormat.trim().toLowerCase());
1883
1887
  this.selectedResponseFormat = format || this.responseFormatOptions[0];
1884
1888
  // Reset max tokens
1885
1889
  this.maxTokens = null;
1886
1890
  // Reset skip validation
1887
1891
  this.skipValidation = false;
1888
1892
  // Reset configuration to default
1889
- const defaultConfig = this.availableConfigurations.find((c) => c.IsDefault);
1893
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1890
1894
  if (defaultConfig) {
1891
1895
  this.selectedConfigurationId = defaultConfig.ID;
1892
1896
  }
@@ -1904,7 +1908,7 @@ export class AITestHarnessComponent {
1904
1908
  seed: null,
1905
1909
  stopSequences: [],
1906
1910
  includeLogProbs: false,
1907
- topLogProbs: 2,
1911
+ topLogProbs: 2
1908
1912
  };
1909
1913
  this.stopSequencesText = '';
1910
1914
  // Reload prompt defaults for advanced params
@@ -1949,14 +1953,14 @@ export class AITestHarnessComponent {
1949
1953
  seed: null,
1950
1954
  stopSequences: [],
1951
1955
  includeLogProbs: false,
1952
- topLogProbs: 2,
1956
+ topLogProbs: 2
1953
1957
  };
1954
1958
  this.stopSequencesText = '';
1955
1959
  this.advancedParamsExpanded = false;
1956
1960
  this.skipValidation = false;
1957
1961
  // Reset agent configuration to default
1958
1962
  if (this.mode === 'agent') {
1959
- const defaultConfig = this.availableConfigurations.find((c) => c.IsDefault);
1963
+ const defaultConfig = this.availableConfigurations.find(c => c.IsDefault);
1960
1964
  this.agentConfigurationId = defaultConfig?.ID || '';
1961
1965
  }
1962
1966
  }
@@ -2002,7 +2006,7 @@ export class AITestHarnessComponent {
2002
2006
  currentAgentRun: !!this.currentAgentRun,
2003
2007
  agentRunStatus: this.currentAgentRun?.Status || 'none',
2004
2008
  conversationMessages: this.conversationMessages.length,
2005
- executionMonitorMode: this.executionMonitorMode,
2009
+ executionMonitorMode: this.executionMonitorMode
2006
2010
  });
2007
2011
  this.activeTab = tab;
2008
2012
  // If switching to execution monitor tab, ensure it has the latest data
@@ -2010,11 +2014,13 @@ export class AITestHarnessComponent {
2010
2014
  console.log('📊 Switching to execution monitor tab');
2011
2015
  // Always ensure we have the latest execution data when switching to monitor
2012
2016
  if (this.conversationMessages.length > 0) {
2013
- const lastAssistantMessage = this.conversationMessages.filter((m) => m.role === 'assistant' && m.agentRunId).pop();
2017
+ const lastAssistantMessage = this.conversationMessages
2018
+ .filter(m => m.role === 'assistant' && m.agentRunId)
2019
+ .pop();
2014
2020
  console.log('🔍 Last assistant message with agent run:', {
2015
2021
  found: !!lastAssistantMessage,
2016
2022
  hasAgentRunId: !!lastAssistantMessage?.agentRunId,
2017
- agentRunId: lastAssistantMessage?.agentRunId,
2023
+ agentRunId: lastAssistantMessage?.agentRunId
2018
2024
  });
2019
2025
  if (lastAssistantMessage && lastAssistantMessage.agentRunId) {
2020
2026
  // Always update agent run to ensure it's fresh
@@ -2025,7 +2031,7 @@ export class AITestHarnessComponent {
2025
2031
  this.lastProcessedRunId = messageRunId;
2026
2032
  console.log('✅ Loading agent run:', {
2027
2033
  mode: this.executionMonitorMode,
2028
- runId: this.lastProcessedRunId,
2034
+ runId: this.lastProcessedRunId
2029
2035
  });
2030
2036
  // Trigger change detection to ensure the execution monitor updates
2031
2037
  setTimeout(() => {
@@ -2042,7 +2048,7 @@ export class AITestHarnessComponent {
2042
2048
  }
2043
2049
  else {
2044
2050
  console.log('📄 Switching away from execution monitor, preserving data:', {
2045
- currentAgentRunExists: !!this.currentAgentRun,
2051
+ currentAgentRunExists: !!this.currentAgentRun
2046
2052
  });
2047
2053
  // Don't clear currentAgentRun when switching away from execution monitor
2048
2054
  // This preserves the state for when the user switches back
@@ -2088,7 +2094,7 @@ export class AITestHarnessComponent {
2088
2094
  this.executionMonitorMode = 'historical';
2089
2095
  console.log('✅ Loaded agent run:', {
2090
2096
  id: agentRunEntity.ID,
2091
- stepCount: this.currentAgentRun.Steps?.length || 0,
2097
+ stepCount: this.currentAgentRun.Steps?.length || 0
2092
2098
  });
2093
2099
  // Force change detection to update the execution monitor
2094
2100
  this.cdr.detectChanges();
@@ -2145,7 +2151,7 @@ export class AITestHarnessComponent {
2145
2151
  id: this.generateMessageId(),
2146
2152
  role: 'user',
2147
2153
  content: this.currentUserMessage.trim(),
2148
- timestamp: new Date(),
2154
+ timestamp: new Date()
2149
2155
  };
2150
2156
  this.conversationMessages.push(userMessage);
2151
2157
  // Clear input and update change detection
@@ -2197,7 +2203,7 @@ export class AITestHarnessComponent {
2197
2203
  streamingContent: this.mode === 'agent' ? 'Running agent...' : 'Running prompt...',
2198
2204
  agentRunId: '',
2199
2205
  streamingStartTime: Date.now(),
2200
- elapsedTime: 0,
2206
+ elapsedTime: 0
2201
2207
  };
2202
2208
  this.conversationMessages.push(assistantMessage);
2203
2209
  this.scrollNeeded = true;
@@ -2229,7 +2235,7 @@ export class AITestHarnessComponent {
2229
2235
  data: Object.keys(dataContext).length > 0 ? dataContext : undefined,
2230
2236
  lastRunId: this.lastAgentRunId || undefined,
2231
2237
  autoPopulateLastRunPayload: this.lastAgentRunId ? true : false,
2232
- configurationId: this.agentConfigurationId || undefined,
2238
+ configurationId: this.agentConfigurationId || undefined
2233
2239
  });
2234
2240
  // Stop elapsed time counter
2235
2241
  if (this.elapsedTimeInterval) {
@@ -2244,7 +2250,7 @@ export class AITestHarnessComponent {
2244
2250
  const parseOptions = {
2245
2251
  extractInlineJson: true,
2246
2252
  maxDepth: 100,
2247
- debug: false,
2253
+ debug: false
2248
2254
  };
2249
2255
  // Apply recursive JSON parsing to extract any nested JSON strings
2250
2256
  const fullResult = ParseJSONRecursive(executionResult, parseOptions);
@@ -2286,7 +2292,7 @@ export class AITestHarnessComponent {
2286
2292
  assistantMessage.payload = payloadData; // Store the payload if present
2287
2293
  const startedAt = executionResult.agentRun?.StartedAt ? new Date(executionResult.agentRun.StartedAt).getTime() : 0;
2288
2294
  const completedAt = executionResult.agentRun?.CompletedAt ? new Date(executionResult.agentRun.CompletedAt).getTime() : 0;
2289
- const executionTime = startedAt && completedAt ? completedAt - startedAt : 0;
2295
+ const executionTime = (startedAt && completedAt) ? (completedAt - startedAt) : 0;
2290
2296
  assistantMessage.executionTime = executionTime;
2291
2297
  assistantMessage.agentRunId = fullResult.agentRun?.ID || assistantMessage.agentRunId;
2292
2298
  // Update the tracking ID when we set new execution data
@@ -2304,7 +2310,7 @@ export class AITestHarnessComponent {
2304
2310
  console.error('❌ AI Test Harness: Execution failed', {
2305
2311
  success: executionResult?.success,
2306
2312
  errorMessage: executionResult?.agentRun?.ErrorMessage,
2307
- hasPayload: !!executionResult?.payload,
2313
+ hasPayload: !!executionResult?.payload
2308
2314
  });
2309
2315
  assistantMessage.content = 'I encountered an error processing your request.';
2310
2316
  assistantMessage.error = executionResult?.agentRun?.ErrorMessage || 'Unknown error occurred';
@@ -2334,7 +2340,7 @@ export class AITestHarnessComponent {
2334
2340
  error: error,
2335
2341
  message: error?.message,
2336
2342
  stack: error?.stack,
2337
- type: error?.constructor?.name,
2343
+ type: error?.constructor?.name
2338
2344
  });
2339
2345
  // Update assistant message with error
2340
2346
  const lastMessage = this.conversationMessages[this.conversationMessages.length - 1];
@@ -2375,7 +2381,7 @@ export class AITestHarnessComponent {
2375
2381
  streamingContent: this.mode === 'agent' ? 'Running agent...' : 'Running prompt...',
2376
2382
  agentRunId: '',
2377
2383
  streamingStartTime: Date.now(),
2378
- elapsedTime: 0,
2384
+ elapsedTime: 0
2379
2385
  };
2380
2386
  this.conversationMessages.push(assistantMessage);
2381
2387
  this.scrollNeeded = true;
@@ -2389,14 +2395,14 @@ export class AITestHarnessComponent {
2389
2395
  // Prepare data context (template variables + user message)
2390
2396
  const dataContext = {
2391
2397
  ...templateVariables,
2392
- userMessage: userMessage,
2398
+ userMessage: userMessage
2393
2399
  };
2394
2400
  // Build conversation messages
2395
2401
  const messages = this.conversationMessages
2396
- .filter((m) => !m.isStreaming && m.content) // Only include non-streaming messages with content
2397
- .map((m) => ({
2402
+ .filter(m => !m.isStreaming && m.content) // Only include non-streaming messages with content
2403
+ .map(m => ({
2398
2404
  role: m.role,
2399
- content: m.content,
2405
+ content: m.content
2400
2406
  }));
2401
2407
  // Execute the prompt using the new AI client
2402
2408
  const executionResult = await dataProvider.AI.RunAIPrompt({
@@ -2420,7 +2426,7 @@ export class AITestHarnessComponent {
2420
2426
  topLogProbs: this.advancedParams.includeLogProbs ? this.advancedParams.topLogProbs : undefined,
2421
2427
  messages: messages.length > 0 ? messages : undefined,
2422
2428
  rerunFromPromptRunID: this.originalPromptRunId || undefined,
2423
- systemPromptOverride: this.systemPromptOverride || undefined,
2429
+ systemPromptOverride: this.systemPromptOverride || undefined
2424
2430
  });
2425
2431
  // Stop elapsed time counter
2426
2432
  if (this.elapsedTimeInterval) {
@@ -2433,16 +2439,16 @@ export class AITestHarnessComponent {
2433
2439
  const parseOptions = {
2434
2440
  extractInlineJson: true,
2435
2441
  maxDepth: 100,
2436
- debug: false,
2442
+ debug: false
2437
2443
  };
2438
2444
  if (executionResult?.success) {
2439
2445
  // Use parsedResult if available, otherwise fall back to output
2440
2446
  // Handle case where parsedResult is already an object (from GraphQL client)
2441
2447
  const contentToDisplay = executionResult.parsedResult
2442
- ? typeof executionResult.parsedResult === 'object'
2448
+ ? (typeof executionResult.parsedResult === 'object'
2443
2449
  ? JSON.stringify(executionResult.parsedResult, null, 2)
2444
- : executionResult.parsedResult
2445
- : executionResult.output || 'No response generated';
2450
+ : executionResult.parsedResult)
2451
+ : (executionResult.output || 'No response generated');
2446
2452
  assistantMessage.content = contentToDisplay;
2447
2453
  assistantMessage.executionTime = executionResult.executionTimeMs;
2448
2454
  // Store the complete execution result for JSON display
@@ -2516,10 +2522,10 @@ export class AITestHarnessComponent {
2516
2522
  startTypingAnimation(message) {
2517
2523
  const initialMessages = [
2518
2524
  "I'm processing your request...",
2519
- 'Let me think about that...',
2520
- 'Working on your request...',
2521
- 'Analyzing your question...',
2522
- 'Processing...',
2525
+ "Let me think about that...",
2526
+ "Working on your request...",
2527
+ "Analyzing your question...",
2528
+ "Processing..."
2523
2529
  ];
2524
2530
  const selectedMessage = initialMessages[Math.floor(Math.random() * initialMessages.length)];
2525
2531
  let index = 0;
@@ -2586,7 +2592,7 @@ export class AITestHarnessComponent {
2586
2592
  this.agentVariables.push({
2587
2593
  name: '',
2588
2594
  value: '',
2589
- type: 'string',
2595
+ type: 'string'
2590
2596
  });
2591
2597
  }
2592
2598
  /**
@@ -2604,7 +2610,7 @@ export class AITestHarnessComponent {
2604
2610
  this.templateVariables.push({
2605
2611
  name: '',
2606
2612
  value: '',
2607
- type: 'string',
2613
+ type: 'string'
2608
2614
  });
2609
2615
  }
2610
2616
  /**
@@ -2648,10 +2654,10 @@ export class AITestHarnessComponent {
2648
2654
  const parsedData = JSON.parse(saved);
2649
2655
  this.savedConversations = parsedData || [];
2650
2656
  // Convert date strings back to Date objects
2651
- this.savedConversations.forEach((conv) => {
2657
+ this.savedConversations.forEach(conv => {
2652
2658
  conv.createdAt = new Date(conv.createdAt);
2653
2659
  conv.updatedAt = new Date(conv.updatedAt);
2654
- conv.messages.forEach((msg) => {
2660
+ conv.messages.forEach(msg => {
2655
2661
  msg.timestamp = new Date(msg.timestamp);
2656
2662
  });
2657
2663
  });
@@ -2694,7 +2700,7 @@ export class AITestHarnessComponent {
2694
2700
  }
2695
2701
  // If updating existing conversation, pre-fill the name
2696
2702
  if (this.currentConversationId) {
2697
- const currentConv = this.savedConversations.find((c) => c.id === this.currentConversationId);
2703
+ const currentConv = this.savedConversations.find(c => c.id === this.currentConversationId);
2698
2704
  this.tempConversationName = currentConv ? currentConv.name : '';
2699
2705
  }
2700
2706
  else {
@@ -2740,11 +2746,11 @@ export class AITestHarnessComponent {
2740
2746
  skipValidation: this.mode === 'prompt' ? this.skipValidation : undefined,
2741
2747
  agentConfigurationId: this.mode === 'agent' ? this.agentConfigurationId : undefined,
2742
2748
  createdAt: new Date(),
2743
- updatedAt: new Date(),
2749
+ updatedAt: new Date()
2744
2750
  };
2745
2751
  if (this.currentConversationId) {
2746
2752
  // Update existing conversation
2747
- const index = this.savedConversations.findIndex((c) => c.id === this.currentConversationId);
2753
+ const index = this.savedConversations.findIndex(c => c.id === this.currentConversationId);
2748
2754
  if (index >= 0) {
2749
2755
  conversation.id = this.currentConversationId;
2750
2756
  conversation.createdAt = this.savedConversations[index].createdAt;
@@ -2797,7 +2803,7 @@ export class AITestHarnessComponent {
2797
2803
  }
2798
2804
  autoSaveConversation() {
2799
2805
  if (this.currentConversationId && this.conversationMessages.length > 0) {
2800
- const index = this.savedConversations.findIndex((c) => c.id === this.currentConversationId);
2806
+ const index = this.savedConversations.findIndex(c => c.id === this.currentConversationId);
2801
2807
  if (index >= 0) {
2802
2808
  this.savedConversations[index].messages = [...this.conversationMessages];
2803
2809
  this.savedConversations[index].dataContext = this.buildDataContext();
@@ -2862,7 +2868,9 @@ export class AITestHarnessComponent {
2862
2868
  this.agentVariables.push({
2863
2869
  name: key,
2864
2870
  value: typeof value === 'object' ? JSON.stringify(value) : String(value),
2865
- type: typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'number' : typeof value === 'object' ? 'object' : 'string',
2871
+ type: typeof value === 'boolean' ? 'boolean' :
2872
+ typeof value === 'number' ? 'number' :
2873
+ typeof value === 'object' ? 'object' : 'string'
2866
2874
  });
2867
2875
  }
2868
2876
  // Restore configuration for agent mode
@@ -2878,7 +2886,9 @@ export class AITestHarnessComponent {
2878
2886
  this.templateVariables.push({
2879
2887
  name: key,
2880
2888
  value: typeof value === 'object' ? JSON.stringify(value) : String(value),
2881
- type: typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'number' : typeof value === 'object' ? 'object' : 'string',
2889
+ type: typeof value === 'boolean' ? 'boolean' :
2890
+ typeof value === 'number' ? 'number' :
2891
+ typeof value === 'object' ? 'object' : 'string'
2882
2892
  });
2883
2893
  }
2884
2894
  // Restore advanced parameters
@@ -2914,7 +2924,9 @@ export class AITestHarnessComponent {
2914
2924
  }
2915
2925
  }
2916
2926
  // Load agent run from the last assistant message if available
2917
- const lastAssistantMessage = this.conversationMessages.filter((m) => m.role === 'assistant' && m.agentRunId).pop();
2927
+ const lastAssistantMessage = this.conversationMessages
2928
+ .filter(m => m.role === 'assistant' && m.agentRunId)
2929
+ .pop();
2918
2930
  if (lastAssistantMessage && lastAssistantMessage.agentRunId) {
2919
2931
  this.loadAgentRun(lastAssistantMessage.agentRunId);
2920
2932
  this.executionMonitorMode = 'historical';
@@ -2932,7 +2944,7 @@ export class AITestHarnessComponent {
2932
2944
  async deleteConversation(conversation, event) {
2933
2945
  event.stopPropagation();
2934
2946
  if (confirm(`Delete conversation "${conversation.name}"?`)) {
2935
- const index = this.savedConversations.findIndex((c) => c.id === conversation.id);
2947
+ const index = this.savedConversations.findIndex(c => c.id === conversation.id);
2936
2948
  if (index >= 0) {
2937
2949
  this.savedConversations.splice(index, 1);
2938
2950
  // Save to localStorage
@@ -2953,17 +2965,17 @@ export class AITestHarnessComponent {
2953
2965
  entity: {
2954
2966
  id: this.entity?.ID,
2955
2967
  name: this.getEntityName(),
2956
- type: this.mode,
2968
+ type: this.mode
2957
2969
  },
2958
2970
  messages: this.conversationMessages,
2959
2971
  dataContext: this.buildDataContext(),
2960
- exportedAt: new Date().toISOString(),
2972
+ exportedAt: new Date().toISOString()
2961
2973
  };
2962
2974
  // Add mode-specific data
2963
2975
  if (this.mode === 'agent') {
2964
2976
  exportData.templateData = this.buildTemplateData();
2965
2977
  exportData.agentSettings = {
2966
- configurationId: this.agentConfigurationId,
2978
+ configurationId: this.agentConfigurationId
2967
2979
  };
2968
2980
  }
2969
2981
  else {
@@ -2973,7 +2985,7 @@ export class AITestHarnessComponent {
2973
2985
  vendorId: this.selectedVendorId,
2974
2986
  configurationId: this.selectedConfigurationId,
2975
2987
  maxTokens: this.maxTokens,
2976
- skipValidation: this.skipValidation,
2988
+ skipValidation: this.skipValidation
2977
2989
  };
2978
2990
  exportData.advancedParams = this.advancedParams;
2979
2991
  }
@@ -3006,7 +3018,7 @@ export class AITestHarnessComponent {
3006
3018
  }
3007
3019
  this.conversationMessages = data.messages.map((msg) => ({
3008
3020
  ...msg,
3009
- timestamp: new Date(msg.timestamp),
3021
+ timestamp: new Date(msg.timestamp)
3010
3022
  }));
3011
3023
  // Import agent variables (unified from dataContext and templateData)
3012
3024
  this.agentVariables = [];
@@ -3015,13 +3027,9 @@ export class AITestHarnessComponent {
3015
3027
  this.agentVariables.push({
3016
3028
  name: key,
3017
3029
  value: typeof value === 'object' ? JSON.stringify(value) : String(value),
3018
- type: typeof value === 'boolean'
3019
- ? 'boolean'
3020
- : typeof value === 'number'
3021
- ? 'number'
3022
- : typeof value === 'object'
3023
- ? 'object'
3024
- : 'string',
3030
+ type: typeof value === 'boolean' ? 'boolean' :
3031
+ typeof value === 'number' ? 'number' :
3032
+ typeof value === 'object' ? 'object' : 'string'
3025
3033
  });
3026
3034
  }
3027
3035
  // Template data is already imported into agentVariables above
@@ -3108,7 +3116,7 @@ export class AITestHarnessComponent {
3108
3116
  formatTimestamp(date) {
3109
3117
  return date.toLocaleTimeString('en-US', {
3110
3118
  hour: '2-digit',
3111
- minute: '2-digit',
3119
+ minute: '2-digit'
3112
3120
  });
3113
3121
  }
3114
3122
  /**
@@ -3172,7 +3180,7 @@ export class AITestHarnessComponent {
3172
3180
  // Add agent run ID for reference
3173
3181
  const enhancedParsed = {
3174
3182
  ...parsed,
3175
- _agentRunID: parsed.agentRunID,
3183
+ _agentRunID: parsed.agentRunID
3176
3184
  };
3177
3185
  this.currentJsonContent = this.formatJson(enhancedParsed);
3178
3186
  }
@@ -3203,7 +3211,7 @@ export class AITestHarnessComponent {
3203
3211
  resizable: true,
3204
3212
  draggable: true,
3205
3213
  top: centerTop,
3206
- left: centerLeft,
3214
+ left: centerLeft
3207
3215
  });
3208
3216
  // Pass the JSON content to the component
3209
3217
  const windowContent = this.jsonWindowRef.content.instance;
@@ -3220,7 +3228,9 @@ export class AITestHarnessComponent {
3220
3228
  * Get the last run ID from conversation messages
3221
3229
  */
3222
3230
  getLastRunId() {
3223
- const lastAssistantMessage = this.conversationMessages.filter((m) => m.role === 'assistant' && m.agentRunId).pop();
3231
+ const lastAssistantMessage = this.conversationMessages
3232
+ .filter(m => m.role === 'assistant' && m.agentRunId)
3233
+ .pop();
3224
3234
  return lastAssistantMessage?.agentRunId || null;
3225
3235
  }
3226
3236
  /**
@@ -3254,7 +3264,9 @@ export class AITestHarnessComponent {
3254
3264
  async copyMessage(message) {
3255
3265
  try {
3256
3266
  // Convert content to string if needed
3257
- const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);
3267
+ const content = typeof message.content === 'string'
3268
+ ? message.content
3269
+ : JSON.stringify(message.content);
3258
3270
  await navigator.clipboard.writeText(content);
3259
3271
  MJNotificationService.Instance.CreateSimpleNotification('Message copied to clipboard', 'success', 2000);
3260
3272
  }
@@ -3298,7 +3310,7 @@ export class AITestHarnessComponent {
3298
3310
  const parseOptions = {
3299
3311
  extractInlineJson: true,
3300
3312
  maxDepth: 100,
3301
- debug: false,
3313
+ debug: false
3302
3314
  };
3303
3315
  try {
3304
3316
  let parsed;
@@ -3380,9 +3392,9 @@ export class AITestHarnessComponent {
3380
3392
  /```[\s\S]*?```/, // Code blocks
3381
3393
  /`[^`]+`/, // Inline code
3382
3394
  /^[-*+]\s/m, // Lists
3383
- /^\d+\.\s/m, // Numbered lists
3395
+ /^\d+\.\s/m // Numbered lists
3384
3396
  ];
3385
- if (markdownPatterns.some((pattern) => pattern.test(content))) {
3397
+ if (markdownPatterns.some(pattern => pattern.test(content))) {
3386
3398
  return 'markdown';
3387
3399
  }
3388
3400
  return 'text';
@@ -3391,7 +3403,9 @@ export class AITestHarnessComponent {
3391
3403
  // Basic markdown to HTML conversion with improved formatting
3392
3404
  let html = content;
3393
3405
  // Escape HTML first
3394
- html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
3406
+ html = html.replace(/&/g, '&amp;')
3407
+ .replace(/</g, '&lt;')
3408
+ .replace(/>/g, '&gt;');
3395
3409
  // Code blocks with language support
3396
3410
  html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
3397
3411
  const language = lang || '';
@@ -3481,7 +3495,12 @@ export class AITestHarnessComponent {
3481
3495
  * Escapes HTML content for use in attributes
3482
3496
  */
3483
3497
  escapeHtmlAttribute(text) {
3484
- return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
3498
+ return text
3499
+ .replace(/&/g, '&amp;')
3500
+ .replace(/"/g, '&quot;')
3501
+ .replace(/'/g, '&#39;')
3502
+ .replace(/</g, '&lt;')
3503
+ .replace(/>/g, '&gt;');
3485
3504
  }
3486
3505
  /**
3487
3506
  * Renders JSON content with human-readable content prominently displayed
@@ -3522,12 +3541,9 @@ export class AITestHarnessComponent {
3522
3541
  */
3523
3542
  copyJsonContent() {
3524
3543
  if (this.currentJsonContent) {
3525
- navigator.clipboard
3526
- .writeText(this.currentJsonContent)
3527
- .then(() => {
3544
+ navigator.clipboard.writeText(this.currentJsonContent).then(() => {
3528
3545
  // Success - JSON copied
3529
- })
3530
- .catch((err) => {
3546
+ }).catch((err) => {
3531
3547
  // Error copying
3532
3548
  });
3533
3549
  }
@@ -3546,14 +3562,15 @@ export class AITestHarnessComponent {
3546
3562
  return parsed.userMessage;
3547
3563
  }
3548
3564
  // Priority 2: Check for nested userMessage in nextStep or other objects
3549
- if (parsed.nextStep &&
3550
- parsed.nextStep.userMessage &&
3551
- typeof parsed.nextStep.userMessage === 'string' &&
3552
- parsed.nextStep.userMessage.trim()) {
3565
+ if (parsed.nextStep && parsed.nextStep.userMessage &&
3566
+ typeof parsed.nextStep.userMessage === 'string' && parsed.nextStep.userMessage.trim()) {
3553
3567
  return parsed.nextStep.userMessage;
3554
3568
  }
3555
3569
  // Priority 3: Other common human-readable fields
3556
- const contentFields = ['message', 'content', 'response', 'text', 'output', 'result', 'answer', 'reply', 'description', 'summary'];
3570
+ const contentFields = [
3571
+ 'message', 'content', 'response', 'text', 'output',
3572
+ 'result', 'answer', 'reply', 'description', 'summary'
3573
+ ];
3557
3574
  for (const field of contentFields) {
3558
3575
  if (parsed[field] && typeof parsed[field] === 'string' && parsed[field].trim()) {
3559
3576
  return parsed[field];
@@ -3648,22 +3665,18 @@ export class AITestHarnessComponent {
3648
3665
  if (Array.isArray(obj)) {
3649
3666
  if (obj.length === 0)
3650
3667
  return '<span class="json-bracket">[]</span>';
3651
- const items = obj
3652
- .map((item) => `<div class="json-array-item">${nextIndent}${this.createJsonDisplayHtml(item, depth + 1)}</div>`)
3653
- .join(',\n');
3668
+ const items = obj.map(item => `<div class="json-array-item">${nextIndent}${this.createJsonDisplayHtml(item, depth + 1)}</div>`).join(',\n');
3654
3669
  return `<span class="json-bracket">[</span>\n${items}\n<div class="json-indent">${indent}</div><span class="json-bracket">]</span>`;
3655
3670
  }
3656
3671
  if (typeof obj === 'object') {
3657
3672
  const keys = Object.keys(obj);
3658
3673
  if (keys.length === 0)
3659
3674
  return '<span class="json-bracket">{}</span>';
3660
- const properties = keys
3661
- .map((key) => {
3675
+ const properties = keys.map(key => {
3662
3676
  const escapedKey = this.escapeHtml(key);
3663
3677
  const value = this.createJsonDisplayHtml(obj[key], depth + 1);
3664
3678
  return `<div class="json-property">${nextIndent}<span class="json-key">"${escapedKey}"</span><span class="json-colon">:</span> ${value}</div>`;
3665
- })
3666
- .join(',\n');
3679
+ }).join(',\n');
3667
3680
  return `<span class="json-bracket">{</span>\n${properties}\n<div class="json-indent">${indent}</div><span class="json-bracket">}</span>`;
3668
3681
  }
3669
3682
  return String(obj);
@@ -3734,8 +3747,8 @@ export class AITestHarnessComponent {
3734
3747
  // Split by comma and trim each sequence
3735
3748
  this.advancedParams.stopSequences = this.stopSequencesText
3736
3749
  .split(',')
3737
- .map((s) => s.trim())
3738
- .filter((s) => s.length > 0);
3750
+ .map(s => s.trim())
3751
+ .filter(s => s.length > 0);
3739
3752
  }
3740
3753
  }
3741
3754
  /**
@@ -3808,16 +3821,12 @@ export class AITestHarnessComponent {
3808
3821
  const convertedMessages = chatMessages.map((msg, index) => ({
3809
3822
  id: `msg-${Date.now()}-${index}`,
3810
3823
  role: msg.role,
3811
- content: typeof msg.content === 'string'
3812
- ? msg.content
3813
- : Array.isArray(msg.content)
3814
- ? msg.content
3815
- .filter((block) => block.type === 'text')
3816
- .map((block) => block.content)
3817
- .join('\n')
3818
- : '',
3824
+ content: typeof msg.content === 'string' ? msg.content :
3825
+ Array.isArray(msg.content) ?
3826
+ msg.content.filter(block => block.type === 'text').map(block => block.content).join('\n') :
3827
+ '',
3819
3828
  timestamp: new Date(),
3820
- isStreaming: false,
3829
+ isStreaming: false
3821
3830
  }));
3822
3831
  console.log('🎯 Converted messages for test harness:', convertedMessages);
3823
3832
  this.conversationMessages = convertedMessages;
@@ -3903,5 +3912,5 @@ export class AITestHarnessComponent {
3903
3912
  type: ViewChild,
3904
3913
  args: ['saveDialogInput']
3905
3914
  }] }); })();
3906
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 178 }); })();
3915
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AITestHarnessComponent, { className: "AITestHarnessComponent", filePath: "lib/ai-test-harness.component.ts", lineNumber: 155 }); })();
3907
3916
  //# sourceMappingURL=ai-test-harness.component.js.map