evaliphy 1.0.1-beta.3 → 1.0.1-beta.5

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/bin.mjs CHANGED
@@ -3744,7 +3744,14 @@ var ConfigLoader = class ConfigLoader {
3744
3744
  const configPath = this.findConfigFile(cwd);
3745
3745
  if (!configPath) {
3746
3746
  this.configLogger.debug("No config file found, using defaults if applicable");
3747
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, "Provided config file is not correct or does not exist.");
3747
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Could not load configuration. Please check the following:
3748
+
3749
+ - Does "evaliphy.config.ts" exist in your project root?
3750
+ - Is the path correct if you specified a custom config location?
3751
+ - Does the config file export a default defineConfig({}) call?
3752
+
3753
+ Expected location: ${process.cwd()}/evaliphy.config.ts
3754
+ Visit https://evaliphy.com/docs/configuration for more details.`);
3748
3755
  }
3749
3756
  if (!this.cachedConfig) {
3750
3757
  this.configLogger.debug({ configPath }, "Loading base configuration from file");
@@ -3757,7 +3764,10 @@ var ConfigLoader = class ConfigLoader {
3757
3764
  error: parsed.error,
3758
3765
  configPath
3759
3766
  }, "Configuration validation failed");
3760
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}: ${parsed.error.message}`);
3767
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}
3768
+
3769
+ Please check your evaliphy.config.ts and fix the above fields.
3770
+ Docs: https://evaliphy.com/docs/configuration`);
3761
3771
  }
3762
3772
  this.cachedConfig = mergeConfigs(parsed.data, {}, this.cliOverrides);
3763
3773
  this.cachedConfig.configFile = configPath;
@@ -3767,7 +3777,11 @@ var ConfigLoader = class ConfigLoader {
3767
3777
  configPath
3768
3778
  }, "Error loading configuration");
3769
3779
  if (error instanceof EvaliphyError) throw error;
3770
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}`);
3780
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}
3781
+
3782
+ Please check your evaliphy.config.ts and fix the above fields.
3783
+ Docs: https://evaliphy.com/docs/configuration
3784
+ `);
3771
3785
  }
3772
3786
  }
3773
3787
  const finalConfig = mergeConfigs(this.cachedConfig, transientOverrides, {});
@@ -4006,50 +4020,99 @@ function handleFatalError(err) {
4006
4020
  //#endregion
4007
4021
  //#region packages/cli/src/initProject/createFolderStructure.ts
4008
4022
  const require$1 = createRequire(import.meta.url);
4023
+ const green = (s) => `\x1b[32m${s}\x1b[0m`;
4024
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
4025
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
4026
+ const red = (s) => `\x1b[31m${s}\x1b[0m`;
4009
4027
  function createProject(projectName) {
4010
4028
  const __filename = fileURLToPath(import.meta.url);
4011
4029
  const __dirname = path.dirname(__filename);
4012
4030
  const { version } = require$1(path.join(__dirname, "../package.json"));
4031
+ if (!/^[a-z0-9-_]+$/i.test(projectName)) {
4032
+ console.error(red(`\n ✗ Invalid project name "${projectName}".`));
4033
+ console.error(dim(" Use only letters, numbers, hyphens and underscores.\n"));
4034
+ process.exit(1);
4035
+ }
4013
4036
  const rootPath = path.join(process.cwd(), projectName);
4014
4037
  if (fs.existsSync(rootPath)) {
4015
- console.error("Folder already exists.");
4038
+ console.error(red(`\n ✗ Directory "${projectName}" already exists.`));
4039
+ console.error(dim(` Choose a different name or remove the existing directory.\n`));
4016
4040
  process.exit(1);
4017
4041
  }
4018
- fs.mkdirSync(rootPath, { recursive: true });
4019
- createStructure(rootPath, {
4020
- evals: { "example.eval.ts": `import { evaluate } from 'evaliphy';
4042
+ console.log(`\n Creating project ${bold(projectName)}...\n`);
4043
+ const structure = {
4044
+ evals: { "example.eval.ts": `import { evaluate, expect } from 'evaliphy';
4045
+
4046
+ /**
4047
+ * Example evaluation — replace this with your own RAG endpoint and samples.
4048
+ * Docs: https://evaliphy.com/docs/quick-start
4049
+ */
4050
+ evaluate("context handling: multiple chunks", async ({ httpClient }) => {
4051
+ const query = "What are the support hours?";
4052
+ const context = [
4053
+ "Support is available 24/7 via email.",
4054
+ "Live chat support is open from 9 AM to 5 PM EST.",
4055
+ "Phone support is currently unavailable."
4056
+ ];
4057
+
4058
+ const res = await httpClient.post("/api/generate", { prompt: query });
4059
+ const data = await res.json();
4021
4060
 
4022
- evaluate('basic test', async ({ httpClient }) => {
4023
- // add your evaluate code
4061
+ await expect({
4062
+ query,
4063
+ response: data.content,
4064
+ context,
4065
+ }).toBeFaithful({ threshold: 0.7 });
4024
4066
  });
4025
4067
  ` },
4026
- utils: {},
4068
+ ".env.example": `# Copy this file to .env and fill in your values
4069
+ OPENAI_API_KEY=your-api-key-here
4070
+ `,
4071
+ ".gitignore": `.env
4072
+ node_modules
4073
+ dist
4074
+ results
4075
+ `,
4027
4076
  "evaliphy.config.ts": `import { defineConfig } from 'evaliphy';
4028
4077
 
4029
4078
  export default defineConfig({
4030
- baseUrl: 'http://localhost:8080',
4031
- testDir: './evals',
4079
+ http: {
4080
+ baseUrl: "http://localhost:8080",
4081
+ timeout: 10_000,
4082
+ },
4083
+ evalDir: './evals',
4032
4084
  llmAsJudgeConfig: {
4033
4085
  model: 'gpt-4o-mini',
4034
4086
  provider: {
4035
- type: 'gateway',
4036
- url: 'https://openrouter.ai/api/v1',
4037
- apiKey: process.env.OPENROUTER_API_KEY,
4087
+ type: 'openai',
4088
+ apiKey: process.env.OPENAI_API_KEY,
4038
4089
  },
4039
- promptsDir: './prompts',
4040
- temperature: 0
4090
+ temperature: 0,
4041
4091
  },
4042
4092
  });
4043
4093
  `,
4044
- "tsconfig.json": JSON.stringify({ compilerOptions: {
4045
- target: "ES2020",
4046
- module: "ESNext",
4047
- moduleResolution: "bundler",
4048
- strict: true,
4049
- esModuleInterop: true,
4050
- skipLibCheck: true
4051
- } }, null, 2)
4052
- });
4094
+ "tsconfig.json": JSON.stringify({
4095
+ compilerOptions: {
4096
+ target: "ES2020",
4097
+ module: "ESNext",
4098
+ moduleResolution: "bundler",
4099
+ strict: true,
4100
+ esModuleInterop: true,
4101
+ skipLibCheck: true,
4102
+ outDir: "./dist"
4103
+ },
4104
+ include: ["**/*.ts"],
4105
+ exclude: ["node_modules", "dist"]
4106
+ }, null, 2)
4107
+ };
4108
+ try {
4109
+ fs.mkdirSync(rootPath, { recursive: true });
4110
+ createStructure(rootPath, structure);
4111
+ } catch (err) {
4112
+ console.error(red("\n ✗ Failed to create project files."));
4113
+ console.error(dim(` ${err.message}\n`));
4114
+ process.exit(1);
4115
+ }
4053
4116
  const pkg = {
4054
4117
  name: projectName,
4055
4118
  version: "1.0.0",
@@ -4064,19 +4127,42 @@ export default defineConfig({
4064
4127
  typescript: "^5.0.0"
4065
4128
  }
4066
4129
  };
4067
- fs.writeFileSync(path.join(rootPath, "package.json"), JSON.stringify(pkg, null, 2));
4068
- console.log(`\nProject "${projectName}" is ready!`);
4069
- console.log(`\nNext steps:`);
4070
- console.log(` cd ${projectName}`);
4071
- console.log(` npm test`);
4130
+ try {
4131
+ fs.writeFileSync(path.join(rootPath, "package.json"), JSON.stringify(pkg, null, 2));
4132
+ } catch (err) {
4133
+ console.error(red("\n Failed to write package.json."));
4134
+ console.error(dim(` ${err.message}\n`));
4135
+ process.exit(1);
4136
+ }
4137
+ console.log(` ${green("✓")} evaliphy.config.ts`);
4138
+ console.log(` ${green("✓")} evals/example.eval.ts`);
4139
+ console.log(` ${green("✓")} .env.example`);
4140
+ console.log(` ${green("✓")} .gitignore`);
4141
+ console.log(` ${green("✓")} tsconfig.json`);
4142
+ console.log(` ${green("✓")} package.json`);
4143
+ console.log(`
4144
+ ${green("✓")} ${bold(`Project "${projectName}" created successfully!`)}
4145
+
4146
+ ${bold("Next steps:")}
4147
+ ${dim("$")} Ensuer you have Node JS either v24.0.0 or higher.
4148
+ ${dim("$")} cd ${projectName}
4149
+ ${dim("$")} cp .env.example .env ${dim("← add your OPENAI_API_KEY")}
4150
+ ${dim("$")} npm install
4151
+ ${dim("$")} npm test
4152
+
4153
+ ${dim(`Docs → https://evaliphy.com/docs`)}
4154
+ ${dim(`Examples → https://evaliphy.com/docs/examples`)}
4155
+ `);
4072
4156
  }
4073
4157
  function createStructure(basePath, structure) {
4074
- for (const name in structure) {
4158
+ for (const [name, content] of Object.entries(structure)) {
4075
4159
  const fullPath = path.join(basePath, name);
4076
- if (typeof structure[name] === "string") fs.writeFileSync(fullPath, structure[name]);
4077
- else {
4160
+ if (typeof content === "string") {
4161
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
4162
+ fs.writeFileSync(fullPath, content, "utf8");
4163
+ } else {
4078
4164
  fs.mkdirSync(fullPath, { recursive: true });
4079
- createStructure(fullPath, structure[name]);
4165
+ createStructure(fullPath, content);
4080
4166
  }
4081
4167
  }
4082
4168
  }
@@ -31257,9 +31343,10 @@ var ConsoleReporter = class {
31257
31343
  const duration = this.formatDuration(payload.duration);
31258
31344
  console.log("\n" + this.getSeparator());
31259
31345
  [
31260
- import_picocolors.default.bold("Tests: ") + (payload.failed > 0 ? import_picocolors.default.red(`${payload.failed} failed`) + import_picocolors.default.dim(", ") : "") + import_picocolors.default.green(`${payload.passed} passed`) + import_picocolors.default.dim(`, ${total} total`),
31261
- import_picocolors.default.bold("Time: ") + import_picocolors.default.white(duration),
31262
- import_picocolors.default.bold("Run ID: ") + import_picocolors.default.dim(payload.runId)
31346
+ import_picocolors.default.bold("Tests: ") + (payload.failed > 0 ? import_picocolors.default.red(`${payload.failed} failed`) + import_picocolors.default.dim(", ") : "") + import_picocolors.default.green(`${payload.passed} passed`) + import_picocolors.default.dim(`, ${total} total`),
31347
+ import_picocolors.default.bold("Time: ") + import_picocolors.default.white(duration),
31348
+ import_picocolors.default.bold("Run ID: ") + import_picocolors.default.dim(payload.runId),
31349
+ import_picocolors.default.bold("HTML Report: ") + import_picocolors.default.dim("report/report-" + payload.runId + ".html")
31263
31350
  ].forEach((line) => console.log(` ${line}`));
31264
31351
  console.log(this.getSeparator() + "\n");
31265
31352
  if (payload.failed > 0) console.log(` ${import_picocolors.default.red(import_picocolors.default.bold("FAIL"))} ${import_picocolors.default.red("Run failed")}\n`);
package/dist/index.cjs CHANGED
@@ -183,7 +183,14 @@ var ConfigLoader = class ConfigLoader {
183
183
  const configPath = this.findConfigFile(cwd);
184
184
  if (!configPath) {
185
185
  this.configLogger.debug("No config file found, using defaults if applicable");
186
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, "Provided config file is not correct or does not exist.");
186
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Could not load configuration. Please check the following:
187
+
188
+ - Does "evaliphy.config.ts" exist in your project root?
189
+ - Is the path correct if you specified a custom config location?
190
+ - Does the config file export a default defineConfig({}) call?
191
+
192
+ Expected location: ${process.cwd()}/evaliphy.config.ts
193
+ Visit https://evaliphy.com/docs/configuration for more details.`);
187
194
  }
188
195
  if (!this.cachedConfig) {
189
196
  this.configLogger.debug({ configPath }, "Loading base configuration from file");
@@ -196,7 +203,10 @@ var ConfigLoader = class ConfigLoader {
196
203
  error: parsed.error,
197
204
  configPath
198
205
  }, "Configuration validation failed");
199
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}: ${parsed.error.message}`);
206
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}
207
+
208
+ Please check your evaliphy.config.ts and fix the above fields.
209
+ Docs: https://evaliphy.com/docs/configuration`);
200
210
  }
201
211
  this.cachedConfig = mergeConfigs(parsed.data, {}, this.cliOverrides);
202
212
  this.cachedConfig.configFile = configPath;
@@ -206,7 +216,11 @@ var ConfigLoader = class ConfigLoader {
206
216
  configPath
207
217
  }, "Error loading configuration");
208
218
  if (error instanceof EvaliphyError) throw error;
209
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}`);
219
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}
220
+
221
+ Please check your evaliphy.config.ts and fix the above fields.
222
+ Docs: https://evaliphy.com/docs/configuration
223
+ `);
210
224
  }
211
225
  }
212
226
  const finalConfig = mergeConfigs(this.cachedConfig, transientOverrides, {});
@@ -672,12 +686,29 @@ var AssertionEngine = class {
672
686
  static loadPrompt(matcherName, assertionDef, config) {
673
687
  const configDir = config.configFile ? node_path.default.dirname(config.configFile) : process.cwd();
674
688
  const customPromptsDir = config.llmAsJudgeConfig?.promptsDir ? node_path.default.resolve(configDir, config.llmAsJudgeConfig.promptsDir) : null;
675
- const defaultPromptsDir = node_path.default.join(process.cwd(), "packages/prompts");
676
- let promptPath = customPromptsDir ? node_path.default.join(customPromptsDir, `${matcherName}.md`) : null;
689
+ const localPromptsDir = node_path.default.join(process.cwd(), "prompts");
690
+ const __dirname = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
691
+ const sdkPromptsDirSource = node_path.default.resolve(__dirname, "../../prompts");
692
+ const sdkPromptsDirDist = node_path.default.resolve(__dirname, "./prompts");
693
+ [
694
+ customPromptsDir ? node_path.default.join(customPromptsDir, `${matcherName}.md`) : null,
695
+ node_path.default.join(localPromptsDir, `${matcherName}.md`),
696
+ node_path.default.join(sdkPromptsDirDist, `${matcherName}.md`),
697
+ node_path.default.join(sdkPromptsDirSource, `${matcherName}.md`)
698
+ ].filter(Boolean);
677
699
  try {
678
- if (promptPath && PromptLoader.exists(promptPath)) return PromptLoader.load(promptPath, assertionDef);
679
- promptPath = node_path.default.join(defaultPromptsDir, `${matcherName}.md`);
680
- return PromptLoader.load(promptPath, assertionDef);
700
+ if (customPromptsDir) {
701
+ const customPath = node_path.default.join(customPromptsDir, `${matcherName}.md`);
702
+ if (PromptLoader.exists(customPath)) return PromptLoader.load(customPath, assertionDef);
703
+ else console.warn(`Custom prompt file not found at: ${customPath}. Falling back to defaults.`);
704
+ }
705
+ const fallbackPaths = [
706
+ node_path.default.join(localPromptsDir, `${matcherName}.md`),
707
+ node_path.default.join(sdkPromptsDirDist, `${matcherName}.md`),
708
+ node_path.default.join(sdkPromptsDirSource, `${matcherName}.md`)
709
+ ];
710
+ for (const promptPath of fallbackPaths) if (PromptLoader.exists(promptPath)) return PromptLoader.load(promptPath, assertionDef);
711
+ return PromptLoader.load(node_path.default.join(sdkPromptsDirDist, `${matcherName}.md`), assertionDef);
681
712
  } catch (error) {
682
713
  throw new EvaliphyError(EvaliphyErrorCode.PROMPT_LOAD_ERROR, `Failed to load prompt for "${matcherName}": ${error.message}`, "Check your prompt file formatting and variables.", error);
683
714
  }
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { i as __toESM, n as __commonJSMin, t as require_token_error } from "./token-error-TubvLIoa.mjs";
2
2
  import fs, { existsSync } from "node:fs";
3
3
  import path, { join } from "node:path";
4
- import { pathToFileURL } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { pino } from "pino";
6
6
  import { z } from "zod";
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -180,7 +180,14 @@ var ConfigLoader = class ConfigLoader {
180
180
  const configPath = this.findConfigFile(cwd);
181
181
  if (!configPath) {
182
182
  this.configLogger.debug("No config file found, using defaults if applicable");
183
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, "Provided config file is not correct or does not exist.");
183
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Could not load configuration. Please check the following:
184
+
185
+ - Does "evaliphy.config.ts" exist in your project root?
186
+ - Is the path correct if you specified a custom config location?
187
+ - Does the config file export a default defineConfig({}) call?
188
+
189
+ Expected location: ${process.cwd()}/evaliphy.config.ts
190
+ Visit https://evaliphy.com/docs/configuration for more details.`);
184
191
  }
185
192
  if (!this.cachedConfig) {
186
193
  this.configLogger.debug({ configPath }, "Loading base configuration from file");
@@ -193,7 +200,10 @@ var ConfigLoader = class ConfigLoader {
193
200
  error: parsed.error,
194
201
  configPath
195
202
  }, "Configuration validation failed");
196
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}: ${parsed.error.message}`);
203
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Invalid configuration in ${configPath}
204
+
205
+ Please check your evaliphy.config.ts and fix the above fields.
206
+ Docs: https://evaliphy.com/docs/configuration`);
197
207
  }
198
208
  this.cachedConfig = mergeConfigs(parsed.data, {}, this.cliOverrides);
199
209
  this.cachedConfig.configFile = configPath;
@@ -203,7 +213,11 @@ var ConfigLoader = class ConfigLoader {
203
213
  configPath
204
214
  }, "Error loading configuration");
205
215
  if (error instanceof EvaliphyError) throw error;
206
- throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}`);
216
+ throw new EvaliphyError(EvaliphyErrorCode.INVALID_CONFIG, `Failed to load config from ${configPath}: ${error.message}
217
+
218
+ Please check your evaliphy.config.ts and fix the above fields.
219
+ Docs: https://evaliphy.com/docs/configuration
220
+ `);
207
221
  }
208
222
  }
209
223
  const finalConfig = mergeConfigs(this.cachedConfig, transientOverrides, {});
@@ -669,12 +683,29 @@ var AssertionEngine = class {
669
683
  static loadPrompt(matcherName, assertionDef, config) {
670
684
  const configDir = config.configFile ? path.dirname(config.configFile) : process.cwd();
671
685
  const customPromptsDir = config.llmAsJudgeConfig?.promptsDir ? path.resolve(configDir, config.llmAsJudgeConfig.promptsDir) : null;
672
- const defaultPromptsDir = path.join(process.cwd(), "packages/prompts");
673
- let promptPath = customPromptsDir ? path.join(customPromptsDir, `${matcherName}.md`) : null;
686
+ const localPromptsDir = path.join(process.cwd(), "prompts");
687
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
688
+ const sdkPromptsDirSource = path.resolve(__dirname, "../../prompts");
689
+ const sdkPromptsDirDist = path.resolve(__dirname, "./prompts");
690
+ [
691
+ customPromptsDir ? path.join(customPromptsDir, `${matcherName}.md`) : null,
692
+ path.join(localPromptsDir, `${matcherName}.md`),
693
+ path.join(sdkPromptsDirDist, `${matcherName}.md`),
694
+ path.join(sdkPromptsDirSource, `${matcherName}.md`)
695
+ ].filter(Boolean);
674
696
  try {
675
- if (promptPath && PromptLoader.exists(promptPath)) return PromptLoader.load(promptPath, assertionDef);
676
- promptPath = path.join(defaultPromptsDir, `${matcherName}.md`);
677
- return PromptLoader.load(promptPath, assertionDef);
697
+ if (customPromptsDir) {
698
+ const customPath = path.join(customPromptsDir, `${matcherName}.md`);
699
+ if (PromptLoader.exists(customPath)) return PromptLoader.load(customPath, assertionDef);
700
+ else console.warn(`Custom prompt file not found at: ${customPath}. Falling back to defaults.`);
701
+ }
702
+ const fallbackPaths = [
703
+ path.join(localPromptsDir, `${matcherName}.md`),
704
+ path.join(sdkPromptsDirDist, `${matcherName}.md`),
705
+ path.join(sdkPromptsDirSource, `${matcherName}.md`)
706
+ ];
707
+ for (const promptPath of fallbackPaths) if (PromptLoader.exists(promptPath)) return PromptLoader.load(promptPath, assertionDef);
708
+ return PromptLoader.load(path.join(sdkPromptsDirDist, `${matcherName}.md`), assertionDef);
678
709
  } catch (error) {
679
710
  throw new EvaliphyError(EvaliphyErrorCode.PROMPT_LOAD_ERROR, `Failed to load prompt for "${matcherName}": ${error.message}`, "Check your prompt file formatting and variables.", error);
680
711
  }