@memberjunction/testing-engine 0.0.1 → 2.119.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +403 -29
  2. package/dist/drivers/AgentEvalDriver.d.ts +197 -0
  3. package/dist/drivers/AgentEvalDriver.d.ts.map +1 -0
  4. package/dist/drivers/AgentEvalDriver.js +370 -0
  5. package/dist/drivers/AgentEvalDriver.js.map +1 -0
  6. package/dist/drivers/BaseTestDriver.d.ts +145 -0
  7. package/dist/drivers/BaseTestDriver.d.ts.map +1 -0
  8. package/dist/drivers/BaseTestDriver.js +266 -0
  9. package/dist/drivers/BaseTestDriver.js.map +1 -0
  10. package/dist/drivers/index.d.ts +6 -0
  11. package/dist/drivers/index.d.ts.map +1 -0
  12. package/dist/drivers/index.js +22 -0
  13. package/dist/drivers/index.js.map +1 -0
  14. package/dist/engine/TestEngine.d.ts +148 -0
  15. package/dist/engine/TestEngine.d.ts.map +1 -0
  16. package/dist/engine/TestEngine.js +490 -0
  17. package/dist/engine/TestEngine.js.map +1 -0
  18. package/dist/index.d.ts +20 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +42 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/oracles/ExactMatchOracle.d.ts +98 -0
  23. package/dist/oracles/ExactMatchOracle.d.ts.map +1 -0
  24. package/dist/oracles/ExactMatchOracle.js +355 -0
  25. package/dist/oracles/ExactMatchOracle.js.map +1 -0
  26. package/dist/oracles/IOracle.d.ts +47 -0
  27. package/dist/oracles/IOracle.d.ts.map +1 -0
  28. package/dist/oracles/IOracle.js +7 -0
  29. package/dist/oracles/IOracle.js.map +1 -0
  30. package/dist/oracles/LLMJudgeOracle.d.ts +65 -0
  31. package/dist/oracles/LLMJudgeOracle.d.ts.map +1 -0
  32. package/dist/oracles/LLMJudgeOracle.js +214 -0
  33. package/dist/oracles/LLMJudgeOracle.js.map +1 -0
  34. package/dist/oracles/SQLValidatorOracle.d.ts +78 -0
  35. package/dist/oracles/SQLValidatorOracle.d.ts.map +1 -0
  36. package/dist/oracles/SQLValidatorOracle.js +215 -0
  37. package/dist/oracles/SQLValidatorOracle.js.map +1 -0
  38. package/dist/oracles/SchemaValidatorOracle.d.ts +61 -0
  39. package/dist/oracles/SchemaValidatorOracle.d.ts.map +1 -0
  40. package/dist/oracles/SchemaValidatorOracle.js +193 -0
  41. package/dist/oracles/SchemaValidatorOracle.js.map +1 -0
  42. package/dist/oracles/TraceValidatorOracle.d.ts +41 -0
  43. package/dist/oracles/TraceValidatorOracle.d.ts.map +1 -0
  44. package/dist/oracles/TraceValidatorOracle.js +159 -0
  45. package/dist/oracles/TraceValidatorOracle.js.map +1 -0
  46. package/dist/oracles/index.d.ts +10 -0
  47. package/dist/oracles/index.d.ts.map +1 -0
  48. package/dist/oracles/index.js +26 -0
  49. package/dist/oracles/index.js.map +1 -0
  50. package/dist/types.d.ts +428 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +6 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/cost-calculator.d.ts +92 -0
  55. package/dist/utils/cost-calculator.d.ts.map +1 -0
  56. package/dist/utils/cost-calculator.js +137 -0
  57. package/dist/utils/cost-calculator.js.map +1 -0
  58. package/dist/utils/result-formatter.d.ts +98 -0
  59. package/dist/utils/result-formatter.d.ts.map +1 -0
  60. package/dist/utils/result-formatter.js +252 -0
  61. package/dist/utils/result-formatter.js.map +1 -0
  62. package/dist/utils/scoring.d.ts +64 -0
  63. package/dist/utils/scoring.d.ts.map +1 -0
  64. package/dist/utils/scoring.js +140 -0
  65. package/dist/utils/scoring.js.map +1 -0
  66. package/package.json +36 -7
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview LLM Judge oracle implementation
4
+ * @module @memberjunction/testing-engine
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.LLMJudgeOracle = void 0;
8
+ const ai_core_plus_1 = require("@memberjunction/ai-core-plus");
9
+ const ai_prompts_1 = require("@memberjunction/ai-prompts");
10
+ const aiengine_1 = require("@memberjunction/aiengine");
11
+ /**
12
+ * LLM Judge Oracle.
13
+ *
14
+ * Uses an LLM to evaluate output quality based on custom criteria.
15
+ * Provides semantic evaluation beyond deterministic checks.
16
+ *
17
+ * Configuration:
18
+ * - criteria: Array of validation criteria (required)
19
+ * - model: Model to use for judging (default: from prompt or default model)
20
+ * - temperature: Temperature for LLM (default: 0.1 for consistency)
21
+ * - promptTemplate: Custom prompt template (optional, uses default if not provided)
22
+ * - strictMode: Require all criteria to pass (default: false, uses weighted scoring)
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const oracle = new LLMJudgeOracle();
27
+ * const result = await oracle.evaluate({
28
+ * actualOutput: { response: 'Sales by region report created successfully' },
29
+ * expectedOutput: {
30
+ * judgeValidationCriteria: [
31
+ * 'Response accurately answers the user\'s question',
32
+ * 'Response includes actionable information',
33
+ * 'Response is professional and clear'
34
+ * ]
35
+ * },
36
+ * contextUser
37
+ * }, {
38
+ * model: 'claude-sonnet-4',
39
+ * temperature: 0.1
40
+ * });
41
+ * ```
42
+ */
43
+ class LLMJudgeOracle {
44
+ constructor() {
45
+ this.type = 'llm-judge';
46
+ /**
47
+ * Default prompt template for LLM judge.
48
+ * @private
49
+ */
50
+ this.defaultPromptTemplate = `You are an expert AI evaluator. Your task is to judge whether an AI agent's output meets the specified validation criteria.
51
+
52
+ **Input:**
53
+ {{input}}
54
+
55
+ **Expected Output Requirements:**
56
+ {{expected}}
57
+
58
+ **Actual Output:**
59
+ {{actual}}
60
+
61
+ **Validation Criteria:**
62
+ {{criteria}}
63
+
64
+ **Instructions:**
65
+ For each criterion, evaluate whether the actual output satisfies it. Provide:
66
+ 1. A score from 0.0 to 1.0 for each criterion
67
+ 2. A brief explanation for each score
68
+ 3. An overall assessment
69
+
70
+ Respond in JSON format:
71
+ {
72
+ "criteriaScores": [
73
+ { "criterion": "...", "score": 0.0-1.0, "explanation": "..." }
74
+ ],
75
+ "overallScore": 0.0-1.0,
76
+ "overallAssessment": "...",
77
+ "passed": true/false
78
+ }`;
79
+ }
80
+ /**
81
+ * Evaluate output using LLM judge.
82
+ *
83
+ * @param input - Oracle input with expected criteria and actual output
84
+ * @param config - Oracle configuration
85
+ * @returns Oracle result with LLM judgment
86
+ */
87
+ async evaluate(input, config) {
88
+ try {
89
+ // Ensure AIEngine is configured
90
+ await aiengine_1.AIEngine.Instance.Config(false, input.contextUser);
91
+ // Get criteria from expected outcomes or config
92
+ const criteria = input.expectedOutput?.judgeValidationCriteria ||
93
+ config.criteria;
94
+ if (!criteria || criteria.length === 0) {
95
+ return {
96
+ oracleType: this.type,
97
+ passed: false,
98
+ score: 0,
99
+ message: 'No validation criteria provided'
100
+ };
101
+ }
102
+ // Find the LLM Judge prompt from AIEngine
103
+ const judgePrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Test LLM Judge' || p.Name.toLowerCase().includes('llm judge'));
104
+ if (!judgePrompt) {
105
+ return {
106
+ oracleType: this.type,
107
+ passed: false,
108
+ score: 0,
109
+ message: 'LLM Judge prompt not found in AIEngine.Instance.Prompts. Please create a prompt named "Test LLM Judge".'
110
+ };
111
+ }
112
+ // Prepare data for prompt template
113
+ const inputDefinition = input.test.InputDefinition ?
114
+ (typeof input.test.InputDefinition === 'string' ?
115
+ JSON.parse(input.test.InputDefinition) :
116
+ input.test.InputDefinition) :
117
+ {};
118
+ const promptData = {
119
+ input: JSON.stringify(inputDefinition, null, 2),
120
+ expected: JSON.stringify(input.expectedOutput, null, 2),
121
+ actual: JSON.stringify(input.actualOutput, null, 2),
122
+ criteria: criteria.map((c, i) => `${i + 1}. ${c}`).join('\n')
123
+ };
124
+ // Execute LLM judgment
125
+ const promptParams = new ai_core_plus_1.AIPromptParams();
126
+ promptParams.prompt = judgePrompt;
127
+ promptParams.data = promptData;
128
+ promptParams.contextUser = input.contextUser;
129
+ const runner = new ai_prompts_1.AIPromptRunner();
130
+ const result = await runner.ExecutePrompt(promptParams);
131
+ if (!result.success) {
132
+ return {
133
+ oracleType: this.type,
134
+ passed: false,
135
+ score: 0,
136
+ message: `LLM judgment failed: ${result.errorMessage}`
137
+ };
138
+ }
139
+ // Parse LLM response
140
+ const judgment = this.parseJudgment(result.result);
141
+ // Determine pass/fail
142
+ const strictMode = config.strictMode;
143
+ const passed = strictMode
144
+ ? judgment.criteriaScores.every(s => s.score >= 0.8)
145
+ : judgment.overallScore >= 0.7;
146
+ return {
147
+ oracleType: this.type,
148
+ passed,
149
+ score: judgment.overallScore,
150
+ message: judgment.overallAssessment,
151
+ details: {
152
+ criteriaScores: judgment.criteriaScores,
153
+ llmModel: config.model || 'default',
154
+ llmCost: result.cost
155
+ }
156
+ };
157
+ }
158
+ catch (error) {
159
+ return {
160
+ oracleType: this.type,
161
+ passed: false,
162
+ score: 0,
163
+ message: `LLM judge error: ${error.message}`
164
+ };
165
+ }
166
+ }
167
+ /**
168
+ * Build prompt for LLM judge.
169
+ * @private
170
+ */
171
+ buildPrompt(input, criteria, customTemplate) {
172
+ const template = customTemplate || this.defaultPromptTemplate;
173
+ // Format input data
174
+ const inputStr = JSON.stringify(input.test.InputDefinition, null, 2);
175
+ const expectedStr = JSON.stringify(input.expectedOutput, null, 2);
176
+ const actualStr = JSON.stringify(input.actualOutput, null, 2);
177
+ const criteriaStr = criteria.map((c, i) => `${i + 1}. ${c}`).join('\n');
178
+ // Replace placeholders
179
+ return template
180
+ .replace('{{input}}', inputStr)
181
+ .replace('{{expected}}', expectedStr)
182
+ .replace('{{actual}}', actualStr)
183
+ .replace('{{criteria}}', criteriaStr);
184
+ }
185
+ /**
186
+ * Parse LLM judgment response.
187
+ * @private
188
+ */
189
+ parseJudgment(response) {
190
+ try {
191
+ // Try to extract JSON from response
192
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
193
+ if (!jsonMatch) {
194
+ throw new Error('No JSON found in LLM response');
195
+ }
196
+ const parsed = JSON.parse(jsonMatch[0]);
197
+ return {
198
+ criteriaScores: parsed.criteriaScores || [],
199
+ overallScore: parsed.overallScore || 0,
200
+ overallAssessment: parsed.overallAssessment || 'No assessment provided'
201
+ };
202
+ }
203
+ catch (error) {
204
+ // Fallback to simple parsing
205
+ return {
206
+ criteriaScores: [],
207
+ overallScore: 0,
208
+ overallAssessment: `Failed to parse LLM response: ${response.substring(0, 200)}`
209
+ };
210
+ }
211
+ }
212
+ }
213
+ exports.LLMJudgeOracle = LLMJudgeOracle;
214
+ //# sourceMappingURL=LLMJudgeOracle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LLMJudgeOracle.js","sourceRoot":"","sources":["../../src/oracles/LLMJudgeOracle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @fileoverview SQL validation oracle implementation
3
+ * @module @memberjunction/testing-engine
4
+ */
5
+ import { IOracle } from './IOracle';
6
+ import { OracleInput, OracleConfig, OracleResult } from '../types';
7
+ /**
8
+ * SQL Validator Oracle.
9
+ *
10
+ * Validates database state by executing SQL queries and comparing results.
11
+ * Useful for testing that agent actions had the expected database effects.
12
+ *
13
+ * Configuration:
14
+ * - queries: Array of SQL validation queries
15
+ * - requireAll: Whether all queries must pass (default: true)
16
+ *
17
+ * Each query object contains:
18
+ * - sql: The SQL query to execute
19
+ * - expectedResult: Expected result (can be value, row count, or boolean)
20
+ * - description: Human-readable description of what the query validates
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const oracle = new SQLValidatorOracle();
25
+ * const result = await oracle.evaluate({
26
+ * expectedOutput: {
27
+ * sqlValidations: [
28
+ * {
29
+ * sql: "SELECT COUNT(*) FROM Reports WHERE Name LIKE '%Sales%'",
30
+ * expectedResult: { count: 1 },
31
+ * description: "Sales report was created"
32
+ * },
33
+ * {
34
+ * sql: "SELECT Status FROM Reports WHERE ID = @ReportID",
35
+ * expectedResult: { status: 'Published' },
36
+ * description: "Report status is Published"
37
+ * }
38
+ * ]
39
+ * },
40
+ * actualOutput: {
41
+ * reportId: 'abc-123'
42
+ * },
43
+ * contextUser
44
+ * }, {});
45
+ * ```
46
+ */
47
+ export declare class SQLValidatorOracle implements IOracle {
48
+ readonly type = "sql-validate";
49
+ /**
50
+ * Evaluate database state using SQL queries.
51
+ *
52
+ * @param input - Oracle input with SQL validations and actual output
53
+ * @param config - Oracle configuration
54
+ * @returns Oracle result with query validation details
55
+ */
56
+ evaluate(input: OracleInput, config: OracleConfig): Promise<OracleResult>;
57
+ /**
58
+ * Execute a single validation query.
59
+ * @private
60
+ */
61
+ private executeValidation;
62
+ /**
63
+ * Replace parameters in SQL query with actual values.
64
+ * @private
65
+ */
66
+ private replaceParameters;
67
+ /**
68
+ * Extract result from query result set.
69
+ * @private
70
+ */
71
+ private extractResult;
72
+ /**
73
+ * Compare expected and actual results.
74
+ * @private
75
+ */
76
+ private compareResults;
77
+ }
78
+ //# sourceMappingURL=SQLValidatorOracle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SQLValidatorOracle.d.ts","sourceRoot":"","sources":["../../src/oracles/SQLValidatorOracle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,kBAAmB,YAAW,OAAO;IAC9C,QAAQ,CAAC,IAAI,kBAAkB;IAE/B;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAgE/E;;;OAGG;YACW,iBAAiB;IAqD/B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA8BzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAqBrB;;;OAGG;IACH,OAAO,CAAC,cAAc;CA4BzB"}
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview SQL validation oracle implementation
4
+ * @module @memberjunction/testing-engine
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SQLValidatorOracle = void 0;
8
+ const core_1 = require("@memberjunction/core");
9
+ /**
10
+ * SQL Validator Oracle.
11
+ *
12
+ * Validates database state by executing SQL queries and comparing results.
13
+ * Useful for testing that agent actions had the expected database effects.
14
+ *
15
+ * Configuration:
16
+ * - queries: Array of SQL validation queries
17
+ * - requireAll: Whether all queries must pass (default: true)
18
+ *
19
+ * Each query object contains:
20
+ * - sql: The SQL query to execute
21
+ * - expectedResult: Expected result (can be value, row count, or boolean)
22
+ * - description: Human-readable description of what the query validates
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const oracle = new SQLValidatorOracle();
27
+ * const result = await oracle.evaluate({
28
+ * expectedOutput: {
29
+ * sqlValidations: [
30
+ * {
31
+ * sql: "SELECT COUNT(*) FROM Reports WHERE Name LIKE '%Sales%'",
32
+ * expectedResult: { count: 1 },
33
+ * description: "Sales report was created"
34
+ * },
35
+ * {
36
+ * sql: "SELECT Status FROM Reports WHERE ID = @ReportID",
37
+ * expectedResult: { status: 'Published' },
38
+ * description: "Report status is Published"
39
+ * }
40
+ * ]
41
+ * },
42
+ * actualOutput: {
43
+ * reportId: 'abc-123'
44
+ * },
45
+ * contextUser
46
+ * }, {});
47
+ * ```
48
+ */
49
+ class SQLValidatorOracle {
50
+ constructor() {
51
+ this.type = 'sql-validate';
52
+ }
53
+ /**
54
+ * Evaluate database state using SQL queries.
55
+ *
56
+ * @param input - Oracle input with SQL validations and actual output
57
+ * @param config - Oracle configuration
58
+ * @returns Oracle result with query validation details
59
+ */
60
+ async evaluate(input, config) {
61
+ try {
62
+ // Get SQL validations from expected outcomes
63
+ const validations = input.expectedOutput?.sqlValidations || [];
64
+ if (validations.length === 0) {
65
+ return {
66
+ oracleType: this.type,
67
+ passed: false,
68
+ score: 0,
69
+ message: 'No SQL validations provided in ExpectedOutcomes.sqlValidations'
70
+ };
71
+ }
72
+ const requireAll = config.requireAll !== false; // Default true
73
+ const results = [];
74
+ // Execute each validation query
75
+ for (const validation of validations) {
76
+ const queryResult = await this.executeValidation(validation, input.actualOutput, input.contextUser);
77
+ results.push(queryResult);
78
+ }
79
+ // Calculate score and determine pass/fail
80
+ const passedCount = results.filter(r => r.passed).length;
81
+ const totalCount = results.length;
82
+ const score = totalCount > 0 ? passedCount / totalCount : 0;
83
+ const passed = requireAll ? passedCount === totalCount : passedCount > 0;
84
+ return {
85
+ oracleType: this.type,
86
+ passed,
87
+ score,
88
+ message: requireAll
89
+ ? `${passedCount}/${totalCount} validation(s) passed`
90
+ : `At least one validation passed (${passedCount}/${totalCount})`,
91
+ details: { validations: results }
92
+ };
93
+ }
94
+ catch (error) {
95
+ return {
96
+ oracleType: this.type,
97
+ passed: false,
98
+ score: 0,
99
+ message: `SQL validation error: ${error.message}`
100
+ };
101
+ }
102
+ }
103
+ /**
104
+ * Execute a single validation query.
105
+ * @private
106
+ */
107
+ async executeValidation(validation, actualOutput, contextUser) {
108
+ try {
109
+ // Replace parameters in SQL with values from actualOutput
110
+ const sql = this.replaceParameters(validation.sql, actualOutput);
111
+ // Get database provider from Metadata.Provider
112
+ const dbProvider = core_1.Metadata.Provider;
113
+ // Execute the SQL query
114
+ const queryResults = await dbProvider.ExecuteSQL(sql, undefined, // No parameters (already substituted in SQL string)
115
+ { description: validation.description || 'SQL Validation' }, contextUser);
116
+ // Extract result (handle single value, single row, or multiple rows)
117
+ const actualResult = this.extractResult(queryResults);
118
+ // Compare with expected result
119
+ const passed = this.compareResults(validation.expectedResult, actualResult);
120
+ return {
121
+ description: validation.description || 'SQL validation',
122
+ sql: validation.sql,
123
+ passed,
124
+ expected: validation.expectedResult,
125
+ actual: actualResult
126
+ };
127
+ }
128
+ catch (error) {
129
+ return {
130
+ description: validation.description || 'SQL validation',
131
+ sql: validation.sql,
132
+ passed: false,
133
+ expected: validation.expectedResult,
134
+ actual: null,
135
+ error: error.message
136
+ };
137
+ }
138
+ }
139
+ /**
140
+ * Replace parameters in SQL query with actual values.
141
+ * @private
142
+ */
143
+ replaceParameters(sql, actualOutput) {
144
+ if (!actualOutput || typeof actualOutput !== 'object') {
145
+ return sql;
146
+ }
147
+ let result = sql;
148
+ const outputObj = actualOutput;
149
+ // Replace @ParameterName with values from actualOutput
150
+ const paramMatches = sql.matchAll(/@(\w+)/g);
151
+ for (const match of paramMatches) {
152
+ const paramName = match[1];
153
+ const camelCaseParam = paramName.charAt(0).toLowerCase() + paramName.slice(1);
154
+ // Try both original and camelCase versions
155
+ const value = outputObj[paramName] || outputObj[camelCaseParam];
156
+ if (value !== undefined) {
157
+ // Properly escape and quote the value
158
+ const escapedValue = typeof value === 'string'
159
+ ? `'${value.replace(/'/g, "''")}'`
160
+ : String(value);
161
+ result = result.replace(new RegExp(`@${paramName}`, 'g'), escapedValue);
162
+ }
163
+ }
164
+ return result;
165
+ }
166
+ /**
167
+ * Extract result from query result set.
168
+ * @private
169
+ */
170
+ extractResult(results) {
171
+ if (!results || results.length === 0) {
172
+ return null;
173
+ }
174
+ // If single row, single column, return the value
175
+ if (results.length === 1) {
176
+ const row = results[0];
177
+ const keys = Object.keys(row);
178
+ if (keys.length === 1) {
179
+ return row[keys[0]];
180
+ }
181
+ return row;
182
+ }
183
+ // Multiple rows
184
+ return results;
185
+ }
186
+ /**
187
+ * Compare expected and actual results.
188
+ * @private
189
+ */
190
+ compareResults(expected, actual) {
191
+ // Handle null/undefined
192
+ if (expected === null || expected === undefined) {
193
+ return actual === null || actual === undefined;
194
+ }
195
+ // Handle boolean
196
+ if (typeof expected === 'boolean') {
197
+ return Boolean(actual) === expected;
198
+ }
199
+ // Handle number
200
+ if (typeof expected === 'number') {
201
+ return Number(actual) === expected;
202
+ }
203
+ // Handle string
204
+ if (typeof expected === 'string') {
205
+ return String(actual) === expected;
206
+ }
207
+ // Handle object/array
208
+ if (typeof expected === 'object') {
209
+ return JSON.stringify(expected) === JSON.stringify(actual);
210
+ }
211
+ return false;
212
+ }
213
+ }
214
+ exports.SQLValidatorOracle = SQLValidatorOracle;
215
+ //# sourceMappingURL=SQLValidatorOracle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SQLValidatorOracle.js","sourceRoot":"","sources":["../../src/oracles/SQLValidatorOracle.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+CAAgF;AAIhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAa,kBAAkB;IAA/B;QACa,SAAI,GAAG,cAAc,CAAC;IA6NnC,CAAC;IA3NG;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAkB,EAAE,MAAoB;QACnD,IAAI,CAAC;YACD,6CAA6C;YAC7C,MAAM,WAAW,GAAK,KAAK,CAAC,cAAsB,EAAE,cAIjD,IAAI,EAAE,CAAC;YAEV,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO;oBACH,UAAU,EAAE,IAAI,CAAC,IAAI;oBACrB,MAAM,EAAE,KAAK;oBACb,KAAK,EAAE,CAAC;oBACR,OAAO,EAAE,gEAAgE;iBAC5E,CAAC;YACN,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,eAAe;YAC/D,MAAM,OAAO,GAOR,EAAE,CAAC;YAER,gCAAgC;YAChC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC5C,UAAU,EACV,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,WAAW,CACpB,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC;YAED,0CAA0C;YAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;YACzD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;YAClC,MAAM,KAAK,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC;YAEzE,OAAO;gBACH,UAAU,EAAE,IAAI,CAAC,IAAI;gBACrB,MAAM;gBACN,KAAK;gBACL,OAAO,EAAE,UAAU;oBACf,CAAC,CAAC,GAAG,WAAW,IAAI,UAAU,uBAAuB;oBACrD,CAAC,CAAC,mCAAmC,WAAW,IAAI,UAAU,GAAG;gBACrE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE;aACpC,CAAC;QAEN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO;gBACH,UAAU,EAAE,IAAI,CAAC,IAAI;gBACrB,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,yBAA0B,KAAe,CAAC,OAAO,EAAE;aAC/D,CAAC;QACN,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB,CAC3B,UAA0E,EAC1E,YAAqB,EACrB,WAAqB;QASrB,IAAI,CAAC;YACD,0DAA0D;YAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAEjE,+CAA+C;YAC/C,MAAM,UAAU,GAAG,eAAQ,CAAC,QAAgC,CAAC;YAE7D,wBAAwB;YACxB,MAAM,YAAY,GAAG,MAAM,UAAU,CAAC,UAAU,CAC5C,GAAG,EACH,SAAS,EAAG,oDAAoD;YAChE,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,gBAAgB,EAAE,EAC3D,WAAW,CACd,CAAC;YAEF,qEAAqE;YACrE,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;YAEtD,+BAA+B;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YAE5E,OAAO;gBACH,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,gBAAgB;gBACvD,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,MAAM;gBACN,QAAQ,EAAE,UAAU,CAAC,cAAc;gBACnC,MAAM,EAAE,YAAY;aACvB,CAAC;QAEN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO;gBACH,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,gBAAgB;gBACvD,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,UAAU,CAAC,cAAc;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAG,KAAe,CAAC,OAAO;aAClC,CAAC;QACN,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,iBAAiB,CAAC,GAAW,EAAE,YAAqB;QACxD,IAAI,CAAC,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,GAAG,CAAC;QACf,CAAC;QAED,IAAI,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,SAAS,GAAG,YAAuC,CAAC;QAE1D,uDAAuD;QACvD,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAE9E,2CAA2C;YAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC;YAEhE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACtB,sCAAsC;gBACtC,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ;oBAC1C,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG;oBAClC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAEpB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,SAAS,EAAE,EAAE,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;YAC5E,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACK,aAAa,CAAC,OAAkB;QACpC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,iDAAiD;QACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAA4B,CAAC;YAClD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC;YAED,OAAO,GAAG,CAAC;QACf,CAAC;QAED,gBAAgB;QAChB,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,QAAiB,EAAE,MAAe;QACrD,wBAAwB;QACxB,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC9C,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,CAAC;QACnD,CAAC;QAED,iBAAiB;QACjB,IAAI,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC;QACxC,CAAC;QAED,gBAAgB;QAChB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC;QACvC,CAAC;QAED,gBAAgB;QAChB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC;QACvC,CAAC;QAED,sBAAsB;QACtB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ;AA9ND,gDA8NC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview Schema validation oracle implementation
3
+ * @module @memberjunction/testing-engine
4
+ */
5
+ import { IOracle } from './IOracle';
6
+ import { OracleInput, OracleConfig, OracleResult } from '../types';
7
+ /**
8
+ * Schema Validator Oracle.
9
+ *
10
+ * Validates that actual output conforms to an expected JSON schema.
11
+ * Uses JSON Schema draft-07 specification for validation.
12
+ *
13
+ * Configuration:
14
+ * - schema: JSON Schema object defining expected structure
15
+ * - strict: Whether to fail on additional properties (default: false)
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const oracle = new SchemaValidatorOracle();
20
+ * const result = await oracle.evaluate({
21
+ * actualOutput: { name: 'John', age: 30 },
22
+ * expectedOutput: {
23
+ * responseSchema: {
24
+ * type: 'object',
25
+ * required: ['name', 'age'],
26
+ * properties: {
27
+ * name: { type: 'string' },
28
+ * age: { type: 'number' }
29
+ * }
30
+ * }
31
+ * }
32
+ * }, {});
33
+ * ```
34
+ */
35
+ export declare class SchemaValidatorOracle implements IOracle {
36
+ readonly type = "schema-validate";
37
+ /**
38
+ * Evaluate actual output against JSON schema.
39
+ *
40
+ * @param input - Oracle input with expected schema and actual output
41
+ * @param config - Oracle configuration
42
+ * @returns Oracle result with pass/fail and validation details
43
+ */
44
+ evaluate(input: OracleInput, config: OracleConfig): Promise<OracleResult>;
45
+ /**
46
+ * Validate data against JSON schema.
47
+ * @private
48
+ */
49
+ private validateAgainstSchema;
50
+ /**
51
+ * Validate a single value against schema.
52
+ * @private
53
+ */
54
+ private validateValue;
55
+ /**
56
+ * Get JSON Schema type for a value.
57
+ * @private
58
+ */
59
+ private getType;
60
+ }
61
+ //# sourceMappingURL=SchemaValidatorOracle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaValidatorOracle.d.ts","sourceRoot":"","sources":["../../src/oracles/SchemaValidatorOracle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,qBAAsB,YAAW,OAAO;IACjD,QAAQ,CAAC,IAAI,qBAAqB;IAElC;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IA+C/E;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAiFrB;;;OAGG;IACH,OAAO,CAAC,OAAO;CA6BlB"}