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.
- package/dist/bin.cjs +208 -125
- package/dist/bin.mjs +208 -125
- package/dist/cli-runtime.cjs +2 -2
- package/dist/cli-runtime.d.cts +1 -1
- package/dist/cli-runtime.d.mts +1 -1
- package/dist/cli-runtime.mjs +2 -2
- package/dist/{client-D22IiHGL.mjs → client-BfdjFtlV.mjs} +7 -6
- package/dist/{client-Byoa41pX.d.mts → client-BgRs8JvW.d.mts} +1891 -227
- package/dist/{client-CFTj9ad0.d.cts → client-BirFO3jz.d.cts} +1891 -227
- package/dist/{client-BnimnYiJ.cjs → client-C-P2I00z.cjs} +7 -6
- package/dist/{compiler-CBMPXIzV.mjs → compiler-D96wI7UP.mjs} +87 -82
- package/dist/{compiler-BFxukiJy.cjs → compiler-uwb1pkdK.cjs} +85 -80
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/eval-validations-BRdoZrTQ.mjs +113 -0
- package/dist/eval-validations-_MlnQ_uv.cjs +148 -0
- package/dist/eval.cjs +1 -1
- package/dist/eval.d.cts +33 -13
- package/dist/eval.d.mts +33 -13
- package/dist/eval.mjs +1 -1
- package/dist/evals-B6aT3xgH.d.cts +1364 -0
- package/dist/evals-B6aT3xgH.d.mts +1364 -0
- package/dist/{evals-CvOTyvCX.mjs → evals-Dcc_x6jW.mjs} +54 -11
- package/dist/{evals-B04M0apj.cjs → evals-DouMsrsM.cjs} +71 -16
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +128 -4
- package/dist/index.d.mts +128 -4
- package/dist/index.mjs +1 -1
- package/dist/source.d.cts +1 -1
- package/dist/source.d.mts +1 -1
- package/dist/{types-oXWOHA-X.d.mts → types-Codjaq-o.d.mts} +65 -19
- package/dist/{types-nr4-1c3W.d.cts → types-ISsteq95.d.cts} +65 -19
- package/dist/validator-runtime.cjs +238 -0
- package/dist/validator-runtime.d.cts +9 -0
- package/dist/validator-runtime.d.mts +9 -0
- package/dist/validator-runtime.mjs +237 -0
- package/package.json +1 -1
- package/dist/evals-BUBzpke_.d.cts +0 -647
- package/dist/evals-BUBzpke_.d.mts +0 -647
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_evals = require("./evals-
|
|
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
|
|
139
|
-
description: "
|
|
140
|
-
identifier: "
|
|
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
|
-
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
163
|
-
import {
|
|
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
|
|
209
|
-
const
|
|
210
|
-
|
|
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
|
|
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
|
|
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:
|
|
320
|
+
source: compiled.source,
|
|
321
|
+
manifest,
|
|
322
|
+
capture: captureValidation
|
|
321
323
|
}] : [];
|
|
322
|
-
return yield* Schema.decodeUnknown(EvalValidator)(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
|
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 === ""
|
|
371
|
+
return origin === "" ? repository : origin;
|
|
367
372
|
});
|
|
368
373
|
const fetchableRef = (cwd) => Effect.gen(function* () {
|
|
369
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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
|
|
163
|
-
import {
|
|
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
|
|
209
|
-
const
|
|
210
|
-
|
|
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
|
|
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
|
|
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:
|
|
320
|
+
source: compiled.source,
|
|
321
|
+
manifest,
|
|
322
|
+
capture: captureValidation
|
|
321
323
|
}] : [];
|
|
322
|
-
return yield* effect.Schema.decodeUnknown(require_evals.EvalValidator)(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
|
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 === ""
|
|
371
|
+
return origin === "" ? repository : origin;
|
|
367
372
|
});
|
|
368
373
|
const fetchableRef = (cwd) => effect.Effect.gen(function* () {
|
|
369
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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");
|