@hasna/evals 0.1.27 → 0.1.28

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.
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/adapters/openai.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,gBAAgB,EAAE,GACzB,OAAO,CAAC,eAAe,CAAC,CAuD1B"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/adapters/openai.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAwBjD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,gBAAgB,EAAE,GACzB,OAAO,CAAC,eAAe,CAAC,CAuD1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-parser.d.ts","sourceRoot":"","sources":["../../src/cli/adapter-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CA8B9E"}
1
+ {"version":3,"file":"adapter-parser.d.ts","sourceRoot":"","sources":["../../src/cli/adapter-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CA+B9E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adapter-parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-parser.test.d.ts","sourceRoot":"","sources":["../../src/cli/adapter-parser.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ci.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,SAAS,IAAI,OAAO,CAiEnC"}
1
+ {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ci.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,SAAS,IAAI,OAAO,CAkEnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,UAAU,IAAI,OAAO,CAyDpC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,UAAU,IAAI,OAAO,CA0DpC"}
package/dist/cli/index.js CHANGED
@@ -8543,6 +8543,20 @@ var require_ajv = __commonJS((exports, module) => {
8543
8543
  } });
8544
8544
  });
8545
8545
 
8546
+ // src/core/redaction.ts
8547
+ function redactAdapterConfig(config) {
8548
+ if (!config || !("apiKey" in config))
8549
+ return config;
8550
+ const { apiKey: _apiKey, ...safeConfig } = config;
8551
+ return safeConfig;
8552
+ }
8553
+ function redactRunSecrets(run) {
8554
+ return {
8555
+ ...run,
8556
+ adapterConfig: redactAdapterConfig(run.adapterConfig)
8557
+ };
8558
+ }
8559
+
8546
8560
  // src/db/store.ts
8547
8561
  var exports_store = {};
8548
8562
  __export(exports_store, {
@@ -8604,10 +8618,11 @@ function migrate(db) {
8604
8618
  }
8605
8619
  function saveRun(run) {
8606
8620
  const db = getDatabase();
8621
+ const safeRun = redactRunSecrets(run);
8607
8622
  db.prepare(`
8608
8623
  INSERT OR REPLACE INTO runs (id, created_at, dataset, stats, adapter, data)
8609
8624
  VALUES (?, ?, ?, ?, ?, ?)
8610
- `).run(run.id, run.createdAt, run.dataset, JSON.stringify(run.stats), run.adapterConfig ? JSON.stringify(run.adapterConfig) : null, JSON.stringify(run));
8625
+ `).run(safeRun.id, safeRun.createdAt, safeRun.dataset, JSON.stringify(safeRun.stats), safeRun.adapterConfig ? JSON.stringify(safeRun.adapterConfig) : null, JSON.stringify(safeRun));
8611
8626
  }
8612
8627
  function getRun(id) {
8613
8628
  const db = getDatabase();
@@ -19769,7 +19784,6 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
19769
19784
  function getEventsDataDir(override) {
19770
19785
  return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
19771
19786
  }
19772
-
19773
19787
  class JsonEventsStore {
19774
19788
  dataDir;
19775
19789
  channelsPath;
@@ -25022,7 +25036,7 @@ var safeJSON2 = (text) => {
25022
25036
  var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25023
25037
 
25024
25038
  // node_modules/openai/version.mjs
25025
- var VERSION2 = "6.42.0";
25039
+ var VERSION2 = "6.44.0";
25026
25040
 
25027
25041
  // node_modules/openai/internal/detect-platform.mjs
25028
25042
  var isRunningInBrowser2 = () => {
@@ -27016,7 +27030,12 @@ _AbstractChatCompletionRunner_instances = new WeakSet, _AbstractChatCompletionRu
27016
27030
  for (let i = this.messages.length - 1;i >= 0; i--) {
27017
27031
  const message = this.messages[i];
27018
27032
  if (isAssistantMessage(message) && message?.tool_calls?.length) {
27019
- return message.tool_calls.filter((x) => x.type === "function").at(-1)?.function;
27033
+ for (let j = message.tool_calls.length - 1;j >= 0; j--) {
27034
+ const toolCall = message.tool_calls[j];
27035
+ if (toolCall?.type === "function") {
27036
+ return toolCall.function;
27037
+ }
27038
+ }
27020
27039
  }
27021
27040
  }
27022
27041
  return;
@@ -28022,6 +28041,12 @@ class SpendAlerts extends APIResource2 {
28022
28041
  __security: { adminAPIKeyAuth: true }
28023
28042
  });
28024
28043
  }
28044
+ retrieve(alertID, options) {
28045
+ return this._client.get(path2`/organization/spend_alerts/${alertID}`, {
28046
+ ...options,
28047
+ __security: { adminAPIKeyAuth: true }
28048
+ });
28049
+ }
28025
28050
  update(alertID, body, options) {
28026
28051
  return this._client.post(path2`/organization/spend_alerts/${alertID}`, {
28027
28052
  body,
@@ -28405,6 +28430,13 @@ class SpendAlerts2 extends APIResource2 {
28405
28430
  __security: { adminAPIKeyAuth: true }
28406
28431
  });
28407
28432
  }
28433
+ retrieve(alertID, params, options) {
28434
+ const { project_id } = params;
28435
+ return this._client.get(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
28436
+ ...options,
28437
+ __security: { adminAPIKeyAuth: true }
28438
+ });
28439
+ }
28408
28440
  update(alertID, params, options) {
28409
28441
  const { project_id, ...body } = params;
28410
28442
  return this._client.post(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
@@ -32179,13 +32211,34 @@ async function callAnthropicAdapter(config, input, turns) {
32179
32211
  }
32180
32212
 
32181
32213
  // src/adapters/openai.ts
32214
+ function normalizeBaseURL(baseURL) {
32215
+ if (!baseURL)
32216
+ return;
32217
+ try {
32218
+ const url = new URL(baseURL);
32219
+ if (url.pathname === "" || url.pathname === "/") {
32220
+ url.pathname = "/v1";
32221
+ return url.toString();
32222
+ }
32223
+ } catch {
32224
+ return baseURL;
32225
+ }
32226
+ return baseURL;
32227
+ }
32228
+ function resolveApiKey(config) {
32229
+ if (config.apiKey)
32230
+ return config.apiKey;
32231
+ if (config.baseURL)
32232
+ return "ollama";
32233
+ return process.env["OPENAI_API_KEY"];
32234
+ }
32182
32235
  async function callOpenAIAdapter(config, input, turns) {
32183
32236
  const start = Date.now();
32184
- const client = new OpenAI({
32185
- apiKey: config.apiKey ?? process.env["OPENAI_API_KEY"],
32186
- baseURL: config.baseURL
32187
- });
32188
32237
  try {
32238
+ const client = new OpenAI({
32239
+ apiKey: resolveApiKey(config),
32240
+ baseURL: normalizeBaseURL(config.baseURL)
32241
+ });
32189
32242
  const messages = [];
32190
32243
  if (config.systemPrompt)
32191
32244
  messages.push({ role: "system", content: config.systemPrompt });
@@ -32443,7 +32496,7 @@ async function runEvals(cases, options) {
32443
32496
  id: randomUUID3(),
32444
32497
  createdAt: new Date().toISOString(),
32445
32498
  dataset: options.dataset,
32446
- adapterConfig: options.adapter,
32499
+ adapterConfig: redactAdapterConfig(options.adapter),
32447
32500
  results,
32448
32501
  stats
32449
32502
  };
@@ -32512,7 +32565,7 @@ function printTerminalReport(run) {
32512
32565
  console.log();
32513
32566
  }
32514
32567
  function toJson(run) {
32515
- return JSON.stringify(run, null, 2);
32568
+ return JSON.stringify(redactRunSecrets(run), null, 2);
32516
32569
  }
32517
32570
  function toMarkdown(run) {
32518
32571
  const { results, stats } = run;
@@ -32607,6 +32660,7 @@ init_store();
32607
32660
  // src/cli/adapter-parser.ts
32608
32661
  function parseAdapterConfig(opts) {
32609
32662
  const type = opts["adapter"] ?? "http";
32663
+ const apiKey = opts["apiKeyEnv"] ? process.env[opts["apiKeyEnv"]] : undefined;
32610
32664
  switch (type) {
32611
32665
  case "http":
32612
32666
  if (!opts["url"])
@@ -32615,11 +32669,11 @@ function parseAdapterConfig(opts) {
32615
32669
  case "anthropic":
32616
32670
  if (!opts["model"])
32617
32671
  throw new Error("--model is required for anthropic adapter");
32618
- return { type: "anthropic", model: opts["model"], systemPrompt: opts["system"] };
32672
+ return { type: "anthropic", model: opts["model"], systemPrompt: opts["system"], ...apiKey ? { apiKey } : {} };
32619
32673
  case "openai":
32620
32674
  if (!opts["model"])
32621
32675
  throw new Error("--model is required for openai adapter");
32622
- return { type: "openai", model: opts["model"], systemPrompt: opts["system"] };
32676
+ return { type: "openai", model: opts["model"], systemPrompt: opts["system"], baseURL: opts["url"], ...apiKey ? { apiKey } : {} };
32623
32677
  case "function":
32624
32678
  if (!opts["module"])
32625
32679
  throw new Error("--module is required for function adapter");
@@ -32645,7 +32699,7 @@ function parseAdapterConfig(opts) {
32645
32699
 
32646
32700
  // src/cli/commands/run.ts
32647
32701
  function runCommand() {
32648
- return new Command("run").description("Run an eval dataset against your app").argument("<dataset>", "Path to JSONL/JSON dataset or glob pattern").option("--adapter <type>", "Adapter type: http|anthropic|openai|mcp|function|cli", "http").option("--url <url>", "App URL (for http adapter)").option("--model <model>", "Model name (for anthropic/openai adapter)").option("--system <prompt>", "System prompt (for anthropic/openai adapter)").option("--module <path>", "Module path (for function adapter)").option("--export <name>", "Export name (for function adapter, default: default)").option("--command <cmd>", "Shell command (for cli adapter, use {{input}} placeholder)").option("--mcp-command <cmd>", "MCP server command (for mcp adapter)").option("--tool <name>", "MCP tool name (for mcp adapter)").option("--concurrency <n>", "Parallel execution limit", "5").option("--repeat <n>", "Run each case N times (Pass^k metric)", "1").option("--tags <tags>", "Comma-separated tags to filter cases").option("--no-judge", "Skip LLM judge, run assertions only").option("--output <format>", "Output format: terminal|json|markdown", "terminal").option("--save", "Save run to database").option("-j, --json", "Alias for --output json").action(async (dataset, opts) => {
32702
+ return new Command("run").description("Run an eval dataset against your app").argument("<dataset>", "Path to JSONL/JSON dataset or glob pattern").option("--adapter <type>", "Adapter type: http|anthropic|openai|mcp|function|cli", "http").option("--url <url>", "App URL (for http) or OpenAI-compatible base URL").option("--model <model>", "Model name (for anthropic/openai adapter)").option("--system <prompt>", "System prompt (for anthropic/openai adapter)").option("--api-key-env <name>", "Env var containing provider API key").option("--module <path>", "Module path (for function adapter)").option("--export <name>", "Export name (for function adapter, default: default)").option("--command <cmd>", "Shell command (for cli adapter, use {{input}} placeholder)").option("--mcp-command <cmd>", "MCP server command (for mcp adapter)").option("--tool <name>", "MCP tool name (for mcp adapter)").option("--concurrency <n>", "Parallel execution limit", "5").option("--repeat <n>", "Run each case N times (Pass^k metric)", "1").option("--tags <tags>", "Comma-separated tags to filter cases").option("--no-judge", "Skip LLM judge, run assertions only").option("--output <format>", "Output format: terminal|json|markdown", "terminal").option("--save", "Save run to database").option("-j, --json", "Alias for --output json").action(async (dataset, opts) => {
32649
32703
  const { cases, warnings } = await loadDataset(dataset, {
32650
32704
  tags: opts["tags"] ? opts["tags"].split(",") : undefined
32651
32705
  });
@@ -32685,7 +32739,7 @@ init_loader();
32685
32739
  init_store();
32686
32740
  function ciCommand() {
32687
32741
  const cmd = new Command("ci").description("Run evals in CI mode \u2014 exit non-zero on regression");
32688
- cmd.command("run <dataset>").description("Run and compare to baseline").option("--adapter <type>", "Adapter type: http|anthropic|openai|mcp|function|cli", "http").option("--url <url>", "App URL (for http adapter)").option("--model <model>", "Model name (for anthropic/openai adapter)").option("--system <prompt>", "System prompt (for anthropic/openai adapter)").option("--module <path>", "Module path (for function adapter)").option("--export <name>", "Export name (for function adapter)").option("--command <cmd>", "Shell command (for cli adapter)").option("--mcp-command <cmd>", "MCP server command (for mcp adapter)").option("--tool <name>", "MCP tool name (for mcp adapter)").option("--no-judge", "Skip LLM judge, assertions only").option("--baseline <name>", "Baseline name to compare against", "main").option("--fail-if-regression <pct>", "Fail if score drops by more than N%", "0").option("--output <format>", "Output format: terminal|markdown", "terminal").option("-j, --json", "Output JSON").action(async (dataset, opts) => {
32742
+ cmd.command("run <dataset>").description("Run and compare to baseline").option("--adapter <type>", "Adapter type: http|anthropic|openai|mcp|function|cli", "http").option("--url <url>", "App URL (for http) or OpenAI-compatible base URL").option("--model <model>", "Model name (for anthropic/openai adapter)").option("--system <prompt>", "System prompt (for anthropic/openai adapter)").option("--api-key-env <name>", "Env var containing provider API key").option("--module <path>", "Module path (for function adapter)").option("--export <name>", "Export name (for function adapter)").option("--command <cmd>", "Shell command (for cli adapter)").option("--mcp-command <cmd>", "MCP server command (for mcp adapter)").option("--tool <name>", "MCP tool name (for mcp adapter)").option("--no-judge", "Skip LLM judge, assertions only").option("--baseline <name>", "Baseline name to compare against", "main").option("--fail-if-regression <pct>", "Fail if score drops by more than N%", "0").option("--output <format>", "Output format: terminal|markdown", "terminal").option("-j, --json", "Output JSON").action(async (dataset, opts) => {
32689
32743
  const { cases } = await loadDataset(dataset);
32690
32744
  const adapter = parseAdapterConfig(opts);
32691
32745
  const run = await runEvals(cases, { dataset, adapter, skipJudge: opts["judge"] === false || opts["noJudge"] === true });
@@ -32993,7 +33047,7 @@ function kappaLabel(k) {
32993
33047
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
32994
33048
  import { homedir as homedir4 } from "os";
32995
33049
  import { join as join4 } from "path";
32996
- function resolveApiKey(envVar, secretsPath, secretsKey) {
33050
+ function resolveApiKey2(envVar, secretsPath, secretsKey) {
32997
33051
  if (process.env[envVar])
32998
33052
  return process.env[envVar];
32999
33053
  const fullPath = join4(homedir4(), ".secrets", secretsPath);
@@ -33018,13 +33072,13 @@ function resolveApiKey(envVar, secretsPath, secretsKey) {
33018
33072
  function doctorCommand() {
33019
33073
  return new Command("doctor").description("Health check \u2014 verify API keys, DB, and config").option("-j, --json", "Output JSON").action(async (opts) => {
33020
33074
  const checks = [];
33021
- const anthropicKey = resolveApiKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
33075
+ const anthropicKey = resolveApiKey2("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
33022
33076
  checks.push({
33023
33077
  name: "ANTHROPIC_API_KEY",
33024
33078
  ok: !!anthropicKey,
33025
33079
  hint: "export ANTHROPIC_API_KEY=<your-key> (or add to ~/.secrets/hasnaxyz/anthropic/live.env)"
33026
33080
  });
33027
- const openaiKey = resolveApiKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
33081
+ const openaiKey = resolveApiKey2("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
33028
33082
  checks.push({
33029
33083
  name: "OPENAI_API_KEY (optional)",
33030
33084
  ok: !!openaiKey,
@@ -0,0 +1,4 @@
1
+ import type { AdapterConfig, EvalRun } from "../types/index.js";
2
+ export declare function redactAdapterConfig(config: AdapterConfig | undefined): AdapterConfig | undefined;
3
+ export declare function redactRunSecrets(run: EvalRun): EvalRun;
4
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../src/core/redaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEhE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAKhG;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKtD"}
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAgB1D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAoCtD;AAID,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE3C;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAkD/C;AAID,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxE,YAAY,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAuBpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAcnD"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAiB1D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAoCtD;AAID,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE3C;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAkD/C;AAID,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxE,YAAY,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAuBpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAcnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,UAAU,EACV,OAAO,EAEP,UAAU,EAGX,MAAM,mBAAmB,CAAC;AAqI3B,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,OAAO,CAAC,CAqClB;AAID,wBAAsB,aAAa,CACjC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,EAC5B,SAAS,UAAQ,GAChB,OAAO,CAAC,UAAU,CAAC,CAKrB"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,UAAU,EACV,OAAO,EAEP,UAAU,EAGX,MAAM,mBAAmB,CAAC;AAqI3B,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,OAAO,CAAC,CAqClB;AAID,wBAAsB,aAAa,CACjC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,EAC5B,SAAS,UAAQ,GAChB,OAAO,CAAC,UAAU,CAAC,CAKrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAQjD,wBAAgB,WAAW,IAAI,QAAQ,CAUtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AA6BD,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAa1C;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAIjD;AAED,wBAAgB,QAAQ,CAAC,KAAK,SAAK,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAMhE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAKxD;AAED,wBAAgB,aAAa,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAKzF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAQjD,wBAAgB,WAAW,IAAI,QAAQ,CAUtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AA6BD,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAc1C;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAIjD;AAED,wBAAgB,QAAQ,CAAC,KAAK,SAAK,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAMhE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAKxD;AAED,wBAAgB,aAAa,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAKzF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD"}
package/dist/index.js CHANGED
@@ -11667,7 +11667,7 @@ var safeJSON2 = (text) => {
11667
11667
  var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11668
11668
 
11669
11669
  // node_modules/openai/version.mjs
11670
- var VERSION2 = "6.42.0";
11670
+ var VERSION2 = "6.44.0";
11671
11671
 
11672
11672
  // node_modules/openai/internal/detect-platform.mjs
11673
11673
  var isRunningInBrowser2 = () => {
@@ -13661,7 +13661,12 @@ _AbstractChatCompletionRunner_instances = new WeakSet, _AbstractChatCompletionRu
13661
13661
  for (let i = this.messages.length - 1;i >= 0; i--) {
13662
13662
  const message = this.messages[i];
13663
13663
  if (isAssistantMessage(message) && message?.tool_calls?.length) {
13664
- return message.tool_calls.filter((x) => x.type === "function").at(-1)?.function;
13664
+ for (let j = message.tool_calls.length - 1;j >= 0; j--) {
13665
+ const toolCall = message.tool_calls[j];
13666
+ if (toolCall?.type === "function") {
13667
+ return toolCall.function;
13668
+ }
13669
+ }
13665
13670
  }
13666
13671
  }
13667
13672
  return;
@@ -14667,6 +14672,12 @@ class SpendAlerts extends APIResource2 {
14667
14672
  __security: { adminAPIKeyAuth: true }
14668
14673
  });
14669
14674
  }
14675
+ retrieve(alertID, options) {
14676
+ return this._client.get(path2`/organization/spend_alerts/${alertID}`, {
14677
+ ...options,
14678
+ __security: { adminAPIKeyAuth: true }
14679
+ });
14680
+ }
14670
14681
  update(alertID, body, options) {
14671
14682
  return this._client.post(path2`/organization/spend_alerts/${alertID}`, {
14672
14683
  body,
@@ -15050,6 +15061,13 @@ class SpendAlerts2 extends APIResource2 {
15050
15061
  __security: { adminAPIKeyAuth: true }
15051
15062
  });
15052
15063
  }
15064
+ retrieve(alertID, params, options) {
15065
+ const { project_id } = params;
15066
+ return this._client.get(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
15067
+ ...options,
15068
+ __security: { adminAPIKeyAuth: true }
15069
+ });
15070
+ }
15053
15071
  update(alertID, params, options) {
15054
15072
  const { project_id, ...body } = params;
15055
15073
  return this._client.post(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
@@ -18824,13 +18842,34 @@ async function callAnthropicAdapter(config, input, turns) {
18824
18842
  }
18825
18843
 
18826
18844
  // src/adapters/openai.ts
18845
+ function normalizeBaseURL(baseURL) {
18846
+ if (!baseURL)
18847
+ return;
18848
+ try {
18849
+ const url = new URL(baseURL);
18850
+ if (url.pathname === "" || url.pathname === "/") {
18851
+ url.pathname = "/v1";
18852
+ return url.toString();
18853
+ }
18854
+ } catch {
18855
+ return baseURL;
18856
+ }
18857
+ return baseURL;
18858
+ }
18859
+ function resolveApiKey(config) {
18860
+ if (config.apiKey)
18861
+ return config.apiKey;
18862
+ if (config.baseURL)
18863
+ return "ollama";
18864
+ return process.env["OPENAI_API_KEY"];
18865
+ }
18827
18866
  async function callOpenAIAdapter(config, input, turns) {
18828
18867
  const start = Date.now();
18829
- const client = new OpenAI({
18830
- apiKey: config.apiKey ?? process.env["OPENAI_API_KEY"],
18831
- baseURL: config.baseURL
18832
- });
18833
18868
  try {
18869
+ const client = new OpenAI({
18870
+ apiKey: resolveApiKey(config),
18871
+ baseURL: normalizeBaseURL(config.baseURL)
18872
+ });
18834
18873
  const messages = [];
18835
18874
  if (config.systemPrompt)
18836
18875
  messages.push({ role: "system", content: config.systemPrompt });
@@ -26651,6 +26690,20 @@ async function callCliAdapter(config2, input) {
26651
26690
  }
26652
26691
  }
26653
26692
 
26693
+ // src/core/redaction.ts
26694
+ function redactAdapterConfig(config2) {
26695
+ if (!config2 || !("apiKey" in config2))
26696
+ return config2;
26697
+ const { apiKey: _apiKey, ...safeConfig } = config2;
26698
+ return safeConfig;
26699
+ }
26700
+ function redactRunSecrets(run) {
26701
+ return {
26702
+ ...run,
26703
+ adapterConfig: redactAdapterConfig(run.adapterConfig)
26704
+ };
26705
+ }
26706
+
26654
26707
  // src/core/runner.ts
26655
26708
  async function callAdapter(config2, input, turns) {
26656
26709
  switch (config2.type) {
@@ -26757,7 +26810,7 @@ async function runEvals(cases, options) {
26757
26810
  id: randomUUID(),
26758
26811
  createdAt: new Date().toISOString(),
26759
26812
  dataset: options.dataset,
26760
- adapterConfig: options.adapter,
26813
+ adapterConfig: redactAdapterConfig(options.adapter),
26761
26814
  results,
26762
26815
  stats
26763
26816
  };
@@ -26829,7 +26882,7 @@ function printTerminalReport(run) {
26829
26882
  console.log();
26830
26883
  }
26831
26884
  function toJson(run) {
26832
- return JSON.stringify(run, null, 2);
26885
+ return JSON.stringify(redactRunSecrets(run), null, 2);
26833
26886
  }
26834
26887
  function toMarkdown(run) {
26835
26888
  const { results, stats } = run;
@@ -27088,10 +27141,11 @@ function migrate(db) {
27088
27141
  }
27089
27142
  function saveRun(run) {
27090
27143
  const db = getDatabase();
27144
+ const safeRun = redactRunSecrets(run);
27091
27145
  db.prepare(`
27092
27146
  INSERT OR REPLACE INTO runs (id, created_at, dataset, stats, adapter, data)
27093
27147
  VALUES (?, ?, ?, ?, ?, ?)
27094
- `).run(run.id, run.createdAt, run.dataset, JSON.stringify(run.stats), run.adapterConfig ? JSON.stringify(run.adapterConfig) : null, JSON.stringify(run));
27148
+ `).run(safeRun.id, safeRun.createdAt, safeRun.dataset, JSON.stringify(safeRun.stats), safeRun.adapterConfig ? JSON.stringify(safeRun.adapterConfig) : null, JSON.stringify(safeRun));
27095
27149
  }
27096
27150
  function getRun(id) {
27097
27151
  const db = getDatabase();
package/dist/mcp/index.js CHANGED
@@ -10572,6 +10572,20 @@ var init_sdk = __esm(() => {
10572
10572
  init_error();
10573
10573
  });
10574
10574
 
10575
+ // src/core/redaction.ts
10576
+ function redactAdapterConfig(config2) {
10577
+ if (!config2 || !("apiKey" in config2))
10578
+ return config2;
10579
+ const { apiKey: _apiKey, ...safeConfig } = config2;
10580
+ return safeConfig;
10581
+ }
10582
+ function redactRunSecrets(run) {
10583
+ return {
10584
+ ...run,
10585
+ adapterConfig: redactAdapterConfig(run.adapterConfig)
10586
+ };
10587
+ }
10588
+
10575
10589
  // src/db/store.ts
10576
10590
  var exports_store = {};
10577
10591
  __export(exports_store, {
@@ -10633,10 +10647,11 @@ function migrate(db) {
10633
10647
  }
10634
10648
  function saveRun(run) {
10635
10649
  const db = getDatabase();
10650
+ const safeRun = redactRunSecrets(run);
10636
10651
  db.prepare(`
10637
10652
  INSERT OR REPLACE INTO runs (id, created_at, dataset, stats, adapter, data)
10638
10653
  VALUES (?, ?, ?, ?, ?, ?)
10639
- `).run(run.id, run.createdAt, run.dataset, JSON.stringify(run.stats), run.adapterConfig ? JSON.stringify(run.adapterConfig) : null, JSON.stringify(run));
10654
+ `).run(safeRun.id, safeRun.createdAt, safeRun.dataset, JSON.stringify(safeRun.stats), safeRun.adapterConfig ? JSON.stringify(safeRun.adapterConfig) : null, JSON.stringify(safeRun));
10640
10655
  }
10641
10656
  function getRun(id) {
10642
10657
  const db = getDatabase();
@@ -10678,7 +10693,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
10678
10693
  // package.json
10679
10694
  var package_default = {
10680
10695
  name: "@hasna/evals",
10681
- version: "0.1.27",
10696
+ version: "0.1.28",
10682
10697
  description: "Open source AI evaluation framework \u2014 LLM-as-judge + assertion-based evals for any AI app. CLI + MCP server.",
10683
10698
  type: "module",
10684
10699
  main: "dist/index.js",
@@ -25558,7 +25573,7 @@ var safeJSON2 = (text) => {
25558
25573
  var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25559
25574
 
25560
25575
  // node_modules/openai/version.mjs
25561
- var VERSION2 = "6.42.0";
25576
+ var VERSION2 = "6.44.0";
25562
25577
 
25563
25578
  // node_modules/openai/internal/detect-platform.mjs
25564
25579
  var isRunningInBrowser2 = () => {
@@ -27552,7 +27567,12 @@ _AbstractChatCompletionRunner_instances = new WeakSet, _AbstractChatCompletionRu
27552
27567
  for (let i = this.messages.length - 1;i >= 0; i--) {
27553
27568
  const message = this.messages[i];
27554
27569
  if (isAssistantMessage(message) && message?.tool_calls?.length) {
27555
- return message.tool_calls.filter((x) => x.type === "function").at(-1)?.function;
27570
+ for (let j = message.tool_calls.length - 1;j >= 0; j--) {
27571
+ const toolCall = message.tool_calls[j];
27572
+ if (toolCall?.type === "function") {
27573
+ return toolCall.function;
27574
+ }
27575
+ }
27556
27576
  }
27557
27577
  }
27558
27578
  return;
@@ -28558,6 +28578,12 @@ class SpendAlerts extends APIResource2 {
28558
28578
  __security: { adminAPIKeyAuth: true }
28559
28579
  });
28560
28580
  }
28581
+ retrieve(alertID, options) {
28582
+ return this._client.get(path2`/organization/spend_alerts/${alertID}`, {
28583
+ ...options,
28584
+ __security: { adminAPIKeyAuth: true }
28585
+ });
28586
+ }
28561
28587
  update(alertID, body, options) {
28562
28588
  return this._client.post(path2`/organization/spend_alerts/${alertID}`, {
28563
28589
  body,
@@ -28941,6 +28967,13 @@ class SpendAlerts2 extends APIResource2 {
28941
28967
  __security: { adminAPIKeyAuth: true }
28942
28968
  });
28943
28969
  }
28970
+ retrieve(alertID, params, options) {
28971
+ const { project_id } = params;
28972
+ return this._client.get(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
28973
+ ...options,
28974
+ __security: { adminAPIKeyAuth: true }
28975
+ });
28976
+ }
28944
28977
  update(alertID, params, options) {
28945
28978
  const { project_id, ...body } = params;
28946
28979
  return this._client.post(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
@@ -32716,13 +32749,34 @@ async function callAnthropicAdapter(config2, input, turns) {
32716
32749
  }
32717
32750
 
32718
32751
  // src/adapters/openai.ts
32752
+ function normalizeBaseURL(baseURL) {
32753
+ if (!baseURL)
32754
+ return;
32755
+ try {
32756
+ const url2 = new URL(baseURL);
32757
+ if (url2.pathname === "" || url2.pathname === "/") {
32758
+ url2.pathname = "/v1";
32759
+ return url2.toString();
32760
+ }
32761
+ } catch {
32762
+ return baseURL;
32763
+ }
32764
+ return baseURL;
32765
+ }
32766
+ function resolveApiKey(config2) {
32767
+ if (config2.apiKey)
32768
+ return config2.apiKey;
32769
+ if (config2.baseURL)
32770
+ return "ollama";
32771
+ return process.env["OPENAI_API_KEY"];
32772
+ }
32719
32773
  async function callOpenAIAdapter(config2, input, turns) {
32720
32774
  const start = Date.now();
32721
- const client = new OpenAI({
32722
- apiKey: config2.apiKey ?? process.env["OPENAI_API_KEY"],
32723
- baseURL: config2.baseURL
32724
- });
32725
32775
  try {
32776
+ const client = new OpenAI({
32777
+ apiKey: resolveApiKey(config2),
32778
+ baseURL: normalizeBaseURL(config2.baseURL)
32779
+ });
32726
32780
  const messages = [];
32727
32781
  if (config2.systemPrompt)
32728
32782
  messages.push({ role: "system", content: config2.systemPrompt });
@@ -32980,7 +33034,7 @@ async function runEvals(cases, options) {
32980
33034
  id: randomUUID(),
32981
33035
  createdAt: new Date().toISOString(),
32982
33036
  dataset: options.dataset,
32983
- adapterConfig: options.adapter,
33037
+ adapterConfig: redactAdapterConfig(options.adapter),
32984
33038
  results,
32985
33039
  stats
32986
33040
  };
@@ -33104,10 +33158,9 @@ function validateEvalCase(raw, location) {
33104
33158
  }
33105
33159
  return obj;
33106
33160
  }
33107
-
33108
33161
  // src/core/reporter.ts
33109
33162
  function toJson(run) {
33110
- return JSON.stringify(run, null, 2);
33163
+ return JSON.stringify(redactRunSecrets(run), null, 2);
33111
33164
  }
33112
33165
  function toMarkdown(run) {
33113
33166
  const { results, stats } = run;
@@ -11666,7 +11666,7 @@ var safeJSON2 = (text) => {
11666
11666
  var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11667
11667
 
11668
11668
  // node_modules/openai/version.mjs
11669
- var VERSION2 = "6.42.0";
11669
+ var VERSION2 = "6.44.0";
11670
11670
 
11671
11671
  // node_modules/openai/internal/detect-platform.mjs
11672
11672
  var isRunningInBrowser2 = () => {
@@ -13660,7 +13660,12 @@ _AbstractChatCompletionRunner_instances = new WeakSet, _AbstractChatCompletionRu
13660
13660
  for (let i = this.messages.length - 1;i >= 0; i--) {
13661
13661
  const message = this.messages[i];
13662
13662
  if (isAssistantMessage(message) && message?.tool_calls?.length) {
13663
- return message.tool_calls.filter((x) => x.type === "function").at(-1)?.function;
13663
+ for (let j = message.tool_calls.length - 1;j >= 0; j--) {
13664
+ const toolCall = message.tool_calls[j];
13665
+ if (toolCall?.type === "function") {
13666
+ return toolCall.function;
13667
+ }
13668
+ }
13664
13669
  }
13665
13670
  }
13666
13671
  return;
@@ -14666,6 +14671,12 @@ class SpendAlerts extends APIResource2 {
14666
14671
  __security: { adminAPIKeyAuth: true }
14667
14672
  });
14668
14673
  }
14674
+ retrieve(alertID, options) {
14675
+ return this._client.get(path2`/organization/spend_alerts/${alertID}`, {
14676
+ ...options,
14677
+ __security: { adminAPIKeyAuth: true }
14678
+ });
14679
+ }
14669
14680
  update(alertID, body, options) {
14670
14681
  return this._client.post(path2`/organization/spend_alerts/${alertID}`, {
14671
14682
  body,
@@ -15049,6 +15060,13 @@ class SpendAlerts2 extends APIResource2 {
15049
15060
  __security: { adminAPIKeyAuth: true }
15050
15061
  });
15051
15062
  }
15063
+ retrieve(alertID, params, options) {
15064
+ const { project_id } = params;
15065
+ return this._client.get(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
15066
+ ...options,
15067
+ __security: { adminAPIKeyAuth: true }
15068
+ });
15069
+ }
15052
15070
  update(alertID, params, options) {
15053
15071
  const { project_id, ...body } = params;
15054
15072
  return this._client.post(path2`/organization/projects/${project_id}/spend_alerts/${alertID}`, {
@@ -18823,13 +18841,34 @@ async function callAnthropicAdapter(config, input, turns) {
18823
18841
  }
18824
18842
 
18825
18843
  // src/adapters/openai.ts
18844
+ function normalizeBaseURL(baseURL) {
18845
+ if (!baseURL)
18846
+ return;
18847
+ try {
18848
+ const url = new URL(baseURL);
18849
+ if (url.pathname === "" || url.pathname === "/") {
18850
+ url.pathname = "/v1";
18851
+ return url.toString();
18852
+ }
18853
+ } catch {
18854
+ return baseURL;
18855
+ }
18856
+ return baseURL;
18857
+ }
18858
+ function resolveApiKey(config) {
18859
+ if (config.apiKey)
18860
+ return config.apiKey;
18861
+ if (config.baseURL)
18862
+ return "ollama";
18863
+ return process.env["OPENAI_API_KEY"];
18864
+ }
18826
18865
  async function callOpenAIAdapter(config, input, turns) {
18827
18866
  const start = Date.now();
18828
- const client = new OpenAI({
18829
- apiKey: config.apiKey ?? process.env["OPENAI_API_KEY"],
18830
- baseURL: config.baseURL
18831
- });
18832
18867
  try {
18868
+ const client = new OpenAI({
18869
+ apiKey: resolveApiKey(config),
18870
+ baseURL: normalizeBaseURL(config.baseURL)
18871
+ });
18833
18872
  const messages = [];
18834
18873
  if (config.systemPrompt)
18835
18874
  messages.push({ role: "system", content: config.systemPrompt });
@@ -26650,6 +26689,20 @@ async function callCliAdapter(config2, input) {
26650
26689
  }
26651
26690
  }
26652
26691
 
26692
+ // src/core/redaction.ts
26693
+ function redactAdapterConfig(config2) {
26694
+ if (!config2 || !("apiKey" in config2))
26695
+ return config2;
26696
+ const { apiKey: _apiKey, ...safeConfig } = config2;
26697
+ return safeConfig;
26698
+ }
26699
+ function redactRunSecrets(run) {
26700
+ return {
26701
+ ...run,
26702
+ adapterConfig: redactAdapterConfig(run.adapterConfig)
26703
+ };
26704
+ }
26705
+
26653
26706
  // src/core/runner.ts
26654
26707
  async function callAdapter(config2, input, turns) {
26655
26708
  switch (config2.type) {
@@ -26756,7 +26809,7 @@ async function runEvals(cases, options) {
26756
26809
  id: randomUUID(),
26757
26810
  createdAt: new Date().toISOString(),
26758
26811
  dataset: options.dataset,
26759
- adapterConfig: options.adapter,
26812
+ adapterConfig: redactAdapterConfig(options.adapter),
26760
26813
  results,
26761
26814
  stats
26762
26815
  };
@@ -26976,10 +27029,11 @@ function migrate(db) {
26976
27029
  }
26977
27030
  function saveRun(run) {
26978
27031
  const db = getDatabase();
27032
+ const safeRun = redactRunSecrets(run);
26979
27033
  db.prepare(`
26980
27034
  INSERT OR REPLACE INTO runs (id, created_at, dataset, stats, adapter, data)
26981
27035
  VALUES (?, ?, ?, ?, ?, ?)
26982
- `).run(run.id, run.createdAt, run.dataset, JSON.stringify(run.stats), run.adapterConfig ? JSON.stringify(run.adapterConfig) : null, JSON.stringify(run));
27036
+ `).run(safeRun.id, safeRun.createdAt, safeRun.dataset, JSON.stringify(safeRun.stats), safeRun.adapterConfig ? JSON.stringify(safeRun.adapterConfig) : null, JSON.stringify(safeRun));
26983
27037
  }
26984
27038
  function getRun(id) {
26985
27039
  const db = getDatabase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/evals",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "Open source AI evaluation framework — LLM-as-judge + assertion-based evals for any AI app. CLI + MCP server.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",