mcp-eval-gateway 1.0.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,479 @@
1
+ // src/init-eval-project.ts
2
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
3
+ import { join } from "path";
4
+ var EXISTING_FILES = [
5
+ "config.ts",
6
+ "config.mts",
7
+ "config.mjs",
8
+ "config.js",
9
+ "tasks.yaml"
10
+ ];
11
+ var INIT_CONFIG = `export default {
12
+ model: 'gateway/anthropic/claude-sonnet-4-6',
13
+ threshold: 0.8,
14
+ mcp: {
15
+ url: 'http://localhost/mcp',
16
+ headers: { Authorization: \`Bearer \${process.env.MCP_API_KEY}\` },
17
+ },
18
+ };
19
+ `;
20
+ var INIT_TASKS = `- name: ping
21
+ prompt: Call the ping tool and return its text
22
+ expected: pong
23
+ required: true
24
+ `;
25
+ function initEvalProject(rootDir, options) {
26
+ const relativeDir = options?.dir ?? "eval";
27
+ const evalDir = join(rootDir, relativeDir);
28
+ for (const filename of EXISTING_FILES) {
29
+ if (existsSync(join(evalDir, filename))) {
30
+ throw new Error(`${relativeDir}/${filename} already exists`);
31
+ }
32
+ }
33
+ mkdirSync(evalDir, { recursive: true });
34
+ writeFileSync(join(evalDir, "config.ts"), INIT_CONFIG);
35
+ writeFileSync(join(evalDir, "tasks.yaml"), INIT_TASKS);
36
+ }
37
+
38
+ // src/mcp-tools.ts
39
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
40
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
41
+ import { dynamicTool, jsonSchema } from "ai";
42
+ var PACKAGE_VERSION = "0.1.0";
43
+ function contentText(result) {
44
+ if (!("content" in result) || !Array.isArray(result.content)) {
45
+ return "";
46
+ }
47
+ return result.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
48
+ }
49
+ async function toolsFromMcp(options) {
50
+ const transport = "transport" in options ? options.transport : new StreamableHTTPClientTransport(new URL(options.url), {
51
+ fetch: options.fetch,
52
+ requestInit: options.headers ? { headers: options.headers } : void 0
53
+ });
54
+ const client = new Client({ name: "mcp-eval-gateway", version: PACKAGE_VERSION });
55
+ await client.connect(transport);
56
+ try {
57
+ const { tools: listed } = await client.listTools();
58
+ const tools = {};
59
+ for (const listedTool of listed) {
60
+ tools[listedTool.name] = dynamicTool({
61
+ description: listedTool.description,
62
+ inputSchema: jsonSchema(listedTool.inputSchema),
63
+ execute: async (input) => {
64
+ const result = await client.callTool({
65
+ name: listedTool.name,
66
+ arguments: input
67
+ });
68
+ return contentText(result);
69
+ }
70
+ });
71
+ }
72
+ return {
73
+ tools,
74
+ close: () => client.close()
75
+ };
76
+ } catch (error) {
77
+ await client.close();
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ // src/evaluation-prompt.ts
83
+ var EVALUATION_PROMPT = `You are an AI assistant with access to tools.
84
+
85
+ When given a task, you MUST:
86
+ 1. Use the available tools to complete the task
87
+ 2. Provide summary of each step in your approach, wrapped in <summary> tags
88
+ 3. Provide feedback on the tools provided, wrapped in <feedback> tags
89
+ 4. Provide your final response, wrapped in <response> tags
90
+
91
+ Summary Requirements:
92
+ - In your <summary> tags, you must explain:
93
+ - The steps you took to complete the task
94
+ - Which tools you used, in what order, and why
95
+ - The inputs you provided to each tool
96
+ - The outputs you received from each tool
97
+ - A summary for how you arrived at the response
98
+
99
+ Feedback Requirements:
100
+ - In your <feedback> tags, provide constructive feedback on the tools:
101
+ - Comment on tool names: Are they clear and descriptive?
102
+ - Comment on input parameters: Are they well-documented? Are required vs optional parameters clear?
103
+ - Comment on descriptions: Do they accurately describe what the tool does?
104
+ - Comment on any errors encountered during tool usage: Did the tool fail to execute? Did the tool return too many tokens?
105
+ - Identify specific areas for improvement and explain WHY they would help
106
+ - Be specific and actionable in your suggestions
107
+
108
+ Response Requirements:
109
+ - Your response should be concise and directly address what was asked
110
+ - Always wrap your final response in <response> tags
111
+ - If you cannot solve the task return <response>NOT_FOUND</response>
112
+ - For numeric responses, provide just the number
113
+ - For IDs, provide just the ID
114
+ - For names or text, provide the exact text requested
115
+ - Your response should go last`;
116
+
117
+ // src/resolve-model.ts
118
+ var UNSUPPORTED_MODEL = (model) => `Unsupported model "${model}". Use one of: anthropic/<id>, openai/<id>, bedrock/<id>, gateway/<id>, or pass a LanguageModel instance.`;
119
+ function isModuleNotFound(error) {
120
+ if (typeof error !== "object" || error === null) {
121
+ return false;
122
+ }
123
+ const code = "code" in error ? error.code : void 0;
124
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
125
+ return true;
126
+ }
127
+ if (error instanceof Error) {
128
+ return error.message.includes("Cannot find module") || error.message.includes("Cannot find package");
129
+ }
130
+ return false;
131
+ }
132
+ function missingPeerError(model, pkg) {
133
+ return new Error(
134
+ `Model "${model}" requires the optional peer dependency "${pkg}". Install it: npm install --save-dev ${pkg}`
135
+ );
136
+ }
137
+ async function loadProvider(model, pkg, load) {
138
+ try {
139
+ return await load();
140
+ } catch (error) {
141
+ if (isModuleNotFound(error)) {
142
+ throw missingPeerError(model, pkg);
143
+ }
144
+ throw error;
145
+ }
146
+ }
147
+ async function resolveModel(model) {
148
+ const slash = model.indexOf("/");
149
+ if (slash === -1) {
150
+ throw new Error(UNSUPPORTED_MODEL(model));
151
+ }
152
+ const prefix = model.slice(0, slash);
153
+ const id = model.slice(slash + 1);
154
+ const providers = {
155
+ gateway: async () => id,
156
+ anthropic: () => loadProvider(
157
+ model,
158
+ "@ai-sdk/anthropic",
159
+ () => import("@ai-sdk/anthropic").then((m) => m.anthropic(id))
160
+ ),
161
+ openai: () => loadProvider(
162
+ model,
163
+ "@ai-sdk/openai",
164
+ () => import("@ai-sdk/openai").then((m) => m.openai(id))
165
+ ),
166
+ bedrock: () => loadProvider(
167
+ model,
168
+ "@ai-sdk/amazon-bedrock",
169
+ () => import("@ai-sdk/amazon-bedrock").then((m) => m.bedrock(id))
170
+ )
171
+ };
172
+ const resolve2 = providers[prefix];
173
+ if (!resolve2) {
174
+ throw new Error(UNSUPPORTED_MODEL(model));
175
+ }
176
+ return resolve2();
177
+ }
178
+
179
+ // src/run-evals.ts
180
+ import { generateText, isStepCount } from "ai";
181
+
182
+ // src/report.ts
183
+ function average(values) {
184
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
185
+ }
186
+ function renderReport(results) {
187
+ const total = results.length;
188
+ const correct = results.filter((result) => result.passed).length;
189
+ const accuracyPct = (correct / total * 100).toFixed(1);
190
+ const avgDurationSec = (average(results.map((result) => result.durationMs)) / 1e3).toFixed(2);
191
+ const toolCallCounts = results.map((result) => result.numToolCalls);
192
+ const totalToolCalls = toolCallCounts.reduce((sum, count) => sum + count, 0);
193
+ const avgToolCalls = average(toolCallCounts).toFixed(2);
194
+ const header = [
195
+ "# Evaluation Report",
196
+ "",
197
+ `- **Accuracy**: ${correct}/${total} (${accuracyPct}%)`,
198
+ `- **Average Duration**: ${avgDurationSec}s`,
199
+ `- **Average Tool Calls**: ${avgToolCalls}`,
200
+ `- **Total Tool Calls**: ${totalToolCalls}`
201
+ ].join("\n");
202
+ const sections = results.map((result) => {
203
+ const actual = result.actual ?? "N/A";
204
+ return [
205
+ `### Task: ${result.name}`,
206
+ "",
207
+ `**Prompt**: ${result.prompt}`,
208
+ "",
209
+ `**Ground Truth Response**: ${result.expected}`,
210
+ "",
211
+ `**Actual Response**: ${actual}`,
212
+ "",
213
+ `**Correct**: ${result.passed ? "\u2705" : "\u274C"}`,
214
+ "",
215
+ `**Duration**: ${(result.durationMs / 1e3).toFixed(2)}s`,
216
+ "",
217
+ `**Tool Calls**:`,
218
+ JSON.stringify(result.toolMetrics, null, 2),
219
+ "",
220
+ `**Summary**: ${result.summary ?? "N/A"}`,
221
+ "",
222
+ `**Feedback**: ${result.feedback ?? "N/A"}`
223
+ ].join("\n");
224
+ });
225
+ return [header, ...sections].join("\n\n---\n\n");
226
+ }
227
+
228
+ // src/run-evals.ts
229
+ var defaultScorer = (actual, task) => actual === task.expected ? 1 : 0;
230
+ function extractTag(text, tag) {
231
+ const regex = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "g");
232
+ let last = null;
233
+ let match;
234
+ while ((match = regex.exec(text)) !== null) {
235
+ last = match[1] ?? null;
236
+ }
237
+ return last === null ? null : last.trim();
238
+ }
239
+ function wrapTools(tools, metrics) {
240
+ const wrapped = {};
241
+ for (const [name, tool] of Object.entries(tools)) {
242
+ const originalExecute = tool.execute;
243
+ wrapped[name] = {
244
+ ...tool,
245
+ execute: async (input, options) => {
246
+ const start = performance.now();
247
+ try {
248
+ return await originalExecute?.(input, options);
249
+ } catch (error) {
250
+ return `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`;
251
+ } finally {
252
+ const bucket = metrics[name] ?? { count: 0, durationsMs: [] };
253
+ bucket.count += 1;
254
+ bucket.durationsMs.push(performance.now() - start);
255
+ metrics[name] = bucket;
256
+ }
257
+ }
258
+ };
259
+ }
260
+ return wrapped;
261
+ }
262
+ async function runEvals(options) {
263
+ if (options.tasks.length === 0) {
264
+ throw new Error("No tasks ran");
265
+ }
266
+ const model = typeof options.model === "string" ? await resolveModel(options.model) : options.model;
267
+ const results = [];
268
+ for (const task of options.tasks) {
269
+ await task.setup?.();
270
+ const toolMetrics = {};
271
+ const wrappedTools = wrapTools(options.tools, toolMetrics);
272
+ const started = performance.now();
273
+ const generated = await generateText({
274
+ model,
275
+ system: options.systemPrompt ?? EVALUATION_PROMPT,
276
+ prompt: task.prompt,
277
+ tools: wrappedTools,
278
+ stopWhen: isStepCount(options.maxSteps ?? 20)
279
+ });
280
+ const durationMs = performance.now() - started;
281
+ const actual = extractTag(generated.text, "response");
282
+ const scorer = task.scorer ?? options.scorer ?? defaultScorer;
283
+ const score = scorer(actual, task);
284
+ const passed = score >= 1;
285
+ const numToolCalls = Object.values(toolMetrics).reduce(
286
+ (sum, metric) => sum + metric.count,
287
+ 0
288
+ );
289
+ results.push({
290
+ name: task.name,
291
+ prompt: task.prompt,
292
+ expected: task.expected,
293
+ actual,
294
+ score,
295
+ passed,
296
+ required: task.required ?? false,
297
+ durationMs,
298
+ toolMetrics,
299
+ numToolCalls,
300
+ summary: extractTag(generated.text, "summary"),
301
+ feedback: extractTag(generated.text, "feedback")
302
+ });
303
+ }
304
+ const total = results.length;
305
+ const correct = results.filter((result) => result.passed).length;
306
+ return {
307
+ total,
308
+ correct,
309
+ accuracy: correct / total,
310
+ results,
311
+ report: renderReport(results)
312
+ };
313
+ }
314
+
315
+ // src/threshold.ts
316
+ import { appendFileSync } from "fs";
317
+ function describeFailure(task) {
318
+ return `${task.name} (expected "${task.expected}", got "${task.actual}")`;
319
+ }
320
+ function assertEvalResult(result, options) {
321
+ if (result.total === 0 || result.results.length === 0) {
322
+ throw new Error("No tasks ran");
323
+ }
324
+ const requiredFailures = result.results.filter((task) => task.required && !task.passed);
325
+ if (requiredFailures.length > 0) {
326
+ const details = requiredFailures.map((task) => `Required task failed: ${describeFailure(task)}`).join("\n");
327
+ throw new Error(details);
328
+ }
329
+ const threshold = options?.threshold;
330
+ if (typeof threshold === "number" && result.accuracy < threshold) {
331
+ const failed = result.results.filter((task) => !task.passed);
332
+ const names = failed.map(describeFailure).join("; ");
333
+ throw new Error(
334
+ `Accuracy ${result.accuracy} is below threshold ${threshold}. Failed tasks: ${names}`
335
+ );
336
+ }
337
+ }
338
+ function writeGitHubSummary(result) {
339
+ const summaryPath = process.env.GITHUB_STEP_SUMMARY;
340
+ if (!summaryPath) {
341
+ return false;
342
+ }
343
+ appendFileSync(summaryPath, `${result.report}
344
+ `);
345
+ return true;
346
+ }
347
+
348
+ // src/run-eval-project.ts
349
+ import { createJiti } from "jiti";
350
+ import { existsSync as existsSync2, readFileSync } from "fs";
351
+ import { extname, isAbsolute, join as join2, resolve } from "path";
352
+ import { pathToFileURL } from "url";
353
+ import { parse } from "yaml";
354
+ var CONFIG_FILES = [
355
+ "config.ts",
356
+ "config.mts",
357
+ "config.mjs",
358
+ "config.js"
359
+ ];
360
+ function loadEnv(rootDir, options) {
361
+ const envFile = options?.envFile;
362
+ if (envFile !== void 0) {
363
+ const abs = isAbsolute(envFile) ? envFile : resolve(rootDir, envFile);
364
+ if (!existsSync2(abs)) {
365
+ throw new Error(`Missing env file: ${envFile}`);
366
+ }
367
+ process.loadEnvFile(abs);
368
+ return;
369
+ }
370
+ const dotenv = join2(rootDir, ".env");
371
+ if (existsSync2(dotenv)) {
372
+ process.loadEnvFile(dotenv);
373
+ }
374
+ }
375
+ function resolveConfigPath(evalDir, relativeDir) {
376
+ for (const filename of CONFIG_FILES) {
377
+ const abs = join2(evalDir, filename);
378
+ if (existsSync2(abs)) {
379
+ return abs;
380
+ }
381
+ }
382
+ const relatives = CONFIG_FILES.map((filename) => `${relativeDir}/${filename}`);
383
+ throw new Error(
384
+ `No ${relativeDir}/config found. Expected one of: ${relatives.join(", ")}`
385
+ );
386
+ }
387
+ async function loadConfig(abs) {
388
+ const ext = extname(abs);
389
+ if (ext === ".ts" || ext === ".mts") {
390
+ const jiti = createJiti(abs, { moduleCache: false });
391
+ const loaded2 = await jiti.import(abs);
392
+ return loaded2.default;
393
+ }
394
+ const loaded = await import(pathToFileURL(abs).href);
395
+ return loaded.default;
396
+ }
397
+ function requireStringField(item, field, relativeDir) {
398
+ const value = item[field];
399
+ if (typeof value !== "string") {
400
+ throw new Error(`${relativeDir}/tasks.yaml item is missing ${field}`);
401
+ }
402
+ return value;
403
+ }
404
+ function loadTasks(evalDir, relativeDir) {
405
+ const tasksPath = join2(evalDir, "tasks.yaml");
406
+ if (!existsSync2(tasksPath)) {
407
+ throw new Error(`Missing ${relativeDir}/tasks.yaml`);
408
+ }
409
+ const parsed = parse(readFileSync(tasksPath, "utf8"));
410
+ if (!Array.isArray(parsed)) {
411
+ throw new Error(`${relativeDir}/tasks.yaml must be an array`);
412
+ }
413
+ return parsed.map((item) => {
414
+ if (typeof item !== "object" || item === null) {
415
+ throw new Error(`${relativeDir}/tasks.yaml item is missing name`);
416
+ }
417
+ const record = item;
418
+ return {
419
+ name: requireStringField(record, "name", relativeDir),
420
+ prompt: requireStringField(record, "prompt", relativeDir),
421
+ expected: requireStringField(record, "expected", relativeDir),
422
+ required: record.required === true
423
+ };
424
+ });
425
+ }
426
+ async function runEvalProject(rootDir, options) {
427
+ loadEnv(rootDir, options);
428
+ const relativeDir = options?.dir ?? "eval";
429
+ const evalDir = join2(rootDir, relativeDir);
430
+ const config = await loadConfig(resolveConfigPath(evalDir, relativeDir));
431
+ const tasks = loadTasks(evalDir, relativeDir);
432
+ const models = options?.model !== void 0 ? [options.model] : Array.isArray(config.model) ? config.model : [config.model];
433
+ if (models.length === 0) {
434
+ throw new Error("model is empty");
435
+ }
436
+ const session = await toolsFromMcp(config.mcp);
437
+ try {
438
+ const results = [];
439
+ for (const entry of models) {
440
+ results.push(
441
+ await runEvals({
442
+ model: entry,
443
+ tools: session.tools,
444
+ tasks
445
+ })
446
+ );
447
+ }
448
+ for (const result of results) {
449
+ writeGitHubSummary(result);
450
+ }
451
+ const assertOptions = config.threshold === void 0 ? void 0 : { threshold: config.threshold };
452
+ const assertErrors = [];
453
+ for (const result of results) {
454
+ try {
455
+ assertEvalResult(result, assertOptions);
456
+ } catch (err) {
457
+ assertErrors.push(err instanceof Error ? err : new Error(String(err)));
458
+ }
459
+ }
460
+ if (assertErrors.length > 0) {
461
+ throw new Error(assertErrors.map((err) => err.message).join("\n"));
462
+ }
463
+ return results[results.length - 1];
464
+ } finally {
465
+ await session.close();
466
+ }
467
+ }
468
+
469
+ export {
470
+ initEvalProject,
471
+ toolsFromMcp,
472
+ EVALUATION_PROMPT,
473
+ resolveModel,
474
+ runEvals,
475
+ assertEvalResult,
476
+ writeGitHubSummary,
477
+ runEvalProject
478
+ };
479
+ //# sourceMappingURL=chunk-6UIMILU4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init-eval-project.ts","../src/mcp-tools.ts","../src/evaluation-prompt.ts","../src/resolve-model.ts","../src/run-evals.ts","../src/report.ts","../src/threshold.ts","../src/run-eval-project.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst EXISTING_FILES = [\n 'config.ts',\n 'config.mts',\n 'config.mjs',\n 'config.js',\n 'tasks.yaml',\n] as const;\n\nconst INIT_CONFIG = `export default {\n model: 'gateway/anthropic/claude-sonnet-4-6',\n threshold: 0.8,\n mcp: {\n url: 'http://localhost/mcp',\n headers: { Authorization: \\`Bearer \\${process.env.MCP_API_KEY}\\` },\n },\n};\n`;\n\nconst INIT_TASKS = `- name: ping\n prompt: Call the ping tool and return its text\n expected: pong\n required: true\n`;\n\nexport type InitEvalProjectOptions = {\n dir?: string;\n};\n\nexport function initEvalProject(\n rootDir: string,\n options?: InitEvalProjectOptions,\n): void {\n const relativeDir = options?.dir ?? 'eval';\n const evalDir = join(rootDir, relativeDir);\n\n for (const filename of EXISTING_FILES) {\n if (existsSync(join(evalDir, filename))) {\n throw new Error(`${relativeDir}/${filename} already exists`);\n }\n }\n\n mkdirSync(evalDir, { recursive: true });\n writeFileSync(join(evalDir, 'config.ts'), INIT_CONFIG);\n writeFileSync(join(evalDir, 'tasks.yaml'), INIT_TASKS);\n}\n","import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { FetchLike, Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { dynamicTool, jsonSchema, type JSONSchema7, type ToolSet } from 'ai';\n\nconst PACKAGE_VERSION = '0.1.0';\n\nexport type ToolsFromMcpOptions =\n | {\n url: string | URL;\n fetch?: FetchLike;\n headers?: Record<string, string>;\n }\n | {\n transport: Transport;\n };\n\nfunction contentText(result: Awaited<ReturnType<Client['callTool']>>): string {\n if (!('content' in result) || !Array.isArray(result.content)) {\n return '';\n }\n\n return result.content\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n}\n\nexport async function toolsFromMcp(\n options: ToolsFromMcpOptions,\n): Promise<{ tools: ToolSet; close: () => Promise<void> }> {\n const transport =\n 'transport' in options\n ? options.transport\n : new StreamableHTTPClientTransport(new URL(options.url), {\n fetch: options.fetch,\n requestInit: options.headers ? { headers: options.headers } : undefined,\n });\n\n const client = new Client({ name: 'mcp-eval-gateway', version: PACKAGE_VERSION });\n await client.connect(transport);\n\n try {\n const { tools: listed } = await client.listTools();\n const tools: ToolSet = {};\n\n for (const listedTool of listed) {\n tools[listedTool.name] = dynamicTool({\n description: listedTool.description,\n inputSchema: jsonSchema(listedTool.inputSchema as JSONSchema7),\n execute: async (input) => {\n const result = await client.callTool({\n name: listedTool.name,\n arguments: input as Record<string, unknown>,\n });\n return contentText(result);\n },\n });\n }\n\n return {\n tools,\n close: () => client.close(),\n };\n } catch (error) {\n await client.close();\n throw error;\n }\n}\n","export const EVALUATION_PROMPT = `You are an AI assistant with access to tools.\n\nWhen given a task, you MUST:\n1. Use the available tools to complete the task\n2. Provide summary of each step in your approach, wrapped in <summary> tags\n3. Provide feedback on the tools provided, wrapped in <feedback> tags\n4. Provide your final response, wrapped in <response> tags\n\nSummary Requirements:\n- In your <summary> tags, you must explain:\n - The steps you took to complete the task\n - Which tools you used, in what order, and why\n - The inputs you provided to each tool\n - The outputs you received from each tool\n - A summary for how you arrived at the response\n\nFeedback Requirements:\n- In your <feedback> tags, provide constructive feedback on the tools:\n - Comment on tool names: Are they clear and descriptive?\n - Comment on input parameters: Are they well-documented? Are required vs optional parameters clear?\n - Comment on descriptions: Do they accurately describe what the tool does?\n - Comment on any errors encountered during tool usage: Did the tool fail to execute? Did the tool return too many tokens?\n - Identify specific areas for improvement and explain WHY they would help\n - Be specific and actionable in your suggestions\n\nResponse Requirements:\n- Your response should be concise and directly address what was asked\n- Always wrap your final response in <response> tags\n- If you cannot solve the task return <response>NOT_FOUND</response>\n- For numeric responses, provide just the number\n- For IDs, provide just the ID\n- For names or text, provide the exact text requested\n- Your response should go last`;\n","import type { LanguageModel } from 'ai';\n\nconst UNSUPPORTED_MODEL = (model: string) =>\n `Unsupported model \"${model}\". Use one of: anthropic/<id>, openai/<id>, bedrock/<id>, gateway/<id>, or pass a LanguageModel instance.`;\n\nfunction isModuleNotFound(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n\n const code = 'code' in error ? error.code : undefined;\n if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {\n return true;\n }\n\n if (error instanceof Error) {\n return (\n error.message.includes('Cannot find module') ||\n error.message.includes('Cannot find package')\n );\n }\n\n return false;\n}\n\nfunction missingPeerError(model: string, pkg: string): Error {\n return new Error(\n `Model \"${model}\" requires the optional peer dependency \"${pkg}\". Install it: npm install --save-dev ${pkg}`,\n );\n}\n\nasync function loadProvider(\n model: string,\n pkg: string,\n load: () => Promise<LanguageModel>,\n): Promise<LanguageModel> {\n try {\n return await load();\n } catch (error) {\n if (isModuleNotFound(error)) {\n throw missingPeerError(model, pkg);\n }\n throw error;\n }\n}\n\nexport async function resolveModel(model: string): Promise<LanguageModel> {\n const slash = model.indexOf('/');\n if (slash === -1) {\n throw new Error(UNSUPPORTED_MODEL(model));\n }\n\n const prefix = model.slice(0, slash);\n const id = model.slice(slash + 1);\n\n const providers: Record<string, () => Promise<LanguageModel>> = {\n gateway: async () => id,\n anthropic: () =>\n loadProvider(model, '@ai-sdk/anthropic', () =>\n import('@ai-sdk/anthropic').then((m) => m.anthropic(id)),\n ),\n openai: () =>\n loadProvider(model, '@ai-sdk/openai', () =>\n import('@ai-sdk/openai').then((m) => m.openai(id)),\n ),\n bedrock: () =>\n loadProvider(model, '@ai-sdk/amazon-bedrock', () =>\n import('@ai-sdk/amazon-bedrock').then((m) => m.bedrock(id)),\n ),\n };\n\n const resolve = providers[prefix];\n if (!resolve) {\n throw new Error(UNSUPPORTED_MODEL(model));\n }\n\n return resolve();\n}\n","import { generateText, isStepCount, type LanguageModel, type ToolSet } from 'ai';\nimport { EVALUATION_PROMPT } from './evaluation-prompt';\nimport { renderReport } from './report';\nimport { resolveModel } from './resolve-model';\nimport type { EvalRunResult, EvalTask, TaskResult, ToolMetrics } from './types';\n\nexport type RunEvalsOptions = {\n model: string | LanguageModel;\n tools: ToolSet;\n tasks: EvalTask[];\n maxSteps?: number;\n systemPrompt?: string;\n scorer?: (actual: string | null, task: EvalTask) => number;\n};\n\nconst defaultScorer = (actual: string | null, task: EvalTask): number =>\n actual === task.expected ? 1 : 0;\n\nfunction extractTag(text: string, tag: string): string | null {\n const regex = new RegExp(`<${tag}>([\\\\s\\\\S]*?)</${tag}>`, 'g');\n let last: string | null = null;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n last = match[1] ?? null;\n }\n return last === null ? null : last.trim();\n}\n\nfunction wrapTools(tools: ToolSet, metrics: ToolMetrics): ToolSet {\n const wrapped: ToolSet = {};\n\n for (const [name, tool] of Object.entries(tools)) {\n const originalExecute = tool.execute;\n wrapped[name] = {\n ...tool,\n execute: async (input, options) => {\n const start = performance.now();\n try {\n return await originalExecute?.(input, options);\n } catch (error) {\n return `Error executing tool ${name}: ${\n error instanceof Error ? error.message : String(error)\n }`;\n } finally {\n const bucket = metrics[name] ?? { count: 0, durationsMs: [] };\n bucket.count += 1;\n bucket.durationsMs.push(performance.now() - start);\n metrics[name] = bucket;\n }\n },\n };\n }\n\n return wrapped;\n}\n\nexport async function runEvals(options: RunEvalsOptions): Promise<EvalRunResult> {\n if (options.tasks.length === 0) {\n throw new Error('No tasks ran');\n }\n\n const model =\n typeof options.model === 'string' ? await resolveModel(options.model) : options.model;\n\n const results: TaskResult[] = [];\n\n for (const task of options.tasks) {\n await task.setup?.();\n\n const toolMetrics: ToolMetrics = {};\n const wrappedTools = wrapTools(options.tools, toolMetrics);\n const started = performance.now();\n\n const generated = await generateText({\n model,\n system: options.systemPrompt ?? EVALUATION_PROMPT,\n prompt: task.prompt,\n tools: wrappedTools,\n stopWhen: isStepCount(options.maxSteps ?? 20),\n });\n\n const durationMs = performance.now() - started;\n const actual = extractTag(generated.text, 'response');\n const scorer = task.scorer ?? options.scorer ?? defaultScorer;\n const score = scorer(actual, task);\n const passed = score >= 1;\n const numToolCalls = Object.values(toolMetrics).reduce(\n (sum, metric) => sum + metric.count,\n 0,\n );\n\n results.push({\n name: task.name,\n prompt: task.prompt,\n expected: task.expected,\n actual,\n score,\n passed,\n required: task.required ?? false,\n durationMs,\n toolMetrics,\n numToolCalls,\n summary: extractTag(generated.text, 'summary'),\n feedback: extractTag(generated.text, 'feedback'),\n });\n }\n\n const total = results.length;\n const correct = results.filter((result) => result.passed).length;\n\n return {\n total,\n correct,\n accuracy: correct / total,\n results,\n report: renderReport(results),\n };\n}\n","import type { TaskResult } from './types';\n\nfunction average(values: number[]): number {\n return values.reduce((sum, value) => sum + value, 0) / values.length;\n}\n\nexport function renderReport(results: TaskResult[]): string {\n const total = results.length;\n const correct = results.filter((result) => result.passed).length;\n const accuracyPct = ((correct / total) * 100).toFixed(1);\n const avgDurationSec = (average(results.map((result) => result.durationMs)) / 1000).toFixed(2);\n const toolCallCounts = results.map((result) => result.numToolCalls);\n const totalToolCalls = toolCallCounts.reduce((sum, count) => sum + count, 0);\n const avgToolCalls = average(toolCallCounts).toFixed(2);\n\n const header = [\n '# Evaluation Report',\n '',\n `- **Accuracy**: ${correct}/${total} (${accuracyPct}%)`,\n `- **Average Duration**: ${avgDurationSec}s`,\n `- **Average Tool Calls**: ${avgToolCalls}`,\n `- **Total Tool Calls**: ${totalToolCalls}`,\n ].join('\\n');\n\n const sections = results.map((result) => {\n const actual = result.actual ?? 'N/A';\n return [\n `### Task: ${result.name}`,\n '',\n `**Prompt**: ${result.prompt}`,\n '',\n `**Ground Truth Response**: ${result.expected}`,\n '',\n `**Actual Response**: ${actual}`,\n '',\n `**Correct**: ${result.passed ? '✅' : '❌'}`,\n '',\n `**Duration**: ${(result.durationMs / 1000).toFixed(2)}s`,\n '',\n `**Tool Calls**:`,\n JSON.stringify(result.toolMetrics, null, 2),\n '',\n `**Summary**: ${result.summary ?? 'N/A'}`,\n '',\n `**Feedback**: ${result.feedback ?? 'N/A'}`,\n ].join('\\n');\n });\n\n return [header, ...sections].join('\\n\\n---\\n\\n');\n}\n","import { appendFileSync } from 'node:fs';\nimport type { EvalRunResult, TaskResult } from './types';\n\nfunction describeFailure(task: TaskResult): string {\n return `${task.name} (expected \"${task.expected}\", got \"${task.actual}\")`;\n}\n\nexport function assertEvalResult(\n result: EvalRunResult,\n options?: { threshold?: number },\n): void {\n if (result.total === 0 || result.results.length === 0) {\n throw new Error('No tasks ran');\n }\n\n const requiredFailures = result.results.filter((task) => task.required && !task.passed);\n if (requiredFailures.length > 0) {\n const details = requiredFailures\n .map((task) => `Required task failed: ${describeFailure(task)}`)\n .join('\\n');\n throw new Error(details);\n }\n\n const threshold = options?.threshold;\n if (typeof threshold === 'number' && result.accuracy < threshold) {\n const failed = result.results.filter((task) => !task.passed);\n const names = failed.map(describeFailure).join('; ');\n throw new Error(\n `Accuracy ${result.accuracy} is below threshold ${threshold}. Failed tasks: ${names}`,\n );\n }\n}\n\nexport function writeGitHubSummary(result: EvalRunResult): boolean {\n const summaryPath = process.env.GITHUB_STEP_SUMMARY;\n if (!summaryPath) {\n return false;\n }\n\n appendFileSync(summaryPath, `${result.report}\\n`);\n return true;\n}\n","import type { LanguageModel } from 'ai';\nimport { createJiti } from 'jiti';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { extname, isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { parse } from 'yaml';\nimport { toolsFromMcp, type ToolsFromMcpOptions } from './mcp-tools';\nimport { runEvals } from './run-evals';\nimport { assertEvalResult, writeGitHubSummary } from './threshold';\nimport type { EvalRunResult, EvalTask } from './types';\n\nconst CONFIG_FILES = [\n 'config.ts',\n 'config.mts',\n 'config.mjs',\n 'config.js',\n] as const;\n\nexport type RunEvalProjectOptions = {\n dir?: string;\n envFile?: string;\n model?: string;\n};\n\ntype EvalProjectModel = string | LanguageModel;\n\ntype EvalProjectConfig = {\n model: EvalProjectModel | EvalProjectModel[];\n threshold?: number;\n mcp: ToolsFromMcpOptions;\n};\n\nfunction loadEnv(rootDir: string, options?: RunEvalProjectOptions): void {\n const envFile = options?.envFile;\n if (envFile !== undefined) {\n const abs = isAbsolute(envFile) ? envFile : resolve(rootDir, envFile);\n if (!existsSync(abs)) {\n throw new Error(`Missing env file: ${envFile}`);\n }\n process.loadEnvFile(abs);\n return;\n }\n\n const dotenv = join(rootDir, '.env');\n if (existsSync(dotenv)) {\n process.loadEnvFile(dotenv);\n }\n}\n\nfunction resolveConfigPath(evalDir: string, relativeDir: string): string {\n for (const filename of CONFIG_FILES) {\n const abs = join(evalDir, filename);\n if (existsSync(abs)) {\n return abs;\n }\n }\n const relatives = CONFIG_FILES.map((filename) => `${relativeDir}/${filename}`);\n throw new Error(\n `No ${relativeDir}/config found. Expected one of: ${relatives.join(', ')}`,\n );\n}\n\nasync function loadConfig(abs: string): Promise<EvalProjectConfig> {\n const ext = extname(abs);\n if (ext === '.ts' || ext === '.mts') {\n const jiti = createJiti(abs, { moduleCache: false });\n const loaded = (await jiti.import(abs)) as { default: EvalProjectConfig };\n return loaded.default;\n }\n const loaded = (await import(pathToFileURL(abs).href)) as {\n default: EvalProjectConfig;\n };\n return loaded.default;\n}\n\nfunction requireStringField(\n item: Record<string, unknown>,\n field: string,\n relativeDir: string,\n): string {\n const value = item[field];\n if (typeof value !== 'string') {\n throw new Error(`${relativeDir}/tasks.yaml item is missing ${field}`);\n }\n return value;\n}\n\nfunction loadTasks(evalDir: string, relativeDir: string): EvalTask[] {\n const tasksPath = join(evalDir, 'tasks.yaml');\n if (!existsSync(tasksPath)) {\n throw new Error(`Missing ${relativeDir}/tasks.yaml`);\n }\n\n const parsed: unknown = parse(readFileSync(tasksPath, 'utf8'));\n if (!Array.isArray(parsed)) {\n throw new Error(`${relativeDir}/tasks.yaml must be an array`);\n }\n\n return parsed.map((item: unknown) => {\n if (typeof item !== 'object' || item === null) {\n throw new Error(`${relativeDir}/tasks.yaml item is missing name`);\n }\n const record = item as Record<string, unknown>;\n return {\n name: requireStringField(record, 'name', relativeDir),\n prompt: requireStringField(record, 'prompt', relativeDir),\n expected: requireStringField(record, 'expected', relativeDir),\n required: record.required === true,\n };\n });\n}\n\nexport async function runEvalProject(\n rootDir: string,\n options?: RunEvalProjectOptions,\n): Promise<EvalRunResult> {\n loadEnv(rootDir, options);\n\n const relativeDir = options?.dir ?? 'eval';\n const evalDir = join(rootDir, relativeDir);\n const config = await loadConfig(resolveConfigPath(evalDir, relativeDir));\n const tasks = loadTasks(evalDir, relativeDir);\n const models = options?.model !== undefined\n ? [options.model]\n : Array.isArray(config.model)\n ? config.model\n : [config.model];\n if (models.length === 0) {\n throw new Error('model is empty');\n }\n\n const session = await toolsFromMcp(config.mcp);\n try {\n const results: EvalRunResult[] = [];\n for (const entry of models) {\n results.push(\n await runEvals({\n model: entry,\n tools: session.tools,\n tasks,\n }),\n );\n }\n\n for (const result of results) {\n writeGitHubSummary(result);\n }\n\n const assertOptions =\n config.threshold === undefined ? undefined : { threshold: config.threshold };\n const assertErrors: Error[] = [];\n for (const result of results) {\n try {\n assertEvalResult(result, assertOptions);\n } catch (err) {\n assertErrors.push(err instanceof Error ? err : new Error(String(err)));\n }\n }\n if (assertErrors.length > 0) {\n throw new Error(assertErrors.map((err) => err.message).join('\\n'));\n }\n\n return results[results.length - 1];\n } finally {\n await session.close();\n }\n}\n"],"mappings":"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","names":["resolve","existsSync","join","existsSync","join","loaded"]}