anpord 0.1.12 → 0.1.13

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.
Files changed (41) hide show
  1. package/dist/bin.cjs +208 -125
  2. package/dist/bin.mjs +208 -125
  3. package/dist/cli-runtime.cjs +2 -2
  4. package/dist/cli-runtime.d.cts +1 -1
  5. package/dist/cli-runtime.d.mts +1 -1
  6. package/dist/cli-runtime.mjs +2 -2
  7. package/dist/{client-D22IiHGL.mjs → client-BfdjFtlV.mjs} +7 -6
  8. package/dist/{client-Byoa41pX.d.mts → client-BgRs8JvW.d.mts} +1891 -227
  9. package/dist/{client-CFTj9ad0.d.cts → client-BirFO3jz.d.cts} +1891 -227
  10. package/dist/{client-BnimnYiJ.cjs → client-C-P2I00z.cjs} +7 -6
  11. package/dist/{compiler-CBMPXIzV.mjs → compiler-D96wI7UP.mjs} +87 -82
  12. package/dist/{compiler-BFxukiJy.cjs → compiler-uwb1pkdK.cjs} +85 -80
  13. package/dist/config.cjs +1 -1
  14. package/dist/config.d.cts +1 -1
  15. package/dist/config.d.mts +1 -1
  16. package/dist/config.mjs +1 -1
  17. package/dist/eval-validations-BRdoZrTQ.mjs +113 -0
  18. package/dist/eval-validations-_MlnQ_uv.cjs +148 -0
  19. package/dist/eval.cjs +1 -1
  20. package/dist/eval.d.cts +33 -13
  21. package/dist/eval.d.mts +33 -13
  22. package/dist/eval.mjs +1 -1
  23. package/dist/evals-B6aT3xgH.d.cts +1364 -0
  24. package/dist/evals-B6aT3xgH.d.mts +1364 -0
  25. package/dist/{evals-CvOTyvCX.mjs → evals-Dcc_x6jW.mjs} +54 -11
  26. package/dist/{evals-B04M0apj.cjs → evals-DouMsrsM.cjs} +71 -16
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.d.cts +128 -4
  29. package/dist/index.d.mts +128 -4
  30. package/dist/index.mjs +1 -1
  31. package/dist/source.d.cts +1 -1
  32. package/dist/source.d.mts +1 -1
  33. package/dist/{types-oXWOHA-X.d.mts → types-Codjaq-o.d.mts} +65 -19
  34. package/dist/{types-nr4-1c3W.d.cts → types-ISsteq95.d.cts} +65 -19
  35. package/dist/validator-runtime.cjs +238 -0
  36. package/dist/validator-runtime.d.cts +9 -0
  37. package/dist/validator-runtime.d.mts +9 -0
  38. package/dist/validator-runtime.mjs +237 -0
  39. package/package.json +1 -1
  40. package/dist/evals-BUBzpke_.d.cts +0 -647
  41. package/dist/evals-BUBzpke_.d.mts +0 -647
@@ -1,4 +1,4 @@
1
- const require_evals = require("./evals-B04M0apj.cjs");
1
+ const require_evals = require("./evals-DouMsrsM.cjs");
2
2
  let _effect_platform = require("@effect/platform");
3
3
  let effect = require("effect");
4
4
  //#region ../schema/src/domain/prompts.ts
@@ -135,9 +135,9 @@ const EvalModelsRequest = effect.Schema.Struct({
135
135
  description: "Select a harness whose available models should be listed.",
136
136
  identifier: "EvalModelsRequest"
137
137
  });
138
- const PublicEvalProvider = require_evals.EvalProvider.annotations({
139
- description: "A hosted sandbox provider.",
140
- identifier: "PublicEvalProvider"
138
+ const PublicEvalSandbox = require_evals.EvalSandbox.annotations({
139
+ description: "The hosted sandbox a task runs in.",
140
+ identifier: "PublicEvalSandbox"
141
141
  });
142
142
  const ListEvalsRequest = effect.Schema.Struct({
143
143
  cursor: effect.Schema.optional(effect.Schema.NullOr(require_evals.EvalPageCursor)),
@@ -162,12 +162,13 @@ const PublicEvalTask = effect.Schema.Struct({
162
162
  harness: require_evals.EvalHarness,
163
163
  model: effect.Schema.String.pipe(effect.Schema.minLength(1)),
164
164
  profile: effect.Schema.optional(require_evals.HarnessProfile),
165
- provider: PublicEvalProvider
165
+ sandbox: effect.Schema.optional(PublicEvalSandbox)
166
166
  }).pipe(effect.Schema.filter(require_evals.profileFitsHarness, { message: () => require_evals.PROFILE_HARNESS_RULE })).annotations({
167
- description: `A harness, model, and hosted sandbox combination, with an optional profile layered on the harness. ${require_evals.PROFILE_HARNESS_RULE}`,
167
+ description: `A harness and model, with an optional sandbox and an optional profile layered on the harness. Omit the sandbox to use the default. ${require_evals.PROFILE_HARNESS_RULE}`,
168
168
  identifier: "StartEvalTask"
169
169
  });
170
170
  const PublicStartEvalRequest = effect.Schema.Struct({
171
+ trigger: effect.Schema.optional(require_evals.EvalTrigger),
171
172
  cases: effect.Schema.Array(PublicEvalCase).pipe(effect.Schema.minItems(1), effect.Schema.maxItems(100)),
172
173
  name: effect.Schema.optional(require_evals.EvalName),
173
174
  prompt: require_evals.EvalPrompt,
@@ -1,8 +1,8 @@
1
- import { _ as HarnessProfile, b as ProfilePath, d as EvalValidator, g as EnvName, x as profileFitsHarness, y as PROFILE_LIMITS } from "./evals-CvOTyvCX.mjs";
1
+ import { S as EvalSourceFiles, _ as HarnessProfile, b as ProfilePath, d as EvalValidator, g as EnvName, x as profileFitsHarness, y as PROFILE_LIMITS } from "./evals-Dcc_x6jW.mjs";
2
2
  import { t as EvalJudge } from "./eval-judges-CwTvTq7N.mjs";
3
3
  import { a as parseRepo, i as cloneUrlOf, r as repo } from "./source-Fg1h2VNn.mjs";
4
- import { Data, Effect, Option, Schema } from "effect";
5
- import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { Config, Data, Effect, Option, Schema } from "effect";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
6
  import { existsSync, realpathSync } from "node:fs";
7
7
  import { mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
8
8
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -12,12 +12,52 @@ import { tmpdir } from "node:os";
12
12
  import { execFile } from "node:child_process";
13
13
  import { promisify } from "node:util";
14
14
  import { parse, stringify } from "smol-toml";
15
+ //#region src/evals/source-files.ts
16
+ const CODE_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
17
+ const sdkRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
18
+ const SourceMap = Schema.parseJson(Schema.Struct({
19
+ version: Schema.Literal(3),
20
+ sources: Schema.Array(Schema.String),
21
+ sourcesContent: Schema.Array(Schema.NullOr(Schema.String))
22
+ }));
23
+ const projectRoot = (entry) => {
24
+ let directory = dirname(entry);
25
+ while (!existsSync(resolve(directory, "package.json"))) {
26
+ const parent = dirname(directory);
27
+ if (parent === directory) return dirname(entry);
28
+ directory = parent;
29
+ }
30
+ return directory;
31
+ };
32
+ const sourceFiles = (map, entry) => {
33
+ const decoded = Schema.decodeUnknownSync(SourceMap)(map);
34
+ const root = realpathSync(projectRoot(entry));
35
+ const entryPath = relative(root, realpathSync(entry)).split(sep).join("/");
36
+ const files = decoded.sources.flatMap((source, index) => {
37
+ const absolute = resolve(dirname(entry), source);
38
+ const path = relative(root, absolute).split(sep).join("/");
39
+ const content = decoded.sourcesContent[index];
40
+ if (content == null || path.startsWith("../") || path.split("/").includes("node_modules") || absolute.startsWith(`${sdkRoot}${sep}`) || !CODE_FILE.test(path) || source.includes(":") || basename(path) === "anpord-eval-entry.ts") return [];
41
+ return [{
42
+ path,
43
+ content
44
+ }];
45
+ });
46
+ return Schema.decodeUnknownSync(EvalSourceFiles)(files.toSorted((a, b) => Number(b.path === entryPath) - Number(a.path === entryPath) || a.path.localeCompare(b.path)));
47
+ };
48
+ //#endregion
15
49
  //#region src/evals/eval-bundle.ts
16
50
  const authoringExports = ["export const defineEval = value => value;", `export { empty, files, repo } from "./source";`].join("\n");
17
51
  const authoringDir = dirname(fileURLToPath(import.meta.url));
18
52
  const ANPORD_MODULE = /^anpord$/;
19
53
  const ANY_MODULE = /.*/;
20
54
  const localModules = [
55
+ {
56
+ built: "validator-runtime.mjs",
57
+ filter: /^anpord\/validators\/runtime$/,
58
+ namespace: "anpord-validator-runtime",
59
+ source: "validator-runtime.ts"
60
+ },
21
61
  {
22
62
  built: "validators.mjs",
23
63
  filter: /^anpord\/validators$/,
@@ -91,6 +131,8 @@ const bundle = (contents, entry, options = {}) => Effect.tryPromise({
91
131
  format: "esm",
92
132
  metafile: true,
93
133
  minify: options.minify,
134
+ outfile: resolve(dirname(entry), "anpord-bundle.mjs"),
135
+ sourcemap: options.captureSource ? "external" : false,
94
136
  platform: "node",
95
137
  resolveExtensions: [
96
138
  ".ts",
@@ -110,7 +152,8 @@ const bundle = (contents, entry, options = {}) => Effect.tryPromise({
110
152
  write: false
111
153
  }).then((result) => ({
112
154
  inputs: Object.keys(result.metafile?.inputs ?? {}).map((path) => resolve(path)),
113
- source: result.outputFiles[0]?.text ?? ""
155
+ source: result.outputFiles.find((file) => file.path.endsWith(".mjs"))?.text ?? "",
156
+ ...options.captureSource ? { sourceFiles: sourceFiles(result.outputFiles.find((file) => file.path.endsWith(".map"))?.text ?? "", entry) } : {}
114
157
  })),
115
158
  catch: (cause) => new Error(`Could not compile ${entry}`, { cause })
116
159
  });
@@ -159,65 +202,12 @@ const packageProgram = (root, entry, source) => {
159
202
  };
160
203
  //#endregion
161
204
  //#region src/evals/runner-source.ts
162
- const runtime = `
163
- import { access, readFile } from "node:fs/promises";
164
- import { spawn } from "node:child_process";
165
-
166
- const exec = (command) => new Promise((resolve, reject) => {
167
- const child = spawn("/bin/sh", ["-lc", command], { cwd: process.cwd() });
168
- let stderr = "";
169
- let stdout = "";
170
- child.stderr.on("data", chunk => { stderr += chunk; });
171
- child.stdout.on("data", chunk => { stdout += chunk; });
172
- child.on("error", reject);
173
- child.on("close", code => resolve({ exitCode: code ?? 1, stderr, stdout }));
174
- });
175
-
176
- const readOrEmpty = (path) =>
177
- path === undefined ? Promise.resolve("") : readFile(path, "utf8").then(text => text, () => "");
178
-
179
- const calls = async (path, key, value) => {
180
- const text = await readOrEmpty(path);
181
- const calls = text.trim() === "" ? [] : text.trim().split("\\n").map((line) => JSON.parse(line));
182
- return value === undefined ? calls : calls.filter((call) => call[key] === value);
183
- };
184
-
185
- const context = {
186
- answer: () => readOrEmpty(process.env.ANPORD_ANSWER_FILE),
187
- cli: { calls: cli => calls(".anpord/cli-calls.jsonl", "cli", cli) },
188
- exec,
189
- exists: path => access(path).then(() => true, () => false),
190
- mcp: { calls: server => calls(".anpord/mcp-calls.jsonl", "server", server) },
191
- readText: path => readFile(path, "utf8"),
192
- prepared: JSON.parse(process.env.ANPORD_PREPARE_VALUE ?? "{}"),
193
- transcript: () => readOrEmpty(process.env.ANPORD_TRANSCRIPT_FILE),
194
- };
195
-
196
- try {
197
- const raw = await validate(context);
198
- const result = typeof raw === "boolean" ? { passed: raw } : raw;
199
- if (typeof result?.passed !== "boolean") throw new Error("A validator must return a boolean or { passed, message? }");
200
- console.log("ANPORD_VALIDATOR_RESULT=" + JSON.stringify(result));
201
- } catch (error) {
202
- console.error(error instanceof Error ? error.stack : String(error));
203
- process.exitCode = 1;
204
- }
205
- `;
206
- const validatorCaseEntry = (entry, index) => `import definition from ${JSON.stringify(entry)};
205
+ const validatorCaseEntry = (entry, index, names = []) => `import definition from ${JSON.stringify(entry)};
206
+ import { runValidators } from "anpord/validators/runtime";
207
207
  const selected = definition.cases[${index}].validate;
208
- const checks = (Array.isArray(selected) ? selected : [selected]).filter(value => typeof value === "function");
209
- const validate = async context => {
210
- const messages = [];
211
- for (const check of checks) {
212
- const raw = await check(context);
213
- const result = typeof raw === "boolean" ? { passed: raw } : raw;
214
- if (typeof result?.passed !== "boolean") throw new Error("Invalid validator result");
215
- if (result.message) messages.push(result.message);
216
- if (!result.passed) return { passed: false, message: messages.join("; ") };
217
- }
218
- return { passed: true, message: messages.join("; ") || "Code validators passed" };
219
- };
220
- ${runtime}`;
208
+ const names = ${JSON.stringify(names)};
209
+ const checks = (Array.isArray(selected) ? selected : [selected]).flatMap((validate, index) => typeof validate === "function" ? [{ index, name: names.find(check => check.index === index)?.name ?? "Validator " + (index + 1), validate }] : []);
210
+ await runValidators(checks, definition.captureValidation !== false);`;
221
211
  const prepareRuntime = `
222
212
  import { access, readFile } from "node:fs/promises";
223
213
  import { spawn } from "node:child_process";
@@ -268,11 +258,12 @@ import { runMcpServer } from "anpord/mcp/runtime";
268
258
  const server = definition.mcp?.[${index}];
269
259
  if (server === undefined) throw new Error("MCP server ${index} is missing");
270
260
  runMcpServer(server);`;
271
- const cliEntry = (entry, index) => `import definition from ${JSON.stringify(entry)};
261
+ const cliEntry = (entry, index) => `import { fileURLToPath } from "node:url";
262
+ import definition from ${JSON.stringify(entry)};
272
263
  import { runCli } from "anpord/cli/runtime";
273
264
  const cli = definition.cli?.[${index}];
274
265
  if (cli === undefined) throw new Error("CLI ${index} is missing");
275
- await runCli(cli);`;
266
+ await runCli(cli, fileURLToPath(new URL("../../cli-calls.jsonl", import.meta.url)));`;
276
267
  //#endregion
277
268
  //#region src/evals/cli-profile.ts
278
269
  const compileClis = (entry, definitions) => Effect.gen(function* () {
@@ -309,22 +300,37 @@ const withClis = (task, clis) => {
309
300
  };
310
301
  //#endregion
311
302
  //#region src/evals/compile-validator.ts
312
- const compileValidator = (entry, subject, caseIndex) => Effect.gen(function* () {
303
+ const compileValidator = (entry, subject, caseIndex, captureSource, captureValidation = true) => Effect.gen(function* () {
313
304
  if (subject.validate === void 0) return null;
314
305
  const validations = Array.isArray(subject.validate) ? subject.validate : [subject.validate];
315
306
  if (validations.length === 0 || validations.length > 20) return yield* Effect.fail(/* @__PURE__ */ new Error("Use between 1 and 20 validators"));
316
307
  const judges = yield* Effect.forEach(validations.filter((value) => typeof value !== "function"), (value) => Schema.decodeUnknown(EvalJudge)(value, { onExcessProperty: "error" }));
317
308
  if (new Set(judges.map(({ name }) => name)).size !== judges.length) return yield* Effect.fail(/* @__PURE__ */ new Error("Judge names must be unique within a case"));
318
- const checks = validations.some((value) => typeof value === "function") ? [{
309
+ const manifest = validations.flatMap((value, index) => typeof value === "function" ? [{
310
+ index,
311
+ name: value.name || `Validator ${index + 1}`
312
+ }] : []);
313
+ const hasCode = manifest.length > 0;
314
+ const compiled = yield* bundle(hasCode ? validatorCaseEntry(entry, caseIndex, manifest) : definitionEntry(entry), entry, {
315
+ minify: true,
316
+ captureSource
317
+ });
318
+ const checks = hasCode ? [{
319
319
  name: typeof subject.validate === "function" ? subject.validate.name || subject.name : subject.name,
320
- source: (yield* bundle(validatorCaseEntry(entry, caseIndex), entry, { minify: true })).source
320
+ source: compiled.source,
321
+ manifest,
322
+ capture: captureValidation
321
323
  }] : [];
322
- return yield* Schema.decodeUnknown(EvalValidator)(judges.length > 0 ? {
323
- kind: "judged",
324
- name: subject.name,
325
- checks,
326
- judges
327
- } : checks[0]);
324
+ return yield* Schema.decodeUnknown(EvalValidator)({
325
+ ...judges.length > 0 ? {
326
+ kind: "judged",
327
+ name: subject.name,
328
+ checks,
329
+ judges
330
+ } : checks[0],
331
+ sourceFiles: compiled.sourceFiles,
332
+ capture: captureValidation
333
+ });
328
334
  });
329
335
  //#endregion
330
336
  //#region src/evals/definition-loader.ts
@@ -355,26 +361,25 @@ const isDefinition = (value) => Option.isSome(decodeShape(value));
355
361
  //#region src/evals/local-repo.ts
356
362
  const run = promisify(execFile);
357
363
  const git = (args, cwd) => Effect.tryPromise(() => run("git", [...args], { cwd })).pipe(Effect.map(({ stdout }) => stdout.trim()), Effect.orElseSucceed(() => ""));
358
- const environment = () => globalThis.process?.env ?? {};
359
364
  const remoteUrl = (cwd) => Effect.gen(function* () {
360
- const { GITHUB_REPOSITORY } = environment();
365
+ const repository = yield* Config.string("GITHUB_REPOSITORY").pipe(Config.withDefault(""));
361
366
  const origin = yield* git([
362
367
  "remote",
363
368
  "get-url",
364
369
  "origin"
365
370
  ], cwd);
366
- return origin === "" && GITHUB_REPOSITORY !== void 0 ? GITHUB_REPOSITORY : origin;
371
+ return origin === "" ? repository : origin;
367
372
  });
368
373
  const fetchableRef = (cwd) => Effect.gen(function* () {
369
- const { GITHUB_HEAD_REF } = environment();
370
- if (GITHUB_HEAD_REF !== void 0 && GITHUB_HEAD_REF !== "") return GITHUB_HEAD_REF;
374
+ const ci = yield* Config.boolean("GITHUB_ACTIONS").pipe(Config.withDefault(false));
371
375
  const [head, onRemote] = yield* Effect.all([git(["rev-parse", "HEAD"], cwd), git([
372
376
  "branch",
373
377
  "--remotes",
374
378
  "--contains",
375
379
  "HEAD"
376
380
  ], cwd)], { concurrency: 2 });
377
- return head === "" || onRemote === "" ? null : head;
381
+ if (ci && head === "") return yield* Effect.fail(/* @__PURE__ */ new Error("Check out the commit before running evals in GitHub Actions."));
382
+ return head === "" || !ci && onRemote === "" ? null : head;
378
383
  });
379
384
  const localRepo = (cwd) => Effect.gen(function* () {
380
385
  const [remote, ref] = yield* Effect.all([remoteUrl(cwd), fetchableRef(cwd)], { concurrency: 2 });
@@ -698,7 +703,7 @@ const profileTask = (entry, task) => Effect.gen(function* () {
698
703
  harness: task.harness.base,
699
704
  model: task.model,
700
705
  profile,
701
- provider: task.provider
706
+ sandbox: task.sandbox
702
707
  };
703
708
  }).pipe(Effect.withSpan("Eval.profileTask", { attributes: { profile: task.harness.profile.name } }));
704
709
  //#endregion
@@ -707,7 +712,7 @@ const taskOf = (entry, task, clis, mcp) => Effect.gen(function* () {
707
712
  const compiled = typeof task.harness === "string" ? {
708
713
  harness: task.harness,
709
714
  model: task.model,
710
- provider: task.provider
715
+ sandbox: task.sandbox
711
716
  } : yield* profileTask(entry, {
712
717
  ...task,
713
718
  harness: task.harness
@@ -732,7 +737,7 @@ const compileEvalEffect = (path) => Effect.gen(function* () {
732
737
  const fallback = definition.source === void 0 && definition.cases.some((subject) => subject.source === void 0) ? yield* localRepo(dirname(entry)) : Option.none();
733
738
  const cases = yield* Effect.forEach(definition.cases, (subject, caseIndex) => Effect.gen(function* () {
734
739
  if (subject.validate !== void 0 === (typeof subject.verify === "string")) return yield* Effect.fail(/* @__PURE__ */ new Error(`${subject.name} must have exactly one of validate or verify`));
735
- const validator = yield* compileValidator(entry, subject, caseIndex);
740
+ const validator = yield* compileValidator(entry, subject, caseIndex, definition.captureSource !== false, definition.captureValidation !== false);
736
741
  const prepare = typeof subject.prepare === "function" ? yield* bundledCaseModule(entry, loaded.inputs, subject.prepare.name || `${subject.name}-prepare`, prepareEntry) : null;
737
742
  return {
738
743
  ...subject.cache === void 0 ? {} : { cache: subject.cache },
@@ -1,4 +1,4 @@
1
- const require_evals = require("./evals-B04M0apj.cjs");
1
+ const require_evals = require("./evals-DouMsrsM.cjs");
2
2
  const require_eval_judges = require("./eval-judges-BkmiVLLq.cjs");
3
3
  const require_source = require("./source-DvlGawEw.cjs");
4
4
  let effect = require("effect");
@@ -12,12 +12,52 @@ let node_os = require("node:os");
12
12
  let node_child_process = require("node:child_process");
13
13
  let node_util = require("node:util");
14
14
  let smol_toml = require("smol-toml");
15
+ //#region src/evals/source-files.ts
16
+ const CODE_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
17
+ const sdkRoot = (0, node_path.resolve)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), "..");
18
+ const SourceMap = effect.Schema.parseJson(effect.Schema.Struct({
19
+ version: effect.Schema.Literal(3),
20
+ sources: effect.Schema.Array(effect.Schema.String),
21
+ sourcesContent: effect.Schema.Array(effect.Schema.NullOr(effect.Schema.String))
22
+ }));
23
+ const projectRoot = (entry) => {
24
+ let directory = (0, node_path.dirname)(entry);
25
+ while (!(0, node_fs.existsSync)((0, node_path.resolve)(directory, "package.json"))) {
26
+ const parent = (0, node_path.dirname)(directory);
27
+ if (parent === directory) return (0, node_path.dirname)(entry);
28
+ directory = parent;
29
+ }
30
+ return directory;
31
+ };
32
+ const sourceFiles = (map, entry) => {
33
+ const decoded = effect.Schema.decodeUnknownSync(SourceMap)(map);
34
+ const root = (0, node_fs.realpathSync)(projectRoot(entry));
35
+ const entryPath = (0, node_path.relative)(root, (0, node_fs.realpathSync)(entry)).split(node_path.sep).join("/");
36
+ const files = decoded.sources.flatMap((source, index) => {
37
+ const absolute = (0, node_path.resolve)((0, node_path.dirname)(entry), source);
38
+ const path = (0, node_path.relative)(root, absolute).split(node_path.sep).join("/");
39
+ const content = decoded.sourcesContent[index];
40
+ if (content == null || path.startsWith("../") || path.split("/").includes("node_modules") || absolute.startsWith(`${sdkRoot}${node_path.sep}`) || !CODE_FILE.test(path) || source.includes(":") || (0, node_path.basename)(path) === "anpord-eval-entry.ts") return [];
41
+ return [{
42
+ path,
43
+ content
44
+ }];
45
+ });
46
+ return effect.Schema.decodeUnknownSync(require_evals.EvalSourceFiles)(files.toSorted((a, b) => Number(b.path === entryPath) - Number(a.path === entryPath) || a.path.localeCompare(b.path)));
47
+ };
48
+ //#endregion
15
49
  //#region src/evals/eval-bundle.ts
16
50
  const authoringExports = ["export const defineEval = value => value;", `export { empty, files, repo } from "./source";`].join("\n");
17
51
  const authoringDir = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
18
52
  const ANPORD_MODULE = /^anpord$/;
19
53
  const ANY_MODULE = /.*/;
20
54
  const localModules = [
55
+ {
56
+ built: "validator-runtime.mjs",
57
+ filter: /^anpord\/validators\/runtime$/,
58
+ namespace: "anpord-validator-runtime",
59
+ source: "validator-runtime.ts"
60
+ },
21
61
  {
22
62
  built: "validators.mjs",
23
63
  filter: /^anpord\/validators$/,
@@ -91,6 +131,8 @@ const bundle = (contents, entry, options = {}) => effect.Effect.tryPromise({
91
131
  format: "esm",
92
132
  metafile: true,
93
133
  minify: options.minify,
134
+ outfile: (0, node_path.resolve)((0, node_path.dirname)(entry), "anpord-bundle.mjs"),
135
+ sourcemap: options.captureSource ? "external" : false,
94
136
  platform: "node",
95
137
  resolveExtensions: [
96
138
  ".ts",
@@ -110,7 +152,8 @@ const bundle = (contents, entry, options = {}) => effect.Effect.tryPromise({
110
152
  write: false
111
153
  }).then((result) => ({
112
154
  inputs: Object.keys(result.metafile?.inputs ?? {}).map((path) => (0, node_path.resolve)(path)),
113
- source: result.outputFiles[0]?.text ?? ""
155
+ source: result.outputFiles.find((file) => file.path.endsWith(".mjs"))?.text ?? "",
156
+ ...options.captureSource ? { sourceFiles: sourceFiles(result.outputFiles.find((file) => file.path.endsWith(".map"))?.text ?? "", entry) } : {}
114
157
  })),
115
158
  catch: (cause) => new Error(`Could not compile ${entry}`, { cause })
116
159
  });
@@ -159,65 +202,12 @@ const packageProgram = (root, entry, source) => {
159
202
  };
160
203
  //#endregion
161
204
  //#region src/evals/runner-source.ts
162
- const runtime = `
163
- import { access, readFile } from "node:fs/promises";
164
- import { spawn } from "node:child_process";
165
-
166
- const exec = (command) => new Promise((resolve, reject) => {
167
- const child = spawn("/bin/sh", ["-lc", command], { cwd: process.cwd() });
168
- let stderr = "";
169
- let stdout = "";
170
- child.stderr.on("data", chunk => { stderr += chunk; });
171
- child.stdout.on("data", chunk => { stdout += chunk; });
172
- child.on("error", reject);
173
- child.on("close", code => resolve({ exitCode: code ?? 1, stderr, stdout }));
174
- });
175
-
176
- const readOrEmpty = (path) =>
177
- path === undefined ? Promise.resolve("") : readFile(path, "utf8").then(text => text, () => "");
178
-
179
- const calls = async (path, key, value) => {
180
- const text = await readOrEmpty(path);
181
- const calls = text.trim() === "" ? [] : text.trim().split("\\n").map((line) => JSON.parse(line));
182
- return value === undefined ? calls : calls.filter((call) => call[key] === value);
183
- };
184
-
185
- const context = {
186
- answer: () => readOrEmpty(process.env.ANPORD_ANSWER_FILE),
187
- cli: { calls: cli => calls(".anpord/cli-calls.jsonl", "cli", cli) },
188
- exec,
189
- exists: path => access(path).then(() => true, () => false),
190
- mcp: { calls: server => calls(".anpord/mcp-calls.jsonl", "server", server) },
191
- readText: path => readFile(path, "utf8"),
192
- prepared: JSON.parse(process.env.ANPORD_PREPARE_VALUE ?? "{}"),
193
- transcript: () => readOrEmpty(process.env.ANPORD_TRANSCRIPT_FILE),
194
- };
195
-
196
- try {
197
- const raw = await validate(context);
198
- const result = typeof raw === "boolean" ? { passed: raw } : raw;
199
- if (typeof result?.passed !== "boolean") throw new Error("A validator must return a boolean or { passed, message? }");
200
- console.log("ANPORD_VALIDATOR_RESULT=" + JSON.stringify(result));
201
- } catch (error) {
202
- console.error(error instanceof Error ? error.stack : String(error));
203
- process.exitCode = 1;
204
- }
205
- `;
206
- const validatorCaseEntry = (entry, index) => `import definition from ${JSON.stringify(entry)};
205
+ const validatorCaseEntry = (entry, index, names = []) => `import definition from ${JSON.stringify(entry)};
206
+ import { runValidators } from "anpord/validators/runtime";
207
207
  const selected = definition.cases[${index}].validate;
208
- const checks = (Array.isArray(selected) ? selected : [selected]).filter(value => typeof value === "function");
209
- const validate = async context => {
210
- const messages = [];
211
- for (const check of checks) {
212
- const raw = await check(context);
213
- const result = typeof raw === "boolean" ? { passed: raw } : raw;
214
- if (typeof result?.passed !== "boolean") throw new Error("Invalid validator result");
215
- if (result.message) messages.push(result.message);
216
- if (!result.passed) return { passed: false, message: messages.join("; ") };
217
- }
218
- return { passed: true, message: messages.join("; ") || "Code validators passed" };
219
- };
220
- ${runtime}`;
208
+ const names = ${JSON.stringify(names)};
209
+ const checks = (Array.isArray(selected) ? selected : [selected]).flatMap((validate, index) => typeof validate === "function" ? [{ index, name: names.find(check => check.index === index)?.name ?? "Validator " + (index + 1), validate }] : []);
210
+ await runValidators(checks, definition.captureValidation !== false);`;
221
211
  const prepareRuntime = `
222
212
  import { access, readFile } from "node:fs/promises";
223
213
  import { spawn } from "node:child_process";
@@ -268,11 +258,12 @@ import { runMcpServer } from "anpord/mcp/runtime";
268
258
  const server = definition.mcp?.[${index}];
269
259
  if (server === undefined) throw new Error("MCP server ${index} is missing");
270
260
  runMcpServer(server);`;
271
- const cliEntry = (entry, index) => `import definition from ${JSON.stringify(entry)};
261
+ const cliEntry = (entry, index) => `import { fileURLToPath } from "node:url";
262
+ import definition from ${JSON.stringify(entry)};
272
263
  import { runCli } from "anpord/cli/runtime";
273
264
  const cli = definition.cli?.[${index}];
274
265
  if (cli === undefined) throw new Error("CLI ${index} is missing");
275
- await runCli(cli);`;
266
+ await runCli(cli, fileURLToPath(new URL("../../cli-calls.jsonl", import.meta.url)));`;
276
267
  //#endregion
277
268
  //#region src/evals/cli-profile.ts
278
269
  const compileClis = (entry, definitions) => effect.Effect.gen(function* () {
@@ -309,22 +300,37 @@ const withClis = (task, clis) => {
309
300
  };
310
301
  //#endregion
311
302
  //#region src/evals/compile-validator.ts
312
- const compileValidator = (entry, subject, caseIndex) => effect.Effect.gen(function* () {
303
+ const compileValidator = (entry, subject, caseIndex, captureSource, captureValidation = true) => effect.Effect.gen(function* () {
313
304
  if (subject.validate === void 0) return null;
314
305
  const validations = Array.isArray(subject.validate) ? subject.validate : [subject.validate];
315
306
  if (validations.length === 0 || validations.length > 20) return yield* effect.Effect.fail(/* @__PURE__ */ new Error("Use between 1 and 20 validators"));
316
307
  const judges = yield* effect.Effect.forEach(validations.filter((value) => typeof value !== "function"), (value) => effect.Schema.decodeUnknown(require_eval_judges.EvalJudge)(value, { onExcessProperty: "error" }));
317
308
  if (new Set(judges.map(({ name }) => name)).size !== judges.length) return yield* effect.Effect.fail(/* @__PURE__ */ new Error("Judge names must be unique within a case"));
318
- const checks = validations.some((value) => typeof value === "function") ? [{
309
+ const manifest = validations.flatMap((value, index) => typeof value === "function" ? [{
310
+ index,
311
+ name: value.name || `Validator ${index + 1}`
312
+ }] : []);
313
+ const hasCode = manifest.length > 0;
314
+ const compiled = yield* bundle(hasCode ? validatorCaseEntry(entry, caseIndex, manifest) : definitionEntry(entry), entry, {
315
+ minify: true,
316
+ captureSource
317
+ });
318
+ const checks = hasCode ? [{
319
319
  name: typeof subject.validate === "function" ? subject.validate.name || subject.name : subject.name,
320
- source: (yield* bundle(validatorCaseEntry(entry, caseIndex), entry, { minify: true })).source
320
+ source: compiled.source,
321
+ manifest,
322
+ capture: captureValidation
321
323
  }] : [];
322
- return yield* effect.Schema.decodeUnknown(require_evals.EvalValidator)(judges.length > 0 ? {
323
- kind: "judged",
324
- name: subject.name,
325
- checks,
326
- judges
327
- } : checks[0]);
324
+ return yield* effect.Schema.decodeUnknown(require_evals.EvalValidator)({
325
+ ...judges.length > 0 ? {
326
+ kind: "judged",
327
+ name: subject.name,
328
+ checks,
329
+ judges
330
+ } : checks[0],
331
+ sourceFiles: compiled.sourceFiles,
332
+ capture: captureValidation
333
+ });
328
334
  });
329
335
  //#endregion
330
336
  //#region src/evals/definition-loader.ts
@@ -355,26 +361,25 @@ const isDefinition = (value) => effect.Option.isSome(decodeShape(value));
355
361
  //#region src/evals/local-repo.ts
356
362
  const run = (0, node_util.promisify)(node_child_process.execFile);
357
363
  const git = (args, cwd) => effect.Effect.tryPromise(() => run("git", [...args], { cwd })).pipe(effect.Effect.map(({ stdout }) => stdout.trim()), effect.Effect.orElseSucceed(() => ""));
358
- const environment = () => globalThis.process?.env ?? {};
359
364
  const remoteUrl = (cwd) => effect.Effect.gen(function* () {
360
- const { GITHUB_REPOSITORY } = environment();
365
+ const repository = yield* effect.Config.string("GITHUB_REPOSITORY").pipe(effect.Config.withDefault(""));
361
366
  const origin = yield* git([
362
367
  "remote",
363
368
  "get-url",
364
369
  "origin"
365
370
  ], cwd);
366
- return origin === "" && GITHUB_REPOSITORY !== void 0 ? GITHUB_REPOSITORY : origin;
371
+ return origin === "" ? repository : origin;
367
372
  });
368
373
  const fetchableRef = (cwd) => effect.Effect.gen(function* () {
369
- const { GITHUB_HEAD_REF } = environment();
370
- if (GITHUB_HEAD_REF !== void 0 && GITHUB_HEAD_REF !== "") return GITHUB_HEAD_REF;
374
+ const ci = yield* effect.Config.boolean("GITHUB_ACTIONS").pipe(effect.Config.withDefault(false));
371
375
  const [head, onRemote] = yield* effect.Effect.all([git(["rev-parse", "HEAD"], cwd), git([
372
376
  "branch",
373
377
  "--remotes",
374
378
  "--contains",
375
379
  "HEAD"
376
380
  ], cwd)], { concurrency: 2 });
377
- return head === "" || onRemote === "" ? null : head;
381
+ if (ci && head === "") return yield* effect.Effect.fail(/* @__PURE__ */ new Error("Check out the commit before running evals in GitHub Actions."));
382
+ return head === "" || !ci && onRemote === "" ? null : head;
378
383
  });
379
384
  const localRepo = (cwd) => effect.Effect.gen(function* () {
380
385
  const [remote, ref] = yield* effect.Effect.all([remoteUrl(cwd), fetchableRef(cwd)], { concurrency: 2 });
@@ -698,7 +703,7 @@ const profileTask = (entry, task) => effect.Effect.gen(function* () {
698
703
  harness: task.harness.base,
699
704
  model: task.model,
700
705
  profile,
701
- provider: task.provider
706
+ sandbox: task.sandbox
702
707
  };
703
708
  }).pipe(effect.Effect.withSpan("Eval.profileTask", { attributes: { profile: task.harness.profile.name } }));
704
709
  //#endregion
@@ -707,7 +712,7 @@ const taskOf = (entry, task, clis, mcp) => effect.Effect.gen(function* () {
707
712
  const compiled = typeof task.harness === "string" ? {
708
713
  harness: task.harness,
709
714
  model: task.model,
710
- provider: task.provider
715
+ sandbox: task.sandbox
711
716
  } : yield* profileTask(entry, {
712
717
  ...task,
713
718
  harness: task.harness
@@ -732,7 +737,7 @@ const compileEvalEffect = (path) => effect.Effect.gen(function* () {
732
737
  const fallback = definition.source === void 0 && definition.cases.some((subject) => subject.source === void 0) ? yield* localRepo((0, node_path.dirname)(entry)) : effect.Option.none();
733
738
  const cases = yield* effect.Effect.forEach(definition.cases, (subject, caseIndex) => effect.Effect.gen(function* () {
734
739
  if (subject.validate !== void 0 === (typeof subject.verify === "string")) return yield* effect.Effect.fail(/* @__PURE__ */ new Error(`${subject.name} must have exactly one of validate or verify`));
735
- const validator = yield* compileValidator(entry, subject, caseIndex);
740
+ const validator = yield* compileValidator(entry, subject, caseIndex, definition.captureSource !== false, definition.captureValidation !== false);
736
741
  const prepare = typeof subject.prepare === "function" ? yield* bundledCaseModule(entry, loaded.inputs, subject.prepare.name || `${subject.name}-prepare`, prepareEntry) : null;
737
742
  return {
738
743
  ...subject.cache === void 0 ? {} : { cache: subject.cache },
package/dist/config.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_client = require("./client-BnimnYiJ.cjs");
2
+ const require_client = require("./client-C-P2I00z.cjs");
3
3
  let effect = require("effect");
4
4
  //#region src/client/config.ts
5
5
  const apiKeyConfig = effect.Config.redacted("ANPORD_API_KEY");
package/dist/config.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as AnpordApi } from "./client-CFTj9ad0.cjs";
1
+ import { t as AnpordApi } from "./client-BirFO3jz.cjs";
2
2
  import { Config, Layer } from "effect";
3
3
  //#region src/client/config.d.ts
4
4
  declare const apiKeyConfig: Config.Config<import("effect/Redacted").Redacted<string>>;
package/dist/config.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as AnpordApi } from "./client-Byoa41pX.mjs";
1
+ import { t as AnpordApi } from "./client-BgRs8JvW.mjs";
2
2
  import { Config, Layer } from "effect";
3
3
  //#region src/client/config.d.ts
4
4
  declare const apiKeyConfig: Config.Config<import("effect/Redacted").Redacted<string>>;
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as DEFAULT_BASE_URL, r as layer } from "./client-D22IiHGL.mjs";
1
+ import { n as DEFAULT_BASE_URL, r as layer } from "./client-BfdjFtlV.mjs";
2
2
  import { Config, Effect, Layer } from "effect";
3
3
  //#region src/client/config.ts
4
4
  const apiKeyConfig = Config.redacted("ANPORD_API_KEY");