llm-testrunner-components 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +165 -242
  3. package/dist/cjs/index.cjs.js +298 -232
  4. package/dist/cjs/index.cjs.js.map +1 -1
  5. package/dist/collection/components/llm-test-runner/llm-test-runner.import-export.test.js +25 -54
  6. package/dist/collection/components/llm-test-runner/llm-test-runner.import-export.test.js.map +1 -1
  7. package/dist/collection/components/llm-test-runner/llm-test-runner.js +6 -49
  8. package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -1
  9. package/dist/collection/components/llm-test-runner/test-cases/evaluation/evaluation-summary.css +60 -21
  10. package/dist/collection/components/llm-test-runner/test-cases/evaluation/evaluation-summary.js +3 -1
  11. package/dist/collection/components/llm-test-runner/test-cases/evaluation/evaluation-summary.js.map +1 -1
  12. package/dist/collection/components/llm-test-runner/test-cases/expected-outcome-renderer.js +31 -11
  13. package/dist/collection/components/llm-test-runner/test-cases/expected-outcome-renderer.js.map +1 -1
  14. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.css +17 -0
  15. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js +2 -12
  16. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js.map +1 -1
  17. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js +2 -2
  18. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js.map +1 -1
  19. package/dist/collection/lib/evaluation/evaluation-engine.js +63 -42
  20. package/dist/collection/lib/evaluation/evaluation-engine.js.map +1 -1
  21. package/dist/collection/lib/evaluation/evaluation-service.js +15 -3
  22. package/dist/collection/lib/evaluation/evaluation-service.js.map +1 -1
  23. package/dist/collection/lib/evaluation/{rouge1-evaluator.test.js → evaluators/rouge1-evaluator.test.js} +2 -2
  24. package/dist/collection/lib/evaluation/evaluators/rouge1-evaluator.test.js.map +1 -0
  25. package/dist/collection/lib/evaluation/field-evaluation-approach.js +24 -0
  26. package/dist/collection/lib/evaluation/field-evaluation-approach.js.map +1 -0
  27. package/dist/collection/lib/evaluation/index.js +0 -4
  28. package/dist/collection/lib/evaluation/index.js.map +1 -1
  29. package/dist/collection/lib/evaluation/types.js.map +1 -1
  30. package/dist/collection/lib/import-export/test-results-csv.js +47 -33
  31. package/dist/collection/lib/import-export/test-results-csv.js.map +1 -1
  32. package/dist/collection/lib/import-export/test-suite-exporter.js +0 -1
  33. package/dist/collection/lib/import-export/test-suite-exporter.js.map +1 -1
  34. package/dist/collection/lib/test-cases/test-case-factory.js +17 -27
  35. package/dist/collection/lib/test-cases/test-case-factory.js.map +1 -1
  36. package/dist/collection/lib/test-cases/test-case-mutations.js +60 -9
  37. package/dist/collection/lib/test-cases/test-case-mutations.js.map +1 -1
  38. package/dist/collection/schemas/expected-outcome.js +20 -2
  39. package/dist/collection/schemas/expected-outcome.js.map +1 -1
  40. package/dist/collection/schemas/test-case.js +2 -20
  41. package/dist/collection/schemas/test-case.js.map +1 -1
  42. package/dist/collection/types/llm-test-runner.js.map +1 -1
  43. package/dist/collection/types/test-case.js.map +1 -1
  44. package/dist/components/index.js +1 -1
  45. package/dist/components/llm-test-runner.js +1 -1
  46. package/dist/components/p-Bb89MYYu.js +7 -0
  47. package/dist/components/p-Bb89MYYu.js.map +1 -0
  48. package/dist/esm/index.js +298 -232
  49. package/dist/esm/index.js.map +1 -1
  50. package/dist/llm-testrunner/index.esm.js +2 -2
  51. package/dist/llm-testrunner/index.esm.js.map +1 -1
  52. package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +0 -1
  53. package/dist/types/components/llm-test-runner/test-cases/expected-outcome-renderer.d.ts +3 -6
  54. package/dist/types/components/llm-test-runner/test-cases/llm-test-case-row.d.ts +0 -2
  55. package/dist/types/components/llm-test-runner/test-cases/llm-test-cases.d.ts +0 -2
  56. package/dist/types/lib/evaluation/evaluation-engine.d.ts +4 -2
  57. package/dist/types/lib/evaluation/field-evaluation-approach.d.ts +6 -0
  58. package/dist/types/lib/evaluation/index.d.ts +0 -1
  59. package/dist/types/lib/evaluation/types.d.ts +26 -0
  60. package/dist/types/lib/import-export/test-suite-exporter.d.ts +0 -4
  61. package/dist/types/lib/test-cases/test-case-factory.d.ts +2 -3
  62. package/dist/types/lib/test-cases/test-case-mutations.d.ts +21 -5
  63. package/dist/types/schemas/expected-outcome.d.ts +65 -17
  64. package/dist/types/schemas/test-case.d.ts +51 -95
  65. package/dist/types/types/llm-test-runner.d.ts +1 -1
  66. package/dist/types/types/test-case.d.ts +1 -1
  67. package/package.json +9 -2
  68. package/dist/collection/lib/evaluation/rouge1-evaluator.test.js.map +0 -1
  69. package/dist/components/p-BF90yb1z.js +0 -7
  70. package/dist/components/p-BF90yb1z.js.map +0 -1
  71. /package/dist/types/lib/evaluation/{rouge1-evaluator.test.d.ts → evaluators/rouge1-evaluator.test.d.ts} +0 -0
@@ -8,14 +8,13 @@ jest.mock('../../lib/file/file-reader');
8
8
  jest.mock('../../lib/file/file-download');
9
9
  jest.mock('../../lib/import-export/test-suite-exporter');
10
10
  jest.mock('../../lib/import-export/test-suite-importer');
11
- import { h } from "@stencil/core";
12
11
  import { newSpecPage } from "@stencil/core/testing";
13
12
  import { LLMTestRunner } from "./llm-test-runner";
14
- import { EvaluationApproach } from "../../lib/evaluation/constants";
15
13
  import { readFileAsync } from "../../lib/file/file-reader";
16
14
  import { downloadFile } from "../../lib/file/file-download";
17
15
  import { formatTestSuiteAsJson } from "../../lib/import-export/test-suite-exporter";
18
16
  import { importTestSuite } from "../../lib/import-export/test-suite-importer";
17
+ import { EvaluationApproach } from "../../lib/evaluation/constants";
19
18
  describe('llm-test-runner import/export', () => {
20
19
  let page;
21
20
  let component;
@@ -31,19 +30,11 @@ describe('llm-test-runner import/export', () => {
31
30
  id: '1',
32
31
  question: 'What is AI?',
33
32
  expectedOutcome: buildExpectedOutcome('artificial intelligence'),
34
- evaluationParameters: {
35
- approach: EvaluationApproach.EXACT,
36
- threshold: 0.6
37
- },
38
33
  isRunning: false
39
34
  };
40
35
  return {
41
36
  ...defaults,
42
37
  ...overrides,
43
- evaluationParameters: {
44
- ...defaults.evaluationParameters,
45
- ...overrides.evaluationParameters,
46
- },
47
38
  };
48
39
  };
49
40
  const createMockFile = (content, filename, type = 'application/json') => {
@@ -65,7 +56,6 @@ describe('llm-test-runner import/export', () => {
65
56
  id: '1',
66
57
  question: 'What is AI?',
67
58
  expectedOutcome: buildExpectedOutcome('artificial intelligence'),
68
- evaluationParameters: { approach: EvaluationApproach.EXACT, threshold: 0.6 },
69
59
  isRunning: false
70
60
  }
71
61
  ];
@@ -86,27 +76,42 @@ describe('llm-test-runner import/export', () => {
86
76
  });
87
77
  });
88
78
  it('should use default evaluation parameters when not provided', async () => {
89
- const mockTestData = [
79
+ const rawImportData = [
90
80
  {
91
81
  id: '1',
92
82
  question: 'Test question',
93
83
  expectedOutcome: buildExpectedOutcome('test'),
94
- evaluationParameters: { approach: EvaluationApproach.EXACT, threshold: 0.6 },
95
84
  isRunning: false
96
85
  }
97
86
  ];
98
- const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');
99
- readFileAsync.mockResolvedValue(JSON.stringify(mockTestData));
87
+ const normalizedImportData = [
88
+ {
89
+ id: '1',
90
+ question: 'Test question',
91
+ expectedOutcome: [
92
+ {
93
+ type: 'textarea',
94
+ label: 'Expected Outcome',
95
+ value: 'test',
96
+ evaluationParameters: {
97
+ approach: EvaluationApproach.EXACT,
98
+ },
99
+ },
100
+ ],
101
+ isRunning: false,
102
+ },
103
+ ];
104
+ const mockFile = createMockFile(JSON.stringify(rawImportData), 'test.json');
105
+ readFileAsync.mockResolvedValue(JSON.stringify(rawImportData));
100
106
  importTestSuite.mockReturnValue({
101
107
  success: true,
102
- testCases: mockTestData
108
+ testCases: normalizedImportData,
103
109
  });
104
110
  await component.handleImport(mockFile);
105
111
  await page.waitForChanges();
106
- expect(component.testCases[0].evaluationParameters).toMatchObject({
107
- approach: EvaluationApproach.EXACT,
108
- threshold: 0.6
109
- });
112
+ expect(component.testCases[0].expectedOutcome[0].evaluationParameters?.approach).toBe(EvaluationApproach.EXACT);
113
+ expect(component.testCases[0].expectedOutcome[0].value).toBe('test');
114
+ expect(component.testCases[0].expectedOutcome[0].label).toBe('Expected Outcome');
110
115
  });
111
116
  });
112
117
  describe('File Import - Multiple Test Cases', () => {
@@ -116,14 +121,12 @@ describe('llm-test-runner import/export', () => {
116
121
  id: '1',
117
122
  question: 'What is AI?',
118
123
  expectedOutcome: buildExpectedOutcome('artificial intelligence'),
119
- evaluationParameters: { approach: EvaluationApproach.EXACT },
120
124
  isRunning: false
121
125
  },
122
126
  {
123
127
  id: '2',
124
128
  question: 'What is ML?',
125
129
  expectedOutcome: buildExpectedOutcome('machine learning'),
126
- evaluationParameters: { approach: EvaluationApproach.EXACT },
127
130
  isRunning: false
128
131
  }
129
132
  ];
@@ -145,21 +148,18 @@ describe('llm-test-runner import/export', () => {
145
148
  id: '1',
146
149
  question: 'Q1',
147
150
  expectedOutcome: buildExpectedOutcome('answer1'),
148
- evaluationParameters: { approach: EvaluationApproach.EXACT },
149
151
  isRunning: false
150
152
  },
151
153
  {
152
154
  id: '2',
153
155
  question: 'Q2',
154
156
  expectedOutcome: buildExpectedOutcome('answer2'),
155
- evaluationParameters: { approach: EvaluationApproach.EXACT },
156
157
  isRunning: false
157
158
  },
158
159
  {
159
160
  id: '3',
160
161
  question: 'Q3',
161
162
  expectedOutcome: buildExpectedOutcome('answer3'),
162
- evaluationParameters: { approach: EvaluationApproach.EXACT },
163
163
  isRunning: false
164
164
  }
165
165
  ];
@@ -257,34 +257,5 @@ describe('llm-test-runner import/export', () => {
257
257
  expect(component.error).toBe('');
258
258
  });
259
259
  });
260
- describe('Initial Test Cases', () => {
261
- it('should normalize legacy string expectedOutcome from initialTestCases', async () => {
262
- const legacyInitialCases = [
263
- {
264
- id: 'legacy-1',
265
- question: 'Whats capital of India ?',
266
- expectedOutcome: 'Delhi',
267
- evaluationParameters: { approach: EvaluationApproach.EXACT },
268
- },
269
- ];
270
- const localPage = await newSpecPage({
271
- components: [LLMTestRunner],
272
- template: () => h('llm-test-runner', {
273
- initialTestCases: legacyInitialCases,
274
- }),
275
- });
276
- const localComponent = localPage.rootInstance;
277
- await localPage.waitForChanges();
278
- expect(localComponent.testCases).toHaveLength(1);
279
- expect(localComponent.testCases[0].id).toBe('legacy-1');
280
- expect(localComponent.testCases[0].expectedOutcome).toEqual([
281
- {
282
- type: 'textarea',
283
- label: 'Expected Outcome',
284
- value: 'Delhi',
285
- },
286
- ]);
287
- });
288
- });
289
260
  });
290
261
  //# sourceMappingURL=llm-test-runner.import-export.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-test-runner.import-export.test.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.import-export.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-env jest */\n\njest.mock('../../lib/evaluation/evaluation-engine', () => ({\n LLMEvaluationEngine: jest.fn().mockImplementation(() => ({\n evaluateResponse: jest.fn()\n }))\n}));\n\njest.mock('../../lib/file/file-reader');\njest.mock('../../lib/file/file-download');\njest.mock('../../lib/import-export/test-suite-exporter');\njest.mock('../../lib/import-export/test-suite-importer');\n\nimport { h } from '@stencil/core';\nimport { newSpecPage, SpecPage } from '@stencil/core/testing';\nimport { LLMTestRunner } from './llm-test-runner';\nimport { TestCase, TestCaseInput } from '../../types/llm-test-runner';\nimport { EvaluationApproach } from '../../lib/evaluation/constants';\nimport { readFileAsync } from '../../lib/file/file-reader';\nimport { downloadFile } from '../../lib/file/file-download';\nimport { formatTestSuiteAsJson } from '../../lib/import-export/test-suite-exporter';\nimport { importTestSuite } from '../../lib/import-export/test-suite-importer';\n\ndescribe('llm-test-runner import/export', () => {\n let page: SpecPage;\n let component: any;\n const buildExpectedOutcome = (value: string) => [\n {\n type: 'textarea' as const,\n label: 'Expected Outcome',\n value,\n },\n ];\n\n const createMockTestCase = (overrides: Partial<TestCase> = {}): TestCase => {\n const defaults: TestCase = {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n evaluationParameters: {\n approach: EvaluationApproach.EXACT,\n threshold: 0.6\n },\n isRunning: false\n };\n\n return {\n ...defaults,\n ...overrides,\n evaluationParameters: {\n ...defaults.evaluationParameters,\n ...overrides.evaluationParameters,\n },\n };\n };\n\n const createMockFile = (content: string, filename: string, type: string = 'application/json'): File => {\n return new File([content], filename, { type });\n };\n\n beforeEach(async () => {\n jest.clearAllMocks();\n \n page = await newSpecPage({\n components: [LLMTestRunner],\n html: '<llm-test-runner></llm-test-runner>',\n });\n component = page.rootInstance;\n \n await page.waitForChanges();\n });\n\n describe('File Import - Basic Functionality', () => {\n it('should import valid test cases structure', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n evaluationParameters: { approach: EvaluationApproach.EXACT, threshold: 0.6 },\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test-suite.json');\n\n // Mock the utility functions\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.testCases).toHaveLength(1);\n expect(component.testCases[0]).toMatchObject({\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n });\n });\n\n it('should use default evaluation parameters when not provided', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'Test question',\n expectedOutcome: buildExpectedOutcome('test'),\n evaluationParameters: { approach: EvaluationApproach.EXACT, threshold: 0.6 },\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.testCases[0].evaluationParameters).toMatchObject({\n approach: EvaluationApproach.EXACT,\n threshold: 0.6\n });\n });\n });\n\n describe('File Import - Multiple Test Cases', () => {\n it('should import multiple test cases successfully', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n isRunning: false\n },\n {\n id: '2',\n question: 'What is ML?',\n expectedOutcome: buildExpectedOutcome('machine learning'),\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.testCases).toHaveLength(2);\n expect(component.testCases[0].question).toBe('What is AI?');\n expect(component.testCases[1].question).toBe('What is ML?');\n });\n\n it('should handle unique IDs for imported test cases', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'Q1',\n expectedOutcome: buildExpectedOutcome('answer1'),\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n isRunning: false\n },\n {\n id: '2',\n question: 'Q2',\n expectedOutcome: buildExpectedOutcome('answer2'),\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n isRunning: false\n },\n {\n id: '3',\n question: 'Q3',\n expectedOutcome: buildExpectedOutcome('answer3'),\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n const ids = component.testCases.map((tc: TestCase) => tc.id);\n expect(new Set(ids).size).toBe(ids.length);\n });\n });\n\n describe('File Import - Error Handling', () => {\n it('should reject non-JSON file type', async () => {\n const mockFile = createMockFile('some content', 'test.txt', 'text/plain');\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toBe('Invalid file type. Please select a JSON file.');\n });\n\n it('should handle import failure from utility', async () => {\n const mockFile = createMockFile('{}', 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue('{}');\n (importTestSuite as jest.Mock).mockReturnValue({\n success: false,\n error: 'Invalid JSON structure. Expected a JSON array.'\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toContain('Invalid JSON structure');\n });\n\n it('should handle file read errors', async () => {\n const mockFile = createMockFile('{}', 'test.json');\n\n (readFileAsync as jest.Mock).mockRejectedValue(new Error('Failed to read file'));\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toBeTruthy();\n });\n });\n\n describe('Export Test Suite', () => {\n it('should export test suite with correct structure', async () => {\n component.testCases = [createMockTestCase()];\n\n const mockJsonContent = JSON.stringify([createMockTestCase()]);\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue(mockJsonContent);\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n await component.handleExportTestSuite();\n await page.waitForChanges();\n\n expect(formatTestSuiteAsJson).toHaveBeenCalledWith(component.testCases);\n expect(downloadFile).toHaveBeenCalledWith(\n mockJsonContent,\n 'test-suite.json',\n 'application/json'\n );\n });\n\n it('should handle exporting state', async () => {\n component.testCases = [createMockTestCase()];\n\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue('[]');\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n expect(component.isExportingTestSuite).toBe(false);\n\n const exportPromise = component.handleExportTestSuite();\n \n // During export\n await page.waitForChanges();\n\n // After export completes\n await exportPromise;\n await page.waitForChanges();\n\n expect(component.isExportingTestSuite).toBe(false);\n });\n\n it('should export multiple test cases', async () => {\n const testCases = [\n createMockTestCase({ id: '1', question: 'Q1' }),\n createMockTestCase({ id: '2', question: 'Q2' }),\n createMockTestCase({ id: '3', question: 'Q3' })\n ];\n\n component.testCases = testCases;\n\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue(JSON.stringify(testCases));\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n await component.handleExportTestSuite();\n await page.waitForChanges();\n\n expect(formatTestSuiteAsJson).toHaveBeenCalledWith(testCases);\n });\n });\n\n describe('Component State Management', () => {\n it('should maintain test cases state', () => {\n expect(component.testCases).toBeDefined();\n expect(Array.isArray(component.testCases)).toBe(true);\n });\n\n it('should maintain error state', () => {\n expect(component.error).toBeDefined();\n expect(typeof component.error).toBe('string');\n });\n\n it('should clear errors', async () => {\n component.error = 'Test error';\n await page.waitForChanges();\n\n expect(component.error).toBe('Test error');\n\n component.error = '';\n await page.waitForChanges();\n\n expect(component.error).toBe('');\n });\n });\n\n describe('Initial Test Cases', () => {\n it('should normalize legacy string expectedOutcome from initialTestCases', async () => {\n const legacyInitialCases = [\n {\n id: 'legacy-1',\n question: 'Whats capital of India ?',\n expectedOutcome: 'Delhi',\n evaluationParameters: { approach: EvaluationApproach.EXACT },\n },\n ] as unknown as TestCase[];\n\n const localPage = await newSpecPage({\n components: [LLMTestRunner],\n template: () =>\n h('llm-test-runner', {\n initialTestCases: legacyInitialCases as TestCaseInput[],\n }),\n });\n\n const localComponent = localPage.rootInstance as LLMTestRunner;\n await localPage.waitForChanges();\n\n expect(localComponent.testCases).toHaveLength(1);\n expect(localComponent.testCases[0].id).toBe('legacy-1');\n expect(localComponent.testCases[0].expectedOutcome).toEqual([\n {\n type: 'textarea',\n label: 'Expected Outcome',\n value: 'Delhi',\n },\n ]);\n });\n });\n});"]}
1
+ {"version":3,"file":"llm-test-runner.import-export.test.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.import-export.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-env jest */\n\njest.mock('../../lib/evaluation/evaluation-engine', () => ({\n LLMEvaluationEngine: jest.fn().mockImplementation(() => ({\n evaluateResponse: jest.fn()\n }))\n}));\n\njest.mock('../../lib/file/file-reader');\njest.mock('../../lib/file/file-download');\njest.mock('../../lib/import-export/test-suite-exporter');\njest.mock('../../lib/import-export/test-suite-importer');\n\nimport { newSpecPage, SpecPage } from '@stencil/core/testing';\nimport { LLMTestRunner } from './llm-test-runner';\nimport { TestCase } from '../../types/llm-test-runner';\nimport { readFileAsync } from '../../lib/file/file-reader';\nimport { downloadFile } from '../../lib/file/file-download';\nimport { formatTestSuiteAsJson } from '../../lib/import-export/test-suite-exporter';\nimport { importTestSuite } from '../../lib/import-export/test-suite-importer';\nimport { EvaluationApproach } from '../../lib/evaluation/constants';\n\ndescribe('llm-test-runner import/export', () => {\n let page: SpecPage;\n let component: any;\n const buildExpectedOutcome = (value: string) => [\n {\n type: 'textarea' as const,\n label: 'Expected Outcome',\n value,\n },\n ];\n\n const createMockTestCase = (overrides: Partial<TestCase> = {}): TestCase => {\n const defaults: TestCase = {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n isRunning: false\n };\n\n return {\n ...defaults,\n ...overrides,\n };\n };\n\n const createMockFile = (content: string, filename: string, type: string = 'application/json'): File => {\n return new File([content], filename, { type });\n };\n\n beforeEach(async () => {\n jest.clearAllMocks();\n \n page = await newSpecPage({\n components: [LLMTestRunner],\n html: '<llm-test-runner></llm-test-runner>',\n });\n component = page.rootInstance;\n \n await page.waitForChanges();\n });\n\n describe('File Import - Basic Functionality', () => {\n it('should import valid test cases structure', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test-suite.json');\n\n // Mock the utility functions\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.testCases).toHaveLength(1);\n expect(component.testCases[0]).toMatchObject({\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n });\n });\n\n it('should use default evaluation parameters when not provided', async () => {\n const rawImportData = [\n {\n id: '1',\n question: 'Test question',\n expectedOutcome: buildExpectedOutcome('test'),\n isRunning: false\n }\n ];\n const normalizedImportData = [\n {\n id: '1',\n question: 'Test question',\n expectedOutcome: [\n {\n type: 'textarea' as const,\n label: 'Expected Outcome',\n value: 'test',\n evaluationParameters: {\n approach: EvaluationApproach.EXACT,\n },\n },\n ],\n isRunning: false,\n },\n ];\n\n const mockFile = createMockFile(JSON.stringify(rawImportData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(rawImportData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: normalizedImportData,\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(\n component.testCases[0].expectedOutcome[0].evaluationParameters?.approach,\n ).toBe(EvaluationApproach.EXACT);\n expect(component.testCases[0].expectedOutcome[0].value).toBe('test');\n expect(component.testCases[0].expectedOutcome[0].label).toBe(\n 'Expected Outcome',\n );\n });\n });\n\n describe('File Import - Multiple Test Cases', () => {\n it('should import multiple test cases successfully', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'What is AI?',\n expectedOutcome: buildExpectedOutcome('artificial intelligence'),\n isRunning: false\n },\n {\n id: '2',\n question: 'What is ML?',\n expectedOutcome: buildExpectedOutcome('machine learning'),\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.testCases).toHaveLength(2);\n expect(component.testCases[0].question).toBe('What is AI?');\n expect(component.testCases[1].question).toBe('What is ML?');\n });\n\n it('should handle unique IDs for imported test cases', async () => {\n const mockTestData = [\n {\n id: '1',\n question: 'Q1',\n expectedOutcome: buildExpectedOutcome('answer1'),\n isRunning: false\n },\n {\n id: '2',\n question: 'Q2',\n expectedOutcome: buildExpectedOutcome('answer2'),\n isRunning: false\n },\n {\n id: '3',\n question: 'Q3',\n expectedOutcome: buildExpectedOutcome('answer3'),\n isRunning: false\n }\n ];\n\n const mockFile = createMockFile(JSON.stringify(mockTestData), 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue(JSON.stringify(mockTestData));\n (importTestSuite as jest.Mock).mockReturnValue({\n success: true,\n testCases: mockTestData\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n const ids = component.testCases.map((tc: TestCase) => tc.id);\n expect(new Set(ids).size).toBe(ids.length);\n });\n });\n\n describe('File Import - Error Handling', () => {\n it('should reject non-JSON file type', async () => {\n const mockFile = createMockFile('some content', 'test.txt', 'text/plain');\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toBe('Invalid file type. Please select a JSON file.');\n });\n\n it('should handle import failure from utility', async () => {\n const mockFile = createMockFile('{}', 'test.json');\n\n (readFileAsync as jest.Mock).mockResolvedValue('{}');\n (importTestSuite as jest.Mock).mockReturnValue({\n success: false,\n error: 'Invalid JSON structure. Expected a JSON array.'\n });\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toContain('Invalid JSON structure');\n });\n\n it('should handle file read errors', async () => {\n const mockFile = createMockFile('{}', 'test.json');\n\n (readFileAsync as jest.Mock).mockRejectedValue(new Error('Failed to read file'));\n\n await component.handleImport(mockFile);\n await page.waitForChanges();\n\n expect(component.error).toBeTruthy();\n });\n });\n\n describe('Export Test Suite', () => {\n it('should export test suite with correct structure', async () => {\n component.testCases = [createMockTestCase()];\n\n const mockJsonContent = JSON.stringify([createMockTestCase()]);\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue(mockJsonContent);\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n await component.handleExportTestSuite();\n await page.waitForChanges();\n\n expect(formatTestSuiteAsJson).toHaveBeenCalledWith(component.testCases);\n expect(downloadFile).toHaveBeenCalledWith(\n mockJsonContent,\n 'test-suite.json',\n 'application/json'\n );\n });\n\n it('should handle exporting state', async () => {\n component.testCases = [createMockTestCase()];\n\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue('[]');\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n expect(component.isExportingTestSuite).toBe(false);\n\n const exportPromise = component.handleExportTestSuite();\n \n // During export\n await page.waitForChanges();\n\n // After export completes\n await exportPromise;\n await page.waitForChanges();\n\n expect(component.isExportingTestSuite).toBe(false);\n });\n\n it('should export multiple test cases', async () => {\n const testCases = [\n createMockTestCase({ id: '1', question: 'Q1' }),\n createMockTestCase({ id: '2', question: 'Q2' }),\n createMockTestCase({ id: '3', question: 'Q3' })\n ];\n\n component.testCases = testCases;\n\n (formatTestSuiteAsJson as jest.Mock).mockReturnValue(JSON.stringify(testCases));\n (downloadFile as jest.Mock).mockImplementation(() => {});\n\n await component.handleExportTestSuite();\n await page.waitForChanges();\n\n expect(formatTestSuiteAsJson).toHaveBeenCalledWith(testCases);\n });\n });\n\n describe('Component State Management', () => {\n it('should maintain test cases state', () => {\n expect(component.testCases).toBeDefined();\n expect(Array.isArray(component.testCases)).toBe(true);\n });\n\n it('should maintain error state', () => {\n expect(component.error).toBeDefined();\n expect(typeof component.error).toBe('string');\n });\n\n it('should clear errors', async () => {\n component.error = 'Test error';\n await page.waitForChanges();\n\n expect(component.error).toBe('Test error');\n\n component.error = '';\n await page.waitForChanges();\n\n expect(component.error).toBe('');\n });\n });\n});"]}
@@ -1,7 +1,6 @@
1
1
  import { h, } from "@stencil/core";
2
2
  import { ErrorMessage } from "../error-message/error-message";
3
3
  import { RateLimitedFetcher } from "../../lib/rate-limited-fetcher/rate-limited-fetcher";
4
- import { EvaluationApproach } from "../../lib/evaluation/constants";
5
4
  import { readFileAsync } from "../../lib/file/file-reader";
6
5
  import { downloadFile } from "../../lib/file/file-download";
7
6
  import { formatTestSuiteAsJson } from "../../lib/import-export/test-suite-exporter";
@@ -32,9 +31,6 @@ export class LLMTestRunner {
32
31
  value: '',
33
32
  },
34
33
  ],
35
- evaluationParameters: {
36
- approach: EvaluationApproach.EXACT,
37
- },
38
34
  isRunning: false,
39
35
  },
40
36
  ];
@@ -141,52 +137,13 @@ export class LLMTestRunner {
141
137
  deleteTestCase(id) {
142
138
  this.testCases = this.testCases.filter(tc => tc.id !== id);
143
139
  }
144
- updateApproach(testCase, approach) {
145
- if (testCase) {
146
- const updated = TestCaseMutations.updateApproach(testCase, approach);
147
- this.updateTestCase(testCase.id, {
148
- evaluationParameters: updated.evaluationParameters,
149
- });
150
- }
151
- }
152
140
  handleExpectedOutcomeChange = (event) => {
153
- const { testCaseId, index, operation, value } = event.detail;
141
+ const { testCaseId, ...change } = event.detail;
154
142
  this.testCases = this.testCases.map(tc => {
155
- if (tc.id !== testCaseId)
156
- return tc;
157
- const expectedOutcome = [...(tc.expectedOutcome || [])];
158
- const target = expectedOutcome[index];
159
- if (!target)
143
+ if (tc.id !== testCaseId) {
160
144
  return tc;
161
- if (operation === 'set-value') {
162
- if (target.type === 'chips-input') {
163
- return tc;
164
- }
165
- expectedOutcome[index] = { ...target, value: value || '' };
166
- return { ...tc, expectedOutcome };
167
- }
168
- if (operation === 'add-chip') {
169
- if (target.type !== 'chips-input' || !value) {
170
- return tc;
171
- }
172
- expectedOutcome[index] = {
173
- ...target,
174
- value: [...target.value, value],
175
- };
176
- return { ...tc, expectedOutcome };
177
- }
178
- if (operation === 'remove-chip') {
179
- if (target.type !== 'chips-input' ||
180
- !value) {
181
- return tc;
182
- }
183
- expectedOutcome[index] = {
184
- ...target,
185
- value: target.value.filter(chip => chip !== value),
186
- };
187
- return { ...tc, expectedOutcome };
188
145
  }
189
- return tc;
146
+ return TestCaseMutations.applyExpectedOutcomeChange(tc, change);
190
147
  });
191
148
  };
192
149
  async evaluateResponse(testCase) {
@@ -286,7 +243,7 @@ export class LLMTestRunner {
286
243
  }
287
244
  }
288
245
  render() {
289
- return (h("div", { key: '5cbdc388678929c271fd2a040aca8118344024c3', class: "test-runner-container" }, h(LLMTestRunnerHeader, { key: '92533803732fc5ec28da802ac9d367f9fbbffe72', isExportingTestSuite: this.isExportingTestSuite, isExportingTestResults: this.isExportingTestResults, isRunningAll: this.isRunningAll, useSave: this.useSave, isSaving: this.isSaving, onImport: file => this.handleImport(file), onExportSuite: () => this.handleExportTestSuite(), onExportResults: () => this.handleExportTestResults(), onRunAll: () => this.runAllTests(), onSave: () => this.handleSave() }), h(ErrorMessage, { key: 'c16a0334b1a71d676a128de18a83991c2625a075', message: this.error, onClear: () => (this.error = '') }), h("div", { key: 'e757f49052a9516c12af858b46b32a957707524c', class: "test-runner-container__content" }, h(LLMTestCases, { key: 'e9a9f6553a3ce97aeb80924b116e1b73c2397b15', testCases: this.testCases, onRun: testCase => this.runSingleTest(testCase).catch(() => { }), onDelete: id => this.deleteTestCase(id), onUpdateApproach: (testCase, approach) => this.updateApproach(testCase, approach), onAddTestCase: () => this.addNewTestCase(), handleTestCaseChange: this.handleTestCaseChange, onExpectedOutcomeChange: this.handleExpectedOutcomeChange }))));
246
+ return (h("div", { key: 'e3d007b453f770fcb59c29f8ee83bd8a35e82a34', class: "test-runner-container" }, h(LLMTestRunnerHeader, { key: 'b7c44bf4807fe8d9e5de514818420d67d2e0dbfb', isExportingTestSuite: this.isExportingTestSuite, isExportingTestResults: this.isExportingTestResults, isRunningAll: this.isRunningAll, useSave: this.useSave, isSaving: this.isSaving, onImport: file => this.handleImport(file), onExportSuite: () => this.handleExportTestSuite(), onExportResults: () => this.handleExportTestResults(), onRunAll: () => this.runAllTests(), onSave: () => this.handleSave() }), h(ErrorMessage, { key: '697237ec0f8d2e704609fd0b240629f22c2a3ef6', message: this.error, onClear: () => (this.error = '') }), h("div", { key: '64a623f897dfb96d922ddc0cbdfcf529c52bef76', class: "test-runner-container__content" }, h(LLMTestCases, { key: '017da41567c5c13933d9cf31d1a972743bd9b100', testCases: this.testCases, onRun: testCase => this.runSingleTest(testCase).catch(() => { }), onDelete: id => this.deleteTestCase(id), onAddTestCase: () => this.addNewTestCase(), handleTestCaseChange: this.handleTestCaseChange, onExpectedOutcomeChange: this.handleExpectedOutcomeChange }))));
290
247
  }
291
248
  static get is() { return "llm-test-runner"; }
292
249
  static get encapsulation() { return "shadow"; }
@@ -347,7 +304,7 @@ export class LLMTestRunner {
347
304
  "mutable": false,
348
305
  "complexType": {
349
306
  "original": "TestCase[]",
350
- "resolved": "{ id: string; question: string; expectedOutcome: ({ label: string; type: \"select\"; options: string[]; value: string; required?: boolean; placeholder?: string; } | { label: string; type: \"text\"; value: string; required?: boolean; placeholder?: string; } | { label: string; type: \"textarea\"; value: string; required?: boolean; placeholder?: string; rows?: number; } | { label: string; type: \"chips-input\"; value: string[]; required?: boolean; placeholder?: string; })[]; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; output?: string; isRunning?: boolean; error?: string; evaluationResult?: EvaluationResult; responseTime?: number; }[]",
307
+ "resolved": "{ id: string; question: string; expectedOutcome: ({ label: string; type: \"select\"; options: string[]; value: string; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"text\"; value: string; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"textarea\"; value: string; placeholder?: string; rows?: number; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"chips-input\"; value: string[]; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; })[]; output?: string; isRunning?: boolean; error?: string; evaluationResult?: EvaluationResult; responseTime?: number; }[]",
351
308
  "references": {
352
309
  "TestCase": {
353
310
  "location": "import",
@@ -371,7 +328,7 @@ export class LLMTestRunner {
371
328
  "mutable": false,
372
329
  "complexType": {
373
330
  "original": "ExpectedOutcomeSchema",
374
- "resolved": "({ label: string; type: \"text\"; required?: boolean; placeholder?: string; } | { label: string; type: \"textarea\"; required?: boolean; placeholder?: string; rows?: number; } | { label: string; type: \"chips-input\"; required?: boolean; placeholder?: string; } | { label: string; type: \"select\"; options: string[]; required?: boolean; placeholder?: string; })[]",
331
+ "resolved": "({ label: string; type: \"text\"; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"textarea\"; placeholder?: string; rows?: number; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"chips-input\"; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"select\"; options: string[]; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; })[]",
375
332
  "references": {
376
333
  "ExpectedOutcomeSchema": {
377
334
  "location": "import",
@@ -1 +1 @@
1
- {"version":3,"file":"llm-test-runner.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,CAAC,EAED,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAOpE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,iBAAiB,MAAM,0CAA0C,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAoB3D,MAAM,OAAO,aAAa;IACf,UAAU,CAAkC;IAC5C,IAAI,CAA4B;IACjC,OAAO,GAAY,GAAG,CAAC;IACvB,OAAO,GAAa,KAAK,CAAC;IAC1B,gBAAgB,CAAc;IAC9B,4BAA4B,CAAyB;IACpD,SAAS,GAAe;QAC/B;YACE,EAAE,EAAE,GAAG;YACP,QAAQ,EAAE,EAAE;YACZ,eAAe,EAAE;gBACf;oBACE,IAAI,EAAE,UAAU;oBAChB,KAAK,EAAE,kBAAkB;oBACzB,KAAK,EAAE,EAAE;iBACV;aACF;YACD,oBAAoB,EAAE;gBACpB,QAAQ,EAAE,kBAAkB,CAAC,KAAK;aACnC;YACD,SAAS,EAAE,KAAK;SACjB;KACF,CAAC;IACO,YAAY,GAAY,KAAK,CAAC;IAC9B,KAAK,GAAW,EAAE,CAAC;IACnB,oBAAoB,GAAY,KAAK,CAAC;IACtC,sBAAsB,GAAY,KAAK,CAAC;IACxC,QAAQ,GAAY,KAAK,CAAC;IAE3B,iBAAiB,CAAoB;IAErC,gCAAgC;QACtC,IAAI,IAAI,CAAC,4BAA4B,KAAK,SAAS,EAAE,CAAC;YACpD,OAAO,+BAA+B,CAAC;QACzC,CAAC;QAED,6BAA6B,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,4BAA4B,CAAC;IAC3C,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,6CAA6C;YAC7C,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACxC,0BAA0B,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAClD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE;oBAChE,IAAI,CAAC;wBACH,OAAO,uBAAuB,CAAC,WAAW,CAAC,CAAC;oBAC9C,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;wBACrE,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,KAAK,OAAO,EAAE,CAAC,CAAC;oBAC7E,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,IAAI,CAAC,gCAAgC,EAAE,CAAC;gBACvD,IAAI,CAAC,SAAS,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,KAAK;gBACR,GAAG,YAAY,KAAK;oBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;oBACb,CAAC,CAAC,gDAAgD,CAAC;YACvD,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAED,gBAAgB,KAAI,CAAC;IAErB,oBAAoB,KAAI,CAAC;IAGzB,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IAEO,oBAAoB,GAAG,CAC7B,KAAsE,EACtE,EAAE;QACF,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CACvC,EAAE,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CACpD,CAAC;IACJ,CAAC,CAAC;IAEM,cAAc;QACpB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,gCAAgC,EAAE,CAAC;YACvD,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,KAAK;gBACR,GAAG,YAAY,KAAK;oBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;oBACb,CAAC,CAAC,gDAAgD,CAAC;QACzD,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,EAAU,EAAE,OAA0B;QAC3D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CACvC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAC1C,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,QAAkB;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACnB,MAAM,EAAE,QAAQ,CAAC,QAAQ;gBACzB,OAAO,EAAE,KAAK,EAAE,UAAkB,EAAE,EAAE;oBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAC3B,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;oBACzC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;wBAC/B,SAAS,EAAE,KAAK;wBAChB,MAAM,EAAE,UAAU;wBAClB,KAAK,EAAE,IAAI;wBACX,YAAY,EAAE,YAAY;qBAC3B,CAAC,CAAC;oBAEH,MAAM,IAAI,CAAC,gBAAgB,CAAC;wBAC1B,GAAG,QAAQ;wBACX,MAAM,EAAE,UAAU;wBAClB,YAAY,EAAE,YAAY;qBAC3B,CAAC,CAAC;oBACH,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;oBACjC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;wBAC/B,SAAS,EAAE,KAAK;wBAChB,MAAM,EAAE,IAAI;wBACZ,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;qBAChE,CAAC,CAAC;oBACH,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,EAAU;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;IAEO,cAAc,CAAC,QAAkB,EAAE,QAA4B;QACrE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,iBAAiB,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACrE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAC/B,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;aACnD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,2BAA2B,GAAG,CACpC,KAA+C,EAC/C,EAAE;QACF,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;QAE7D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YACvC,IAAI,EAAE,CAAC,EAAE,KAAK,UAAU;gBAAE,OAAO,EAAE,CAAC;YAEpC,MAAM,eAAe,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,MAAM;gBAAE,OAAO,EAAE,CAAC;YAEvB,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;gBAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBAClC,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,eAAe,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;gBAC3D,OAAO,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,CAAC;YACpC,CAAC;YAED,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;gBAC7B,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC5C,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,eAAe,CAAC,KAAK,CAAC,GAAG;oBACvB,GAAG,MAAM;oBACT,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;iBAChC,CAAC;gBACF,OAAO,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,CAAC;YACpC,CAAC;YAED,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;gBAChC,IACE,MAAM,CAAC,IAAI,KAAK,aAAa;oBAC7B,CAAC,KAAK,EACN,CAAC;oBACD,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,eAAe,CAAC,KAAK,CAAC,GAAG;oBACvB,GAAG,MAAM;oBACT,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC;iBACnD,CAAC;gBACF,OAAO,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,CAAC;YACpC,CAAC;YAED,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAAC,QAAkB;QAC/C,MAAM,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAC3C,QAAQ,EACR,CAAC,MAAwB,EAAE,EAAE;YAC3B,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAC/B,gBAAgB,EAAE,MAAM;aACzB,CAAC,CAAC;QACL,CAAC,CACF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;gBACpD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CACd,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;oBACvC,OAAO,CAAC,KAAK,CAAC,gBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;gBAC3D,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,IAAU;QACnC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,kBAAkB,CAAC;QACpD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAElE,IAAI,CAAC,UAAU,IAAI,CAAC,eAAe,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,GAAG,+CAA+C,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YAExC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,uCAAuC,CAAC;gBACrE,OAAO;YACT,CAAC;YAED,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,KAAK;gBACR,GAAG,YAAY,KAAK;oBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;oBACb,CAAC,CAAC,gEAAgE,CAAC;YACvE,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,qBAAqB;QACjC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAE1D,gDAAgD;YAChD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAEvD,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,CAAC,CAAC;QACnE,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;QACpC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACnC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAE1D,gDAAgD;YAChD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAEvD,YAAY,CAAC,UAAU,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAC;QAC3D,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG;gBACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAExB,yEAAyE;YACzE,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClB,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;oBAC1D,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACxB,CAAC;YACH,CAAC,EAAE,KAAK,CAAC,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,iEAAiE;YACjE,mEAAmE;QACrE,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,CACL,4DAAK,KAAK,EAAC,uBAAuB;YAChC,EAAC,mBAAmB,qDAClB,oBAAoB,EAAE,IAAI,CAAC,oBAAoB,EAC/C,sBAAsB,EAAE,IAAI,CAAC,sBAAsB,EACnD,YAAY,EAAE,IAAI,CAAC,YAAY,EAC/B,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EACzC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,EACjD,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,EACrD,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAClC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,GAC/B;YACF,EAAC,YAAY,qDAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAI;YACvE,4DAAK,KAAK,EAAC,gCAAgC;gBACzC,EAAC,YAAY,qDACX,SAAS,EAAE,IAAI,CAAC,SAAS,EACzB,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,EAC/D,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,EACvC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CACvC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAEzC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAC1C,oBAAoB,EAAE,IAAI,CAAC,oBAAoB,EAC/C,uBAAuB,EAAE,IAAI,CAAC,2BAA2B,GACzD,CACE,CACF,CACP,CAAC;IACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF","sourcesContent":["import {\n Component,\n State,\n Prop,\n h,\n EventEmitter,\n Event,\n Method,\n} from '@stencil/core';\nimport { EvaluationResult } from '../../lib/evaluation/types';\nimport { ErrorMessage } from '../error-message/error-message';\nimport { RateLimitedFetcher } from '../../lib/rate-limited-fetcher/rate-limited-fetcher';\nimport { EvaluationApproach } from '../../lib/evaluation/constants';\nimport {\n ExpectedOutcomeSchema,\n TestCase,\n LLMRequestPayload,\n SavePayload,\n} from '../../types/llm-test-runner';\nimport { readFileAsync } from '../../lib/file/file-reader';\nimport { downloadFile } from '../../lib/file/file-download';\nimport { formatTestSuiteAsJson } from '../../lib/import-export/test-suite-exporter';\nimport { exportTestResultsToCsv } from '../../lib/import-export/test-results-csv';\nimport { importTestSuite } from '../../lib/import-export/test-suite-importer';\nimport {\n createTestCase,\n createTestCaseFromInput,\n DEFAULT_EXPECTED_OUTCOME_SCHEMA,\n} from '../../lib/test-cases/test-case-factory';\nimport * as TestCaseMutations from '../../lib/test-cases/test-case-mutations';\nimport { EvaluationService } from '../../lib/evaluation/evaluation-service';\nimport { validateTestCaseInputArray } from '../../schemas/test-case';\nimport { validateExpectedOutcomeSchema } from '../../schemas/expected-outcome';\nimport { LLMTestRunnerHeader } from './header/llm-test-runner-header';\nimport { LLMTestCases } from './test-cases/llm-test-cases';\nimport { ExpectedOutcomeChangeDetail } from './test-cases/expected-outcome-renderer';\n\n@Component({\n tag: 'llm-test-runner',\n styleUrls: [\n '../../styles/tokens.css',\n 'llm-test-runner.css',\n 'header/llm-test-runner-header.css',\n 'test-cases/llm-test-cases.css',\n 'test-cases/llm-test-case-row.css',\n 'test-cases/actions/row-actions.css',\n 'test-cases/evaluation/evaluation-summary.css',\n 'test-cases/output/response-output.css',\n '../error-message/error-message.css',\n '../../lib/ui/button/button.css',\n '../../lib/ui/icon-button/icon-button.css',\n ],\n shadow: true,\n})\nexport class LLMTestRunner {\n @Event() llmRequest: EventEmitter<LLMRequestPayload>;\n @Event() save: EventEmitter<SavePayload>;\n @Prop() delayMs?: number = 500;\n @Prop() useSave?: boolean = false;\n @Prop() initialTestCases?: TestCase[];\n @Prop() defaultExpectedOutcomeSchema?: ExpectedOutcomeSchema;\n @State() testCases: TestCase[] = [\n {\n id: '1',\n question: '',\n expectedOutcome: [\n {\n type: 'textarea',\n label: 'Expected Outcome',\n value: '',\n },\n ],\n evaluationParameters: {\n approach: EvaluationApproach.EXACT,\n },\n isRunning: false,\n },\n ];\n @State() isRunningAll: boolean = false;\n @State() error: string = '';\n @State() isExportingTestSuite: boolean = false;\n @State() isExportingTestResults: boolean = false;\n @State() isSaving: boolean = false;\n\n private evaluationService: EvaluationService;\n\n private getResolvedExpectedOutcomeSchema(): ExpectedOutcomeSchema {\n if (this.defaultExpectedOutcomeSchema === undefined) {\n return DEFAULT_EXPECTED_OUTCOME_SCHEMA;\n }\n\n validateExpectedOutcomeSchema(this.defaultExpectedOutcomeSchema);\n return this.defaultExpectedOutcomeSchema;\n }\n\n componentWillLoad() {\n this.evaluationService = new EvaluationService();\n try {\n // Initialize testCases from prop if provided\n if (this.initialTestCases !== undefined) {\n validateTestCaseInputArray(this.initialTestCases);\n this.testCases = this.initialTestCases.map((rawTestCase, index) => {\n try {\n return createTestCaseFromInput(rawTestCase);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n throw new Error(`Invalid initial test case at index ${index}: ${message}`);\n }\n });\n } else {\n const schema = this.getResolvedExpectedOutcomeSchema();\n this.testCases = [createTestCase(schema)];\n }\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Invalid defaultExpectedOutcomeSchema provided.';\n this.testCases = [];\n }\n }\n\n componentDidLoad() {}\n\n disconnectedCallback() {}\n\n @Method()\n async resetSavingState(): Promise<void> {\n this.isSaving = false;\n }\n\n private handleTestCaseChange = (\n event: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => {\n const { testCaseId, key, value } = event.detail;\n this.testCases = this.testCases.map(tc =>\n tc.id === testCaseId ? { ...tc, [key]: value } : tc,\n );\n };\n\n private addNewTestCase() {\n try {\n const schema = this.getResolvedExpectedOutcomeSchema();\n const newTestCase = createTestCase(schema);\n this.testCases = [...this.testCases, newTestCase];\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Invalid defaultExpectedOutcomeSchema provided.';\n }\n }\n\n private updateTestCase(id: string, updates: Partial<TestCase>) {\n this.testCases = this.testCases.map(tc =>\n tc.id === id ? { ...tc, ...updates } : tc,\n );\n }\n\n private async runSingleTest(testCase: TestCase): Promise<void> {\n const startTime = Date.now();\n this.updateTestCase(testCase.id, { isRunning: true });\n return new Promise<void>((resolve, reject) => {\n this.llmRequest.emit({\n prompt: testCase.question,\n resolve: async (aiResponse: string) => {\n const endTime = Date.now();\n const responseTime = endTime - startTime;\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null,\n responseTime: responseTime,\n });\n\n await this.evaluateResponse({\n ...testCase,\n output: aiResponse,\n responseTime: responseTime,\n });\n resolve();\n },\n reject: (error: Error | unknown) => {\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n reject(error);\n },\n });\n });\n }\n\n private deleteTestCase(id: string) {\n this.testCases = this.testCases.filter(tc => tc.id !== id);\n }\n\n private updateApproach(testCase: TestCase, approach: EvaluationApproach) {\n if (testCase) {\n const updated = TestCaseMutations.updateApproach(testCase, approach);\n this.updateTestCase(testCase.id, {\n evaluationParameters: updated.evaluationParameters,\n });\n }\n }\n\n private handleExpectedOutcomeChange = (\n event: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => {\n const { testCaseId, index, operation, value } = event.detail;\n\n this.testCases = this.testCases.map(tc => {\n if (tc.id !== testCaseId) return tc;\n\n const expectedOutcome = [...(tc.expectedOutcome || [])];\n const target = expectedOutcome[index];\n if (!target) return tc;\n\n if (operation === 'set-value') {\n if (target.type === 'chips-input') {\n return tc;\n }\n expectedOutcome[index] = { ...target, value: value || '' };\n return { ...tc, expectedOutcome };\n }\n\n if (operation === 'add-chip') {\n if (target.type !== 'chips-input' || !value) {\n return tc;\n }\n expectedOutcome[index] = {\n ...target,\n value: [...target.value, value],\n };\n return { ...tc, expectedOutcome };\n }\n\n if (operation === 'remove-chip') {\n if (\n target.type !== 'chips-input' ||\n !value\n ) {\n return tc;\n }\n expectedOutcome[index] = {\n ...target,\n value: target.value.filter(chip => chip !== value),\n };\n return { ...tc, expectedOutcome };\n }\n\n return tc;\n });\n };\n\n private async evaluateResponse(testCase: TestCase): Promise<void> {\n await this.evaluationService.evaluateTestCase(\n testCase,\n (result: EvaluationResult) => {\n this.updateTestCase(testCase.id, {\n evaluationResult: result,\n });\n },\n );\n }\n\n private async runAllTests() {\n this.isRunningAll = true;\n const tasks = [];\n for (const testCase of this.testCases) {\n if (!testCase.isRunning && testCase.question.trim()) {\n tasks.push(() =>\n this.runSingleTest(testCase).catch(err => {\n console.error(`⚠️ Test case ${testCase.id} failed`, err);\n }),\n );\n }\n }\n try {\n const fetcher = new RateLimitedFetcher(this.delayMs);\n await fetcher.runAll(tasks);\n } catch (err) {\n console.error('⚠️ Error running all tests:', err);\n }\n this.isRunningAll = false;\n }\n\n private async handleImport(file: File): Promise<void> {\n const isJsonType = file.type === 'application/json';\n const isJsonExtension = file.name.toLowerCase().endsWith('.json');\n\n if (!isJsonType && !isJsonExtension) {\n this.error = 'Invalid file type. Please select a JSON file.';\n return;\n }\n\n this.error = '';\n\n try {\n const content = await readFileAsync(file);\n const result = importTestSuite(content);\n\n if (!result.success) {\n this.error = result.error || 'Unknown error occurred during import.';\n return;\n }\n\n this.testCases = result.testCases || [];\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Error processing file. Please ensure it is a valid JSON array.';\n console.error('File Processing Error:', err);\n }\n }\n\n private async handleExportTestSuite() {\n this.isExportingTestSuite = true;\n try {\n const jsonContent = formatTestSuiteAsJson(this.testCases);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n downloadFile(jsonContent, 'test-suite.json', 'application/json');\n } finally {\n this.isExportingTestSuite = false;\n }\n }\n\n private async handleExportTestResults() {\n this.isExportingTestResults = true;\n try {\n const csvContent = exportTestResultsToCsv(this.testCases);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n downloadFile(csvContent, 'test-results.csv', 'text/csv');\n } finally {\n this.isExportingTestResults = false;\n }\n }\n\n private async handleSave() {\n this.isSaving = true;\n try {\n const testRun = {\n timestamp: new Date().toISOString(),\n testCases: this.testCases,\n };\n this.save.emit(testRun);\n\n // Failsafe: Auto-reset saving state after 10 seconds to prevent stuck UI\n setTimeout(() => {\n if (this.isSaving) {\n console.warn('Save operation timed out, resetting state');\n this.isSaving = false;\n }\n }, 10000);\n } finally {\n // Parent will call resetSavingState() when actual save completes\n // If not called within 10 seconds, failsafe above will reset state\n }\n }\n\n render() {\n return (\n <div class=\"test-runner-container\">\n <LLMTestRunnerHeader\n isExportingTestSuite={this.isExportingTestSuite}\n isExportingTestResults={this.isExportingTestResults}\n isRunningAll={this.isRunningAll}\n useSave={this.useSave}\n isSaving={this.isSaving}\n onImport={file => this.handleImport(file)}\n onExportSuite={() => this.handleExportTestSuite()}\n onExportResults={() => this.handleExportTestResults()}\n onRunAll={() => this.runAllTests()}\n onSave={() => this.handleSave()}\n />\n <ErrorMessage message={this.error} onClear={() => (this.error = '')} />\n <div class=\"test-runner-container__content\">\n <LLMTestCases\n testCases={this.testCases}\n onRun={testCase => this.runSingleTest(testCase).catch(() => {})}\n onDelete={id => this.deleteTestCase(id)}\n onUpdateApproach={(testCase, approach) =>\n this.updateApproach(testCase, approach)\n }\n onAddTestCase={() => this.addNewTestCase()}\n handleTestCaseChange={this.handleTestCaseChange}\n onExpectedOutcomeChange={this.handleExpectedOutcomeChange}\n />\n </div>\n </div>\n );\n }\n}\n"]}
1
+ {"version":3,"file":"llm-test-runner.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n State,\n Prop,\n h,\n EventEmitter,\n Event,\n Method,\n} from '@stencil/core';\nimport { EvaluationResult } from '../../lib/evaluation/types';\nimport { ErrorMessage } from '../error-message/error-message';\nimport { RateLimitedFetcher } from '../../lib/rate-limited-fetcher/rate-limited-fetcher';\nimport {\n ExpectedOutcomeSchema,\n TestCase,\n LLMRequestPayload,\n SavePayload,\n} from '../../types/llm-test-runner';\nimport { readFileAsync } from '../../lib/file/file-reader';\nimport { downloadFile } from '../../lib/file/file-download';\nimport { formatTestSuiteAsJson } from '../../lib/import-export/test-suite-exporter';\nimport { exportTestResultsToCsv } from '../../lib/import-export/test-results-csv';\nimport { importTestSuite } from '../../lib/import-export/test-suite-importer';\nimport {\n createTestCase,\n createTestCaseFromInput,\n DEFAULT_EXPECTED_OUTCOME_SCHEMA,\n} from '../../lib/test-cases/test-case-factory';\nimport * as TestCaseMutations from '../../lib/test-cases/test-case-mutations';\nimport { EvaluationService } from '../../lib/evaluation/evaluation-service';\nimport { validateTestCaseInputArray } from '../../schemas/test-case';\nimport { validateExpectedOutcomeSchema } from '../../schemas/expected-outcome';\nimport { LLMTestRunnerHeader } from './header/llm-test-runner-header';\nimport { LLMTestCases } from './test-cases/llm-test-cases';\nimport { ExpectedOutcomeChangeDetail } from './test-cases/expected-outcome-renderer';\n\n@Component({\n tag: 'llm-test-runner',\n styleUrls: [\n '../../styles/tokens.css',\n 'llm-test-runner.css',\n 'header/llm-test-runner-header.css',\n 'test-cases/llm-test-cases.css',\n 'test-cases/llm-test-case-row.css',\n 'test-cases/actions/row-actions.css',\n 'test-cases/evaluation/evaluation-summary.css',\n 'test-cases/output/response-output.css',\n '../error-message/error-message.css',\n '../../lib/ui/button/button.css',\n '../../lib/ui/icon-button/icon-button.css',\n ],\n shadow: true,\n})\nexport class LLMTestRunner {\n @Event() llmRequest: EventEmitter<LLMRequestPayload>;\n @Event() save: EventEmitter<SavePayload>;\n @Prop() delayMs?: number = 500;\n @Prop() useSave?: boolean = false;\n @Prop() initialTestCases?: TestCase[];\n @Prop() defaultExpectedOutcomeSchema?: ExpectedOutcomeSchema;\n @State() testCases: TestCase[] = [\n {\n id: '1',\n question: '',\n expectedOutcome: [\n {\n type: 'textarea',\n label: 'Expected Outcome',\n value: '',\n },\n ],\n isRunning: false,\n },\n ];\n @State() isRunningAll: boolean = false;\n @State() error: string = '';\n @State() isExportingTestSuite: boolean = false;\n @State() isExportingTestResults: boolean = false;\n @State() isSaving: boolean = false;\n\n private evaluationService: EvaluationService;\n\n private getResolvedExpectedOutcomeSchema(): ExpectedOutcomeSchema {\n if (this.defaultExpectedOutcomeSchema === undefined) {\n return DEFAULT_EXPECTED_OUTCOME_SCHEMA;\n }\n\n validateExpectedOutcomeSchema(this.defaultExpectedOutcomeSchema);\n return this.defaultExpectedOutcomeSchema;\n }\n\n componentWillLoad() {\n this.evaluationService = new EvaluationService();\n try {\n // Initialize testCases from prop if provided\n if (this.initialTestCases !== undefined) {\n validateTestCaseInputArray(this.initialTestCases);\n this.testCases = this.initialTestCases.map((rawTestCase, index) => {\n try {\n return createTestCaseFromInput(rawTestCase);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n throw new Error(`Invalid initial test case at index ${index}: ${message}`);\n }\n });\n } else {\n const schema = this.getResolvedExpectedOutcomeSchema();\n this.testCases = [createTestCase(schema)];\n }\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Invalid defaultExpectedOutcomeSchema provided.';\n this.testCases = [];\n }\n }\n\n componentDidLoad() {}\n\n disconnectedCallback() {}\n\n @Method()\n async resetSavingState(): Promise<void> {\n this.isSaving = false;\n }\n\n private handleTestCaseChange = (\n event: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => {\n const { testCaseId, key, value } = event.detail;\n this.testCases = this.testCases.map(tc =>\n tc.id === testCaseId ? { ...tc, [key]: value } : tc,\n );\n };\n\n private addNewTestCase() {\n try {\n const schema = this.getResolvedExpectedOutcomeSchema();\n const newTestCase = createTestCase(schema);\n this.testCases = [...this.testCases, newTestCase];\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Invalid defaultExpectedOutcomeSchema provided.';\n }\n }\n\n private updateTestCase(id: string, updates: Partial<TestCase>) {\n this.testCases = this.testCases.map(tc =>\n tc.id === id ? { ...tc, ...updates } : tc,\n );\n }\n\n private async runSingleTest(testCase: TestCase): Promise<void> {\n const startTime = Date.now();\n this.updateTestCase(testCase.id, { isRunning: true });\n return new Promise<void>((resolve, reject) => {\n this.llmRequest.emit({\n prompt: testCase.question,\n resolve: async (aiResponse: string) => {\n const endTime = Date.now();\n const responseTime = endTime - startTime;\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null,\n responseTime: responseTime,\n });\n\n await this.evaluateResponse({\n ...testCase,\n output: aiResponse,\n responseTime: responseTime,\n });\n resolve();\n },\n reject: (error: Error | unknown) => {\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n reject(error);\n },\n });\n });\n }\n\n private deleteTestCase(id: string) {\n this.testCases = this.testCases.filter(tc => tc.id !== id);\n }\n\n private handleExpectedOutcomeChange = (\n event: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => {\n const { testCaseId, ...change } = event.detail;\n\n this.testCases = this.testCases.map(tc => {\n if (tc.id !== testCaseId) {\n return tc;\n }\n\n return TestCaseMutations.applyExpectedOutcomeChange(tc, change);\n });\n };\n\n private async evaluateResponse(testCase: TestCase): Promise<void> {\n await this.evaluationService.evaluateTestCase(\n testCase,\n (result: EvaluationResult) => {\n this.updateTestCase(testCase.id, {\n evaluationResult: result,\n });\n },\n );\n }\n\n private async runAllTests() {\n this.isRunningAll = true;\n const tasks = [];\n for (const testCase of this.testCases) {\n if (!testCase.isRunning && testCase.question.trim()) {\n tasks.push(() =>\n this.runSingleTest(testCase).catch(err => {\n console.error(`⚠️ Test case ${testCase.id} failed`, err);\n }),\n );\n }\n }\n try {\n const fetcher = new RateLimitedFetcher(this.delayMs);\n await fetcher.runAll(tasks);\n } catch (err) {\n console.error('⚠️ Error running all tests:', err);\n }\n this.isRunningAll = false;\n }\n\n private async handleImport(file: File): Promise<void> {\n const isJsonType = file.type === 'application/json';\n const isJsonExtension = file.name.toLowerCase().endsWith('.json');\n\n if (!isJsonType && !isJsonExtension) {\n this.error = 'Invalid file type. Please select a JSON file.';\n return;\n }\n\n this.error = '';\n\n try {\n const content = await readFileAsync(file);\n const result = importTestSuite(content);\n\n if (!result.success) {\n this.error = result.error || 'Unknown error occurred during import.';\n return;\n }\n\n this.testCases = result.testCases || [];\n } catch (err) {\n this.error =\n err instanceof Error\n ? err.message\n : 'Error processing file. Please ensure it is a valid JSON array.';\n console.error('File Processing Error:', err);\n }\n }\n\n private async handleExportTestSuite() {\n this.isExportingTestSuite = true;\n try {\n const jsonContent = formatTestSuiteAsJson(this.testCases);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n downloadFile(jsonContent, 'test-suite.json', 'application/json');\n } finally {\n this.isExportingTestSuite = false;\n }\n }\n\n private async handleExportTestResults() {\n this.isExportingTestResults = true;\n try {\n const csvContent = exportTestResultsToCsv(this.testCases);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n downloadFile(csvContent, 'test-results.csv', 'text/csv');\n } finally {\n this.isExportingTestResults = false;\n }\n }\n\n private async handleSave() {\n this.isSaving = true;\n try {\n const testRun = {\n timestamp: new Date().toISOString(),\n testCases: this.testCases,\n };\n this.save.emit(testRun);\n\n // Failsafe: Auto-reset saving state after 10 seconds to prevent stuck UI\n setTimeout(() => {\n if (this.isSaving) {\n console.warn('Save operation timed out, resetting state');\n this.isSaving = false;\n }\n }, 10000);\n } finally {\n // Parent will call resetSavingState() when actual save completes\n // If not called within 10 seconds, failsafe above will reset state\n }\n }\n\n render() {\n return (\n <div class=\"test-runner-container\">\n <LLMTestRunnerHeader\n isExportingTestSuite={this.isExportingTestSuite}\n isExportingTestResults={this.isExportingTestResults}\n isRunningAll={this.isRunningAll}\n useSave={this.useSave}\n isSaving={this.isSaving}\n onImport={file => this.handleImport(file)}\n onExportSuite={() => this.handleExportTestSuite()}\n onExportResults={() => this.handleExportTestResults()}\n onRunAll={() => this.runAllTests()}\n onSave={() => this.handleSave()}\n />\n <ErrorMessage message={this.error} onClear={() => (this.error = '')} />\n <div class=\"test-runner-container__content\">\n <LLMTestCases\n testCases={this.testCases}\n onRun={testCase => this.runSingleTest(testCase).catch(() => {})}\n onDelete={id => this.deleteTestCase(id)}\n onAddTestCase={() => this.addNewTestCase()}\n handleTestCaseChange={this.handleTestCaseChange}\n onExpectedOutcomeChange={this.handleExpectedOutcomeChange}\n />\n </div>\n </div>\n );\n }\n}\n"]}
@@ -7,49 +7,88 @@
7
7
  flex-direction: column;
8
8
  }
9
9
 
10
- .evaluation-summary__details {
10
+ .evaluation-summary__field-results {
11
11
  display: flex;
12
12
  flex-direction: column;
13
13
  gap: var(--spacing-2);
14
+ margin-top: var(--spacing-2);
14
15
  }
15
16
 
16
- .evaluation-summary__placeholder {
17
+ .evaluation-summary__field-result {
18
+ border: var(--border-width) solid var(--border);
19
+ border-radius: var(--radius-md);
20
+ padding: var(--spacing-2);
17
21
  display: flex;
18
- align-items: center;
19
- justify-content: center;
22
+ flex-direction: column;
23
+ gap: var(--spacing-1);
24
+ }
25
+
26
+ .evaluation-summary__field-header {
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: var(--spacing-1);
30
+ }
31
+
32
+ .evaluation-summary__field-label {
33
+ font-weight: var(--font-weight-semibold);
34
+ font-size: var(--font-size-xs);
35
+ }
36
+
37
+ .evaluation-summary__field-approach {
20
38
  color: var(--muted-foreground);
21
- font-style: italic;
22
- flex: 1;
23
- background: var(--muted);
24
- border: 2px dashed var(--border);
25
- border-radius: var(--radius);
39
+ font-size: 11px;
26
40
  }
27
41
 
28
- /* Evaluation Result Element */
29
- .evaluation-summary__result {
42
+ .evaluation-summary__field-details {
30
43
  display: flex;
31
44
  flex-direction: column;
32
- gap: var(--spacing-2);
45
+ gap: var(--spacing-1);
46
+ font-size: var(--font-size-xs);
33
47
  }
34
48
 
35
- .evaluation-summary__result-status {
49
+ .evaluation-summary__field-status {
50
+ width: fit-content;
51
+ padding: 2px var(--spacing-2);
52
+ border-radius: var(--radius-sm);
53
+ font-size: 11px;
36
54
  font-weight: var(--font-weight-semibold);
37
- font-size: var(--font-size-sm);
38
- padding: var(--spacing-2) var(--spacing-3);
39
- border-radius: var(--radius-md);
40
- text-align: center;
55
+ border: var(--border-width) solid transparent;
41
56
  }
42
57
 
43
- .evaluation-summary__result-status--passed {
58
+ .evaluation-summary__field-status--passed {
44
59
  background: var(--success);
45
60
  color: var(--success-foreground);
46
- border: var(--border-width) solid var(--success);
61
+ border-color: var(--success);
47
62
  }
48
63
 
49
- .evaluation-summary__result-status--failed {
64
+ .evaluation-summary__field-status--failed {
50
65
  background: var(--destructive);
51
66
  color: var(--destructive-foreground);
52
- border: var(--border-width) solid var(--destructive);
67
+ border-color: var(--destructive);
68
+ }
69
+
70
+ .evaluation-summary__error-message {
71
+ color: var(--destructive);
72
+ font-size: var(--font-size-xs);
73
+ }
74
+
75
+ .evaluation-summary__placeholder {
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ color: var(--muted-foreground);
80
+ font-style: italic;
81
+ flex: 1;
82
+ background: var(--muted);
83
+ border: 2px dashed var(--border);
84
+ border-radius: var(--radius);
85
+ }
86
+
87
+ /* Evaluation Result Element */
88
+ .evaluation-summary__result {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: var(--spacing-2);
53
92
  }
54
93
 
55
94
  /* Responsive Design */
@@ -1,5 +1,7 @@
1
1
  import { h } from "@stencil/core";
2
2
  export const EvaluationSummary = ({ result, isRunning, }) => {
3
- return (h("div", { class: "evaluation-summary" }, result ? (h("div", { class: "evaluation-summary__result" }, h("div", { class: `evaluation-summary__result-status evaluation-summary__result-status--${result.passed ? 'passed' : 'failed'}` }, result.passed ? '✅ PASSED' : '❌ FAILED'), h("div", { class: "evaluation-summary__details" }, "Keywords: ", result.keywordMatches.filter(m => m.found).length, "/", result.keywordMatches.length, " found"))) : (h("div", { class: "evaluation-summary__placeholder" }, isRunning ? 'Evaluating...' : ''))));
3
+ const fieldResults = result?.fieldResults || [];
4
+ const hasFieldResults = fieldResults.length > 0;
5
+ return (h("div", { class: "evaluation-summary" }, result ? (h("div", { class: "evaluation-summary__result" }, hasFieldResults ? (h("div", { class: "evaluation-summary__field-results" }, fieldResults.map(fieldResult => (h("div", { class: "evaluation-summary__field-result" }, h("div", { class: "evaluation-summary__field-header" }, h("span", { class: "evaluation-summary__field-label" }, fieldResult.label), h("span", { class: "evaluation-summary__field-approach" }, "Strategy: ", fieldResult.evaluationParameters.approach)), h("div", { class: "evaluation-summary__field-details" }, h("span", { class: `evaluation-summary__field-status evaluation-summary__field-status--${fieldResult.passed ? 'passed' : 'failed'}` }, fieldResult.passed ? 'PASSED' : 'FAILED'), fieldResult.error && (h("span", { class: "evaluation-summary__error-message" }, fieldResult.error)), h("span", null, "Score: ", fieldResult.evaluationApproachResult.score.toFixed(2)), h("span", null, "Matches:", ' ', fieldResult.keywordMatches.filter(match => match.found).length, "/", fieldResult.keywordMatches.length))))))) : null)) : (h("div", { class: "evaluation-summary__placeholder" }, isRunning ? 'Evaluating...' : ''))));
4
6
  };
5
7
  //# sourceMappingURL=evaluation-summary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"evaluation-summary.js","sourceRoot":"","sources":["../../../../../src/components/llm-test-runner/test-cases/evaluation/evaluation-summary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAQvD,MAAM,CAAC,MAAM,iBAAiB,GAAgD,CAAC,EAC7E,MAAM,EACN,SAAS,GACV,EAAE,EAAE;IACH,OAAO,CACL,WAAK,KAAK,EAAC,oBAAoB,IAC5B,MAAM,CAAC,CAAC,CAAC,CACR,WAAK,KAAK,EAAC,4BAA4B;QACrC,WACE,KAAK,EAAE,wEAAwE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,IAEnH,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CACpC;QACN,WAAK,KAAK,EAAC,6BAA6B;;YAC3B,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM;;YAC3D,MAAM,CAAC,cAAc,CAAC,MAAM;qBACzB,CACF,CACP,CAAC,CAAC,CAAC,CACF,WAAK,KAAK,EAAC,iCAAiC,IACzC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAC7B,CACP,CACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { EvaluationResult } from '../../../../lib/evaluation/types';\n\nexport interface EvaluationSummaryProps {\n result?: EvaluationResult;\n isRunning: boolean;\n}\n\nexport const EvaluationSummary: FunctionalComponent<EvaluationSummaryProps> = ({\n result,\n isRunning,\n}) => {\n return (\n <div class=\"evaluation-summary\">\n {result ? (\n <div class=\"evaluation-summary__result\">\n <div\n class={`evaluation-summary__result-status evaluation-summary__result-status--${result.passed ? 'passed' : 'failed'}`}\n >\n {result.passed ? 'PASSED' : 'FAILED'}\n </div>\n <div class=\"evaluation-summary__details\">\n Keywords: {result.keywordMatches.filter(m => m.found).length}/\n {result.keywordMatches.length} found\n </div>\n </div>\n ) : (\n <div class=\"evaluation-summary__placeholder\">\n {isRunning ? 'Evaluating...' : ''}\n </div>\n )}\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"evaluation-summary.js","sourceRoot":"","sources":["../../../../../src/components/llm-test-runner/test-cases/evaluation/evaluation-summary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAQvD,MAAM,CAAC,MAAM,iBAAiB,GAAgD,CAAC,EAC7E,MAAM,EACN,SAAS,GACV,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;IAChD,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IAEhD,OAAO,CACL,WAAK,KAAK,EAAC,oBAAoB,IAC5B,MAAM,CAAC,CAAC,CAAC,CACR,WAAK,KAAK,EAAC,4BAA4B,IACpC,eAAe,CAAC,CAAC,CAAC,CACjB,WAAK,KAAK,EAAC,mCAAmC,IAC3C,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAC/B,WAAK,KAAK,EAAC,kCAAkC;QAC3C,WAAK,KAAK,EAAC,kCAAkC;YAC3C,YAAM,KAAK,EAAC,iCAAiC,IAC1C,WAAW,CAAC,KAAK,CACb;YACP,YAAM,KAAK,EAAC,oCAAoC;;gBACnC,WAAW,CAAC,oBAAoB,CAAC,QAAQ,CAC/C,CACH;QACN,WAAK,KAAK,EAAC,mCAAmC;YAC5C,YACE,KAAK,EAAE,sEAAsE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,IAEtH,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CACpC;YACN,WAAW,CAAC,KAAK,IAAI,CACpB,YAAM,KAAK,EAAC,mCAAmC,IAC5C,WAAW,CAAC,KAAK,CACb,CACR;YACD;;gBACU,WAAW,CAAC,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CACxD;YACP;;gBACW,GAAG;gBACX,WAAW,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM;;gBAC9D,WAAW,CAAC,cAAc,CAAC,MAAM,CAC7B,CACH,CACF,CACP,CAAC,CACE,CACP,CAAC,CAAC,CAAC,IAAI,CACJ,CACP,CAAC,CAAC,CAAC,CACF,WAAK,KAAK,EAAC,iCAAiC,IACzC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAC7B,CACP,CACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { EvaluationResult } from '../../../../lib/evaluation/types';\n\nexport interface EvaluationSummaryProps {\n result?: EvaluationResult;\n isRunning: boolean;\n}\n\nexport const EvaluationSummary: FunctionalComponent<EvaluationSummaryProps> = ({\n result,\n isRunning,\n}) => {\n const fieldResults = result?.fieldResults || [];\n const hasFieldResults = fieldResults.length > 0;\n\n return (\n <div class=\"evaluation-summary\">\n {result ? (\n <div class=\"evaluation-summary__result\">\n {hasFieldResults ? (\n <div class=\"evaluation-summary__field-results\">\n {fieldResults.map(fieldResult => (\n <div class=\"evaluation-summary__field-result\">\n <div class=\"evaluation-summary__field-header\">\n <span class=\"evaluation-summary__field-label\">\n {fieldResult.label}\n </span>\n <span class=\"evaluation-summary__field-approach\">\n Strategy: {fieldResult.evaluationParameters.approach}\n </span>\n </div>\n <div class=\"evaluation-summary__field-details\">\n <span\n class={`evaluation-summary__field-status evaluation-summary__field-status--${fieldResult.passed ? 'passed' : 'failed'}`}\n >\n {fieldResult.passed ? 'PASSED' : 'FAILED'}\n </span>\n {fieldResult.error && (\n <span class=\"evaluation-summary__error-message\">\n {fieldResult.error}\n </span>\n )}\n <span>\n Score: {fieldResult.evaluationApproachResult.score.toFixed(2)}\n </span>\n <span>\n Matches:{' '}\n {fieldResult.keywordMatches.filter(match => match.found).length}/\n {fieldResult.keywordMatches.length}\n </span>\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n ) : (\n <div class=\"evaluation-summary__placeholder\">\n {isRunning ? 'Evaluating...' : ''}\n </div>\n )}\n </div>\n );\n};\n"]}