@axiom-lattice/agent-eval 2.1.9

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.
package/dist/index.js ADDED
@@ -0,0 +1,1092 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ LatticeEval: () => LatticeEval,
34
+ LatticeEvalProject: () => LatticeEvalProject,
35
+ LatticeEvalSuite: () => LatticeEvalSuite,
36
+ evaluateLatticeCase: () => evaluateLatticeCase,
37
+ evaluateLatticeCaseWithLogs: () => evaluateLatticeCaseWithLogs
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+
41
+ // src/LatticeEval.ts
42
+ var import_core = require("@axiom-lattice/core");
43
+ var import_messages = require("@langchain/core/messages");
44
+ var import_uuid = require("uuid");
45
+ var LatticeEval = class {
46
+ /**
47
+ * Create a new LatticeEval instance
48
+ * @param config Optional server configuration (defaults to localhost:3203)
49
+ */
50
+ constructor(config) {
51
+ this.inMemoryLogs = [];
52
+ this.lastDurationMs = 0;
53
+ this.config = config;
54
+ this.baseUrl = this.config.base_url;
55
+ this.verbose = this.config.verbose ?? true;
56
+ }
57
+ getLastRunMeta() {
58
+ return {
59
+ duration_ms: this.lastDurationMs,
60
+ thread_id: this.lastThreadId,
61
+ judge_thread_id: this.lastJudgeThreadId,
62
+ test_prompt: this.lastTestPrompt,
63
+ final_output: this.lastFinalOutput
64
+ };
65
+ }
66
+ getInMemoryLogs() {
67
+ return [...this.inMemoryLogs];
68
+ }
69
+ record(level, message, data) {
70
+ const event = {
71
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
72
+ level,
73
+ message,
74
+ data
75
+ };
76
+ this.inMemoryLogs.push(event);
77
+ if (!this.verbose) return;
78
+ if (level === "error") {
79
+ const keyInfo = this.getKeyInfo(data);
80
+ console.log(` \u2717 ${message}${keyInfo ? ` ${keyInfo}` : ""}`);
81
+ } else if (message.includes("Starting case") || message.includes("Case evaluation completed")) {
82
+ const keyInfo = this.getKeyInfo(data);
83
+ console.log(` ${message}${keyInfo ? ` ${keyInfo}` : ""}`);
84
+ }
85
+ }
86
+ log(message, data) {
87
+ this.record("info", message, data);
88
+ }
89
+ getKeyInfo(data) {
90
+ if (!data) return "";
91
+ const parts = [];
92
+ if (data.case_id) parts.push(`case=${data.case_id}`);
93
+ if (data.pass !== void 0) parts.push(`pass=${data.pass}`);
94
+ if (data.final_score !== void 0) parts.push(`score=${data.final_score}`);
95
+ if (data.error) parts.push(`error=${data.error}`);
96
+ return parts.length > 0 ? `(${parts.join(" ")})` : "";
97
+ }
98
+ /**
99
+ * Execute a single agent step and return the thread ID and response data
100
+ */
101
+ async executeAgentStep(step, threadId, inputMessage, files) {
102
+ this.log("Executing agent step", {
103
+ agent_id: step.agent_id,
104
+ thread_id: threadId,
105
+ has_override_input_message: Boolean(step.override_input_message),
106
+ input_message_length: step.override_input_message ? step.override_input_message.length : inputMessage.length,
107
+ files_count: Object.keys(files || {}).length
108
+ });
109
+ const response = await fetch(`${this.baseUrl}/api/runs`, {
110
+ method: "POST",
111
+ headers: {
112
+ "Content-Type": "application/json"
113
+ },
114
+ body: JSON.stringify({
115
+ assistant_id: step.agent_id,
116
+ thread_id: threadId,
117
+ files: Object.keys(files).reduce((acc, key) => {
118
+ acc[key] = { content: files[key].split("\n"), created_at: (/* @__PURE__ */ new Date()).toISOString(), modified_at: (/* @__PURE__ */ new Date()).toISOString() };
119
+ return acc;
120
+ }, {}),
121
+ message: step.override_input_message || inputMessage
122
+ })
123
+ });
124
+ const responseData = await response.json();
125
+ if (responseData.error) {
126
+ this.log("Agent step failed", {
127
+ agent_id: step.agent_id,
128
+ thread_id: threadId,
129
+ error: responseData.error
130
+ });
131
+ throw new Error(
132
+ `Failed to run agent ${step.agent_id}: ${responseData.error}`
133
+ );
134
+ }
135
+ this.log("Agent step completed", {
136
+ agent_id: step.agent_id,
137
+ thread_id: threadId,
138
+ response_keys: responseData ? Object.keys(responseData) : []
139
+ });
140
+ return { threadId, responseData };
141
+ }
142
+ /**
143
+ * Extract output content based on OutputType
144
+ */
145
+ async extractOutput(outputType, agentId, threadId, runResponseData) {
146
+ if (outputType.type === "file_content") {
147
+ this.log("Extracting file output", {
148
+ agent_id: agentId,
149
+ thread_id: threadId,
150
+ file_path: outputType.file_path
151
+ });
152
+ const responseState = await fetch(
153
+ `${this.baseUrl}/api/assistants/${agentId}/${threadId}/state`,
154
+ {
155
+ method: "GET"
156
+ }
157
+ );
158
+ if (!responseState.ok) {
159
+ this.log("Failed to fetch assistant state", {
160
+ agent_id: agentId,
161
+ thread_id: threadId,
162
+ status: responseState.status,
163
+ statusText: responseState.statusText
164
+ });
165
+ throw new Error(`Failed to get state: ${responseState.statusText}`);
166
+ }
167
+ const state = await responseState.json();
168
+ const stateValues = state.values;
169
+ const fileContent = stateValues.files[outputType.file_path]?.content;
170
+ if (!fileContent) {
171
+ this.log("File output not found in state", {
172
+ agent_id: agentId,
173
+ thread_id: threadId,
174
+ file_path: outputType.file_path
175
+ });
176
+ throw new Error(
177
+ `File not found in output: ${outputType.file_path}`
178
+ );
179
+ }
180
+ const content = Array.isArray(fileContent) ? fileContent.join("\n") : fileContent;
181
+ this.log("File output extracted", {
182
+ agent_id: agentId,
183
+ thread_id: threadId,
184
+ file_path: outputType.file_path,
185
+ output_length: typeof content === "string" ? content.length : void 0
186
+ });
187
+ return content;
188
+ } else {
189
+ if (runResponseData?.messages && runResponseData.messages.length > 0) {
190
+ const content = runResponseData.messages[runResponseData.messages.length - 1]?.content || "";
191
+ this.log("Message output extracted", {
192
+ agent_id: agentId,
193
+ thread_id: threadId,
194
+ output_length: typeof content === "string" ? content.length : void 0
195
+ });
196
+ return content;
197
+ }
198
+ this.log("No message content found in run response", {
199
+ agent_id: agentId,
200
+ thread_id: threadId
201
+ });
202
+ throw new Error("No message content found in run response");
203
+ }
204
+ }
205
+ /**
206
+ * Evaluate a single Lattice evaluation case
207
+ * @param evalCase The evaluation case to run
208
+ * @returns Evaluation result with pass/fail status and scores
209
+ */
210
+ async evaluateCase(evalCase) {
211
+ const startedAt = Date.now();
212
+ const threadId = `${evalCase.caseId}||${(0, import_uuid.v4)()}`;
213
+ this.inMemoryLogs = [];
214
+ this.lastThreadId = threadId;
215
+ this.lastJudgeThreadId = void 0;
216
+ this.lastTestPrompt = void 0;
217
+ this.lastFinalOutput = void 0;
218
+ this.lastDurationMs = 0;
219
+ this.log("Starting case evaluation", {
220
+ case_id: evalCase.caseId,
221
+ thread_id: threadId,
222
+ steps_count: evalCase.steps?.length,
223
+ output_type: evalCase.output?.type
224
+ });
225
+ let currentThreadId = threadId;
226
+ let lastResponseData = null;
227
+ for (const step of evalCase.steps) {
228
+ const result = await this.executeAgentStep(
229
+ step,
230
+ currentThreadId,
231
+ evalCase.input.message,
232
+ evalCase.input.files || {}
233
+ );
234
+ currentThreadId = result.threadId;
235
+ lastResponseData = result.responseData;
236
+ }
237
+ const finalAgentId = evalCase.steps[evalCase.steps.length - 1]?.agent_id || "";
238
+ this.log("All agent steps completed", {
239
+ case_id: evalCase.caseId,
240
+ final_agent_id: finalAgentId,
241
+ final_thread_id: currentThreadId
242
+ });
243
+ const finalOutput = await this.extractOutput(
244
+ evalCase.output,
245
+ finalAgentId,
246
+ currentThreadId,
247
+ lastResponseData
248
+ );
249
+ this.lastFinalOutput = finalOutput;
250
+ this.log("Final output extracted", {
251
+ case_id: evalCase.caseId,
252
+ output_type: evalCase.output.type,
253
+ output_length: finalOutput.length
254
+ });
255
+ const testCaseFilesContent = evalCase.input.files ? Object.keys(evalCase.input.files).map(
256
+ (key) => `File name: ${key}
257
+ File content: ${evalCase.input.files[key]}`
258
+ ).join("\n\n") : "";
259
+ const outputTypeDescription = evalCase.output.type === "file_content" ? `\u865A\u62DF\u4EA7\u7269\uFF08\u6587\u4EF6\uFF1A${evalCase.output.file_path}\uFF09` : "\u6D88\u606F\u5185\u5BB9";
260
+ const defaultRubrics = [
261
+ {
262
+ dimension: "correctness",
263
+ weight: 100,
264
+ description: "\u6574\u4F53\u6B63\u786E\u6027\uFF0C\u662F\u5426\u7B26\u5408\u9884\u671F\u8F93\u51FA\u63CF\u8FF0\u3002"
265
+ }
266
+ ];
267
+ const evalRubrics = evalCase.eval.eval_rubrics && evalCase.eval.eval_rubrics.length > 0 ? evalCase.eval.eval_rubrics : defaultRubrics;
268
+ this.log("Prepared evaluation rubrics", {
269
+ case_id: evalCase.caseId,
270
+ rubrics_count: evalRubrics.length,
271
+ rubric_dimensions: evalRubrics.map((r) => r.dimension)
272
+ });
273
+ const rubricsSection = `
274
+ ## \u8BC4\u4F30\u6307\u6807\uFF08Evaluation Rubrics\uFF09
275
+ ${evalRubrics.map(
276
+ (r) => `- **${r.dimension}**\uFF08\u6743\u91CD\uFF1A${r.weight}\uFF09\uFF1A${r.description}`
277
+ ).join("\n")}`;
278
+ const testPrompt = `# \u89D2\u8272
279
+ \u4F60\u662F\u4E00\u540D\u8D44\u6DF1\u7684 AI Agent \u8BC4\u4F30\u4E13\u5BB6\uFF0C\u8D1F\u8D23\u6839\u636E\u9884\u8BBE\u7684\u6307\u6807\uFF08Rubrics\uFF09\u5BF9 Agent \u7684\u6267\u884C\u7ED3\u679C\u8FDB\u884C"\u9ED1\u76D2\u6D4B\u8BD5"\u5224\u5B9A\u3002
280
+
281
+ # \u8F93\u5165\u4FE1\u606F
282
+ \u6D4B\u8BD5\u6846\u67B6\u5C06\u4E3A\u4F60\u63D0\u4F9B\u4EE5\u4E0B\u56DB\u4E2A\u6838\u5FC3\u4E0A\u4E0B\u6587\uFF1A
283
+
284
+ 1. **\u7528\u6237\u610F\u56FE\uFF08User Intent\uFF09**\uFF1A${evalCase.input.message}
285
+
286
+ 2. **\u8F93\u5165\u6587\u4EF6\uFF08Input Files\uFF09**\uFF1A${testCaseFilesContent || "\u65E0"}
287
+
288
+ 3. **\u5B9E\u9645\u8F93\u51FA\uFF08Actual Output\uFF0C${outputTypeDescription}\uFF09**\uFF1A
289
+ ${finalOutput}
290
+
291
+ 4. **\u671F\u671B\u8F93\u51FA\u63CF\u8FF0\uFF08Expected Output Description\uFF09**\uFF1A${evalCase.eval.content_assertion}
292
+ ${rubricsSection}
293
+
294
+ # \u4EFB\u52A1
295
+ \u4F60\u5FC5\u987B\u4E25\u683C\u5BF9\u7167"\u8BC4\u4F30\u6307\u6807\uFF08Evaluation Rubrics\uFF09"\u4E2D\u7684\u6BCF\u4E00\u9879\u6307\u6807\uFF0C\u5206\u6790"\u5B9E\u9645\u8F93\u51FA\uFF08Actual Output\uFF09"\u662F\u5426\u8FBE\u6807\u3002
296
+
297
+ # \u89C4\u5219
298
+ 1. **\u5BA2\u89C2\u6027**\uFF1A\u4EC5\u6839\u636E\u63D0\u4F9B\u7684\u4E0A\u4E0B\u6587\u5224\u5B9A\u3002\u5982\u679C\u6807\u51C6\u8981\u6C42"\u5305\u542B\u6570\u5B57"\uFF0C\u4F46\u8F93\u51FA\u53EA\u6709\u6587\u5B57\uFF0C\u5373\u4F7F\u8BED\u6C14\u518D\u597D\u4E5F\u5FC5\u987B\u6263\u5206\u3002
299
+ 2. **\u7ED3\u679C\u6821\u9A8C**\uFF1A\u5982\u679C"\u5B9E\u9645\u8F93\u51FA"\u4E2D\u7F3A\u5931\u9884\u671F\u7684\u5185\u5BB9\uFF0C\u6216\u5185\u5BB9\u4E0D\u7B26\u5408"\u8BC4\u4F30\u6307\u6807"\u4E2D\u7684\u6807\u51C6\uFF0C\u5BF9\u5E94\u7684\u6307\u6807\u5E94\u5224\u5B9A\u4E3A\u5931\u8D25\u3002
300
+ 3. **\u8BC1\u636E\u5BFC\u5411**\uFF1A\u5728\u7ED9\u51FA\u539F\u56E0\uFF08reason\uFF09\u65F6\uFF0C\u5FC5\u987B\u5F15\u7528\u8F93\u51FA\u4E2D\u7684\u539F\u6587\u6216\u865A\u62DF\u4EA7\u7269\u4E2D\u7684\u5177\u4F53\u6570\u636E\u7247\u6BB5\u3002
301
+ 4. **\u52A0\u6743\u8BA1\u7B97**\uFF1A\u6700\u7EC8\u5206\u6570\u4E3A\u5404\u9879\u6307\u6807\u5F97\u5206\u4E0E\u5176\u6743\u91CD\u7684\u4E58\u79EF\u4E4B\u548C\uFF080-100\u5206\u5236\uFF09\u3002
302
+
303
+ # \u8F93\u51FA\u683C\u5F0F\uFF08\u4EC5JSON\uFF09
304
+ \u4F60\u5FC5\u987B\u4EC5\u4EE5 JSON \u683C\u5F0F\u56DE\u590D\uFF0C\u7ED3\u6784\u5982\u4E0B\uFF1A
305
+ {
306
+ "pass": true | false,
307
+ "final_score": number,
308
+ "dimension_results": [
309
+ {
310
+ "name": "\u6307\u6807\u540D\u79F0",
311
+ "score": number,
312
+ "reason": "\u5177\u4F53\u7684\u6263\u5206\u6216\u7ED9\u5206\u7406\u7531\uFF0C\u9700\u5F15\u7528\u8BC1\u636E"
313
+ }
314
+ ],
315
+ "summary": "\u5BF9 Agent \u8868\u73B0\u7684\u6574\u4F53\u8BC4\u4EF7"
316
+ }
317
+
318
+ \u6CE8\u610F\uFF1A\u5982\u679C final_score >= 80 \u4E14\u6CA1\u6709\u81F4\u547D\u6027\u9519\u8BEF\uFF0Cpass \u5E94\u4E3A true\uFF1B\u5426\u5219\u4E3A false\u3002`;
319
+ this.lastTestPrompt = testPrompt;
320
+ const judgeThreadId = (0, import_uuid.v4)();
321
+ this.lastJudgeThreadId = judgeThreadId;
322
+ this.log("Invoking judge agent", { agent_key: "LatticeTest", case_id: evalCase.caseId });
323
+ const testResponse = await (0, import_core.getAgentClient)("LatticeTest").invoke(
324
+ {
325
+ messages: [new import_messages.HumanMessage(testPrompt)]
326
+ },
327
+ {
328
+ configurable: {
329
+ thread_id: judgeThreadId
330
+ }
331
+ }
332
+ );
333
+ this.log("Judge agent responded", {
334
+ case_id: evalCase.caseId,
335
+ messages_count: testResponse?.messages?.length
336
+ });
337
+ const testResultContent = testResponse.messages[testResponse.messages.length - 1]?.content || "";
338
+ this.log("Judge raw output received", {
339
+ case_id: evalCase.caseId,
340
+ output_length: typeof testResultContent === "string" ? testResultContent.length : void 0
341
+ });
342
+ let parsedResult = {};
343
+ try {
344
+ const jsonMatch = testResultContent.match(/```(?:json)?\s*(\{[\s\S]*\})\s*```/) || testResultContent.match(/\{[\s\S]*\}/);
345
+ if (jsonMatch) {
346
+ parsedResult = JSON.parse(jsonMatch[1] || jsonMatch[0]);
347
+ this.log("Parsed judge JSON successfully", {
348
+ case_id: evalCase.caseId,
349
+ parsed_keys: Object.keys(parsedResult || {})
350
+ });
351
+ } else {
352
+ this.log("No JSON detected in judge output; will fallback", {
353
+ case_id: evalCase.caseId
354
+ });
355
+ }
356
+ } catch (error) {
357
+ console.warn("Failed to parse JSON from judge agent response, falling back to keyword-based parsing:", error);
358
+ this.log("Failed to parse judge JSON; falling back", {
359
+ case_id: evalCase.caseId,
360
+ error: error instanceof Error ? error.message : String(error)
361
+ });
362
+ }
363
+ let pass;
364
+ if (parsedResult.pass !== void 0) {
365
+ pass = parsedResult.pass;
366
+ this.log("Pass determined from parsedResult.pass", { case_id: evalCase.caseId, pass });
367
+ } else if (parsedResult.final_score !== void 0) {
368
+ pass = parsedResult.final_score >= 80;
369
+ this.log("Pass determined from parsedResult.final_score", {
370
+ case_id: evalCase.caseId,
371
+ final_score: parsedResult.final_score,
372
+ pass
373
+ });
374
+ } else {
375
+ pass = testResultContent.toLowerCase().includes("pass") || testResultContent.toLowerCase().includes("success") || testResultContent.toLowerCase().includes("\u901A\u8FC7") || testResultContent.toLowerCase().includes("\u7B26\u5408");
376
+ this.log("Pass determined from keyword fallback", { case_id: evalCase.caseId, pass });
377
+ }
378
+ let dimensionResults = [];
379
+ if (parsedResult.dimension_results && parsedResult.dimension_results.length > 0) {
380
+ dimensionResults = parsedResult.dimension_results;
381
+ this.log("Using parsed dimension_results from judge", {
382
+ case_id: evalCase.caseId,
383
+ dimensions_count: dimensionResults.length
384
+ });
385
+ } else if (evalRubrics.length > 0) {
386
+ dimensionResults = evalRubrics.map((rubric) => ({
387
+ name: rubric.dimension,
388
+ score: 0,
389
+ reason: ""
390
+ }));
391
+ this.log("No dimension_results parsed; using rubric skeleton", {
392
+ case_id: evalCase.caseId,
393
+ dimensions_count: dimensionResults.length
394
+ });
395
+ }
396
+ let finalScore;
397
+ if (parsedResult.final_score !== void 0) {
398
+ finalScore = parsedResult.final_score;
399
+ this.log("Final score taken from parsedResult.final_score", {
400
+ case_id: evalCase.caseId,
401
+ final_score: finalScore
402
+ });
403
+ } else if (dimensionResults.length > 0 && evalRubrics.length > 0) {
404
+ const rubricMap = new Map(evalRubrics.map((r) => [r.dimension, r.weight]));
405
+ const totalWeight = Array.from(rubricMap.values()).reduce((sum, w) => sum + w, 0);
406
+ if (totalWeight > 0) {
407
+ finalScore = dimensionResults.reduce((sum, result) => {
408
+ const weight = rubricMap.get(result.name) || 1;
409
+ return sum + result.score * weight;
410
+ }, 0) / totalWeight;
411
+ } else {
412
+ finalScore = dimensionResults.reduce((sum, result) => sum + result.score, 0) / dimensionResults.length;
413
+ }
414
+ this.log("Final score computed from dimension_results", {
415
+ case_id: evalCase.caseId,
416
+ final_score: finalScore,
417
+ total_weight: totalWeight
418
+ });
419
+ } else {
420
+ finalScore = pass ? 100 : 0;
421
+ this.log("Final score fallback (pass-based)", {
422
+ case_id: evalCase.caseId,
423
+ final_score: finalScore,
424
+ pass
425
+ });
426
+ }
427
+ this.log("Case evaluation completed", {
428
+ case_id: evalCase.caseId,
429
+ pass,
430
+ final_score: finalScore
431
+ });
432
+ const finishedAt = Date.now();
433
+ this.lastDurationMs = finishedAt - startedAt;
434
+ this.record("info", "Case duration recorded", {
435
+ case_id: evalCase.caseId,
436
+ duration_ms: this.lastDurationMs
437
+ });
438
+ return {
439
+ pass,
440
+ final_score: finalScore,
441
+ dimension_results: dimensionResults,
442
+ summary: parsedResult.summary || testResultContent
443
+ };
444
+ }
445
+ };
446
+ async function evaluateLatticeCase(evalCase, config) {
447
+ const defaultConfig = {
448
+ base_url: "http://localhost:3203"
449
+ };
450
+ const evaluator = new LatticeEval(config || defaultConfig);
451
+ return evaluator.evaluateCase(evalCase);
452
+ }
453
+ async function evaluateLatticeCaseWithLogs(evalCase, config) {
454
+ const defaultConfig = {
455
+ base_url: "http://localhost:3203"
456
+ };
457
+ const evaluator = new LatticeEval(config || defaultConfig);
458
+ try {
459
+ const result = await evaluator.evaluateCase(evalCase);
460
+ const meta = evaluator.getLastRunMeta();
461
+ return {
462
+ caseId: evalCase.caseId,
463
+ result,
464
+ duration_ms: meta.duration_ms,
465
+ thread_id: meta.thread_id,
466
+ judge_thread_id: meta.judge_thread_id,
467
+ test_prompt: meta.test_prompt,
468
+ final_output: meta.final_output,
469
+ logs: evaluator.getInMemoryLogs()
470
+ };
471
+ } catch (error) {
472
+ const errorMessage = error instanceof Error ? error.message : String(error);
473
+ const errorStack = error instanceof Error ? error.stack : void 0;
474
+ evaluator.record("error", "Case evaluation failed", {
475
+ case_id: evalCase.caseId,
476
+ error: errorMessage
477
+ });
478
+ const meta = evaluator.getLastRunMeta();
479
+ return {
480
+ caseId: evalCase.caseId,
481
+ error: errorMessage,
482
+ error_stack: errorStack,
483
+ duration_ms: meta.duration_ms,
484
+ thread_id: meta.thread_id,
485
+ judge_thread_id: meta.judge_thread_id,
486
+ test_prompt: meta.test_prompt,
487
+ final_output: meta.final_output,
488
+ logs: evaluator.getInMemoryLogs()
489
+ };
490
+ }
491
+ }
492
+
493
+ // src/LatticeEvalSuite.ts
494
+ async function limitConcurrency(tasks, concurrency) {
495
+ const results = [];
496
+ const executing = [];
497
+ let index = 0;
498
+ const executeTask = async (task, taskIndex) => {
499
+ try {
500
+ const result = await task();
501
+ results[taskIndex] = { success: true, result };
502
+ } catch (error) {
503
+ results[taskIndex] = {
504
+ success: false,
505
+ error: error instanceof Error ? error.message : String(error)
506
+ };
507
+ }
508
+ };
509
+ while (index < tasks.length || executing.length > 0) {
510
+ while (executing.length < concurrency && index < tasks.length) {
511
+ const task = tasks[index];
512
+ const currentIndex = index++;
513
+ const promise = executeTask(task, currentIndex).catch((err) => {
514
+ console.error(`Unexpected error in task execution:`, err);
515
+ }).finally(() => {
516
+ const idx = executing.indexOf(promise);
517
+ if (idx > -1) {
518
+ executing.splice(idx, 1);
519
+ }
520
+ });
521
+ executing.push(promise);
522
+ }
523
+ if (executing.length > 0) {
524
+ await Promise.race(executing);
525
+ }
526
+ }
527
+ await Promise.allSettled(executing);
528
+ return results;
529
+ }
530
+ function resolveTemplateCase(templateCase, templates) {
531
+ const template = templates.get(templateCase.templateId);
532
+ if (!template) {
533
+ throw new Error(`Template not found: ${templateCase.templateId}`);
534
+ }
535
+ const resolvedCase = {
536
+ caseId: templateCase.caseId,
537
+ input: {
538
+ message: templateCase.input.message ?? template.default_case.input.message,
539
+ files: {
540
+ ...template.default_case.input.files,
541
+ ...templateCase.input.files
542
+ }
543
+ },
544
+ steps: template.default_case.steps,
545
+ output: templateCase.output || template.default_case.output,
546
+ eval: {
547
+ content_assertion: templateCase.eval.content_assertion,
548
+ eval_rubrics: templateCase.eval.eval_rubrics || template.default_case.eval?.eval_rubrics
549
+ }
550
+ };
551
+ return resolvedCase;
552
+ }
553
+ function isTemplateCase(case_) {
554
+ return "templateId" in case_;
555
+ }
556
+ var LatticeEvalSuite = class {
557
+ constructor(suite, projectConfig, templates = /* @__PURE__ */ new Map()) {
558
+ this.suite = suite;
559
+ this.projectConfig = projectConfig;
560
+ this.templates = templates;
561
+ }
562
+ /**
563
+ * Get resolved configuration from project
564
+ */
565
+ getResolvedConfig() {
566
+ return this.projectConfig;
567
+ }
568
+ /**
569
+ * Get suite name
570
+ */
571
+ getSuiteName() {
572
+ return this.suite.suiteName;
573
+ }
574
+ /**
575
+ * Get suite version
576
+ */
577
+ getVersion() {
578
+ return this.suite.version;
579
+ }
580
+ /**
581
+ * Get all cases in this suite (resolved from templates if needed)
582
+ */
583
+ getCases() {
584
+ return this.suite.cases.map((case_) => {
585
+ if (isTemplateCase(case_)) {
586
+ return resolveTemplateCase(case_, this.templates);
587
+ }
588
+ return case_;
589
+ });
590
+ }
591
+ /**
592
+ * Get a specific case by ID (resolved from template if needed)
593
+ */
594
+ getCase(caseId) {
595
+ const case_ = this.suite.cases.find((c) => c.caseId === caseId);
596
+ if (!case_) {
597
+ return void 0;
598
+ }
599
+ if (isTemplateCase(case_)) {
600
+ return resolveTemplateCase(case_, this.templates);
601
+ }
602
+ return case_;
603
+ }
604
+ /**
605
+ * Run a single case in this suite with error handling
606
+ * @param caseId The case ID to run
607
+ * @returns Case run result with error handling
608
+ */
609
+ async runCase(caseId) {
610
+ try {
611
+ const evalCase = this.getCase(caseId);
612
+ if (!evalCase) {
613
+ return {
614
+ caseId,
615
+ error: `Case not found: ${caseId}`,
616
+ logs: []
617
+ };
618
+ }
619
+ const config = this.getResolvedConfig();
620
+ const evalConfig = {
621
+ base_url: config.lattice_server_config.base_url,
622
+ api_key: config.lattice_server_config.api_key
623
+ };
624
+ const run = await evaluateLatticeCaseWithLogs(evalCase, evalConfig);
625
+ return {
626
+ caseId,
627
+ result: run.result,
628
+ error: run.error,
629
+ error_stack: run.error_stack,
630
+ duration_ms: run.duration_ms,
631
+ thread_id: run.thread_id,
632
+ judge_thread_id: run.judge_thread_id,
633
+ test_prompt: run.test_prompt,
634
+ final_output: run.final_output,
635
+ logs: run.logs
636
+ };
637
+ } catch (error) {
638
+ return {
639
+ caseId,
640
+ error: error instanceof Error ? error.message : String(error),
641
+ logs: []
642
+ };
643
+ }
644
+ }
645
+ /**
646
+ * Run all cases in this suite with concurrency control and error isolation
647
+ * @param concurrency Optional concurrency limit (overrides project config)
648
+ * @returns Array of case run results with error handling
649
+ */
650
+ async runAllCases(concurrency) {
651
+ const config = this.getResolvedConfig();
652
+ const maxConcurrency = concurrency ?? config.concurrency;
653
+ const tasks = this.suite.cases.map((case_) => async () => {
654
+ try {
655
+ const evalCase = isTemplateCase(case_) ? resolveTemplateCase(case_, this.templates) : case_;
656
+ const evalConfig = {
657
+ base_url: config.lattice_server_config.base_url,
658
+ api_key: config.lattice_server_config.api_key
659
+ };
660
+ const run = await evaluateLatticeCaseWithLogs(evalCase, evalConfig);
661
+ return {
662
+ caseId: evalCase.caseId,
663
+ result: run.result,
664
+ error: run.error,
665
+ error_stack: run.error_stack,
666
+ duration_ms: run.duration_ms,
667
+ thread_id: run.thread_id,
668
+ judge_thread_id: run.judge_thread_id,
669
+ test_prompt: run.test_prompt,
670
+ final_output: run.final_output,
671
+ logs: run.logs
672
+ };
673
+ } catch (error) {
674
+ return {
675
+ caseId: case_.caseId,
676
+ error: error instanceof Error ? error.message : String(error),
677
+ logs: []
678
+ };
679
+ }
680
+ });
681
+ const taskResults = await limitConcurrency(tasks, maxConcurrency);
682
+ return taskResults.map((taskResult, index) => {
683
+ if (taskResult.success && taskResult.result) {
684
+ return taskResult.result;
685
+ }
686
+ return {
687
+ caseId: this.suite.cases[index].caseId,
688
+ error: taskResult.error || "Unknown error",
689
+ logs: []
690
+ };
691
+ });
692
+ }
693
+ };
694
+
695
+ // src/LatticeEvalProject.ts
696
+ var import_core2 = require("@axiom-lattice/core");
697
+ var import_promises = require("fs/promises");
698
+ var import_path = __toESM(require("path"));
699
+ var LatticeEvalProject = class {
700
+ constructor(project) {
701
+ this.suites = /* @__PURE__ */ new Map();
702
+ this.project = project;
703
+ this.reportConfig = project.report_config;
704
+ const judgeModelKey = `${this.project.projectName}_judge_model`;
705
+ (0, import_core2.registerModelLattice)(judgeModelKey, this.project.judge_agent_config.model);
706
+ const judgeAgentKey = "LatticeTest";
707
+ const judgeAgentConfig = {
708
+ key: judgeAgentKey,
709
+ name: "Lattice Test Judge Agent",
710
+ description: "Judge agent for evaluating Lattice test cases",
711
+ type: import_core2.AgentType.REACT,
712
+ prompt: "",
713
+ // No prompt as requested
714
+ modelKey: judgeModelKey
715
+ };
716
+ (0, import_core2.registerAgentLattice)(judgeAgentConfig);
717
+ const projectConfig = {
718
+ lattice_server_config: {
719
+ base_url: this.project.lattice_server_config.base_url,
720
+ api_key: this.project.lattice_server_config.api_key
721
+ },
722
+ judge_agent_config: this.project.judge_agent_config,
723
+ concurrency: this.project.concurrency ?? 1
724
+ };
725
+ const templatesMap = /* @__PURE__ */ new Map();
726
+ if (this.project.templates) {
727
+ for (const template of this.project.templates) {
728
+ templatesMap.set(template.templateId, template);
729
+ }
730
+ }
731
+ for (const suite of this.project.suites) {
732
+ this.suites.set(
733
+ suite.suiteName,
734
+ new LatticeEvalSuite(suite, projectConfig, templatesMap)
735
+ );
736
+ }
737
+ }
738
+ /**
739
+ * Get project name
740
+ */
741
+ getProjectName() {
742
+ return this.project.projectName;
743
+ }
744
+ /**
745
+ * Get project version
746
+ */
747
+ getVersion() {
748
+ return this.project.version;
749
+ }
750
+ /**
751
+ * Get project description
752
+ */
753
+ getDescription() {
754
+ return this.project.description;
755
+ }
756
+ /**
757
+ * Get all suite names
758
+ */
759
+ getSuiteNames() {
760
+ return Array.from(this.suites.keys());
761
+ }
762
+ /**
763
+ * Get a specific suite by name
764
+ */
765
+ getSuite(suiteName) {
766
+ return this.suites.get(suiteName);
767
+ }
768
+ /**
769
+ * Run a specific case in a specific suite
770
+ * @param suiteName The suite name
771
+ * @param caseId The case ID to run
772
+ * @returns Case run result with error handling
773
+ */
774
+ async runCase(suiteName, caseId) {
775
+ const suite = this.getSuite(suiteName);
776
+ if (!suite) {
777
+ return {
778
+ caseId,
779
+ error: `Suite not found: ${suiteName}`,
780
+ logs: []
781
+ };
782
+ }
783
+ return suite.runCase(caseId);
784
+ }
785
+ /**
786
+ * Run all cases in a specific suite with concurrency control and error isolation
787
+ * @param suiteName The suite name
788
+ * @param concurrency Optional concurrency limit (overrides project config)
789
+ * @returns Array of case run results with error handling
790
+ */
791
+ async runSuite(suiteName, concurrency) {
792
+ const suite = this.getSuite(suiteName);
793
+ if (!suite) {
794
+ throw new Error(`Suite not found: ${suiteName}`);
795
+ }
796
+ return suite.runAllCases(concurrency);
797
+ }
798
+ /**
799
+ * Run all cases in all suites with concurrency control and error isolation
800
+ * @param concurrency Optional concurrency limit (overrides project config)
801
+ * @returns Map of suite names to their case run results
802
+ */
803
+ async runAllSuites(concurrency) {
804
+ const results = /* @__PURE__ */ new Map();
805
+ for (const suiteName of this.getSuiteNames()) {
806
+ try {
807
+ const suiteResults = await this.runSuite(suiteName, concurrency);
808
+ results.set(suiteName, suiteResults);
809
+ } catch (error) {
810
+ const suite = this.getSuite(suiteName);
811
+ if (suite) {
812
+ const errorResults = suite.getCases().map((c) => ({
813
+ caseId: c.caseId,
814
+ error: error instanceof Error ? error.message : String(error),
815
+ logs: []
816
+ }));
817
+ results.set(suiteName, errorResults);
818
+ }
819
+ }
820
+ }
821
+ return results;
822
+ }
823
+ /**
824
+ * Run all suites as a "batch", build a report, and optionally write it to disk.
825
+ */
826
+ async runAllSuitesBatch(concurrency) {
827
+ const started_at = (/* @__PURE__ */ new Date()).toISOString();
828
+ const batch_id = this.reportConfig?.batch_id || `${Date.now()}`;
829
+ console.log(`
830
+ Running batch: ${this.project.projectName} (${this.getSuiteNames().length} suites)`);
831
+ const results = await this.runAllSuites(concurrency);
832
+ let total_cases = 0;
833
+ let passed_cases = 0;
834
+ let failed_cases = 0;
835
+ const suites = [];
836
+ const durations = [];
837
+ for (const [suiteName, caseResults] of results.entries()) {
838
+ const suiteTotal = caseResults.length;
839
+ const suitePassed = caseResults.filter((r) => r.result?.pass).length;
840
+ const suiteFailed = suiteTotal - suitePassed;
841
+ total_cases += suiteTotal;
842
+ passed_cases += suitePassed;
843
+ failed_cases += suiteFailed;
844
+ suites.push({
845
+ suiteName,
846
+ total_cases: suiteTotal,
847
+ passed_cases: suitePassed,
848
+ failed_cases: suiteFailed,
849
+ cases: caseResults.map((r) => ({
850
+ caseId: r.caseId,
851
+ pass: r.result?.pass,
852
+ final_score: r.result?.final_score,
853
+ error: r.error
854
+ }))
855
+ });
856
+ for (const r of caseResults) {
857
+ if (typeof r.duration_ms === "number") durations.push(r.duration_ms);
858
+ }
859
+ }
860
+ const finished_at = (/* @__PURE__ */ new Date()).toISOString();
861
+ const report = {
862
+ batch_id,
863
+ started_at,
864
+ finished_at,
865
+ project: {
866
+ projectName: this.project.projectName,
867
+ version: this.project.version,
868
+ description: this.project.description
869
+ },
870
+ summary: {
871
+ total_cases,
872
+ passed_cases,
873
+ failed_cases,
874
+ pass_rate: total_cases > 0 ? passed_cases / total_cases : 0
875
+ },
876
+ suites
877
+ };
878
+ const batch_dir = await this.maybeWriteBatchArtifacts(
879
+ batch_id,
880
+ report,
881
+ results
882
+ );
883
+ console.log(`
884
+ === Summary ===`);
885
+ console.log(`Total: ${report.summary.total_cases} | Passed: ${report.summary.passed_cases} | Failed: ${report.summary.failed_cases} | Pass Rate: ${(report.summary.pass_rate * 100).toFixed(2)}%`);
886
+ if (batch_dir) {
887
+ console.log(`
888
+ Results saved to: ${batch_dir}`);
889
+ }
890
+ return { batch_id, batch_dir, results, report };
891
+ }
892
+ generateCaseMarkdown(index, suiteName, caseResult, payload) {
893
+ const lines = [];
894
+ const status = caseResult.result?.pass ? "\u2705 PASS" : "\u274C FAIL";
895
+ lines.push(`# Test ${index}: ${status}`);
896
+ lines.push(``);
897
+ lines.push(`- **Suite**: ${suiteName}`);
898
+ lines.push(`- **Case ID**: ${caseResult.caseId}`);
899
+ lines.push(`- **Status**: ${caseResult.result?.pass ? "PASS" : "FAIL"}`);
900
+ if (typeof payload.duration === "number") {
901
+ lines.push(`- **Duration**: ${(payload.duration / 1e3).toFixed(2)}s`);
902
+ }
903
+ if (payload.threadId) {
904
+ lines.push(`- **Thread ID**: ${payload.threadId}`);
905
+ }
906
+ if (payload.judgeThreadId) {
907
+ lines.push(`- **Judge Thread ID**: ${payload.judgeThreadId}`);
908
+ }
909
+ lines.push(``);
910
+ if (caseResult.result) {
911
+ lines.push(`## Result`);
912
+ lines.push(``);
913
+ lines.push(`- **Final Score**: ${caseResult.result.final_score}`);
914
+ lines.push(`- **Summary**: ${caseResult.result.summary || "N/A"}`);
915
+ lines.push(``);
916
+ if (caseResult.result.dimension_results && caseResult.result.dimension_results.length > 0) {
917
+ lines.push(`## Dimension Results`);
918
+ lines.push(``);
919
+ for (const dim of caseResult.result.dimension_results) {
920
+ lines.push(`### ${dim.name}`);
921
+ lines.push(`- **Score**: ${dim.score}`);
922
+ lines.push(`- **Reason**: ${dim.reason}`);
923
+ lines.push(``);
924
+ }
925
+ }
926
+ }
927
+ if (caseResult.error) {
928
+ lines.push(`## Error`);
929
+ lines.push(``);
930
+ lines.push(`\`\`\``);
931
+ lines.push(caseResult.error);
932
+ if (caseResult.error_stack) {
933
+ lines.push(``);
934
+ lines.push(caseResult.error_stack);
935
+ }
936
+ lines.push(`\`\`\``);
937
+ lines.push(``);
938
+ }
939
+ if (payload.finalOutput) {
940
+ lines.push(`## Final Output`);
941
+ lines.push(``);
942
+ lines.push(`\`\`\``);
943
+ const output = payload.finalOutput.length > 5e3 ? payload.finalOutput.substring(0, 5e3) + "\n\n... (truncated, see JSON for full output)" : payload.finalOutput;
944
+ lines.push(output);
945
+ lines.push(`\`\`\``);
946
+ lines.push(``);
947
+ }
948
+ if (payload.testPrompt) {
949
+ lines.push(`## Test Prompt`);
950
+ lines.push(``);
951
+ lines.push(`\`\`\``);
952
+ const prompt = payload.testPrompt.length > 5e3 ? payload.testPrompt.substring(0, 5e3) + "\n\n... (truncated, see JSON for full prompt)" : payload.testPrompt;
953
+ lines.push(prompt);
954
+ lines.push(`\`\`\``);
955
+ lines.push(``);
956
+ }
957
+ return lines.join("\n");
958
+ }
959
+ generateMarkdownSummary(batch_id, report, results) {
960
+ const lines = [];
961
+ lines.push(`# Lattice Eval Batch Summary`);
962
+ lines.push(``);
963
+ lines.push(`- **Project**: ${report.project.projectName}`);
964
+ if (report.project.version) lines.push(`- **Version**: ${report.project.version}`);
965
+ if (report.project.description) lines.push(`- **Description**: ${report.project.description}`);
966
+ lines.push(`- **Batch ID**: ${batch_id}`);
967
+ lines.push(`- **Started**: ${report.started_at}`);
968
+ lines.push(`- **Finished**: ${report.finished_at}`);
969
+ lines.push(``);
970
+ lines.push(`## Overview`);
971
+ lines.push(``);
972
+ lines.push(`| Metric | Value |`);
973
+ lines.push(`|---|---:|`);
974
+ lines.push(`| Total cases | ${report.summary.total_cases} |`);
975
+ lines.push(`| Passed | ${report.summary.passed_cases} |`);
976
+ lines.push(`| Failed | ${report.summary.failed_cases} |`);
977
+ lines.push(`| Pass rate | ${(report.summary.pass_rate * 100).toFixed(2)}% |`);
978
+ lines.push(``);
979
+ lines.push(`## Suites`);
980
+ lines.push(``);
981
+ for (const suite of report.suites) {
982
+ lines.push(`### ${suite.suiteName}`);
983
+ lines.push(``);
984
+ lines.push(`| Case | Status | Score | Duration (ms) | Thread |`);
985
+ lines.push(`|---|---|---:|---:|---|`);
986
+ const suiteResults = results.get(suite.suiteName) || [];
987
+ for (const r of suiteResults) {
988
+ const status = r.result?.pass ? "PASS" : "FAIL";
989
+ const score = r.result?.final_score ?? "";
990
+ const dur = typeof r.duration_ms === "number" ? r.duration_ms : "";
991
+ const thread = r.thread_id ?? "";
992
+ lines.push(`| ${r.caseId} | ${status} | ${score} | ${dur} | ${thread} |`);
993
+ }
994
+ lines.push(``);
995
+ }
996
+ return lines.join("\n");
997
+ }
998
+ async maybeWriteBatchArtifacts(batch_id, report, results) {
999
+ const config = this.reportConfig;
1000
+ if (!config?.output_dir) return void 0;
1001
+ const batchDir = import_path.default.join(config.output_dir, batch_id);
1002
+ await (0, import_promises.mkdir)(batchDir, { recursive: true });
1003
+ const writeReportJson = config.write_report_json ?? true;
1004
+ const writeCaseLogs = config.write_case_logs ?? true;
1005
+ if (writeReportJson) {
1006
+ await (0, import_promises.writeFile)(
1007
+ import_path.default.join(batchDir, "report.json"),
1008
+ JSON.stringify(report, null, 2),
1009
+ "utf-8"
1010
+ );
1011
+ }
1012
+ const resultsJsonPath = import_path.default.join(batchDir, "results.json");
1013
+ const resultsJson = {
1014
+ executionTimestamp: batch_id,
1015
+ summary: report.summary,
1016
+ report,
1017
+ results: Array.from(results.entries()).map(([suiteName, caseResults]) => ({
1018
+ suiteName,
1019
+ cases: caseResults.map((r) => ({
1020
+ caseId: r.caseId,
1021
+ passed: r.result?.pass === true,
1022
+ message: r.result?.summary || r.error || "",
1023
+ error: r.error ? {
1024
+ message: r.error,
1025
+ stack: r.error_stack
1026
+ } : void 0,
1027
+ duration: r.duration_ms,
1028
+ testPrompt: r.test_prompt,
1029
+ finalOutput: r.final_output,
1030
+ threadId: r.thread_id,
1031
+ judgeThreadId: r.judge_thread_id
1032
+ }))
1033
+ }))
1034
+ };
1035
+ await (0, import_promises.writeFile)(resultsJsonPath, JSON.stringify(resultsJson, null, 2), "utf-8");
1036
+ const summaryMdPath = import_path.default.join(batchDir, "summary.md");
1037
+ const summaryMd = this.generateMarkdownSummary(batch_id, report, results);
1038
+ await (0, import_promises.writeFile)(summaryMdPath, summaryMd, "utf-8");
1039
+ const individualDir = import_path.default.join(batchDir, "individual");
1040
+ await (0, import_promises.mkdir)(individualDir, { recursive: true });
1041
+ let index = 1;
1042
+ for (const [suiteName, caseResults] of results.entries()) {
1043
+ for (const r of caseResults) {
1044
+ const status = r.result?.pass ? "PASS" : "FAIL";
1045
+ const baseFilename = `test-${index}-${suiteName}-${r.caseId}-${status}`.replace(/[\/\\]/g, "_");
1046
+ const jsonPath = import_path.default.join(individualDir, `${baseFilename}.json`);
1047
+ const payload = {
1048
+ index,
1049
+ suiteName,
1050
+ caseId: r.caseId,
1051
+ passed: r.result?.pass === true,
1052
+ result: r.result,
1053
+ message: r.result?.summary || r.error || "",
1054
+ error: r.error ? { message: r.error, stack: r.error_stack } : void 0,
1055
+ duration: r.duration_ms,
1056
+ threadId: r.thread_id,
1057
+ judgeThreadId: r.judge_thread_id,
1058
+ finalOutput: r.final_output,
1059
+ testPrompt: r.test_prompt
1060
+ };
1061
+ await (0, import_promises.writeFile)(jsonPath, JSON.stringify(payload, null, 2), "utf-8");
1062
+ const mdPath = import_path.default.join(individualDir, `${baseFilename}.md`);
1063
+ const mdContent = this.generateCaseMarkdown(index, suiteName, r, payload);
1064
+ await (0, import_promises.writeFile)(mdPath, mdContent, "utf-8");
1065
+ index += 1;
1066
+ }
1067
+ }
1068
+ if (writeCaseLogs) {
1069
+ for (const [suiteName, caseResults] of results.entries()) {
1070
+ const suiteDir = import_path.default.join(batchDir, "cases", suiteName);
1071
+ await (0, import_promises.mkdir)(suiteDir, { recursive: true });
1072
+ for (const r of caseResults) {
1073
+ await (0, import_promises.writeFile)(
1074
+ import_path.default.join(suiteDir, `${r.caseId}.logs.json`),
1075
+ JSON.stringify(r.logs || [], null, 2),
1076
+ "utf-8"
1077
+ );
1078
+ }
1079
+ }
1080
+ }
1081
+ return batchDir;
1082
+ }
1083
+ };
1084
+ // Annotate the CommonJS export names for ESM import in node:
1085
+ 0 && (module.exports = {
1086
+ LatticeEval,
1087
+ LatticeEvalProject,
1088
+ LatticeEvalSuite,
1089
+ evaluateLatticeCase,
1090
+ evaluateLatticeCaseWithLogs
1091
+ });
1092
+ //# sourceMappingURL=index.js.map