llm-testrunner-components 1.0.0 → 1.0.1

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 (103) hide show
  1. package/README.md +139 -81
  2. package/dist/cjs/{index-CCrH7f-W.js → index-CY2lQip_.js} +190 -33
  3. package/dist/cjs/index-CY2lQip_.js.map +1 -0
  4. package/dist/cjs/index.cjs.js +391 -5
  5. package/dist/cjs/index.cjs.js.map +1 -1
  6. package/dist/cjs/llm-test-runner.cjs.entry.js +9 -0
  7. package/dist/cjs/llm-test-runner.entry.cjs.js.map +1 -0
  8. package/dist/cjs/{llm-testrunner-components.cjs.js → llm-testrunner.cjs.js} +5 -7
  9. package/dist/cjs/llm-testrunner.cjs.js.map +1 -0
  10. package/dist/cjs/loader.cjs.js +2 -4
  11. package/dist/collection/collection-manifest.json +3 -4
  12. package/dist/collection/components/error-message/error-message.js +8 -0
  13. package/dist/collection/components/error-message/error-message.js.map +1 -0
  14. package/dist/collection/components/llm-test-runner/llm-test-runner.css +671 -0
  15. package/dist/collection/components/llm-test-runner/llm-test-runner.js +310 -0
  16. package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -0
  17. package/dist/collection/index.js +4 -10
  18. package/dist/collection/index.js.map +1 -1
  19. package/dist/collection/lib/evaluation/evaluation-engine.js +61 -0
  20. package/dist/collection/lib/evaluation/evaluation-engine.js.map +1 -0
  21. package/dist/collection/lib/evaluation/index.js +7 -0
  22. package/dist/collection/lib/evaluation/index.js.map +1 -0
  23. package/dist/collection/lib/evaluation/types.js +2 -0
  24. package/dist/collection/lib/evaluation/types.js.map +1 -0
  25. package/dist/components/index.js +1652 -4
  26. package/dist/components/index.js.map +1 -1
  27. package/dist/components/{current-time.d.ts → llm-test-runner.d.ts} +4 -4
  28. package/dist/components/llm-test-runner.js +9 -0
  29. package/dist/components/llm-test-runner.js.map +1 -0
  30. package/dist/esm/{index-0jlGA6MK.js → index-DBp-rMPb.js} +190 -33
  31. package/dist/esm/index-DBp-rMPb.js.map +1 -0
  32. package/dist/esm/index.js +391 -5
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/llm-test-runner.entry.js +3 -0
  35. package/dist/esm/llm-test-runner.entry.js.map +1 -0
  36. package/dist/esm/{llm-testrunner-components.js → llm-testrunner.js} +5 -7
  37. package/dist/esm/llm-testrunner.js.map +1 -0
  38. package/dist/esm/loader.js +3 -5
  39. package/dist/llm-testrunner/index.esm.js +2 -0
  40. package/dist/llm-testrunner/index.esm.js.map +1 -0
  41. package/dist/llm-testrunner/llm-test-runner.entry.esm.js.map +1 -0
  42. package/dist/llm-testrunner/llm-testrunner.esm.js +2 -0
  43. package/dist/llm-testrunner/llm-testrunner.esm.js.map +1 -0
  44. package/dist/llm-testrunner/p-DBp-rMPb.js +3 -0
  45. package/dist/llm-testrunner/p-DBp-rMPb.js.map +1 -0
  46. package/dist/llm-testrunner/p-ed2ea423.entry.js +2 -0
  47. package/dist/llm-testrunner/p-ed2ea423.entry.js.map +1 -0
  48. package/dist/react/components.d.ts +9 -0
  49. package/dist/react/components.d.ts.map +1 -0
  50. package/dist/react/components.js +12 -0
  51. package/dist/react/index.d.ts +2 -0
  52. package/dist/react/index.d.ts.map +1 -0
  53. package/dist/react/index.js +2 -0
  54. package/dist/types/components/error-message/error-message.d.ts +7 -0
  55. package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +42 -0
  56. package/dist/types/components.d.ts +11 -46
  57. package/dist/types/index.d.ts +2 -10
  58. package/dist/types/lib/evaluation/evaluation-engine.d.ts +8 -0
  59. package/dist/types/lib/evaluation/index.d.ts +5 -0
  60. package/dist/types/lib/evaluation/types.d.ts +23 -0
  61. package/dist/types/stencil-public-runtime.d.ts +41 -3
  62. package/package.json +33 -12
  63. package/dist/cjs/current-time.my-component.entry.cjs.js.map +0 -1
  64. package/dist/cjs/current-time_2.cjs.entry.js +0 -67
  65. package/dist/cjs/current-time_2.cjs.entry.js.map +0 -1
  66. package/dist/cjs/index-CCrH7f-W.js.map +0 -1
  67. package/dist/cjs/llm-testrunner-components.cjs.js.map +0 -1
  68. package/dist/collection/components/my-component/current-time.js +0 -35
  69. package/dist/collection/components/my-component/current-time.js.map +0 -1
  70. package/dist/collection/components/my-component/my-component.css +0 -3
  71. package/dist/collection/components/my-component/my-component.js +0 -96
  72. package/dist/collection/components/my-component/my-component.js.map +0 -1
  73. package/dist/collection/utils/utils.js +0 -4
  74. package/dist/collection/utils/utils.js.map +0 -1
  75. package/dist/components/current-time.js +0 -9
  76. package/dist/components/current-time.js.map +0 -1
  77. package/dist/components/my-component.d.ts +0 -11
  78. package/dist/components/my-component.js +0 -63
  79. package/dist/components/my-component.js.map +0 -1
  80. package/dist/components/p-CbvWSaCI.js +0 -53
  81. package/dist/components/p-CbvWSaCI.js.map +0 -1
  82. package/dist/components/p-DnDi6fKi.js +0 -1101
  83. package/dist/components/p-DnDi6fKi.js.map +0 -1
  84. package/dist/esm/current-time.my-component.entry.js.map +0 -1
  85. package/dist/esm/current-time_2.entry.js +0 -64
  86. package/dist/esm/current-time_2.entry.js.map +0 -1
  87. package/dist/esm/index-0jlGA6MK.js.map +0 -1
  88. package/dist/esm/llm-testrunner-components.js.map +0 -1
  89. package/dist/llm-testrunner-components/current-time.my-component.entry.esm.js.map +0 -1
  90. package/dist/llm-testrunner-components/index.esm.js +0 -2
  91. package/dist/llm-testrunner-components/index.esm.js.map +0 -1
  92. package/dist/llm-testrunner-components/llm-testrunner-components.esm.js +0 -2
  93. package/dist/llm-testrunner-components/llm-testrunner-components.esm.js.map +0 -1
  94. package/dist/llm-testrunner-components/p-0jlGA6MK.js +0 -3
  95. package/dist/llm-testrunner-components/p-0jlGA6MK.js.map +0 -1
  96. package/dist/llm-testrunner-components/p-15e5e0fe.entry.js +0 -2
  97. package/dist/llm-testrunner-components/p-15e5e0fe.entry.js.map +0 -1
  98. package/dist/types/components/my-component/current-time.d.ts +0 -7
  99. package/dist/types/components/my-component/my-component.d.ts +0 -16
  100. package/dist/types/utils/utils.d.ts +0 -1
  101. /package/dist/{llm-testrunner-components → llm-testrunner}/loader.esm.js.map +0 -0
  102. /package/dist/{llm-testrunner-components → llm-testrunner}/p-DQuL1Twl.js +0 -0
  103. /package/dist/{llm-testrunner-components → llm-testrunner}/p-DQuL1Twl.js.map +0 -0
@@ -0,0 +1,310 @@
1
+ import { h } from "@stencil/core";
2
+ import { LLMEvaluationEngine } from "../../lib/evaluation/evaluation-engine";
3
+ import { v4 as uuidv4 } from "uuid";
4
+ import { ErrorMessage } from "../error-message/error-message";
5
+ export class LLMTestRunner {
6
+ apiKey;
7
+ testCases = [
8
+ {
9
+ id: '1',
10
+ question: '',
11
+ expectedKeywords: [],
12
+ expectedSourceLinks: [],
13
+ isRunning: false
14
+ }
15
+ ];
16
+ isRunningAll = false;
17
+ error = '';
18
+ fileInput;
19
+ isExportingTestSuite = false;
20
+ evaluationEngine;
21
+ apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
22
+ async componentWillLoad() {
23
+ this.evaluationEngine = new LLMEvaluationEngine();
24
+ console.log('🔍 componentWillLoad - apiKey:', this.apiKey ? 'SET' : 'NOT SET');
25
+ console.log('🔍 componentWillLoad - apiKey value:', this.apiKey);
26
+ if (!this.apiKey) {
27
+ throw new Error('API key is required. Please provide the apiKey prop: <llm-test-runner apiKey="your-api-key" />');
28
+ }
29
+ }
30
+ componentDidLoad() {
31
+ }
32
+ disconnectedCallback() {
33
+ }
34
+ addNewTestCase() {
35
+ const newTestCase = {
36
+ id: this.generateId(),
37
+ question: '',
38
+ expectedKeywords: [],
39
+ expectedSourceLinks: [],
40
+ isRunning: false
41
+ };
42
+ this.testCases = [...this.testCases, newTestCase];
43
+ }
44
+ updateTestCase(id, updates) {
45
+ this.testCases = this.testCases.map(tc => tc.id === id ? { ...tc, ...updates } : tc);
46
+ }
47
+ async runSingleTest(testCase) {
48
+ console.log('🚀 Starting test for question:', testCase.question);
49
+ this.updateTestCase(testCase.id, { isRunning: true });
50
+ try {
51
+ const aiResponse = await this.callGeminiAPI(testCase.question);
52
+ console.log('✅ AI call completed for test case:', testCase.id);
53
+ this.updateTestCase(testCase.id, {
54
+ isRunning: false,
55
+ output: aiResponse,
56
+ error: null
57
+ });
58
+ await this.evaluateResponse({
59
+ ...testCase,
60
+ output: aiResponse
61
+ });
62
+ }
63
+ catch (error) {
64
+ console.error('❌ Error in runSingleTest:', error);
65
+ this.updateTestCase(testCase.id, {
66
+ isRunning: false,
67
+ output: null,
68
+ error: error instanceof Error ? error.message : 'Unknown error'
69
+ });
70
+ }
71
+ }
72
+ deleteTestCase(id) {
73
+ this.testCases = this.testCases.filter(tc => tc.id !== id);
74
+ }
75
+ addKeyword(testCaseId, keyword) {
76
+ if (keyword.trim()) {
77
+ const testCase = this.testCases.find(tc => tc.id === testCaseId);
78
+ if (testCase) {
79
+ this.updateTestCase(testCaseId, {
80
+ expectedKeywords: [...testCase.expectedKeywords, keyword.trim()]
81
+ });
82
+ }
83
+ }
84
+ }
85
+ removeKeyword(testCaseId, index) {
86
+ const testCase = this.testCases.find(tc => tc.id === testCaseId);
87
+ if (testCase) {
88
+ const newKeywords = testCase.expectedKeywords.filter((_, i) => i !== index);
89
+ this.updateTestCase(testCaseId, { expectedKeywords: newKeywords });
90
+ }
91
+ }
92
+ addSourceLink(testCaseId, link) {
93
+ if (link.trim()) {
94
+ const testCase = this.testCases.find(tc => tc.id === testCaseId);
95
+ if (testCase) {
96
+ this.updateTestCase(testCaseId, {
97
+ expectedSourceLinks: [...testCase.expectedSourceLinks, link.trim()]
98
+ });
99
+ }
100
+ }
101
+ }
102
+ removeSourceLink(testCaseId, index) {
103
+ const testCase = this.testCases.find(tc => tc.id === testCaseId);
104
+ if (testCase) {
105
+ const newLinks = testCase.expectedSourceLinks.filter((_, i) => i !== index);
106
+ this.updateTestCase(testCaseId, { expectedSourceLinks: newLinks });
107
+ }
108
+ }
109
+ async callGeminiAPI(prompt) {
110
+ console.log('🔍 callGeminiAPI - apiKey:', this.apiKey ? 'SET' : 'NOT SET');
111
+ console.log('🔍 callGeminiAPI - apiKey value:', this.apiKey ? `${this.apiKey.substring(0, 10)}...` : 'undefined');
112
+ if (!this.apiKey) {
113
+ throw new Error('API key is required. Please provide the apiKey prop.');
114
+ }
115
+ const requestBody = {
116
+ contents: [{
117
+ parts: [{
118
+ text: prompt
119
+ }]
120
+ }]
121
+ };
122
+ const response = await fetch(`${this.apiUrl}?key=${this.apiKey}`, {
123
+ method: 'POST',
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ },
127
+ body: JSON.stringify(requestBody)
128
+ });
129
+ if (!response.ok) {
130
+ const errorData = await response.json().catch(() => ({}));
131
+ throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);
132
+ }
133
+ const data = await response.json();
134
+ if (data.candidates && data.candidates[0] && data.candidates[0].content) {
135
+ return data.candidates[0].content.parts[0].text;
136
+ }
137
+ else {
138
+ throw new Error('Unexpected response format from Gemini API');
139
+ }
140
+ }
141
+ async evaluateResponse(testCase) {
142
+ if (!testCase.output) {
143
+ console.warn('⚠️ No output to evaluate for test case:', testCase.id);
144
+ return;
145
+ }
146
+ const evaluationRequest = {
147
+ testCaseId: testCase.id,
148
+ question: testCase.question,
149
+ expectedKeywords: testCase.expectedKeywords,
150
+ expectedSourceLinks: testCase.expectedSourceLinks,
151
+ actualResponse: testCase.output
152
+ };
153
+ await this.evaluationEngine.evaluateResponse(evaluationRequest, (result) => {
154
+ console.log('📊 Evaluation result received:', result);
155
+ this.updateTestCase(testCase.id, {
156
+ evaluationResult: result
157
+ });
158
+ });
159
+ }
160
+ async runAllTests() {
161
+ this.isRunningAll = true;
162
+ for (const testCase of this.testCases) {
163
+ if (!testCase.isRunning && testCase.question.trim()) {
164
+ await this.runSingleTest(testCase);
165
+ // Delay between tests to avoid rate limiting
166
+ await new Promise(resolve => setTimeout(resolve, 1000));
167
+ }
168
+ }
169
+ this.isRunningAll = false;
170
+ }
171
+ generateId() {
172
+ return uuidv4();
173
+ }
174
+ handleFileSelect() {
175
+ this.fileInput.click();
176
+ }
177
+ async handleFileChange(event) {
178
+ const target = event.target;
179
+ const file = target.files?.[0];
180
+ // Immediately clear the input value to allow for a new upload.
181
+ target.value = '';
182
+ if (!file) {
183
+ this.error = 'No file selected.';
184
+ return;
185
+ }
186
+ const isJsonType = file.type === 'application/json';
187
+ const isJsonExtension = file.name.toLowerCase().endsWith('.json');
188
+ if (!isJsonType && !isJsonExtension) {
189
+ this.error = 'Invalid file type. Please select a JSON file.';
190
+ return;
191
+ }
192
+ this.error = '';
193
+ try {
194
+ const content = await this.readFileAsync(file);
195
+ const fileContent = JSON.parse(content);
196
+ if (!Array.isArray(fileContent)) {
197
+ throw new Error("Invalid JSON structure. Expected a JSON array.");
198
+ }
199
+ const importedTestCases = fileContent.map((item) => ({
200
+ id: this.generateId(),
201
+ question: item.question || '',
202
+ expectedKeywords: Array.isArray(item.expectedKeywords) ? item.expectedKeywords : [],
203
+ expectedSourceLinks: Array.isArray(item.expectedSourceLinks) ? item.expectedSourceLinks : [],
204
+ isRunning: false
205
+ }));
206
+ this.testCases = importedTestCases;
207
+ }
208
+ catch (err) {
209
+ this.error = err?.message || 'Error processing file. Please ensure it is a valid JSON array.';
210
+ console.error('File Processing Error:', err);
211
+ }
212
+ }
213
+ readFileAsync(file) {
214
+ return new Promise((resolve, reject) => {
215
+ const reader = new FileReader();
216
+ reader.onload = () => resolve(reader.result);
217
+ reader.onerror = () => reject(reader.error);
218
+ reader.readAsText(file);
219
+ });
220
+ }
221
+ downloadFile(content, filename, mimeType) {
222
+ const blob = new Blob([content], { type: mimeType });
223
+ const url = URL.createObjectURL(blob);
224
+ const link = document.createElement('a');
225
+ link.href = url;
226
+ link.download = filename;
227
+ document.body.appendChild(link);
228
+ link.click();
229
+ document.body.removeChild(link);
230
+ URL.revokeObjectURL(url);
231
+ }
232
+ async handleExportTestSuite() {
233
+ this.isExportingTestSuite = true;
234
+ try {
235
+ // Exporting only input data (question, expected keywords, expected source links)
236
+ const exportData = this.testCases.map(testCase => ({
237
+ id: testCase.id,
238
+ question: testCase.question,
239
+ expectedKeywords: testCase.expectedKeywords,
240
+ expectedSourceLinks: testCase.expectedSourceLinks
241
+ }));
242
+ const jsonContent = JSON.stringify(exportData, null, 2);
243
+ // Added a small delay to show the loading state
244
+ await new Promise(resolve => setTimeout(resolve, 500));
245
+ this.downloadFile(jsonContent, 'test-suite.json', 'application/json');
246
+ }
247
+ finally {
248
+ this.isExportingTestSuite = false;
249
+ }
250
+ }
251
+ render() {
252
+ return (h("div", { key: 'dc5b661334cb4d4bb9bf51fb25363fe08ad938e3', class: "test-runner-container" }, h("header", { key: 'eede0d7f00c0bf5ff794fe2e53bad7a239f2d4d4', class: "test-runner-header" }, h("div", { key: '19327ae6f7408843110a10f791e00ffdf3da6d64', class: "header-left" }, h("input", { key: 'b24227b27dc0f562318a67ca9c38b8793b55c644', class: "hidden", type: "file", ref: (el) => (this.fileInput = el), onChange: (e) => this.handleFileChange(e), accept: ".json,application/json" }), h("button", { key: '65adec40d3787115546c9b59e8691bc89c55c688', class: "btn btn-secondary", onClick: () => this.handleFileSelect() }, h("span", { key: '6fd40e85b4c99232330242b41199df1c4f947351', class: "icon" }, "\u2191"), "Import Test Suite"), h("button", { key: 'd7c4d6b7e3e9bb6951395a3c2c10b964ef2d2fca', class: "btn btn-secondary", onClick: () => this.handleExportTestSuite(), disabled: this.isExportingTestSuite }, h("span", { key: 'bab67984c37b2744f35b4b2c34bfa3a500d196fb', class: "icon" }, this.isExportingTestSuite ? '⏳' : '↓'), this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite')), h("div", { key: '74a7d6e148311151de86a66d7b146bd0d01c215c', class: "header-right" }, h("button", { key: '3e9c33ef795755ebdf11fafa68801294b61a03d1', class: "btn btn-secondary" }, h("span", { key: '89b3582178782392cbea1309ba32b5edc57f9392', class: "icon" }, "\u2699\uFE0F"), "Prompt Editor"), h("button", { key: 'e68e8edd5f532c7a8ec87746fa6d393c4297bc36', class: "btn btn-secondary" }, h("span", { key: '7298d968bbc108cf060a0c309c9a8b2bce88aa90', class: "icon" }, "\u2193"), "Export Test Results"), h("button", { key: 'fb7d10cf9abda9968a2502bd8b4bf8e4cade11e8', class: "btn btn-primary", onClick: () => this.runAllTests(), disabled: this.isRunningAll }, this.isRunningAll ? 'Running...' : 'Run All'))), h(ErrorMessage, { key: '71eb4e561018a176a8c944107d734c32cd74334b', message: this.error, onClear: () => (this.error = '') }), h("div", { key: 'c120a8e40c6c6721dacd400266d4cd6270057c66', class: "test-runner-content" }, h("div", { key: '7b864c6e0671d8be117b001fd87047fabdc851c0', class: "column-headers" }, h("div", { key: 'fcd6ae26d7b98422d800c4e3a4bcec587187be2b', class: "column-header" }, "Input"), h("div", { key: '2855a067b11f8f9ddaf489daffb8a9fd2a317a44', class: "column-header" }, "Output"), h("div", { key: '8b6d75b16005d19bacd8fa6d2008fa64c268e1ef', class: "column-header" }, "Evaluation"), h("div", { key: 'd14ea8cecb426c9692b16044124f3d23ddae671d', class: "column-header" }, "Actions")), h("div", { key: '958aaba85391f7aadabd86c0395d0fe18b942ed4', class: "test-cases" }, this.testCases.map((testCase) => (h("div", { class: "test-case-row", key: testCase.id }, h("div", { class: "input-column" }, h("div", { class: "input-group" }, h("label", null, "Question"), h("textarea", { value: testCase.question, onInput: (e) => this.updateTestCase(testCase.id, {
253
+ question: e.target.value
254
+ }), placeholder: "Enter your question here...", rows: 3 })), h("div", { class: "keywords-group" }, h("label", null, "Expected keywords"), h("div", { class: "tags-container" }, testCase.expectedKeywords.map((keyword, index) => (h("span", { class: "tag", key: index }, keyword, h("button", { class: "tag-remove", onClick: () => this.removeKeyword(testCase.id, index) }, "\u00D7")))), h("input", { type: "text", placeholder: "New item...", onKeyDown: (e) => {
255
+ if (e.key === 'Enter') {
256
+ this.addKeyword(testCase.id, e.target.value);
257
+ e.target.value = '';
258
+ }
259
+ } }))), h("div", { class: "links-group" }, h("label", null, "Expected source links"), h("div", { class: "links-container" }, testCase.expectedSourceLinks.map((link, index) => (h("div", { class: "link-item", key: index }, h("a", { href: link, target: "_blank", rel: "noopener noreferrer" }, link), h("button", { class: "link-remove", onClick: () => this.removeSourceLink(testCase.id, index) }, "\u00D7")))), h("input", { type: "url", placeholder: "New item...", onKeyDown: (e) => {
260
+ if (e.key === 'Enter') {
261
+ this.addSourceLink(testCase.id, e.target.value);
262
+ e.target.value = '';
263
+ }
264
+ } })))), h("div", { class: "output-column" }, testCase.output ? (h("div", { class: "output-content" }, testCase.output)) : (h("div", { class: "output-placeholder" }, testCase.isRunning ? 'Running...' : ''))), h("div", { class: "evaluation-column" }, testCase.evaluationResult ? (h("div", { class: "evaluation-result" }, h("div", { class: `evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}` }, testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'), h("div", { class: "evaluation-details" }, "Keywords: ", testCase.evaluationResult.keywordMatches.filter(m => m.found).length, "/", testCase.evaluationResult.keywordMatches.length, " found"))) : (h("div", { class: "evaluation-placeholder" }, testCase.isRunning ? 'Evaluating...' : ''))), h("div", { class: "actions-column" }, h("button", { class: "btn btn-icon btn-run", onClick: () => this.runSingleTest(testCase), disabled: testCase.isRunning || !testCase.question.trim(), title: !testCase.question.trim() ? "Enter a question first" : "Run this test" }, testCase.isRunning ? '⏳' : '▶️'), h("button", { class: "btn btn-icon btn-delete", onClick: () => this.deleteTestCase(testCase.id), title: "Delete this test" }, "\uD83D\uDDD1\uFE0F")))))), h("div", { key: '678932d3554c7ef2c86373bc4c972eb0f9894916', class: "add-test-case" }, h("button", { key: '7f8447a4681214320647c55e06d1cfc0fc87b3fb', class: "btn btn-outline", onClick: () => this.addNewTestCase() }, "+ Add Question")))));
265
+ }
266
+ static get is() { return "llm-test-runner"; }
267
+ static get encapsulation() { return "shadow"; }
268
+ static get originalStyleUrls() {
269
+ return {
270
+ "$": ["llm-test-runner.css"]
271
+ };
272
+ }
273
+ static get styleUrls() {
274
+ return {
275
+ "$": ["llm-test-runner.css"]
276
+ };
277
+ }
278
+ static get properties() {
279
+ return {
280
+ "apiKey": {
281
+ "type": "string",
282
+ "mutable": false,
283
+ "complexType": {
284
+ "original": "string",
285
+ "resolved": "string",
286
+ "references": {}
287
+ },
288
+ "required": false,
289
+ "optional": false,
290
+ "docs": {
291
+ "tags": [],
292
+ "text": ""
293
+ },
294
+ "getter": false,
295
+ "setter": false,
296
+ "reflect": false,
297
+ "attribute": "api-key"
298
+ }
299
+ };
300
+ }
301
+ static get states() {
302
+ return {
303
+ "testCases": {},
304
+ "isRunningAll": {},
305
+ "error": {},
306
+ "isExportingTestSuite": {}
307
+ };
308
+ }
309
+ }
310
+ //# sourceMappingURL=llm-test-runner.js.map
@@ -0,0 +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 { Component, State, Prop, h } from '@stencil/core';\nimport { LLMEvaluationEngine } from '../../lib/evaluation/evaluation-engine';\nimport { EvaluationRequest, EvaluationResult } from '../../lib/evaluation/types';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ErrorMessage } from '../error-message/error-message';\n\nexport interface TestCase {\n id: string;\n question: string;\n expectedKeywords: string[];\n expectedSourceLinks: string[];\n output?: string;\n isRunning?: boolean;\n error?: string;\n evaluationResult?: EvaluationResult;\n}\n\n@Component({\n tag: 'llm-test-runner',\n styleUrl: 'llm-test-runner.css',\n shadow: true,\n})\nexport class LLMTestRunner {\n @Prop() apiKey: string;\n \n @State() testCases: TestCase[] = [\n {\n id: '1',\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n }\n ];\n @State() isRunningAll: boolean = false;\n @State() error: string = '';\n\n private fileInput!: HTMLInputElement;\n @State() isExportingTestSuite: boolean = false;\n\n private evaluationEngine: LLMEvaluationEngine;\n private apiUrl: string = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';\n\n async componentWillLoad() {\n this.evaluationEngine = new LLMEvaluationEngine();\n \n console.log('🔍 componentWillLoad - apiKey:', this.apiKey ? 'SET' : 'NOT SET');\n console.log('🔍 componentWillLoad - apiKey value:', this.apiKey);\n \n if (!this.apiKey) {\n throw new Error('API key is required. Please provide the apiKey prop: <llm-test-runner apiKey=\"your-api-key\" />');\n }\n }\n\n\n componentDidLoad() {\n }\n\n disconnectedCallback() {\n }\n\n private addNewTestCase() {\n const newTestCase: TestCase = {\n id: this.generateId(),\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n };\n this.testCases = [...this.testCases, newTestCase];\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) {\n console.log('🚀 Starting test for question:', testCase.question);\n \n this.updateTestCase(testCase.id, { isRunning: true });\n \n try {\n const aiResponse = await this.callGeminiAPI(testCase.question);\n console.log('✅ AI call completed for test case:', testCase.id);\n \n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null\n });\n \n await this.evaluateResponse({\n ...testCase,\n output: aiResponse\n });\n \n } catch (error) {\n console.error('❌ Error in runSingleTest:', error);\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n }\n\n private deleteTestCase(id: string) {\n this.testCases = this.testCases.filter(tc => tc.id !== id);\n }\n\n private addKeyword(testCaseId: string, keyword: string) {\n if (keyword.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedKeywords: [...testCase.expectedKeywords, keyword.trim()]\n });\n }\n }\n }\n\n private removeKeyword(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newKeywords = testCase.expectedKeywords.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedKeywords: newKeywords });\n }\n }\n\n private addSourceLink(testCaseId: string, link: string) {\n if (link.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedSourceLinks: [...testCase.expectedSourceLinks, link.trim()]\n });\n }\n }\n }\n\n private removeSourceLink(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newLinks = testCase.expectedSourceLinks.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedSourceLinks: newLinks });\n }\n }\n\n private async callGeminiAPI(prompt: string): Promise<string> {\n console.log('🔍 callGeminiAPI - apiKey:', this.apiKey ? 'SET' : 'NOT SET');\n console.log('🔍 callGeminiAPI - apiKey value:', this.apiKey ? `${this.apiKey.substring(0, 10)}...` : 'undefined');\n \n if (!this.apiKey) {\n throw new Error('API key is required. Please provide the apiKey prop.');\n }\n\n const requestBody = {\n contents: [{\n parts: [{\n text: prompt\n }]\n }]\n };\n\n const response = await fetch(`${this.apiUrl}?key=${this.apiKey}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody)\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n \n if (data.candidates && data.candidates[0] && data.candidates[0].content) {\n return data.candidates[0].content.parts[0].text;\n } else {\n throw new Error('Unexpected response format from Gemini API');\n }\n }\n\n private async evaluateResponse(testCase: TestCase): Promise<void> {\n if (!testCase.output) {\n console.warn('⚠️ No output to evaluate for test case:', testCase.id);\n return;\n }\n\n const evaluationRequest: EvaluationRequest = {\n testCaseId: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks,\n actualResponse: testCase.output\n };\n\n await this.evaluationEngine.evaluateResponse(evaluationRequest, (result: EvaluationResult) => {\n console.log('📊 Evaluation result received:', result);\n \n this.updateTestCase(testCase.id, {\n evaluationResult: result\n });\n });\n }\n\n private async runAllTests() {\n this.isRunningAll = true;\n \n for (const testCase of this.testCases) {\n if (!testCase.isRunning && testCase.question.trim()) {\n await this.runSingleTest(testCase);\n // Delay between tests to avoid rate limiting\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n }\n this.isRunningAll = false;\n }\n\n private generateId(): string {\n return uuidv4();\n }\n\n private handleFileSelect(): void {\n this.fileInput.click();\n }\n\n private async handleFileChange(event: Event): Promise<void> {\n const target = event.target as HTMLInputElement;\n const file = target.files?.[0];\n\n // Immediately clear the input value to allow for a new upload.\n target.value = '';\n\n if (!file) {\n this.error = 'No file selected.';\n return;\n }\n\n const isJsonType = file.type === 'application/json';\n const isJsonExtension = file.name.toLowerCase().endsWith('.json');\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 this.readFileAsync(file);\n const fileContent = JSON.parse(content);\n\n if (!Array.isArray(fileContent)) {\n throw new Error(\"Invalid JSON structure. Expected a JSON array.\");\n } \n const importedTestCases: TestCase[] = fileContent.map((item) => ({\n id: this.generateId(),\n question: item.question || '',\n expectedKeywords: Array.isArray(item.expectedKeywords) ? item.expectedKeywords : [],\n expectedSourceLinks: Array.isArray(item.expectedSourceLinks) ? item.expectedSourceLinks : [],\n isRunning: false\n }));\n this.testCases = importedTestCases; \n } catch (err) {\n this.error = err?.message || 'Error processing file. Please ensure it is a valid JSON array.';\n console.error('File Processing Error:', err);\n }\n }\n\n private readFileAsync(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsText(file);\n });\n }\n\n private downloadFile(content: string, filename: string, mimeType: string) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n private async handleExportTestSuite() {\n this.isExportingTestSuite = true;\n try {\n // Exporting only input data (question, expected keywords, expected source links)\n const exportData = this.testCases.map(testCase => ({\n id: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks\n }));\n\n const jsonContent = JSON.stringify(exportData, null, 2);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n this.downloadFile(jsonContent, 'test-suite.json', 'application/json');\n } finally {\n this.isExportingTestSuite = false;\n }\n }\n\n render() {\n return (\n <div class=\"test-runner-container\">\n <header class=\"test-runner-header\">\n <div class=\"header-left\">\n <input\n class=\"hidden\"\n type=\"file\"\n ref={(el) => (this.fileInput = el as HTMLInputElement)}\n onChange={(e) => this.handleFileChange(e)}\n accept=\".json,application/json\"\n />\n <button class=\"btn btn-secondary\" onClick={() => this.handleFileSelect()}>\n <span class=\"icon\">↑</span>\n Import Test Suite\n </button>\n <button\n class=\"btn btn-secondary\"\n onClick={() => this.handleExportTestSuite()}\n disabled={this.isExportingTestSuite}\n >\n <span class=\"icon\">\n {this.isExportingTestSuite ? '⏳' : '↓'}\n </span>\n {this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite'}\n </button>\n </div>\n \n <div class=\"header-right\">\n <button class=\"btn btn-secondary\">\n <span class=\"icon\">⚙️</span>\n Prompt Editor\n </button>\n <button class=\"btn btn-secondary\">\n <span class=\"icon\">↓</span>\n Export Test Results\n </button>\n <button \n class=\"btn btn-primary\" \n onClick={() => this.runAllTests()}\n disabled={this.isRunningAll}\n >\n {this.isRunningAll ? 'Running...' : 'Run All'}\n </button>\n </div>\n </header>\n <ErrorMessage\n message={this.error}\n onClear={() => (this.error = '')}\n />\n <div class=\"test-runner-content\">\n <div class=\"column-headers\">\n <div class=\"column-header\">Input</div>\n <div class=\"column-header\">Output</div>\n <div class=\"column-header\">Evaluation</div>\n <div class=\"column-header\">Actions</div>\n </div>\n\n <div class=\"test-cases\">\n {this.testCases.map((testCase) => (\n <div class=\"test-case-row\" key={testCase.id}>\n <div class=\"input-column\">\n <div class=\"input-group\">\n <label>Question</label>\n <textarea\n value={testCase.question}\n onInput={(e) => this.updateTestCase(testCase.id, { \n question: (e.target as HTMLTextAreaElement).value \n })}\n placeholder=\"Enter your question here...\"\n rows={3}\n ></textarea>\n </div>\n \n <div class=\"keywords-group\">\n <label>Expected keywords</label>\n <div class=\"tags-container\">\n {testCase.expectedKeywords.map((keyword, index) => (\n <span class=\"tag\" key={index}>\n {keyword}\n <button \n class=\"tag-remove\" \n onClick={() => this.removeKeyword(testCase.id, index)}\n >×</button>\n </span>\n ))}\n <input\n type=\"text\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addKeyword(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n \n <div class=\"links-group\">\n <label>Expected source links</label>\n <div class=\"links-container\">\n {testCase.expectedSourceLinks.map((link, index) => (\n <div class=\"link-item\" key={index}>\n <a href={link} target=\"_blank\" rel=\"noopener noreferrer\">{link}</a>\n <button \n class=\"link-remove\" \n onClick={() => this.removeSourceLink(testCase.id, index)}\n >×</button>\n </div>\n ))}\n <input\n type=\"url\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addSourceLink(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n </div>\n\n <div class=\"output-column\">\n {testCase.output ? (\n <div class=\"output-content\">\n {testCase.output}\n </div>\n ) : (\n <div class=\"output-placeholder\">\n {testCase.isRunning ? 'Running...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"evaluation-column\">\n {testCase.evaluationResult ? (\n <div class=\"evaluation-result\">\n <div class={`evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}`}>\n {testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'}\n </div>\n <div class=\"evaluation-details\">\n Keywords: {testCase.evaluationResult.keywordMatches.filter(m => m.found).length}/{testCase.evaluationResult.keywordMatches.length} found\n </div>\n </div>\n ) : (\n <div class=\"evaluation-placeholder\">\n {testCase.isRunning ? 'Evaluating...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"actions-column\">\n <button \n class=\"btn btn-icon btn-run\"\n onClick={() => this.runSingleTest(testCase)}\n disabled={testCase.isRunning || !testCase.question.trim()}\n title={!testCase.question.trim() ? \"Enter a question first\" : \"Run this test\"}\n >\n {testCase.isRunning ? '⏳' : '▶️'}\n </button>\n <button \n class=\"btn btn-icon btn-delete\"\n onClick={() => this.deleteTestCase(testCase.id)}\n title=\"Delete this test\"\n >\n 🗑️\n </button>\n </div>\n </div>\n ))}\n </div>\n\n <div class=\"add-test-case\">\n <button class=\"btn btn-outline\" onClick={() => this.addNewTestCase()}>\n + Add Question\n </button>\n </div>\n </div>\n </div>\n );\n }\n}"]}
@@ -1,11 +1,5 @@
1
- /**
2
- * @fileoverview entry point for your component library
3
- *
4
- * This is the entry point for your component library. Use this file to export utilities,
5
- * constants or data structure that accompany your components.
6
- *
7
- * DO NOT use this file to export your components. Instead, use the recommended approaches
8
- * to consume components of this package as outlined in the `README.md`.
9
- */
10
- export { format } from './utils/utils';
1
+ // Core web component exports (vanilla JS)
2
+ export { LLMTestRunner } from './components/llm-test-runner/llm-test-runner';
3
+ // Note: React components are available via the /react subpath export
4
+ // import { LlmTestRunner } from 'llm-testrunner-components/react';
11
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC","sourcesContent":["/**\n * @fileoverview entry point for your component library\n *\n * This is the entry point for your component library. Use this file to export utilities,\n * constants or data structure that accompany your components.\n *\n * DO NOT use this file to export your components. Instead, use the recommended approaches\n * to consume components of this package as outlined in the `README.md`.\n */\n\nexport { format } from './utils/utils';\nexport type * from './components.d.ts';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAI7E,qEAAqE;AACrE,mEAAmE","sourcesContent":["// Core web component exports (vanilla JS)\nexport { LLMTestRunner } from './components/llm-test-runner/llm-test-runner';\nexport type { TestCase } from './components/llm-test-runner/llm-test-runner';\nexport type * from './components.d.ts';\n\n// Note: React components are available via the /react subpath export\n// import { LlmTestRunner } from 'llm-testrunner-components/react';\n"]}
@@ -0,0 +1,61 @@
1
+ export class LLMEvaluationEngine {
2
+ constructor() { }
3
+ async evaluateResponse(request, callback) {
4
+ try {
5
+ console.log('🔍 Starting evaluation for test case:', request.testCaseId);
6
+ const result = await this.performEvaluation(request);
7
+ console.log('Evaluation completed for test case:', request.testCaseId);
8
+ console.log('Result:', result);
9
+ callback(result);
10
+ }
11
+ catch (error) {
12
+ console.error('Evaluation failed:', error);
13
+ const errorResult = {
14
+ testCaseId: request.testCaseId,
15
+ passed: false,
16
+ keywordMatches: [],
17
+ sourceLinkMatches: [],
18
+ timestamp: new Date().toISOString()
19
+ };
20
+ callback(errorResult);
21
+ }
22
+ }
23
+ async performEvaluation(request) {
24
+ const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;
25
+ const keywordMatches = this.evaluateKeywords(expectedKeywords, actualResponse);
26
+ const sourceLinkMatches = this.evaluateSourceLinks(expectedSourceLinks, actualResponse);
27
+ // Test passes only if ALL expected keywords and source links are found
28
+ const totalItems = keywordMatches.length + sourceLinkMatches.length;
29
+ const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;
30
+ const passed = foundItems === totalItems;
31
+ return {
32
+ testCaseId,
33
+ passed,
34
+ keywordMatches,
35
+ sourceLinkMatches,
36
+ timestamp: new Date().toISOString()
37
+ };
38
+ }
39
+ evaluateKeywords(expectedKeywords, actualResponse) {
40
+ // Case-insensitive keyword matching
41
+ const response = actualResponse.toLowerCase();
42
+ return expectedKeywords.map(keyword => {
43
+ const keywordToMatch = keyword.toLowerCase();
44
+ const found = response.includes(keywordToMatch);
45
+ return {
46
+ keyword,
47
+ found
48
+ };
49
+ });
50
+ }
51
+ evaluateSourceLinks(expectedSourceLinks, actualResponse) {
52
+ return expectedSourceLinks.map(link => {
53
+ const found = actualResponse.includes(link);
54
+ return {
55
+ link,
56
+ found
57
+ };
58
+ });
59
+ }
60
+ }
61
+ //# sourceMappingURL=evaluation-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-engine.js","sourceRoot":"","sources":["../../../src/lib/evaluation/evaluation-engine.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,mBAAmB;IAC9B,gBAAgB,CAAC;IAEjB,KAAK,CAAC,gBAAgB,CACpB,OAA0B,EAC1B,QAA4B;QAE5B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAEzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAErD,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAE/B,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;YAE3C,MAAM,WAAW,GAAqB;gBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,KAAK;gBACb,cAAc,EAAE,EAAE;gBAClB,iBAAiB,EAAE,EAAE;gBACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YAEF,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,OAA0B;QACxD,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAEtF,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;QAC/E,MAAM,iBAAiB,GAAG,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;QAExF,uEAAuE;QACvE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC;QACpE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QAC9G,MAAM,MAAM,GAAG,UAAU,KAAK,UAAU,CAAC;QAEzC,OAAO;YACL,UAAU;YACV,MAAM;YACN,cAAc;YACd,iBAAiB;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,gBAA0B,EAAE,cAAsB;QACzE,oCAAoC;QACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;QAE9C,OAAO,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YACpC,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAEhD,OAAO;gBACL,OAAO;gBACP,KAAK;aACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,mBAAmB,CAAC,mBAA6B,EAAE,cAAsB;QAC/E,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACpC,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAE5C,OAAO;gBACL,IAAI;gBACJ,KAAK;aACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CAIF","sourcesContent":["import {\n EvaluationRequest,\n EvaluationResult,\n KeywordMatch,\n SourceLinkMatch,\n EvaluationCallback\n} from './types';\n\nexport class LLMEvaluationEngine {\n constructor() { }\n\n async evaluateResponse(\n request: EvaluationRequest,\n callback: EvaluationCallback\n ): Promise<void> {\n try {\n console.log('🔍 Starting evaluation for test case:', request.testCaseId);\n\n const result = await this.performEvaluation(request);\n\n console.log('Evaluation completed for test case:', request.testCaseId);\n console.log('Result:', result);\n\n callback(result);\n\n } catch (error) {\n console.error('Evaluation failed:', error);\n\n const errorResult: EvaluationResult = {\n testCaseId: request.testCaseId,\n passed: false,\n keywordMatches: [],\n sourceLinkMatches: [],\n timestamp: new Date().toISOString()\n };\n\n callback(errorResult);\n }\n }\n\n private async performEvaluation(request: EvaluationRequest): Promise<EvaluationResult> {\n const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;\n\n const keywordMatches = this.evaluateKeywords(expectedKeywords, actualResponse);\n const sourceLinkMatches = this.evaluateSourceLinks(expectedSourceLinks, actualResponse);\n\n // Test passes only if ALL expected keywords and source links are found\n const totalItems = keywordMatches.length + sourceLinkMatches.length;\n const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;\n const passed = foundItems === totalItems;\n\n return {\n testCaseId,\n passed,\n keywordMatches,\n sourceLinkMatches,\n timestamp: new Date().toISOString()\n };\n }\n\n private evaluateKeywords(expectedKeywords: string[], actualResponse: string): KeywordMatch[] {\n // Case-insensitive keyword matching\n const response = actualResponse.toLowerCase();\n\n return expectedKeywords.map(keyword => {\n const keywordToMatch = keyword.toLowerCase();\n const found = response.includes(keywordToMatch);\n\n return {\n keyword,\n found\n };\n });\n }\n\n private evaluateSourceLinks(expectedSourceLinks: string[], actualResponse: string): SourceLinkMatch[] {\n return expectedSourceLinks.map(link => {\n const found = actualResponse.includes(link);\n\n return {\n link,\n found\n };\n });\n }\n\n\n\n}\n\n"]}
@@ -0,0 +1,7 @@
1
+ import { LLMEvaluationEngine } from "./evaluation-engine";
2
+ export { LLMEvaluationEngine };
3
+ export async function evaluateLLMResponse(request, callback) {
4
+ const engine = new LLMEvaluationEngine();
5
+ await engine.evaluateResponse(request, callback);
6
+ }
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/evaluation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAS1D,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAS/B,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA0B,EAC1B,QAA4B;IAE5B,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IACzC,MAAM,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import { LLMEvaluationEngine } from './evaluation-engine';\nimport type {\n EvaluationRequest,\n EvaluationResult,\n KeywordMatch,\n SourceLinkMatch,\n EvaluationCallback\n} from './types';\n\nexport { LLMEvaluationEngine };\nexport type {\n EvaluationRequest,\n EvaluationResult,\n KeywordMatch,\n SourceLinkMatch,\n EvaluationCallback\n};\n\nexport async function evaluateLLMResponse(\n request: EvaluationRequest,\n callback: EvaluationCallback\n): Promise<void> {\n const engine = new LLMEvaluationEngine();\n await engine.evaluateResponse(request, callback);\n}\n\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/evaluation/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface EvaluationRequest {\n testCaseId: string;\n question: string;\n expectedKeywords: string[];\n expectedSourceLinks: string[];\n actualResponse: string;\n}\n\nexport interface EvaluationResult {\n testCaseId: string;\n passed: boolean;\n keywordMatches: KeywordMatch[];\n sourceLinkMatches: SourceLinkMatch[];\n timestamp?: string;\n}\n\nexport interface KeywordMatch {\n keyword: string;\n found: boolean;\n}\n\nexport interface SourceLinkMatch {\n link: string;\n found: boolean;\n}\n\nexport type EvaluationCallback = (result: EvaluationResult) => void;\n\n"]}