langium-ai-tools 4.1.5 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Testing API for langium-ai evaluations
3
+ *
4
+ * Provides a vitest-style API for defining evaluation test cases.
5
+ */
6
+ import type { EvaluatorResult } from '../evaluator/evaluator.js';
7
+ /**
8
+ * Standard data that can be expected from a case
9
+ */
10
+ export type EvaluationData = {
11
+ /**
12
+ * Whether this case passed
13
+ */
14
+ passed: boolean;
15
+ /**
16
+ * Whether this case was skipped (via .skip() or .only() filtering)
17
+ */
18
+ skipped?: boolean;
19
+ /**
20
+ * When passed is false, expect an error here
21
+ */
22
+ error?: Error | string;
23
+ };
24
+ /**
25
+ * Evaluation case result from running the lai cli
26
+ *
27
+ * A modified version of the baseline evaluator result, to accomodate for additional
28
+ * requisite properties (certain metadat for cases + suites & a 'pass' result)
29
+ */
30
+ export type EvaluationCaseResult = EvaluatorResult<EvaluationData> & {
31
+ metadata: {
32
+ /**
33
+ * Containing evaluation file for the associated case
34
+ */
35
+ evalFile: string;
36
+ /**
37
+ * Name of the suite that we ran under
38
+ */
39
+ suiteName: string;
40
+ /**
41
+ * Evaluation case name
42
+ */
43
+ caseName: string;
44
+ /**
45
+ * Duration of evaluation case from start to finish
46
+ */
47
+ duration: number;
48
+ };
49
+ };
50
+ export interface EvalContext {
51
+ systemPrompt: string;
52
+ project: {
53
+ name: string;
54
+ };
55
+ }
56
+ /**
57
+ * Evalutor function definition, takes some context & produce evaluation data
58
+ */
59
+ export type EvaluatorFunction = (ctx: EvalContext) => Promise<EvaluationData>;
60
+ interface EvalDefinition {
61
+ name: string;
62
+ fn: EvaluatorFunction;
63
+ skip?: boolean;
64
+ only?: boolean;
65
+ }
66
+ interface EvalSuite {
67
+ name: string;
68
+ evaluations: EvalDefinition[];
69
+ beforeAllHook?: () => void | Promise<void>;
70
+ afterAllHook?: () => void | Promise<void>;
71
+ beforeEachHook?: () => void | Promise<void>;
72
+ afterEachHook?: () => void | Promise<void>;
73
+ skip?: boolean;
74
+ only?: boolean;
75
+ }
76
+ /**
77
+ * Define a test suite
78
+ */
79
+ export declare function describe(name: string, fn: () => void): void;
80
+ export declare namespace describe {
81
+ var skip: (name: string, fn: () => void) => void;
82
+ var only: (name: string, fn: () => void) => void;
83
+ }
84
+ /**
85
+ * Define an evaluation case
86
+ */
87
+ export declare function evaluation(name: string, fn: EvaluatorFunction): void;
88
+ export declare namespace evaluation {
89
+ var skip: (name: string, fn: EvaluatorFunction) => void;
90
+ var only: (name: string, fn: EvaluatorFunction) => void;
91
+ var each: <T>(cases: T[]) => (name: string, fn: (data: T) => EvaluatorFunction) => void;
92
+ }
93
+ /**
94
+ * Define a hook that runs before each evaluation in the suite
95
+ */
96
+ export declare function beforeEach(fn: () => void | Promise<void>): void;
97
+ /**
98
+ * Define a hook that runs after each evaluation in the suite
99
+ */
100
+ export declare function afterEach(fn: () => void | Promise<void>): void;
101
+ /**
102
+ * Define a hook that runs once before all evaluations in the suite
103
+ */
104
+ export declare function beforeAll(fn: () => void | Promise<void>): void;
105
+ /**
106
+ * Define a hook that runs once after all evaluations in the suite
107
+ */
108
+ export declare function afterAll(fn: () => void | Promise<void>): void;
109
+ /**
110
+ * Export collected suites for runner
111
+ */
112
+ export declare function getCollectedSuites(): EvalSuite[];
113
+ /**
114
+ * Clear all collected suites
115
+ */
116
+ export declare function clearSuites(): void;
117
+ export { runEvalFile, type EvalProgressCallback } from './runner.js';
118
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Testing API for langium-ai evaluations
3
+ *
4
+ * Provides a vitest-style API for defining evaluation test cases.
5
+ */
6
+ const suites = [];
7
+ let currentSuite = null;
8
+ /**
9
+ * Define a test suite
10
+ */
11
+ export function describe(name, fn) {
12
+ const parentSuite = currentSuite;
13
+ currentSuite = { name, evaluations: [] };
14
+ fn();
15
+ suites.push(currentSuite);
16
+ currentSuite = parentSuite;
17
+ }
18
+ /**
19
+ * Define a test suite that will be skipped
20
+ */
21
+ describe.skip = function (name, fn) {
22
+ const parentSuite = currentSuite;
23
+ currentSuite = { name, evaluations: [], skip: true };
24
+ fn();
25
+ suites.push(currentSuite);
26
+ currentSuite = parentSuite;
27
+ };
28
+ /**
29
+ * Define a test suite that will run exclusively (skips all other tests)
30
+ */
31
+ describe.only = function (name, fn) {
32
+ const parentSuite = currentSuite;
33
+ currentSuite = { name, evaluations: [], only: true };
34
+ fn();
35
+ suites.push(currentSuite);
36
+ currentSuite = parentSuite;
37
+ };
38
+ /**
39
+ * Define an evaluation case
40
+ */
41
+ export function evaluation(name, fn) {
42
+ if (!currentSuite) {
43
+ throw new Error('evaluation() must be called inside describe()');
44
+ }
45
+ currentSuite.evaluations.push({ name, fn });
46
+ }
47
+ /**
48
+ * Define an evaluation case that will be skipped
49
+ */
50
+ evaluation.skip = function (name, fn) {
51
+ if (!currentSuite) {
52
+ throw new Error('evaluation.skip() must be called inside describe()');
53
+ }
54
+ currentSuite.evaluations.push({ name, fn, skip: true });
55
+ };
56
+ /**
57
+ * Define an evaluation case that will run exclusively (skips all other tests)
58
+ */
59
+ evaluation.only = function (name, fn) {
60
+ if (!currentSuite) {
61
+ throw new Error('evaluation.only() must be called inside describe()');
62
+ }
63
+ currentSuite.evaluations.push({ name, fn, only: true });
64
+ };
65
+ /**
66
+ * Define parametrized evaluation cases
67
+ *
68
+ * @example
69
+ * evaluation.each([
70
+ * { input: 'test1', expected: 'result1' },
71
+ * { input: 'test2', expected: 'result2' }
72
+ * ])('testing $input', (data) => async (ctx) => {
73
+ * // test implementation using data.input and data.expected
74
+ * });
75
+ */
76
+ evaluation.each = function (cases) {
77
+ return (name, fn) => {
78
+ if (!currentSuite) {
79
+ throw new Error('evaluation.each() must be called inside describe()');
80
+ }
81
+ // create an evaluation for each case
82
+ for (let i = 0; i < cases.length; i++) {
83
+ const testCase = cases[i];
84
+ // replace placeholders in name with case values
85
+ let caseName = name;
86
+ // support $property syntax (e.g., "$input" -> testCase.input)
87
+ if (typeof testCase === 'object' && testCase !== null) {
88
+ caseName = name.replace(/\$(\w+)/g, (match, key) => {
89
+ const value = testCase[key];
90
+ return value !== undefined ? String(value) : match;
91
+ });
92
+ }
93
+ // support %i, %s, %o, etc. for positional replacement
94
+ caseName = caseName
95
+ .replace(/%s/g, String(testCase))
96
+ .replace(/%i/g, String(testCase))
97
+ .replace(/%o/g, JSON.stringify(testCase))
98
+ .replace(/%j/g, JSON.stringify(testCase));
99
+ // if no placeholders matched, append case index
100
+ if (caseName === name) {
101
+ caseName = `${name} [${i}]`;
102
+ }
103
+ currentSuite.evaluations.push({
104
+ name: caseName,
105
+ fn: fn(testCase)
106
+ });
107
+ }
108
+ };
109
+ };
110
+ /**
111
+ * Define a hook that runs before each evaluation in the suite
112
+ */
113
+ export function beforeEach(fn) {
114
+ if (!currentSuite) {
115
+ throw new Error('beforeEach() must be called inside describe()');
116
+ }
117
+ currentSuite.beforeEachHook = fn;
118
+ }
119
+ /**
120
+ * Define a hook that runs after each evaluation in the suite
121
+ */
122
+ export function afterEach(fn) {
123
+ if (!currentSuite) {
124
+ throw new Error('afterEach() must be called inside describe()');
125
+ }
126
+ currentSuite.afterEachHook = fn;
127
+ }
128
+ /**
129
+ * Define a hook that runs once before all evaluations in the suite
130
+ */
131
+ export function beforeAll(fn) {
132
+ if (!currentSuite) {
133
+ throw new Error('beforeAll() must be called inside describe()');
134
+ }
135
+ currentSuite.beforeAllHook = fn;
136
+ }
137
+ /**
138
+ * Define a hook that runs once after all evaluations in the suite
139
+ */
140
+ export function afterAll(fn) {
141
+ if (!currentSuite) {
142
+ throw new Error('afterAll() must be called inside describe()');
143
+ }
144
+ currentSuite.afterAllHook = fn;
145
+ }
146
+ /**
147
+ * Export collected suites for runner
148
+ */
149
+ export function getCollectedSuites() {
150
+ const collected = [...suites];
151
+ suites.length = 0;
152
+ return collected;
153
+ }
154
+ /**
155
+ * Clear all collected suites
156
+ */
157
+ export function clearSuites() {
158
+ suites.length = 0;
159
+ currentSuite = null;
160
+ }
161
+ // re-export runner types and functions
162
+ export { runEvalFile } from './runner.js';
163
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Test runner for evaluation files
3
+ */
4
+ import type { EvalContext, EvaluationCaseResult } from './index.js';
5
+ /**
6
+ * Progress callback for evaluation execution
7
+ */
8
+ export interface EvalProgressCallback {
9
+ (current: number, total: number): void;
10
+ }
11
+ /**
12
+ * Result callback for evaluation execution (called as each test completes)
13
+ */
14
+ export interface EvalResultCallback {
15
+ (result: EvaluationCaseResult, current: number, total: number): void;
16
+ }
17
+ /**
18
+ * Run a single evaluation file
19
+ */
20
+ export declare function runEvalFile(filePath: string, context: EvalContext, onProgress?: EvalProgressCallback, onResult?: EvalResultCallback): Promise<EvaluationCaseResult[]>;
21
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKpE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,oBAAoB,EACjC,QAAQ,CAAC,EAAE,kBAAkB,GAC5B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAiKjC"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Test runner for evaluation files
3
+ */
4
+ import { pathToFileURL } from 'url';
5
+ import { register } from 'node:module';
6
+ // track if tsx loader is registered
7
+ let tsxLoaderRegistered = false;
8
+ /**
9
+ * Run a single evaluation file
10
+ */
11
+ export async function runEvalFile(filePath, context, onProgress, onResult) {
12
+ // register tsx loader for TypeScript support (only once)
13
+ if (!tsxLoaderRegistered && filePath.endsWith('.ts')) {
14
+ try {
15
+ // use tsx's ESM loader (Node 20.6+ compatible)
16
+ register('tsx/esm', import.meta.url);
17
+ tsxLoaderRegistered = true;
18
+ }
19
+ catch (error) {
20
+ // tsx may not be available, continue anyway (silence warning since it's working)
21
+ }
22
+ }
23
+ const { getCollectedSuites, clearSuites } = await import('./index.js');
24
+ // clear any previous state
25
+ clearSuites();
26
+ // dynamically import eval file (triggers describe/test calls)
27
+ // add cache-busting query parameter to force fresh import (prevents module caching issues)
28
+ await import(pathToFileURL(filePath).href + '?run=' + Date.now());
29
+ // collect suites
30
+ const suites = getCollectedSuites();
31
+ // check if any suite or evaluation has .only()
32
+ const hasOnly = suites.some(s => s.only || s.evaluations.some(e => e.only));
33
+ // count total evaluations for progress tracking
34
+ const totalEvaluations = suites.reduce((sum, suite) => sum + suite.evaluations.length, 0);
35
+ let completedEvaluations = 0;
36
+ // execute all tests (including creating results for skipped ones)
37
+ const results = [];
38
+ for (const suite of suites) {
39
+ // determine if this entire suite is skipped
40
+ const suiteSkipped = suite.skip || (hasOnly && !suite.only && !suite.evaluations.some(e => e.only));
41
+ // run beforeAll hook once before all evaluations in the suite
42
+ if (!suiteSkipped && suite.beforeAllHook) {
43
+ try {
44
+ await suite.beforeAllHook();
45
+ }
46
+ catch (error) {
47
+ console.error('beforeAll hook failed:', error);
48
+ // continue anyway, tests will fail if setup is incomplete
49
+ }
50
+ }
51
+ for (const evalDef of suite.evaluations) {
52
+ // determine if this evaluation is skipped
53
+ const evalSkipped = suiteSkipped || evalDef.skip || (hasOnly && !evalDef.only && !suite.only);
54
+ if (evalSkipped) {
55
+ // add skipped result without executing the test
56
+ const skippedResult = {
57
+ name: `${suite.name} - ${evalDef.name}`,
58
+ metadata: {
59
+ evalFile: filePath,
60
+ suiteName: suite.name,
61
+ caseName: evalDef.name,
62
+ duration: 0
63
+ },
64
+ data: {
65
+ passed: false,
66
+ skipped: true
67
+ }
68
+ };
69
+ results.push(skippedResult);
70
+ completedEvaluations++;
71
+ if (onProgress) {
72
+ onProgress(completedEvaluations, totalEvaluations);
73
+ }
74
+ if (onResult) {
75
+ onResult(skippedResult, completedEvaluations, totalEvaluations);
76
+ }
77
+ continue;
78
+ }
79
+ // execute non-skipped test
80
+ const start = Date.now();
81
+ try {
82
+ // run beforeEach hook if it exists
83
+ if (suite.beforeEachHook) {
84
+ await suite.beforeEachHook();
85
+ }
86
+ // get core evaluation data
87
+ const evaluationData = await evalDef.fn(context);
88
+ // run afterEach hook if it exists
89
+ if (suite.afterEachHook) {
90
+ await suite.afterEachHook();
91
+ }
92
+ // construct a result around it
93
+ const evaluatorCaseResult = {
94
+ name: `${suite.name} - ${evalDef.name}`,
95
+ metadata: {
96
+ evalFile: filePath,
97
+ suiteName: suite.name,
98
+ caseName: evalDef.name,
99
+ duration: Date.now() - start
100
+ },
101
+ data: evaluationData
102
+ };
103
+ results.push(evaluatorCaseResult);
104
+ completedEvaluations++;
105
+ if (onProgress) {
106
+ onProgress(completedEvaluations, totalEvaluations);
107
+ }
108
+ if (onResult) {
109
+ onResult(evaluatorCaseResult, completedEvaluations, totalEvaluations);
110
+ }
111
+ }
112
+ catch (error) {
113
+ // run afterEach hook even on error
114
+ if (suite.afterEachHook) {
115
+ try {
116
+ await suite.afterEachHook();
117
+ }
118
+ catch (afterEachError) {
119
+ // log afterEach errors but don't fail the test twice
120
+ console.error('afterEach hook failed:', afterEachError);
121
+ }
122
+ }
123
+ // treat errors as failures
124
+ const failureResult = {
125
+ name: `${suite.name} - ${evalDef.name}`,
126
+ metadata: {
127
+ evalFile: filePath,
128
+ suiteName: suite.name,
129
+ caseName: evalDef.name,
130
+ duration: Date.now() - start,
131
+ },
132
+ data: {
133
+ passed: false,
134
+ error: error instanceof Error ? error.message : String(error)
135
+ }
136
+ };
137
+ results.push(failureResult);
138
+ completedEvaluations++;
139
+ if (onProgress) {
140
+ onProgress(completedEvaluations, totalEvaluations);
141
+ }
142
+ if (onResult) {
143
+ onResult(failureResult, completedEvaluations, totalEvaluations);
144
+ }
145
+ }
146
+ }
147
+ // run afterAll hook once after all evaluations in the suite
148
+ if (!suiteSkipped && suite.afterAllHook) {
149
+ try {
150
+ await suite.afterAllHook();
151
+ }
152
+ catch (error) {
153
+ console.error('afterAll hook failed:', error);
154
+ }
155
+ }
156
+ }
157
+ return results;
158
+ }
159
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"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"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { LangiumServices, LangiumSharedServices } from "langium/lsp";
2
+ /**
3
+ * General service set that is produced by most Langium implementations
4
+ */
5
+ export type LangiumServiceSet = {
6
+ shared: LangiumSharedServices;
7
+ grammar: LangiumServices;
8
+ };
9
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEzE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,MAAM,EAAE,qBAAqB,CAAA;IAC7B,OAAO,EAAE,eAAe,CAAA;CAC3B,CAAA"}
package/dist/util.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langium-ai-tools",
3
- "version": "4.1.5",
3
+ "version": "4.2.0",
4
4
  "description": "Tooling for building AI Applications that leverage Langium DSLs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -50,7 +50,7 @@
50
50
  "dependencies": {
51
51
  "@protobuf-ts/runtime": "^2.11.1",
52
52
  "js-yaml": "^4.1.1",
53
- "langium": "~4.1.0"
53
+ "langium": "~4.2.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@protobuf-ts/plugin": "^2.11.1",