llm-testrunner-components 1.2.2 → 1.2.3

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 (61) hide show
  1. package/dist/cjs/app-chips_4.cjs.entry.js +5 -2
  2. package/dist/cjs/app-chips_4.cjs.entry.js.map +1 -1
  3. package/dist/cjs/index.cjs.js +202 -44
  4. package/dist/cjs/index.cjs.js.map +1 -1
  5. package/dist/cjs/llm-testrunner.cjs.js +1 -1
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/collection/components/llm-test-runner/llm-test-runner.js +80 -30
  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/expected-outcome-renderer.js +37 -4
  10. package/dist/collection/components/llm-test-runner/test-cases/expected-outcome-renderer.js.map +1 -1
  11. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js +2 -2
  12. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js.map +1 -1
  13. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js +2 -2
  14. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js.map +1 -1
  15. package/dist/collection/lib/evaluation/evaluation-service.js +14 -7
  16. package/dist/collection/lib/evaluation/evaluation-service.js.map +1 -1
  17. package/dist/collection/lib/form/components/app-textarea.css +17 -0
  18. package/dist/collection/lib/form/components/app-textarea.js +4 -1
  19. package/dist/collection/lib/form/components/app-textarea.js.map +1 -1
  20. package/dist/collection/lib/test-cases/dynamic-expected-outcome-resolver.js +44 -0
  21. package/dist/collection/lib/test-cases/dynamic-expected-outcome-resolver.js.map +1 -0
  22. package/dist/collection/lib/test-cases/test-case-mutations.js +35 -0
  23. package/dist/collection/lib/test-cases/test-case-mutations.js.map +1 -1
  24. package/dist/collection/schemas/expected-outcome.js +15 -1
  25. package/dist/collection/schemas/expected-outcome.js.map +1 -1
  26. package/dist/collection/schemas/test-case.js.map +1 -1
  27. package/dist/collection/types/expected-outcome.js.map +1 -1
  28. package/dist/collection/types/llm-test-runner.js.map +1 -1
  29. package/dist/components/app-textarea.js +1 -1
  30. package/dist/components/index.js +1 -1
  31. package/dist/components/llm-test-runner.js +1 -1
  32. package/dist/components/{p-CJBscebi.js → p-BcygfrMf.js} +3 -3
  33. package/dist/components/p-BcygfrMf.js.map +1 -0
  34. package/dist/components/p-CVtKFBJl.js +2 -0
  35. package/dist/components/p-CVtKFBJl.js.map +1 -0
  36. package/dist/esm/app-chips_4.entry.js +5 -2
  37. package/dist/esm/app-chips_4.entry.js.map +1 -1
  38. package/dist/esm/index.js +202 -44
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/llm-testrunner.js +1 -1
  41. package/dist/esm/loader.js +1 -1
  42. package/dist/llm-testrunner/index.esm.js +2 -2
  43. package/dist/llm-testrunner/index.esm.js.map +1 -1
  44. package/dist/llm-testrunner/llm-testrunner.esm.js +1 -1
  45. package/dist/llm-testrunner/{p-2cc09217.entry.js → p-5df053b4.entry.js} +2 -2
  46. package/dist/llm-testrunner/{p-2cc09217.entry.js.map → p-5df053b4.entry.js.map} +1 -1
  47. package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +5 -0
  48. package/dist/types/components/llm-test-runner/test-cases/expected-outcome-renderer.d.ts +1 -0
  49. package/dist/types/components/llm-test-runner/test-cases/llm-test-case-row.d.ts +1 -0
  50. package/dist/types/components/llm-test-runner/test-cases/llm-test-cases.d.ts +1 -0
  51. package/dist/types/components.d.ts +4 -0
  52. package/dist/types/lib/test-cases/dynamic-expected-outcome-resolver.d.ts +7 -0
  53. package/dist/types/lib/test-cases/test-case-mutations.d.ts +9 -1
  54. package/dist/types/schemas/expected-outcome.d.ts +16 -1
  55. package/dist/types/schemas/test-case.d.ts +17 -2
  56. package/dist/types/types/expected-outcome.d.ts +1 -1
  57. package/dist/types/types/llm-test-runner.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/dist/components/p-BZrzx5jG.js +0 -2
  60. package/dist/components/p-BZrzx5jG.js.map +0 -1
  61. package/dist/components/p-CJBscebi.js.map +0 -1
@@ -19,7 +19,7 @@ var patchBrowser = () => {
19
19
 
20
20
  patchBrowser().then(async (options) => {
21
21
  await appGlobals.globalScripts();
22
- return index.bootstrapLazy([["app-chips_4.cjs",[[513,"llm-test-runner",{"delayMs":[2,"delay-ms"],"useSave":[4,"use-save"],"usePromptEditor":[4,"use-prompt-editor"],"initialTestCases":[16],"defaultExpectedOutcomeSchema":[16],"testCases":[32],"isRunningAll":[32],"error":[32],"isExportingTestSuite":[32],"isExportingTestResults":[32],"isSaving":[32],"resetSavingState":[64],"getTestCases":[64]}],[513,"app-chips",{"value":[16],"config":[16]}],[513,"app-select",{"value":[1],"config":[16]}],[513,"app-textarea",{"value":[1],"config":[16]}]]]], options);
22
+ return index.bootstrapLazy([["app-chips_4.cjs",[[513,"llm-test-runner",{"delayMs":[2,"delay-ms"],"useSave":[4,"use-save"],"usePromptEditor":[4,"use-prompt-editor"],"resolveExpectedOutcome":[16],"initialTestCases":[16],"defaultExpectedOutcomeSchema":[16],"testCases":[32],"isRunningAll":[32],"error":[32],"isExportingTestSuite":[32],"isExportingTestResults":[32],"isSaving":[32],"resetSavingState":[64],"getTestCases":[64]}],[513,"app-chips",{"value":[16],"config":[16]}],[513,"app-select",{"value":[1],"config":[16]}],[513,"app-textarea",{"value":[1],"config":[16]}]]]], options);
23
23
  });
24
24
 
25
25
  exports.setNonce = index.setNonce;
@@ -6,7 +6,7 @@ var appGlobals = require('./app-globals-Chb-oJtg.js');
6
6
  const defineCustomElements = async (win, options) => {
7
7
  if (typeof window === 'undefined') return undefined;
8
8
  await appGlobals.globalScripts();
9
- return index.bootstrapLazy([["app-chips_4.cjs",[[513,"llm-test-runner",{"delayMs":[2,"delay-ms"],"useSave":[4,"use-save"],"usePromptEditor":[4,"use-prompt-editor"],"initialTestCases":[16],"defaultExpectedOutcomeSchema":[16],"testCases":[32],"isRunningAll":[32],"error":[32],"isExportingTestSuite":[32],"isExportingTestResults":[32],"isSaving":[32],"resetSavingState":[64],"getTestCases":[64]}],[513,"app-chips",{"value":[16],"config":[16]}],[513,"app-select",{"value":[1],"config":[16]}],[513,"app-textarea",{"value":[1],"config":[16]}]]]], options);
9
+ return index.bootstrapLazy([["app-chips_4.cjs",[[513,"llm-test-runner",{"delayMs":[2,"delay-ms"],"useSave":[4,"use-save"],"usePromptEditor":[4,"use-prompt-editor"],"resolveExpectedOutcome":[16],"initialTestCases":[16],"defaultExpectedOutcomeSchema":[16],"testCases":[32],"isRunningAll":[32],"error":[32],"isExportingTestSuite":[32],"isExportingTestResults":[32],"isSaving":[32],"resetSavingState":[64],"getTestCases":[64]}],[513,"app-chips",{"value":[16],"config":[16]}],[513,"app-select",{"value":[1],"config":[16]}],[513,"app-textarea",{"value":[1],"config":[16]}]]]], options);
10
10
  };
11
11
 
12
12
  exports.setNonce = index.setNonce;
@@ -7,6 +7,7 @@ import { formatTestSuiteAsJson } from "../../lib/import-export/test-suite-export
7
7
  import { exportTestResultsToCsv } from "../../lib/import-export/test-results-csv";
8
8
  import { importTestSuite } from "../../lib/import-export/test-suite-importer";
9
9
  import { createTestCase, createTestCaseFromInput, DEFAULT_EXPECTED_OUTCOME_SCHEMA, } from "../../lib/test-cases/test-case-factory";
10
+ import { resolveDynamicExpectedOutcomes, } from "../../lib/test-cases/dynamic-expected-outcome-resolver";
10
11
  import * as TestCaseMutations from "../../lib/test-cases/test-case-mutations";
11
12
  import { EvaluationService } from "../../lib/evaluation/evaluation-service";
12
13
  import { validateTestCaseInputArray } from "../../schemas/test-case";
@@ -19,6 +20,7 @@ export class LLMTestRunner {
19
20
  delayMs = 500;
20
21
  useSave = false;
21
22
  usePromptEditor = false;
23
+ resolveExpectedOutcome;
22
24
  initialTestCases;
23
25
  defaultExpectedOutcomeSchema;
24
26
  testCases = [
@@ -105,39 +107,63 @@ export class LLMTestRunner {
105
107
  updateTestCase(id, updates) {
106
108
  this.testCases = this.testCases.map(tc => tc.id === id ? { ...tc, ...updates } : tc);
107
109
  }
108
- async runSingleTest(testCase) {
109
- const startTime = Date.now();
110
- this.updateTestCase(testCase.id, { isRunning: true });
110
+ requestLlmText(testCase) {
111
111
  return new Promise((resolve, reject) => {
112
112
  this.llmRequest.emit({
113
113
  prompt: testCase.question,
114
- resolve: async (aiResponse) => {
115
- const endTime = Date.now();
116
- const responseTime = endTime - startTime;
117
- this.updateTestCase(testCase.id, {
118
- isRunning: false,
119
- output: aiResponse,
120
- error: null,
121
- responseTime: responseTime,
122
- });
123
- await this.evaluateResponse({
124
- ...testCase,
125
- output: aiResponse,
126
- responseTime: responseTime,
127
- });
128
- resolve();
129
- },
130
- reject: (error) => {
131
- this.updateTestCase(testCase.id, {
132
- isRunning: false,
133
- output: null,
134
- error: error instanceof Error ? error.message : 'Unknown error',
135
- });
136
- reject(error);
137
- },
114
+ resolve,
115
+ reject,
138
116
  });
139
117
  });
140
118
  }
119
+ throwError(reason) {
120
+ throw reason instanceof Error ? reason : new Error(String(reason));
121
+ }
122
+ addErrorMessage(reason, fallback) {
123
+ return reason instanceof Error ? reason.message : fallback;
124
+ }
125
+ async runSingleTest(testCase) {
126
+ const startTime = Date.now();
127
+ this.updateTestCase(testCase.id, { isRunning: true });
128
+ const [llmSettled, resolutionSettled] = await Promise.allSettled([
129
+ this.requestLlmText(testCase),
130
+ resolveDynamicExpectedOutcomes(testCase, this.resolveExpectedOutcome),
131
+ ]);
132
+ const responseTime = Date.now() - startTime;
133
+ if (llmSettled.status === 'rejected') {
134
+ this.updateTestCase(testCase.id, {
135
+ isRunning: false,
136
+ output: null,
137
+ error: this.addErrorMessage(llmSettled.reason, 'Unknown error'),
138
+ responseTime,
139
+ });
140
+ this.throwError(llmSettled.reason);
141
+ }
142
+ const aiResponse = llmSettled.value;
143
+ if (resolutionSettled.status === 'rejected') {
144
+ this.updateTestCase(testCase.id, {
145
+ isRunning: false,
146
+ output: aiResponse,
147
+ error: this.addErrorMessage(resolutionSettled.reason, 'Failed to resolve dynamic expected outcome.'),
148
+ responseTime,
149
+ });
150
+ this.throwError(resolutionSettled.reason);
151
+ }
152
+ const resolvedTestCase = resolutionSettled.value;
153
+ const forEvaluationTestCase = {
154
+ ...resolvedTestCase,
155
+ output: aiResponse,
156
+ responseTime,
157
+ };
158
+ this.updateTestCase(testCase.id, {
159
+ isRunning: false,
160
+ output: aiResponse,
161
+ error: null,
162
+ responseTime,
163
+ expectedOutcome: forEvaluationTestCase.expectedOutcome,
164
+ });
165
+ await this.evaluateResponse(forEvaluationTestCase);
166
+ }
141
167
  deleteTestCase(id) {
142
168
  this.testCases = this.testCases.filter(tc => tc.id !== id);
143
169
  }
@@ -247,7 +273,7 @@ export class LLMTestRunner {
247
273
  }
248
274
  }
249
275
  render() {
250
- return (h("div", { key: '29cf8a93402ebad6f6df43e147fa10406577c9aa', class: "test-runner-container" }, h(LLMTestRunnerHeader, { key: 'a07d3d1d823f8d473808752932cd1b2ab72d9e08', isExportingTestSuite: this.isExportingTestSuite, isExportingTestResults: this.isExportingTestResults, isRunningAll: this.isRunningAll, useSave: this.useSave, isSaving: this.isSaving, usePromptEditor: this.usePromptEditor, onImport: file => this.handleImport(file), onExportSuite: () => this.handleExportTestSuite(), onExportResults: () => this.handleExportTestResults(), onRunAll: () => this.runAllTests(), onSave: () => this.handleSave() }), h(ErrorMessage, { key: 'ec68912728b06fc4a76c330fb1b7d5acde92c3d1', message: this.error, onClear: () => (this.error = '') }), h("div", { key: 'ce308dd4bd5437c94ae6e3e8a28970b799865281', class: "test-runner-container__content" }, h(LLMTestCases, { key: '3368df0bb7de4d099da1fad400f59dfc9a2cfb62', testCases: this.testCases, onRun: testCase => this.runSingleTest(testCase).catch(() => { }), onDelete: id => this.deleteTestCase(id), onAddTestCase: () => this.addNewTestCase(), handleTestCaseChange: this.handleTestCaseChange, onExpectedOutcomeChange: this.handleExpectedOutcomeChange }))));
276
+ return (h("div", { key: '5536c02dcbf03e1d21de2df307f5255a17c000c7', class: "test-runner-container" }, h(LLMTestRunnerHeader, { key: 'b6b7db13d7b5576986f4de469c4eeff62b9be873', isExportingTestSuite: this.isExportingTestSuite, isExportingTestResults: this.isExportingTestResults, isRunningAll: this.isRunningAll, useSave: this.useSave, isSaving: this.isSaving, usePromptEditor: this.usePromptEditor, onImport: file => this.handleImport(file), onExportSuite: () => this.handleExportTestSuite(), onExportResults: () => this.handleExportTestResults(), onRunAll: () => this.runAllTests(), onSave: () => this.handleSave() }), h(ErrorMessage, { key: '48407658a40dd79864ddf24426df743df9206b30', message: this.error, onClear: () => (this.error = '') }), h("div", { key: '2b1db34dbb4defc98c255ca7bcb9318ca1c52cba', class: "test-runner-container__content" }, h(LLMTestCases, { key: '90b4d25f51d5de43790cabeb4fa6fc1c90c246cd', testCases: this.testCases, dynamicResolutionSupported: !!this.resolveExpectedOutcome, onRun: testCase => this.runSingleTest(testCase).catch(() => { }), onDelete: id => this.deleteTestCase(id), onAddTestCase: () => this.addNewTestCase(), handleTestCaseChange: this.handleTestCaseChange, onExpectedOutcomeChange: this.handleExpectedOutcomeChange }))));
251
277
  }
252
278
  static get is() { return "llm-test-runner"; }
253
279
  static get encapsulation() { return "shadow"; }
@@ -323,12 +349,36 @@ export class LLMTestRunner {
323
349
  "attribute": "use-prompt-editor",
324
350
  "defaultValue": "false"
325
351
  },
352
+ "resolveExpectedOutcome": {
353
+ "type": "unknown",
354
+ "mutable": false,
355
+ "complexType": {
356
+ "original": "ExpectedOutcomeResolver",
357
+ "resolved": "(resolutionQuery: string, context: { testCase: { id: string; question: string; expectedOutcome: ({ 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; }; outcomeMode?: \"static\" | \"dynamic\"; resolutionQuery?: string; } | { label: string; type: \"chips-input\"; value: string[]; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"select\"; options: string[]; value: string; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; })[]; output?: string; isRunning?: boolean; error?: string; evaluationResult?: EvaluationResult; responseTime?: number; }; fieldIndex: number; }) => Promise<string>",
358
+ "references": {
359
+ "ExpectedOutcomeResolver": {
360
+ "location": "import",
361
+ "path": "../../lib/test-cases/dynamic-expected-outcome-resolver",
362
+ "id": "src/lib/test-cases/dynamic-expected-outcome-resolver.ts::ExpectedOutcomeResolver",
363
+ "referenceLocation": "ExpectedOutcomeResolver"
364
+ }
365
+ }
366
+ },
367
+ "required": false,
368
+ "optional": true,
369
+ "docs": {
370
+ "tags": [],
371
+ "text": ""
372
+ },
373
+ "getter": false,
374
+ "setter": false
375
+ },
326
376
  "initialTestCases": {
327
377
  "type": "unknown",
328
378
  "mutable": false,
329
379
  "complexType": {
330
380
  "original": "TestCase[]",
331
- "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; }[]",
381
+ "resolved": "{ id: string; question: string; expectedOutcome: ({ 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; }; outcomeMode?: \"static\" | \"dynamic\"; resolutionQuery?: string; } | { label: string; type: \"chips-input\"; value: string[]; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"select\"; options: string[]; value: string; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; })[]; output?: string; isRunning?: boolean; error?: string; evaluationResult?: EvaluationResult; responseTime?: number; }[]",
332
382
  "references": {
333
383
  "TestCase": {
334
384
  "location": "import",
@@ -471,7 +521,7 @@ export class LLMTestRunner {
471
521
  "referenceLocation": "TestCase"
472
522
  }
473
523
  },
474
- "return": "Promise<{ 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; }[]>"
524
+ "return": "Promise<{ id: string; question: string; expectedOutcome: ({ 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; }; outcomeMode?: \"static\" | \"dynamic\"; resolutionQuery?: string; } | { label: string; type: \"chips-input\"; value: string[]; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; } | { label: string; type: \"select\"; options: string[]; value: string; placeholder?: string; evaluationParameters?: { approach: EvaluationApproach; threshold?: number; }; })[]; output?: string; isRunning?: boolean; error?: string; evaluationResult?: EvaluationResult; responseTime?: number; }[]>"
475
525
  },
476
526
  "docs": {
477
527
  "text": "",
@@ -1 +1 @@
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() usePromptEditor?: 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 @Method()\n async getTestCases(): Promise<TestCase[]> {\n return this.testCases;\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 usePromptEditor={this.usePromptEditor}\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"]}
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 {\n type ExpectedOutcomeResolver,\n resolveDynamicExpectedOutcomes,\n} from '../../lib/test-cases/dynamic-expected-outcome-resolver';\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() usePromptEditor?: boolean = false;\n @Prop() resolveExpectedOutcome?: ExpectedOutcomeResolver;\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 @Method()\n async getTestCases(): Promise<TestCase[]> {\n return this.testCases;\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 requestLlmText(testCase: TestCase): Promise<string> {\n return new Promise((resolve, reject) => {\n this.llmRequest.emit({\n prompt: testCase.question,\n resolve,\n reject,\n });\n });\n }\n\n private throwError(reason: unknown): never {\n throw reason instanceof Error ? reason : new Error(String(reason));\n }\n\n private addErrorMessage(reason: unknown, fallback: string): string {\n return reason instanceof Error ? reason.message : fallback;\n }\n\n private async runSingleTest(testCase: TestCase): Promise<void> {\n const startTime = Date.now();\n this.updateTestCase(testCase.id, { isRunning: true });\n const [llmSettled, resolutionSettled] = await Promise.allSettled([\n this.requestLlmText(testCase),\n resolveDynamicExpectedOutcomes(testCase, this.resolveExpectedOutcome),\n ]);\n\n const responseTime = Date.now() - startTime;\n\n if (llmSettled.status === 'rejected') {\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: this.addErrorMessage(llmSettled.reason, 'Unknown error'),\n responseTime,\n });\n this.throwError(llmSettled.reason);\n }\n const aiResponse = llmSettled.value;\n\n if (resolutionSettled.status === 'rejected') {\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: this.addErrorMessage(\n resolutionSettled.reason,\n 'Failed to resolve dynamic expected outcome.',\n ),\n responseTime,\n });\n this.throwError(resolutionSettled.reason);\n }\n const resolvedTestCase = resolutionSettled.value;\n\n const forEvaluationTestCase: TestCase = {\n ...resolvedTestCase,\n output: aiResponse,\n responseTime,\n };\n\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null,\n responseTime,\n expectedOutcome: forEvaluationTestCase.expectedOutcome,\n });\n\n await this.evaluateResponse(forEvaluationTestCase);\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 usePromptEditor={this.usePromptEditor}\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 dynamicResolutionSupported={!!this.resolveExpectedOutcome}\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"]}
@@ -2,7 +2,7 @@ import { h } from "@stencil/core";
2
2
  import { FormFieldType } from "../../../lib/form/schema";
3
3
  import { EvaluationApproach, } from "../../../lib/evaluation/constants";
4
4
  import { getAllowedApproachesForFieldType } from "../../../lib/evaluation/field-evaluation-approach";
5
- export const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange, }) => {
5
+ export const ExpectedOutcomeRenderer = ({ testCaseId, fields, dynamicResolutionSupported = false, onExpectedOutcomeChange, }) => {
6
6
  const emit = (detail) => onExpectedOutcomeChange({
7
7
  detail,
8
8
  });
@@ -15,6 +15,23 @@ export const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeC
15
15
  optionList,
16
16
  defaultValue: EvaluationApproach.EXACT,
17
17
  });
18
+ const buildOutcomeModeConfig = (index) => ({
19
+ name: `expectedOutcomeMode-${index}`,
20
+ fieldType: FormFieldType.SELECT,
21
+ label: 'Outcome Mode',
22
+ placeholder: 'Select outcome mode',
23
+ required: true,
24
+ optionList: ['static', 'dynamic'],
25
+ defaultValue: 'static',
26
+ });
27
+ const buildResolutionQueryConfig = (index) => ({
28
+ name: `expectedOutcomeResolutionQuery-${index}`,
29
+ fieldType: FormFieldType.TEXT_AREA,
30
+ label: 'Resolution Query',
31
+ placeholder: 'Query used to resolve expected value',
32
+ required: false,
33
+ rows: 2,
34
+ });
18
35
  const renderEvaluationSelector = (field, index) => {
19
36
  const optionList = getAllowedApproachesForFieldType(field.type);
20
37
  return (h("app-select", { config: buildEvaluationConfig(index, optionList), value: field.evaluationParameters?.approach, onValueChange: (e) => emit({
@@ -26,12 +43,17 @@ export const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeC
26
43
  };
27
44
  return (h("div", { class: "expected-outcome-renderer" }, (fields || []).map((field, index) => {
28
45
  if (field.type === 'textarea') {
46
+ const isDynamic = dynamicResolutionSupported && field.outcomeMode === 'dynamic';
29
47
  const config = {
30
48
  name: `expectedOutcome-${index}`,
31
49
  fieldType: FormFieldType.TEXT_AREA,
32
50
  label: field.label,
33
- placeholder: field.placeholder,
34
- required: true,
51
+ placeholder: isDynamic ? 'Resolved on run' : field.placeholder,
52
+ required: !isDynamic,
53
+ readOnly: isDynamic,
54
+ helpText: isDynamic
55
+ ? 'Filled automatically when the test is run'
56
+ : undefined,
35
57
  rows: field.rows || 2,
36
58
  };
37
59
  return (h("div", { class: "expected-outcome-renderer__group" }, h("app-textarea", { config: config, value: field.value, onValueChange: (e) => emit({
@@ -39,7 +61,18 @@ export const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeC
39
61
  index,
40
62
  operation: 'set-value',
41
63
  value: e.detail.value,
42
- }) }), renderEvaluationSelector(field, index)));
64
+ }) }), dynamicResolutionSupported && (h("app-select", { config: buildOutcomeModeConfig(index), value: field.outcomeMode || 'static', onValueChange: (e) => emit({
65
+ testCaseId,
66
+ index,
67
+ operation: 'set-outcome-mode',
68
+ value: e.detail.value,
69
+ }) })), dynamicResolutionSupported &&
70
+ field.outcomeMode === 'dynamic' && (h("app-textarea", { config: buildResolutionQueryConfig(index), value: field.resolutionQuery || '', onValueChange: (e) => emit({
71
+ testCaseId,
72
+ index,
73
+ operation: 'set-resolution-query',
74
+ value: e.detail.value,
75
+ }) })), !isDynamic && renderEvaluationSelector(field, index)));
43
76
  }
44
77
  if (field.type === 'chips-input') {
45
78
  const config = {
@@ -1 +1 @@
1
- {"version":3,"file":"expected-outcome-renderer.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/expected-outcome-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAIvD,OAAO,EAAe,aAAa,EAAgC,MAAM,0BAA0B,CAAC;AACpG,OAAO,EACL,kBAAkB,GACnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gCAAgC,EAAE,MAAM,mDAAmD,CAAC;AAerG,MAAM,CAAC,MAAM,uBAAuB,GAAsD,CAAC,EACzF,UAAU,EACV,MAAM,EACN,uBAAuB,GACxB,EAAE,EAAE;IACH,MAAM,IAAI,GAAG,CAAC,MAAmC,EAAE,EAAE,CACnD,uBAAuB,CAAC;QACtB,MAAM;KACqC,CAAC,CAAC;IAEjD,MAAM,qBAAqB,GAAG,CAC5B,KAAa,EACb,UAAoB,EACN,EAAE,CAAC,CAAC;QAClB,IAAI,EAAE,6BAA6B,KAAK,EAAE;QAC1C,SAAS,EAAE,aAAa,CAAC,MAAM;QAC/B,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,6BAA6B;QAC1C,QAAQ,EAAE,IAAI;QACd,UAAU;QACV,YAAY,EAAE,kBAAkB,CAAC,KAAK;KACvC,CAAC,CAAC;IAEH,MAAM,wBAAwB,GAAG,CAC/B,KAA2B,EAC3B,KAAa,EACb,EAAE;QACF,MAAM,UAAU,GAAG,gCAAgC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEhE,OAAO,CACL,kBACE,MAAM,EAAE,qBAAqB,CAAC,KAAK,EAAE,UAAU,CAAC,EAChD,KAAK,EAAE,KAAK,CAAC,oBAAoB,EAAE,QAAQ,EAC3C,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,IAAI,CAAC;gBACH,UAAU;gBACV,KAAK;gBACL,SAAS,EAAE,yBAAyB;gBACpC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAA2B;aAC5C,CAAC,GAEJ,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,WAAK,KAAK,EAAC,2BAA2B,IACnC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACnC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAmB;gBAC7B,IAAI,EAAE,mBAAmB,KAAK,EAAE;gBAChC,SAAS,EAAE,aAAa,CAAC,SAAS;gBAClC,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;aACtB,CAAC;YACF,OAAO,CACL,WAAK,KAAK,EAAC,kCAAkC;gBAC3C,oBACE,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,IAAI,CAAC;wBACH,UAAU;wBACV,KAAK;wBACL,SAAS,EAAE,WAAW;wBACtB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB,CAAC,GAEJ;gBACD,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CACnC,CACP,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACjC,MAAM,MAAM,GAAgB;gBAC1B,IAAI,EAAE,mBAAmB,KAAK,EAAE;gBAChC,SAAS,EAAE,aAAa,CAAC,KAAK;gBAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,IAAI;aACf,CAAC;YAEF,OAAO,CACL,WAAK,KAAK,EAAC,kCAAkC;gBAC3C,iBACE,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CACf,IAAI,CAAC;wBACH,UAAU;wBACV,KAAK;wBACL,SAAS,EAAE,UAAU;wBACrB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB,CAAC,EAEJ,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAClB,IAAI,CAAC;wBACH,UAAU;wBACV,KAAK;wBACL,SAAS,EAAE,aAAa;wBACxB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB,CAAC,GAEJ;gBACD,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CACnC,CACP,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAiB;gBAC3B,IAAI,EAAE,mBAAmB,KAAK,EAAE;gBAChC,SAAS,EAAE,aAAa,CAAC,MAAM;gBAC/B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE,KAAK,CAAC,OAAO;aAC1B,CAAC;YAEF,OAAO,CACL,WAAK,KAAK,EAAC,kCAAkC;gBAC3C,kBACE,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,IAAI,CAAC;wBACH,UAAU;wBACV,KAAK;wBACL,SAAS,EAAE,WAAW;wBACtB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB,CAAC,GAEJ;gBACD,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CACnC,CACP,CAAC;QACJ,CAAC;QAED,OAAO,CACL,WAAK,KAAK,EAAC,kCAAkC;YAC3C,WAAK,KAAK,EAAC,iCAAiC;gBAC1C,iBAAQ,KAAK,CAAC,KAAK,CAAS;gBAC5B,aACE,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,WAAW,EAAE,KAAK,CAAC,WAAW,EAC9B,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CACb,IAAI,CAAC;wBACH,UAAU;wBACV,KAAK;wBACL,SAAS,EAAE,WAAW;wBACtB,KAAK,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK;qBAC5C,CAAC,GAEJ,CACE;YACL,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CACnC,CACP,CAAC;IACJ,CAAC,CAAC,CACE,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport {\n ExpectedOutcomeField,\n} from '../../../types/llm-test-runner';\nimport { ChipsConfig, FormFieldType, SelectConfig, TextAreaConfig } from '../../../lib/form/schema';\nimport {\n EvaluationApproach,\n} from '../../../lib/evaluation/constants';\nimport { getAllowedApproachesForFieldType } from '../../../lib/evaluation/field-evaluation-approach';\nimport { ExpectedOutcomeChange } from '../../../lib/test-cases/test-case-mutations';\n\nexport type ExpectedOutcomeChangeDetail = {\n testCaseId: string;\n} & ExpectedOutcomeChange;\n\ninterface ExpectedOutcomeRendererProps {\n testCaseId: string;\n fields: ExpectedOutcomeField[];\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const ExpectedOutcomeRenderer: FunctionalComponent<ExpectedOutcomeRendererProps> = ({\n testCaseId,\n fields,\n onExpectedOutcomeChange,\n}) => {\n const emit = (detail: ExpectedOutcomeChangeDetail) =>\n onExpectedOutcomeChange({\n detail,\n } as CustomEvent<ExpectedOutcomeChangeDetail>);\n\n const buildEvaluationConfig = (\n index: number,\n optionList: string[],\n ): SelectConfig => ({\n name: `expectedOutcomeEvaluation-${index}`,\n fieldType: FormFieldType.SELECT,\n label: 'Evaluation Approach',\n placeholder: 'Select evaluation approach…',\n required: true,\n optionList,\n defaultValue: EvaluationApproach.EXACT,\n });\n\n const renderEvaluationSelector = (\n field: ExpectedOutcomeField,\n index: number,\n ) => {\n const optionList = getAllowedApproachesForFieldType(field.type);\n\n return (\n <app-select\n config={buildEvaluationConfig(index, optionList)}\n value={field.evaluationParameters?.approach}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-evaluation-approach',\n value: e.detail.value as EvaluationApproach,\n })\n }\n />\n );\n };\n\n return (\n <div class=\"expected-outcome-renderer\">\n {(fields || []).map((field, index) => {\n if (field.type === 'textarea') {\n const config: TextAreaConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.TEXT_AREA,\n label: field.label,\n placeholder: field.placeholder,\n required: true,\n rows: field.rows || 2,\n };\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-textarea\n config={config}\n value={field.value}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: e.detail.value,\n })\n }\n />\n {renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n if (field.type === 'chips-input') {\n const config: ChipsConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.CHIPS,\n label: field.label,\n placeholder: field.placeholder,\n required: true,\n };\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-chips\n config={config}\n value={field.value}\n onAddChip={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'add-chip',\n value: e.detail.value,\n })\n }\n onRemoveChip={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'remove-chip',\n value: e.detail.value,\n })\n }\n />\n {renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n if (field.type === 'select') {\n const config: SelectConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.SELECT,\n label: field.label,\n placeholder: field.placeholder,\n required: true,\n optionList: field.options,\n };\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-select\n config={config}\n value={field.value}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: e.detail.value,\n })\n }\n />\n {renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <div class=\"expected-outcome-renderer__text\">\n <label>{field.label}</label>\n <input\n type=\"text\"\n value={field.value}\n placeholder={field.placeholder}\n onInput={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: (e.target as HTMLInputElement).value,\n })\n }\n />\n </div>\n {renderEvaluationSelector(field, index)}\n </div>\n );\n })}\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"expected-outcome-renderer.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/expected-outcome-renderer.tsx"],"names":[],"mappings":"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","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport {\n ExpectedOutcomeField,\n type ExpectedOutcomeMode,\n} from '../../../types/llm-test-runner';\nimport { ChipsConfig, FormFieldType, SelectConfig, TextAreaConfig } from '../../../lib/form/schema';\nimport {\n EvaluationApproach,\n} from '../../../lib/evaluation/constants';\nimport { getAllowedApproachesForFieldType } from '../../../lib/evaluation/field-evaluation-approach';\nimport { ExpectedOutcomeChange } from '../../../lib/test-cases/test-case-mutations';\n\nexport type ExpectedOutcomeChangeDetail = {\n testCaseId: string;\n} & ExpectedOutcomeChange;\n\ninterface ExpectedOutcomeRendererProps {\n testCaseId: string;\n fields: ExpectedOutcomeField[];\n dynamicResolutionSupported?: boolean;\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const ExpectedOutcomeRenderer: FunctionalComponent<ExpectedOutcomeRendererProps> = ({\n testCaseId,\n fields,\n dynamicResolutionSupported = false,\n onExpectedOutcomeChange,\n}) => {\n const emit = (detail: ExpectedOutcomeChangeDetail) =>\n onExpectedOutcomeChange({\n detail,\n } as CustomEvent<ExpectedOutcomeChangeDetail>);\n\n const buildEvaluationConfig = (\n index: number,\n optionList: string[],\n ): SelectConfig => ({\n name: `expectedOutcomeEvaluation-${index}`,\n fieldType: FormFieldType.SELECT,\n label: 'Evaluation Approach',\n placeholder: 'Select evaluation approach…',\n required: true,\n optionList,\n defaultValue: EvaluationApproach.EXACT,\n });\n\n const buildOutcomeModeConfig = (index: number): SelectConfig => ({\n name: `expectedOutcomeMode-${index}`,\n fieldType: FormFieldType.SELECT,\n label: 'Outcome Mode',\n placeholder: 'Select outcome mode',\n required: true,\n optionList: ['static', 'dynamic'],\n defaultValue: 'static',\n });\n\n const buildResolutionQueryConfig = (index: number): TextAreaConfig => ({\n name: `expectedOutcomeResolutionQuery-${index}`,\n fieldType: FormFieldType.TEXT_AREA,\n label: 'Resolution Query',\n placeholder: 'Query used to resolve expected value',\n required: false,\n rows: 2,\n });\n\n const renderEvaluationSelector = (\n field: ExpectedOutcomeField,\n index: number,\n ) => {\n const optionList = getAllowedApproachesForFieldType(field.type);\n\n return (\n <app-select\n config={buildEvaluationConfig(index, optionList)}\n value={field.evaluationParameters?.approach}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-evaluation-approach',\n value: e.detail.value as EvaluationApproach,\n })\n }\n />\n );\n };\n\n return (\n <div class=\"expected-outcome-renderer\">\n {(fields || []).map((field, index) => {\n if (field.type === 'textarea') {\n const isDynamic =\n dynamicResolutionSupported && field.outcomeMode === 'dynamic';\n const config: TextAreaConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.TEXT_AREA,\n label: field.label,\n placeholder: isDynamic ? 'Resolved on run' : field.placeholder,\n required: !isDynamic,\n readOnly: isDynamic,\n helpText: isDynamic\n ? 'Filled automatically when the test is run'\n : undefined,\n rows: field.rows || 2,\n };\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-textarea\n config={config}\n value={field.value}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: e.detail.value,\n })\n }\n />\n {dynamicResolutionSupported && (\n <app-select\n config={buildOutcomeModeConfig(index)}\n value={field.outcomeMode || 'static'}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-outcome-mode',\n value: e.detail.value as ExpectedOutcomeMode,\n })\n }\n />\n )}\n {dynamicResolutionSupported &&\n field.outcomeMode === 'dynamic' && (\n <app-textarea\n config={buildResolutionQueryConfig(index)}\n value={field.resolutionQuery || ''}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-resolution-query',\n value: e.detail.value,\n })\n }\n />\n )}\n {!isDynamic && renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n if (field.type === 'chips-input') {\n const config: ChipsConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.CHIPS,\n label: field.label,\n placeholder: field.placeholder,\n required: true,\n };\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-chips\n config={config}\n value={field.value}\n onAddChip={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'add-chip',\n value: e.detail.value,\n })\n }\n onRemoveChip={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'remove-chip',\n value: e.detail.value,\n })\n }\n />\n {renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n if (field.type === 'select') {\n const config: SelectConfig = {\n name: `expectedOutcome-${index}`,\n fieldType: FormFieldType.SELECT,\n label: field.label,\n placeholder: field.placeholder,\n required: true,\n optionList: field.options,\n };\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <app-select\n config={config}\n value={field.value}\n onValueChange={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: e.detail.value,\n })\n }\n />\n {renderEvaluationSelector(field, index)}\n </div>\n );\n }\n\n return (\n <div class=\"expected-outcome-renderer__group\">\n <div class=\"expected-outcome-renderer__text\">\n <label>{field.label}</label>\n <input\n type=\"text\"\n value={field.value}\n placeholder={field.placeholder}\n onInput={(e) =>\n emit({\n testCaseId,\n index,\n operation: 'set-value',\n value: (e.target as HTMLInputElement).value,\n })\n }\n />\n </div>\n {renderEvaluationSelector(field, index)}\n </div>\n );\n })}\n </div>\n );\n};\n"]}
@@ -4,7 +4,7 @@ import { EvaluationSummary } from "./evaluation/evaluation-summary";
4
4
  import { RowActions } from "./actions/row-actions";
5
5
  import { FormFieldType } from "../../../lib/form/schema";
6
6
  import { ExpectedOutcomeRenderer, } from "./expected-outcome-renderer";
7
- export const LLMTestCaseRow = ({ testCase, onRun, onDelete, handleTestCaseChange, onExpectedOutcomeChange, }) => {
7
+ export const LLMTestCaseRow = ({ testCase, dynamicResolutionSupported = false, onRun, onDelete, handleTestCaseChange, onExpectedOutcomeChange, }) => {
8
8
  const questionConfig = {
9
9
  name: 'question',
10
10
  fieldType: FormFieldType.TEXT_AREA,
@@ -20,6 +20,6 @@ export const LLMTestCaseRow = ({ testCase, onRun, onDelete, handleTestCaseChange
20
20
  key: 'question',
21
21
  value: e.detail.value,
22
22
  },
23
- }) }), h(ExpectedOutcomeRenderer, { testCaseId: testCase.id, fields: testCase.expectedOutcome || [], onExpectedOutcomeChange: onExpectedOutcomeChange })), h(ResponseOutput, { output: testCase.output, isRunning: testCase.isRunning }), h(EvaluationSummary, { result: testCase.evaluationResult, isRunning: testCase.isRunning }), h(RowActions, { isRunning: testCase.isRunning, canRun: !!testCase.question.trim(), onRun: () => onRun(testCase), onDelete: () => onDelete(testCase.id) })));
23
+ }) }), h(ExpectedOutcomeRenderer, { testCaseId: testCase.id, fields: testCase.expectedOutcome || [], dynamicResolutionSupported: dynamicResolutionSupported, onExpectedOutcomeChange: onExpectedOutcomeChange })), h(ResponseOutput, { output: testCase.output, isRunning: testCase.isRunning }), h(EvaluationSummary, { result: testCase.evaluationResult, isRunning: testCase.isRunning }), h(RowActions, { isRunning: testCase.isRunning, canRun: !!testCase.question.trim(), onRun: () => onRun(testCase), onDelete: () => onDelete(testCase.id) })));
24
24
  };
25
25
  //# sourceMappingURL=llm-test-case-row.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-test-case-row.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/llm-test-case-row.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAkB,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAEL,uBAAuB,GACxB,MAAM,6BAA6B,CAAC;AAcrC,MAAM,CAAC,MAAM,cAAc,GAA6C,CAAC,EACvE,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,oBAAoB,EACpB,uBAAuB,GACxB,EAAE,EAAE;IACH,MAAM,cAAc,GAAmB;QACrC,IAAI,EAAE,UAAU;QAChB,SAAS,EAAE,aAAa,CAAC,SAAS;QAClC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,6BAA6B;QAC1C,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,CAAC;KACR,CAAC;IACF,OAAO,CACL,WAAK,KAAK,EAAC,eAAe,EAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;QACzC,WAAK,KAAK,EAAC,6BAA6B;YACtC,oBACE,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,QAAQ,CAAC,QAAQ,EACxB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,oBAAoB,CAAC;oBACnB,MAAM,EAAE;wBACN,UAAU,EAAE,QAAQ,CAAC,EAAE;wBACvB,GAAG,EAAE,UAAU;wBACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB;iBACiE,CAAC,GAEvE;YACF,EAAC,uBAAuB,IACtB,UAAU,EAAE,QAAQ,CAAC,EAAE,EACvB,MAAM,EAAE,QAAQ,CAAC,eAAe,IAAI,EAAE,EACtC,uBAAuB,EAAE,uBAAuB,GAChD,CACE;QAEN,EAAC,cAAc,IAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,GAAI;QAE1E,EAAC,iBAAiB,IAChB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,EACjC,SAAS,EAAE,QAAQ,CAAC,SAAS,GAC7B;QAEF,EAAC,UAAU,IACT,SAAS,EAAE,QAAQ,CAAC,SAAS,EAC7B,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAClC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAC5B,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GACrC,CACE,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { TestCase } from '../../../types/llm-test-runner';\nimport { ResponseOutput } from './output/response-output';\nimport { EvaluationSummary } from './evaluation/evaluation-summary';\nimport { RowActions } from './actions/row-actions';\nimport { FormFieldType, TextAreaConfig } from '../../../lib/form/schema';\nimport {\n ExpectedOutcomeChangeDetail,\n ExpectedOutcomeRenderer,\n} from './expected-outcome-renderer';\n\nexport interface LLMTestCaseRowProps {\n testCase: TestCase;\n onRun: (testCase: TestCase) => void;\n onDelete: (id: string) => void;\n handleTestCaseChange: (\n e: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => void;\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const LLMTestCaseRow: FunctionalComponent<LLMTestCaseRowProps> = ({\n testCase,\n onRun,\n onDelete,\n handleTestCaseChange,\n onExpectedOutcomeChange,\n}) => {\n const questionConfig: TextAreaConfig = {\n name: 'question',\n fieldType: FormFieldType.TEXT_AREA,\n type: 'text',\n label: 'Question',\n placeholder: 'Enter your question here...',\n required: true,\n rows: 3,\n };\n return (\n <div class=\"test-case-row\" key={testCase.id}>\n <div class=\"test-case-row__input-column\">\n <app-textarea\n config={questionConfig}\n value={testCase.question}\n onValueChange={(e) =>\n handleTestCaseChange({\n detail: {\n testCaseId: testCase.id,\n key: 'question',\n value: e.detail.value,\n },\n } as CustomEvent<{ testCaseId: string; key: string; value: string }>)\n }\n />\n <ExpectedOutcomeRenderer\n testCaseId={testCase.id}\n fields={testCase.expectedOutcome || []}\n onExpectedOutcomeChange={onExpectedOutcomeChange}\n />\n </div>\n\n <ResponseOutput output={testCase.output} isRunning={testCase.isRunning} />\n\n <EvaluationSummary\n result={testCase.evaluationResult}\n isRunning={testCase.isRunning}\n />\n\n <RowActions\n isRunning={testCase.isRunning}\n canRun={!!testCase.question.trim()}\n onRun={() => onRun(testCase)}\n onDelete={() => onDelete(testCase.id)}\n />\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"llm-test-case-row.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/llm-test-case-row.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAkB,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAEL,uBAAuB,GACxB,MAAM,6BAA6B,CAAC;AAerC,MAAM,CAAC,MAAM,cAAc,GAA6C,CAAC,EACvE,QAAQ,EACR,0BAA0B,GAAG,KAAK,EAClC,KAAK,EACL,QAAQ,EACR,oBAAoB,EACpB,uBAAuB,GACxB,EAAE,EAAE;IACH,MAAM,cAAc,GAAmB;QACrC,IAAI,EAAE,UAAU;QAChB,SAAS,EAAE,aAAa,CAAC,SAAS;QAClC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,6BAA6B;QAC1C,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,CAAC;KACR,CAAC;IACF,OAAO,CACL,WAAK,KAAK,EAAC,eAAe,EAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;QACzC,WAAK,KAAK,EAAC,6BAA6B;YACtC,oBACE,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,QAAQ,CAAC,QAAQ,EACxB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CACnB,oBAAoB,CAAC;oBACnB,MAAM,EAAE;wBACN,UAAU,EAAE,QAAQ,CAAC,EAAE;wBACvB,GAAG,EAAE,UAAU;wBACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;qBACtB;iBACiE,CAAC,GAEvE;YACF,EAAC,uBAAuB,IACtB,UAAU,EAAE,QAAQ,CAAC,EAAE,EACvB,MAAM,EAAE,QAAQ,CAAC,eAAe,IAAI,EAAE,EACtC,0BAA0B,EAAE,0BAA0B,EACtD,uBAAuB,EAAE,uBAAuB,GAChD,CACE;QAEN,EAAC,cAAc,IAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,GAAI;QAE1E,EAAC,iBAAiB,IAChB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,EACjC,SAAS,EAAE,QAAQ,CAAC,SAAS,GAC7B;QAEF,EAAC,UAAU,IACT,SAAS,EAAE,QAAQ,CAAC,SAAS,EAC7B,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAClC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAC5B,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GACrC,CACE,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { TestCase } from '../../../types/llm-test-runner';\nimport { ResponseOutput } from './output/response-output';\nimport { EvaluationSummary } from './evaluation/evaluation-summary';\nimport { RowActions } from './actions/row-actions';\nimport { FormFieldType, TextAreaConfig } from '../../../lib/form/schema';\nimport {\n ExpectedOutcomeChangeDetail,\n ExpectedOutcomeRenderer,\n} from './expected-outcome-renderer';\n\nexport interface LLMTestCaseRowProps {\n testCase: TestCase;\n dynamicResolutionSupported?: boolean;\n onRun: (testCase: TestCase) => void;\n onDelete: (id: string) => void;\n handleTestCaseChange: (\n e: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => void;\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const LLMTestCaseRow: FunctionalComponent<LLMTestCaseRowProps> = ({\n testCase,\n dynamicResolutionSupported = false,\n onRun,\n onDelete,\n handleTestCaseChange,\n onExpectedOutcomeChange,\n}) => {\n const questionConfig: TextAreaConfig = {\n name: 'question',\n fieldType: FormFieldType.TEXT_AREA,\n type: 'text',\n label: 'Question',\n placeholder: 'Enter your question here...',\n required: true,\n rows: 3,\n };\n return (\n <div class=\"test-case-row\" key={testCase.id}>\n <div class=\"test-case-row__input-column\">\n <app-textarea\n config={questionConfig}\n value={testCase.question}\n onValueChange={(e) =>\n handleTestCaseChange({\n detail: {\n testCaseId: testCase.id,\n key: 'question',\n value: e.detail.value,\n },\n } as CustomEvent<{ testCaseId: string; key: string; value: string }>)\n }\n />\n <ExpectedOutcomeRenderer\n testCaseId={testCase.id}\n fields={testCase.expectedOutcome || []}\n dynamicResolutionSupported={dynamicResolutionSupported}\n onExpectedOutcomeChange={onExpectedOutcomeChange}\n />\n </div>\n\n <ResponseOutput output={testCase.output} isRunning={testCase.isRunning} />\n\n <EvaluationSummary\n result={testCase.evaluationResult}\n isRunning={testCase.isRunning}\n />\n\n <RowActions\n isRunning={testCase.isRunning}\n canRun={!!testCase.question.trim()}\n onRun={() => onRun(testCase)}\n onDelete={() => onDelete(testCase.id)}\n />\n </div>\n );\n};\n"]}
@@ -1,7 +1,7 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { LLMTestCaseRow } from "./llm-test-case-row";
3
3
  import { Button } from "../../../lib/ui/button/index";
4
- export const LLMTestCases = ({ testCases, onRun, onDelete, onAddTestCase, handleTestCaseChange, onExpectedOutcomeChange, }) => {
5
- return (h("div", { class: "test-cases" }, h("div", { class: "test-cases__column-headers" }, h("div", { class: "test-cases__column-header" }, "Input"), h("div", { class: "test-cases__column-header" }, "Output"), h("div", { class: "test-cases__column-header" }, "Evaluation"), h("div", { class: "test-cases__column-header" }, "Actions")), testCases.map(testCase => (h(LLMTestCaseRow, { testCase: testCase, onRun: onRun, onDelete: onDelete, handleTestCaseChange: handleTestCaseChange, onExpectedOutcomeChange: onExpectedOutcomeChange }))), h("div", { class: "test-cases__add-section" }, h(Button, { variant: "outline", size: "md", onClick: onAddTestCase }, "+ Add Question"))));
4
+ export const LLMTestCases = ({ testCases, dynamicResolutionSupported = false, onRun, onDelete, onAddTestCase, handleTestCaseChange, onExpectedOutcomeChange, }) => {
5
+ return (h("div", { class: "test-cases" }, h("div", { class: "test-cases__column-headers" }, h("div", { class: "test-cases__column-header" }, "Input"), h("div", { class: "test-cases__column-header" }, "Output"), h("div", { class: "test-cases__column-header" }, "Evaluation"), h("div", { class: "test-cases__column-header" }, "Actions")), testCases.map(testCase => (h(LLMTestCaseRow, { testCase: testCase, dynamicResolutionSupported: dynamicResolutionSupported, onRun: onRun, onDelete: onDelete, handleTestCaseChange: handleTestCaseChange, onExpectedOutcomeChange: onExpectedOutcomeChange }))), h("div", { class: "test-cases__add-section" }, h(Button, { variant: "outline", size: "md", onClick: onAddTestCase }, "+ Add Question"))));
6
6
  };
7
7
  //# sourceMappingURL=llm-test-cases.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-test-cases.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/llm-test-cases.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAgBtD,MAAM,CAAC,MAAM,YAAY,GAA2C,CAAC,EACnE,SAAS,EACT,KAAK,EACL,QAAQ,EACR,aAAa,EACb,oBAAoB,EACpB,uBAAuB,GACxB,EAAE,EAAE;IACH,OAAO,CACL,WAAK,KAAK,EAAC,YAAY;QACrB,WAAK,KAAK,EAAC,4BAA4B;YACrC,WAAK,KAAK,EAAC,2BAA2B,YAAY;YAClD,WAAK,KAAK,EAAC,2BAA2B,aAAa;YACnD,WAAK,KAAK,EAAC,2BAA2B,iBAAiB;YACvD,WAAK,KAAK,EAAC,2BAA2B,cAAc,CAChD;QAEL,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CACzB,EAAC,cAAc,IACb,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,oBAAoB,EAAE,oBAAoB,EAC1C,uBAAuB,EAAE,uBAAuB,GAChD,CACH,CAAC;QAEF,WAAK,KAAK,EAAC,yBAAyB;YAClC,EAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,aAAa,qBAEjD,CACL,CACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { TestCase } from '../../../types/llm-test-runner';\nimport { LLMTestCaseRow } from './llm-test-case-row';\nimport { Button } from '../../../lib/ui/button/index';\nimport { ExpectedOutcomeChangeDetail } from './expected-outcome-renderer';\n\nexport interface LLMTestCasesProps {\n testCases: TestCase[];\n onRun: (testCase: TestCase) => void;\n onDelete: (id: string) => void;\n onAddTestCase: () => void;\n handleTestCaseChange: (\n e: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => void;\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const LLMTestCases: FunctionalComponent<LLMTestCasesProps> = ({\n testCases,\n onRun,\n onDelete,\n onAddTestCase,\n handleTestCaseChange,\n onExpectedOutcomeChange,\n}) => {\n return (\n <div class=\"test-cases\">\n <div class=\"test-cases__column-headers\">\n <div class=\"test-cases__column-header\">Input</div>\n <div class=\"test-cases__column-header\">Output</div>\n <div class=\"test-cases__column-header\">Evaluation</div>\n <div class=\"test-cases__column-header\">Actions</div>\n </div>\n\n {testCases.map(testCase => (\n <LLMTestCaseRow\n testCase={testCase}\n onRun={onRun}\n onDelete={onDelete}\n handleTestCaseChange={handleTestCaseChange}\n onExpectedOutcomeChange={onExpectedOutcomeChange}\n />\n ))}\n\n <div class=\"test-cases__add-section\">\n <Button variant=\"outline\" size=\"md\" onClick={onAddTestCase}>\n + Add Question\n </Button>\n </div>\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"llm-test-cases.js","sourceRoot":"","sources":["../../../../src/components/llm-test-runner/test-cases/llm-test-cases.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAuB,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAiBtD,MAAM,CAAC,MAAM,YAAY,GAA2C,CAAC,EACnE,SAAS,EACT,0BAA0B,GAAG,KAAK,EAClC,KAAK,EACL,QAAQ,EACR,aAAa,EACb,oBAAoB,EACpB,uBAAuB,GACxB,EAAE,EAAE;IACH,OAAO,CACL,WAAK,KAAK,EAAC,YAAY;QACrB,WAAK,KAAK,EAAC,4BAA4B;YACrC,WAAK,KAAK,EAAC,2BAA2B,YAAY;YAClD,WAAK,KAAK,EAAC,2BAA2B,aAAa;YACnD,WAAK,KAAK,EAAC,2BAA2B,iBAAiB;YACvD,WAAK,KAAK,EAAC,2BAA2B,cAAc,CAChD;QAEL,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CACzB,EAAC,cAAc,IACb,QAAQ,EAAE,QAAQ,EAClB,0BAA0B,EAAE,0BAA0B,EACtD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,oBAAoB,EAAE,oBAAoB,EAC1C,uBAAuB,EAAE,uBAAuB,GAChD,CACH,CAAC;QAEF,WAAK,KAAK,EAAC,yBAAyB;YAClC,EAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,aAAa,qBAEjD,CACL,CACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { h, FunctionalComponent } from '@stencil/core';\nimport { TestCase } from '../../../types/llm-test-runner';\nimport { LLMTestCaseRow } from './llm-test-case-row';\nimport { Button } from '../../../lib/ui/button/index';\nimport { ExpectedOutcomeChangeDetail } from './expected-outcome-renderer';\n\nexport interface LLMTestCasesProps {\n testCases: TestCase[];\n dynamicResolutionSupported?: boolean;\n onRun: (testCase: TestCase) => void;\n onDelete: (id: string) => void;\n onAddTestCase: () => void;\n handleTestCaseChange: (\n e: CustomEvent<{ testCaseId: string; key: string; value: string }>,\n ) => void;\n onExpectedOutcomeChange: (\n e: CustomEvent<ExpectedOutcomeChangeDetail>,\n ) => void;\n}\n\nexport const LLMTestCases: FunctionalComponent<LLMTestCasesProps> = ({\n testCases,\n dynamicResolutionSupported = false,\n onRun,\n onDelete,\n onAddTestCase,\n handleTestCaseChange,\n onExpectedOutcomeChange,\n}) => {\n return (\n <div class=\"test-cases\">\n <div class=\"test-cases__column-headers\">\n <div class=\"test-cases__column-header\">Input</div>\n <div class=\"test-cases__column-header\">Output</div>\n <div class=\"test-cases__column-header\">Evaluation</div>\n <div class=\"test-cases__column-header\">Actions</div>\n </div>\n\n {testCases.map(testCase => (\n <LLMTestCaseRow\n testCase={testCase}\n dynamicResolutionSupported={dynamicResolutionSupported}\n onRun={onRun}\n onDelete={onDelete}\n handleTestCaseChange={handleTestCaseChange}\n onExpectedOutcomeChange={onExpectedOutcomeChange}\n />\n ))}\n\n <div class=\"test-cases__add-section\">\n <Button variant=\"outline\" size=\"md\" onClick={onAddTestCase}>\n + Add Question\n </Button>\n </div>\n </div>\n );\n};\n"]}
@@ -18,13 +18,20 @@ export class EvaluationService {
18
18
  console.warn('⚠️ No output to evaluate for test case:', testCase.id);
19
19
  return;
20
20
  }
21
- const fields = (testCase.expectedOutcome || []).map((field, index) => ({
22
- index,
23
- label: field.label,
24
- type: field.type,
25
- expectedValue: getFieldExpectedValue(field),
26
- evaluationParameters: normalizeEvaluationParametersForField(field.type, field.evaluationParameters),
27
- }));
21
+ const fields = (testCase.expectedOutcome || []).flatMap((field, index) => {
22
+ if (field.type === 'textarea' && field.outcomeMode === 'dynamic') {
23
+ return [];
24
+ }
25
+ return [
26
+ {
27
+ index,
28
+ label: field.label,
29
+ type: field.type,
30
+ expectedValue: getFieldExpectedValue(field),
31
+ evaluationParameters: normalizeEvaluationParametersForField(field.type, field.evaluationParameters),
32
+ },
33
+ ];
34
+ });
28
35
  const evaluationRequest = {
29
36
  testCaseId: testCase.id,
30
37
  question: testCase.question,
@@ -1 +1 @@
1
- {"version":3,"file":"evaluation-service.js","sourceRoot":"","sources":["../../../src/lib/evaluation/evaluation-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO1D,OAAO,EAAE,qCAAqC,EAAE,MAAM,6BAA6B,CAAC;AAEpF;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAsB;IAEpC;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAkB,EAClB,QAA4C;QAE5C,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,yCAAyC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAA2B,CAAC,QAAQ,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CACzE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACjB,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,aAAa,EAAE,qBAAqB,CAAC,KAAK,CAAC;YAC3C,oBAAoB,EAAE,qCAAqC,CACzD,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,oBAAoB,CAC3B;SACF,CAAC,CACH,CAAC;QAEF,MAAM,iBAAiB,GAAwB;YAC7C,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,MAAM;SACP,CAAC;QAEF,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAChC,iBAAiB,EACjB,CAAC,MAAwB,EAAE,EAAE;YAC3B,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;YACtD,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,SAAS,qBAAqB,CAAC,KAA2B;IACxD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC;AACrB,CAAC","sourcesContent":["import { LLMEvaluationEngine } from './evaluation-engine';\nimport {\n EvaluationResult,\n FieldEvaluationInput,\n EvaluationRequestV2,\n} from './types';\nimport { TestCase, ExpectedOutcomeField } from '../../types/llm-test-runner';\nimport { normalizeEvaluationParametersForField } from './field-evaluation-approach';\n\n/**\n * Service for evaluating test case responses\n */\nexport class EvaluationService {\n private engine: LLMEvaluationEngine;\n\n constructor() {\n this.engine = new LLMEvaluationEngine();\n }\n\n /**\n * Evaluates a test case response\n * @param testCase - The test case to evaluate\n * @param onResult - Callback to handle the evaluation result\n */\n async evaluateTestCase(\n testCase: TestCase,\n onResult: (result: EvaluationResult) => void,\n ): Promise<void> {\n if (!testCase.output) {\n console.warn('⚠️ No output to evaluate for test case:', testCase.id);\n return;\n }\n\n const fields: FieldEvaluationInput[] = (testCase.expectedOutcome || []).map(\n (field, index) => ({\n index,\n label: field.label,\n type: field.type,\n expectedValue: getFieldExpectedValue(field),\n evaluationParameters: normalizeEvaluationParametersForField(\n field.type,\n field.evaluationParameters,\n ),\n }),\n );\n\n const evaluationRequest: EvaluationRequestV2 = {\n testCaseId: testCase.id,\n question: testCase.question,\n actualResponse: testCase.output,\n fields,\n };\n\n await this.engine.evaluateResponse(\n evaluationRequest,\n (result: EvaluationResult) => {\n console.log('📊 Evaluation result received:', result);\n onResult(result);\n },\n );\n }\n}\n\nfunction getFieldExpectedValue(field: ExpectedOutcomeField): string {\n if (field.type === 'chips-input') {\n return field.value.join(', ');\n }\n return field.value;\n}\n"]}
1
+ {"version":3,"file":"evaluation-service.js","sourceRoot":"","sources":["../../../src/lib/evaluation/evaluation-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO1D,OAAO,EAAE,qCAAqC,EAAE,MAAM,6BAA6B,CAAC;AAEpF;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAsB;IAEpC;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAkB,EAClB,QAA4C;QAE5C,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,yCAAyC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAA2B,CAAC,QAAQ,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,OAAO,CAC7E,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACf,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACjE,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,OAAO;gBACL;oBACE,KAAK;oBACL,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,aAAa,EAAE,qBAAqB,CAAC,KAAK,CAAC;oBAC3C,oBAAoB,EAAE,qCAAqC,CACzD,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,oBAAoB,CAC3B;iBACF;aACF,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,MAAM,iBAAiB,GAAwB;YAC7C,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,MAAM;SACP,CAAC;QAEF,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAChC,iBAAiB,EACjB,CAAC,MAAwB,EAAE,EAAE;YAC3B,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;YACtD,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,SAAS,qBAAqB,CAAC,KAA2B;IACxD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC;AACrB,CAAC","sourcesContent":["import { LLMEvaluationEngine } from './evaluation-engine';\nimport {\n EvaluationResult,\n FieldEvaluationInput,\n EvaluationRequestV2,\n} from './types';\nimport { TestCase, ExpectedOutcomeField } from '../../types/llm-test-runner';\nimport { normalizeEvaluationParametersForField } from './field-evaluation-approach';\n\n/**\n * Service for evaluating test case responses\n */\nexport class EvaluationService {\n private engine: LLMEvaluationEngine;\n\n constructor() {\n this.engine = new LLMEvaluationEngine();\n }\n\n /**\n * Evaluates a test case response\n * @param testCase - The test case to evaluate\n * @param onResult - Callback to handle the evaluation result\n */\n async evaluateTestCase(\n testCase: TestCase,\n onResult: (result: EvaluationResult) => void,\n ): Promise<void> {\n if (!testCase.output) {\n console.warn('⚠️ No output to evaluate for test case:', testCase.id);\n return;\n }\n\n const fields: FieldEvaluationInput[] = (testCase.expectedOutcome || []).flatMap(\n (field, index) => {\n if (field.type === 'textarea' && field.outcomeMode === 'dynamic') {\n return [];\n }\n\n return [\n {\n index,\n label: field.label,\n type: field.type,\n expectedValue: getFieldExpectedValue(field),\n evaluationParameters: normalizeEvaluationParametersForField(\n field.type,\n field.evaluationParameters,\n ),\n },\n ];\n },\n );\n\n const evaluationRequest: EvaluationRequestV2 = {\n testCaseId: testCase.id,\n question: testCase.question,\n actualResponse: testCase.output,\n fields,\n };\n\n await this.engine.evaluateResponse(\n evaluationRequest,\n (result: EvaluationResult) => {\n console.log('📊 Evaluation result received:', result);\n onResult(result);\n },\n );\n }\n}\n\nfunction getFieldExpectedValue(field: ExpectedOutcomeField): string {\n if (field.type === 'chips-input') {\n return field.value.join(', ');\n }\n return field.value;\n}\n"]}
@@ -30,6 +30,23 @@
30
30
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
31
31
  }
32
32
 
33
+ .textarea-wrapper--read-only .textarea-label {
34
+ color: var(--muted-foreground);
35
+ }
36
+
37
+ .textarea-element:read-only {
38
+ background: var(--muted);
39
+ color: var(--muted-foreground);
40
+ border-color: var(--border);
41
+ cursor: not-allowed;
42
+ resize: none;
43
+ }
44
+
45
+ .textarea-element:read-only:focus {
46
+ border-color: var(--border);
47
+ box-shadow: none;
48
+ }
49
+
33
50
  .help-text {
34
51
  margin-top: var(--spacing-1);
35
52
  font-size: var(--font-size-xs);
@@ -21,7 +21,10 @@ export class AppTextarea {
21
21
  name: c.name,
22
22
  autocomplete: c.autocomplete,
23
23
  };
24
- return (h("div", { key: 'cc0073d70c9de40a8a12a1cabc3c1c06ac8c1863', class: "textarea-wrapper" }, c.label && (h("label", { key: 'a886cf95f25afee2e09ebcbc4dc62d2c9bca5ee0', class: "textarea-label", htmlFor: c.name }, c.label)), h("textarea", { key: 'c16b072269c450f3e09764b23cdfdaf966975977', ...allowedAttrs, class: "textarea-element", value: this.value, onInput: this.handleChange }), c.helpText && h("p", { key: '9df941aa068b937d90f9a5f2a841a8fe426b3371', class: "help-text" }, c.helpText)));
24
+ return (h("div", { key: '29bbcd954df6d18e968f6b2670224fda6f03a9f2', class: {
25
+ 'textarea-wrapper': true,
26
+ 'textarea-wrapper--read-only': !!c.readOnly,
27
+ } }, c.label && (h("label", { key: 'd95d3cbf01ce66c5bd074ede2eb1f87a0c98f3e4', class: "textarea-label", htmlFor: c.name }, c.label)), h("textarea", { key: 'faeb28c35a543213d9c5847e93779f957e367ff0', ...allowedAttrs, class: "textarea-element", value: this.value, onInput: this.handleChange }), c.helpText && h("p", { key: '558abfe03f7107352a6d40aea78a35b304bc11a6', class: "help-text" }, c.helpText)));
25
28
  }
26
29
  static get is() { return "app-textarea"; }
27
30
  static get encapsulation() { return "shadow"; }