anpord 0.1.11 → 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/README.md +56 -78
- package/dist/bin.cjs +211 -204
- package/dist/bin.mjs +211 -204
- 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-BfdjFtlV.mjs +305 -0
- package/dist/{client-C9m0uLCz.d.cts → client-BgRs8JvW.d.mts} +2150 -174
- package/dist/{client-TFCLuMv8.d.mts → client-BirFO3jz.d.cts} +2150 -174
- package/dist/client-C-P2I00z.cjs +346 -0
- package/dist/{compiler-DXlpU_In.mjs → compiler-D96wI7UP.mjs} +108 -75
- package/dist/{compiler-Ap8DM-JU.cjs → compiler-uwb1pkdK.cjs} +116 -83
- 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/{errors-C9bQUcA3.mjs → errors-B0YknR5V.mjs} +3 -19
- package/dist/{errors-Boum34f5.cjs → errors-BX1wry8K.cjs} +3 -19
- package/dist/{errors-BK3f7Rdr.d.cts → errors-aGrd21jy.d.cts} +0 -3
- package/dist/{errors-BK3f7Rdr.d.mts → errors-aGrd21jy.d.mts} +0 -3
- package/dist/eval-judges-BkmiVLLq.cjs +59 -0
- package/dist/eval-judges-CwTvTq7N.mjs +42 -0
- package/dist/eval-judges-DPPUftbh.d.cts +48 -0
- package/dist/eval-judges-DPPUftbh.d.mts +48 -0
- 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 +60 -6
- package/dist/eval.d.mts +60 -6
- 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-Dcc_x6jW.mjs +582 -0
- package/dist/evals-DouMsrsM.cjs +737 -0
- package/dist/index.cjs +23 -99
- package/dist/index.d.cts +138 -34
- package/dist/index.d.mts +138 -34
- package/dist/index.mjs +23 -99
- package/dist/source.d.cts +1 -1
- package/dist/source.d.mts +1 -1
- package/dist/{types-oaMF6-E1.d.mts → types-Codjaq-o.d.mts} +146 -45
- package/dist/{types-H9L450Iu.d.cts → types-ISsteq95.d.cts} +146 -45
- 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/dist/validators.cjs +10 -0
- package/dist/validators.d.cts +8 -0
- package/dist/validators.d.mts +8 -0
- package/dist/validators.mjs +9 -0
- package/package.json +11 -1
- package/dist/client-5K3dMI5Q.mjs +0 -849
- package/dist/client-Ci0woWLW.cjs +0 -890
- package/dist/evals-BEgEmfiO.d.cts +0 -603
- package/dist/evals-BEgEmfiO.d.mts +0 -603
- package/dist/harness-profile-BMjsN460.mjs +0 -43
- package/dist/harness-profile-CDQpPLPd.cjs +0 -78
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_evals = require("./evals-DouMsrsM.cjs");
|
|
2
|
+
const require_eval_judges = require("./eval-judges-BkmiVLLq.cjs");
|
|
2
3
|
const require_source = require("./source-DvlGawEw.cjs");
|
|
3
4
|
let effect = require("effect");
|
|
4
5
|
let node_path = require("node:path");
|
|
@@ -11,12 +12,58 @@ let node_os = require("node:os");
|
|
|
11
12
|
let node_child_process = require("node:child_process");
|
|
12
13
|
let node_util = require("node:util");
|
|
13
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
|
|
14
49
|
//#region src/evals/eval-bundle.ts
|
|
15
50
|
const authoringExports = ["export const defineEval = value => value;", `export { empty, files, repo } from "./source";`].join("\n");
|
|
16
51
|
const authoringDir = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
17
52
|
const ANPORD_MODULE = /^anpord$/;
|
|
18
53
|
const ANY_MODULE = /.*/;
|
|
19
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
|
+
},
|
|
61
|
+
{
|
|
62
|
+
built: "validators.mjs",
|
|
63
|
+
filter: /^anpord\/validators$/,
|
|
64
|
+
namespace: "anpord-validators",
|
|
65
|
+
source: "../validators.ts"
|
|
66
|
+
},
|
|
20
67
|
{
|
|
21
68
|
built: "cli.mjs",
|
|
22
69
|
filter: /^anpord\/cli$/,
|
|
@@ -84,6 +131,8 @@ const bundle = (contents, entry, options = {}) => effect.Effect.tryPromise({
|
|
|
84
131
|
format: "esm",
|
|
85
132
|
metafile: true,
|
|
86
133
|
minify: options.minify,
|
|
134
|
+
outfile: (0, node_path.resolve)((0, node_path.dirname)(entry), "anpord-bundle.mjs"),
|
|
135
|
+
sourcemap: options.captureSource ? "external" : false,
|
|
87
136
|
platform: "node",
|
|
88
137
|
resolveExtensions: [
|
|
89
138
|
".ts",
|
|
@@ -103,7 +152,8 @@ const bundle = (contents, entry, options = {}) => effect.Effect.tryPromise({
|
|
|
103
152
|
write: false
|
|
104
153
|
}).then((result) => ({
|
|
105
154
|
inputs: Object.keys(result.metafile?.inputs ?? {}).map((path) => (0, node_path.resolve)(path)),
|
|
106
|
-
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) } : {}
|
|
107
157
|
})),
|
|
108
158
|
catch: (cause) => new Error(`Could not compile ${entry}`, { cause })
|
|
109
159
|
});
|
|
@@ -152,51 +202,12 @@ const packageProgram = (root, entry, source) => {
|
|
|
152
202
|
};
|
|
153
203
|
//#endregion
|
|
154
204
|
//#region src/evals/runner-source.ts
|
|
155
|
-
const
|
|
156
|
-
import {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
let stderr = "";
|
|
162
|
-
let stdout = "";
|
|
163
|
-
child.stderr.on("data", chunk => { stderr += chunk; });
|
|
164
|
-
child.stdout.on("data", chunk => { stdout += chunk; });
|
|
165
|
-
child.on("error", reject);
|
|
166
|
-
child.on("close", code => resolve({ exitCode: code ?? 1, stderr, stdout }));
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const readOrEmpty = (path) =>
|
|
170
|
-
path === undefined ? Promise.resolve("") : readFile(path, "utf8").then(text => text, () => "");
|
|
171
|
-
|
|
172
|
-
const calls = async (path, key, value) => {
|
|
173
|
-
const text = await readOrEmpty(path);
|
|
174
|
-
const calls = text.trim() === "" ? [] : text.trim().split("\\n").map((line) => JSON.parse(line));
|
|
175
|
-
return value === undefined ? calls : calls.filter((call) => call[key] === value);
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const context = {
|
|
179
|
-
answer: () => readOrEmpty(process.env.ANPORD_ANSWER_FILE),
|
|
180
|
-
cli: { calls: cli => calls(".anpord/cli-calls.jsonl", "cli", cli) },
|
|
181
|
-
exec,
|
|
182
|
-
exists: path => access(path).then(() => true, () => false),
|
|
183
|
-
mcp: { calls: server => calls(".anpord/mcp-calls.jsonl", "server", server) },
|
|
184
|
-
readText: path => readFile(path, "utf8"),
|
|
185
|
-
prepared: JSON.parse(process.env.ANPORD_PREPARE_VALUE ?? "{}"),
|
|
186
|
-
transcript: () => readOrEmpty(process.env.ANPORD_TRANSCRIPT_FILE),
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
const raw = await validate(context);
|
|
191
|
-
const result = typeof raw === "boolean" ? { passed: raw } : raw;
|
|
192
|
-
if (typeof result?.passed !== "boolean") throw new Error("A validator must return a boolean or { passed, message? }");
|
|
193
|
-
console.log("ANPORD_VALIDATOR_RESULT=" + JSON.stringify(result));
|
|
194
|
-
} catch (error) {
|
|
195
|
-
console.error(error instanceof Error ? error.stack : String(error));
|
|
196
|
-
process.exitCode = 1;
|
|
197
|
-
}
|
|
198
|
-
`;
|
|
199
|
-
const validatorEntry = (module, name) => `import { ${name} as validate } from ${JSON.stringify(module)};\n${runtime}`;
|
|
205
|
+
const validatorCaseEntry = (entry, index, names = []) => `import definition from ${JSON.stringify(entry)};
|
|
206
|
+
import { runValidators } from "anpord/validators/runtime";
|
|
207
|
+
const selected = definition.cases[${index}].validate;
|
|
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);`;
|
|
200
211
|
const prepareRuntime = `
|
|
201
212
|
import { access, readFile } from "node:fs/promises";
|
|
202
213
|
import { spawn } from "node:child_process";
|
|
@@ -247,11 +258,12 @@ import { runMcpServer } from "anpord/mcp/runtime";
|
|
|
247
258
|
const server = definition.mcp?.[${index}];
|
|
248
259
|
if (server === undefined) throw new Error("MCP server ${index} is missing");
|
|
249
260
|
runMcpServer(server);`;
|
|
250
|
-
const cliEntry = (entry, index) => `import
|
|
261
|
+
const cliEntry = (entry, index) => `import { fileURLToPath } from "node:url";
|
|
262
|
+
import definition from ${JSON.stringify(entry)};
|
|
251
263
|
import { runCli } from "anpord/cli/runtime";
|
|
252
264
|
const cli = definition.cli?.[${index}];
|
|
253
265
|
if (cli === undefined) throw new Error("CLI ${index} is missing");
|
|
254
|
-
await runCli(cli);`;
|
|
266
|
+
await runCli(cli, fileURLToPath(new URL("../../cli-calls.jsonl", import.meta.url)));`;
|
|
255
267
|
//#endregion
|
|
256
268
|
//#region src/evals/cli-profile.ts
|
|
257
269
|
const compileClis = (entry, definitions) => effect.Effect.gen(function* () {
|
|
@@ -287,6 +299,40 @@ const withClis = (task, clis) => {
|
|
|
287
299
|
};
|
|
288
300
|
};
|
|
289
301
|
//#endregion
|
|
302
|
+
//#region src/evals/compile-validator.ts
|
|
303
|
+
const compileValidator = (entry, subject, caseIndex, captureSource, captureValidation = true) => effect.Effect.gen(function* () {
|
|
304
|
+
if (subject.validate === void 0) return null;
|
|
305
|
+
const validations = Array.isArray(subject.validate) ? subject.validate : [subject.validate];
|
|
306
|
+
if (validations.length === 0 || validations.length > 20) return yield* effect.Effect.fail(/* @__PURE__ */ new Error("Use between 1 and 20 validators"));
|
|
307
|
+
const judges = yield* effect.Effect.forEach(validations.filter((value) => typeof value !== "function"), (value) => effect.Schema.decodeUnknown(require_eval_judges.EvalJudge)(value, { onExcessProperty: "error" }));
|
|
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"));
|
|
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
|
+
name: typeof subject.validate === "function" ? subject.validate.name || subject.name : subject.name,
|
|
320
|
+
source: compiled.source,
|
|
321
|
+
manifest,
|
|
322
|
+
capture: captureValidation
|
|
323
|
+
}] : [];
|
|
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
|
+
});
|
|
334
|
+
});
|
|
335
|
+
//#endregion
|
|
290
336
|
//#region src/evals/definition-loader.ts
|
|
291
337
|
const loadDefinition = (entry) => bundle(definitionEntry(entry), entry).pipe(effect.Effect.flatMap(({ inputs, source }) => effect.Effect.acquireUseRelease(effect.Effect.tryPromise(() => (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "anpord-eval-"))), (directory) => effect.Effect.tryPromise({
|
|
292
338
|
try: async () => {
|
|
@@ -315,26 +361,25 @@ const isDefinition = (value) => effect.Option.isSome(decodeShape(value));
|
|
|
315
361
|
//#region src/evals/local-repo.ts
|
|
316
362
|
const run = (0, node_util.promisify)(node_child_process.execFile);
|
|
317
363
|
const git = (args, cwd) => effect.Effect.tryPromise(() => run("git", [...args], { cwd })).pipe(effect.Effect.map(({ stdout }) => stdout.trim()), effect.Effect.orElseSucceed(() => ""));
|
|
318
|
-
const environment = () => globalThis.process?.env ?? {};
|
|
319
364
|
const remoteUrl = (cwd) => effect.Effect.gen(function* () {
|
|
320
|
-
const
|
|
365
|
+
const repository = yield* effect.Config.string("GITHUB_REPOSITORY").pipe(effect.Config.withDefault(""));
|
|
321
366
|
const origin = yield* git([
|
|
322
367
|
"remote",
|
|
323
368
|
"get-url",
|
|
324
369
|
"origin"
|
|
325
370
|
], cwd);
|
|
326
|
-
return origin === ""
|
|
371
|
+
return origin === "" ? repository : origin;
|
|
327
372
|
});
|
|
328
373
|
const fetchableRef = (cwd) => effect.Effect.gen(function* () {
|
|
329
|
-
const
|
|
330
|
-
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));
|
|
331
375
|
const [head, onRemote] = yield* effect.Effect.all([git(["rev-parse", "HEAD"], cwd), git([
|
|
332
376
|
"branch",
|
|
333
377
|
"--remotes",
|
|
334
378
|
"--contains",
|
|
335
379
|
"HEAD"
|
|
336
380
|
], cwd)], { concurrency: 2 });
|
|
337
|
-
|
|
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;
|
|
338
383
|
});
|
|
339
384
|
const localRepo = (cwd) => effect.Effect.gen(function* () {
|
|
340
385
|
const [remote, ref] = yield* effect.Effect.all([remoteUrl(cwd), fetchableRef(cwd)], { concurrency: 2 });
|
|
@@ -442,7 +487,7 @@ const adapters = {
|
|
|
442
487
|
const applyMcpHarness = (harness, profile, servers) => {
|
|
443
488
|
const adapter = adapters[harness];
|
|
444
489
|
if (adapter === null) throw new Error(`MCP mock servers are not supported by ${harness}`);
|
|
445
|
-
return effect.Schema.decodeUnknownSync(
|
|
490
|
+
return effect.Schema.decodeUnknownSync(require_evals.HarnessProfile)(adapter.apply(profile, servers));
|
|
446
491
|
};
|
|
447
492
|
//#endregion
|
|
448
493
|
//#region src/evals/mcp-profile.ts
|
|
@@ -488,17 +533,17 @@ var ProfilePathInvalid = class extends effect.Data.TaggedError("ProfilePathInval
|
|
|
488
533
|
};
|
|
489
534
|
var ProfileFileTooLarge = class extends effect.Data.TaggedError("ProfileFileTooLarge") {
|
|
490
535
|
get message() {
|
|
491
|
-
return `${this.path} is ${this.chars} characters; a profile file holds at most ${
|
|
536
|
+
return `${this.path} is ${this.chars} characters; a profile file holds at most ${require_evals.PROFILE_LIMITS.fileChars}`;
|
|
492
537
|
}
|
|
493
538
|
};
|
|
494
539
|
var ProfileTooLarge = class extends effect.Data.TaggedError("ProfileTooLarge") {
|
|
495
540
|
get message() {
|
|
496
|
-
return `The profile's files hold ${this.chars} characters; at most ${
|
|
541
|
+
return `The profile's files hold ${this.chars} characters; at most ${require_evals.PROFILE_LIMITS.totalChars} fit`;
|
|
497
542
|
}
|
|
498
543
|
};
|
|
499
544
|
var ProfileTooManyFiles = class extends effect.Data.TaggedError("ProfileTooManyFiles") {
|
|
500
545
|
get message() {
|
|
501
|
-
return `The profile has ${this.count} files; at most ${
|
|
546
|
+
return `The profile has ${this.count} files; at most ${require_evals.PROFILE_LIMITS.files} fit`;
|
|
502
547
|
}
|
|
503
548
|
};
|
|
504
549
|
var ProfileManifestInvalid = class extends effect.Data.TaggedError("ProfileManifestInvalid") {
|
|
@@ -525,7 +570,7 @@ var ProfileStepNotSupported = class extends effect.Data.TaggedError("ProfileStep
|
|
|
525
570
|
//#region src/evals/profile-manifest.ts
|
|
526
571
|
const Manifest = effect.Schema.Struct({
|
|
527
572
|
env: effect.Schema.optional(effect.Schema.Record({
|
|
528
|
-
key:
|
|
573
|
+
key: require_evals.EnvName,
|
|
529
574
|
value: effect.Schema.String
|
|
530
575
|
})),
|
|
531
576
|
install: effect.Schema.optional(effect.Schema.String),
|
|
@@ -542,14 +587,6 @@ const decodeManifest = (dir, text) => effect.Schema.decodeUnknown(ManifestJson)(
|
|
|
542
587
|
dir,
|
|
543
588
|
reason: issue.message
|
|
544
589
|
})));
|
|
545
|
-
/**
|
|
546
|
-
* A manifest value that names a regular file is replaced by that file's
|
|
547
|
-
* content; anything else is kept as written. Env values are always literal.
|
|
548
|
-
*
|
|
549
|
-
* A file outside the profile directory is refused rather than read: the
|
|
550
|
-
* manifest is shipped with the profile, and a prompt that only exists on one
|
|
551
|
-
* machine is not part of it.
|
|
552
|
-
*/
|
|
553
590
|
const inlined = (dir, value) => effect.Effect.gen(function* () {
|
|
554
591
|
const target = (0, node_path.resolve)(dir, value);
|
|
555
592
|
const position = (0, node_path.relative)(dir, target);
|
|
@@ -589,7 +626,6 @@ const readProfileManifest = (dir) => effect.Effect.gen(function* () {
|
|
|
589
626
|
const SHIPPED_ROOTS = ["home", "workspace"];
|
|
590
627
|
const SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
591
628
|
const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
592
|
-
/** Every regular file below `current`, as a posix path relative to `dir`. */
|
|
593
629
|
const walk = async (dir, current) => {
|
|
594
630
|
const entries = await (0, node_fs_promises.readdir)(current, { withFileTypes: true });
|
|
595
631
|
return (await Promise.all(entries.map((entry) => {
|
|
@@ -611,8 +647,8 @@ const shippedPaths = (dir) => effect.Effect.tryPromise({
|
|
|
611
647
|
return (await Promise.all(SHIPPED_ROOTS.map((root) => walkRoot(dir, root)))).flat().sort();
|
|
612
648
|
}
|
|
613
649
|
});
|
|
614
|
-
const validPath = (path) => effect.Schema.decodeUnknown(
|
|
615
|
-
/**
|
|
650
|
+
const validPath = (path) => effect.Schema.decodeUnknown(require_evals.ProfilePath)(path).pipe(effect.Effect.mapError(() => new ProfilePathInvalid({ path })));
|
|
651
|
+
/** Nothing when the file holds a NUL byte and so is not text. */
|
|
616
652
|
const readShipped = (dir, path) => effect.Effect.gen(function* () {
|
|
617
653
|
const bytes = yield* effect.Effect.tryPromise({
|
|
618
654
|
catch: (cause) => new ProfileDirectoryUnreadable({
|
|
@@ -623,7 +659,7 @@ const readShipped = (dir, path) => effect.Effect.gen(function* () {
|
|
|
623
659
|
});
|
|
624
660
|
if (bytes.includes(0)) return [];
|
|
625
661
|
const content = bytes.toString("utf8");
|
|
626
|
-
if (content.length >
|
|
662
|
+
if (content.length > require_evals.PROFILE_LIMITS.fileChars) return yield* new ProfileFileTooLarge({
|
|
627
663
|
chars: content.length,
|
|
628
664
|
path
|
|
629
665
|
});
|
|
@@ -631,14 +667,14 @@ const readShipped = (dir, path) => effect.Effect.gen(function* () {
|
|
|
631
667
|
});
|
|
632
668
|
const shippedFiles = (dir) => effect.Effect.gen(function* () {
|
|
633
669
|
const paths = yield* shippedPaths(dir);
|
|
634
|
-
if (paths.length >
|
|
670
|
+
if (paths.length > require_evals.PROFILE_LIMITS.files) return yield* new ProfileTooManyFiles({ count: paths.length });
|
|
635
671
|
const entries = yield* effect.Effect.forEach(paths, (path) => readShipped(dir, path), { concurrency: 8 }).pipe(effect.Effect.map((read) => read.flat()));
|
|
636
672
|
const chars = entries.reduce((sum, [, content]) => sum + content.length, 0);
|
|
637
|
-
if (chars >
|
|
673
|
+
if (chars > require_evals.PROFILE_LIMITS.totalChars) return yield* new ProfileTooLarge({ chars });
|
|
638
674
|
return Object.fromEntries(entries);
|
|
639
675
|
});
|
|
640
676
|
const fittingHarness = (base, profile) => {
|
|
641
|
-
if (
|
|
677
|
+
if (require_evals.profileFitsHarness({
|
|
642
678
|
harness: base,
|
|
643
679
|
profile
|
|
644
680
|
})) return effect.Effect.succeed(profile);
|
|
@@ -648,8 +684,6 @@ const fittingHarness = (base, profile) => {
|
|
|
648
684
|
step: "run"
|
|
649
685
|
});
|
|
650
686
|
};
|
|
651
|
-
/** The task a definition's `{ base, profile }` harness compiles to, with the
|
|
652
|
-
* profile directory read relative to the eval file. */
|
|
653
687
|
const profileTask = (entry, task) => effect.Effect.gen(function* () {
|
|
654
688
|
const dir = (0, node_path.resolve)((0, node_path.dirname)(entry), task.harness.profile.dir);
|
|
655
689
|
yield* effect.Effect.tryPromise({
|
|
@@ -669,7 +703,7 @@ const profileTask = (entry, task) => effect.Effect.gen(function* () {
|
|
|
669
703
|
harness: task.harness.base,
|
|
670
704
|
model: task.model,
|
|
671
705
|
profile,
|
|
672
|
-
|
|
706
|
+
sandbox: task.sandbox
|
|
673
707
|
};
|
|
674
708
|
}).pipe(effect.Effect.withSpan("Eval.profileTask", { attributes: { profile: task.harness.profile.name } }));
|
|
675
709
|
//#endregion
|
|
@@ -678,7 +712,7 @@ const taskOf = (entry, task, clis, mcp) => effect.Effect.gen(function* () {
|
|
|
678
712
|
const compiled = typeof task.harness === "string" ? {
|
|
679
713
|
harness: task.harness,
|
|
680
714
|
model: task.model,
|
|
681
|
-
|
|
715
|
+
sandbox: task.sandbox
|
|
682
716
|
} : yield* profileTask(entry, {
|
|
683
717
|
...task,
|
|
684
718
|
harness: task.harness
|
|
@@ -701,10 +735,9 @@ const compileEvalEffect = (path) => effect.Effect.gen(function* () {
|
|
|
701
735
|
const clis = yield* compileClis(entry, definition.cli ?? []);
|
|
702
736
|
const mcp = yield* compileMcpServers(entry, definition.mcp ?? []);
|
|
703
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();
|
|
704
|
-
const cases = yield* effect.Effect.forEach(definition.cases, (subject) => effect.Effect.gen(function* () {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
const validator = hasValidator ? yield* bundledCaseModule(entry, loaded.inputs, subject.validate?.name || subject.name, validatorEntry) : null;
|
|
738
|
+
const cases = yield* effect.Effect.forEach(definition.cases, (subject, caseIndex) => effect.Effect.gen(function* () {
|
|
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`));
|
|
740
|
+
const validator = yield* compileValidator(entry, subject, caseIndex, definition.captureSource !== false, definition.captureValidation !== false);
|
|
708
741
|
const prepare = typeof subject.prepare === "function" ? yield* bundledCaseModule(entry, loaded.inputs, subject.prepare.name || `${subject.name}-prepare`, prepareEntry) : null;
|
|
709
742
|
return {
|
|
710
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");
|
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
import { ArrayFormatter } from "effect/ParseResult";
|
|
2
2
|
//#region ../template/src/syntax.ts
|
|
3
|
-
/**
|
|
4
|
-
* What a variable looks like, defined once.
|
|
5
|
-
*
|
|
6
|
-
* The editor's atom node, the extractor and the renderer have to agree
|
|
7
|
-
* exactly: a name the editor draws as a chip but the renderer does not fill
|
|
8
|
-
* reaches the model as literal braces, and nobody notices until the output is
|
|
9
|
-
* wrong.
|
|
10
|
-
*/
|
|
11
3
|
const VARIABLE_PATTERN = String.raw`\{\{\s*([\w.-]+)\s*\}\}`;
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* They cannot be two passes: `{{{{name}}}}` contains `{{name}}` starting at
|
|
16
|
-
* its third brace, so a substitution pass run on its own would fill the very
|
|
17
|
-
* text the escape exists to protect. Reading both in one sweep is what keeps
|
|
18
|
-
* the extractor and the renderer agreeing on what counts as a variable.
|
|
19
|
-
*
|
|
20
|
-
* A fresh instance each call, because a global regular expression carries its
|
|
21
|
-
* own `lastIndex` and a shared one silently skips matches on a second pass.
|
|
22
|
-
*/
|
|
4
|
+
/** One sweep, escapes first: `{{{{name}}}}` contains `{{name}}` from its third
|
|
5
|
+
* brace, so a separate substitution pass would fill the escaped text. Fresh
|
|
6
|
+
* instance each call because a global regex carries its own `lastIndex`. */
|
|
23
7
|
const tokenMatcher = () => new RegExp(String.raw`(\{\{\{\{)|(\}\}\}\})|${VARIABLE_PATTERN}`, "g");
|
|
24
8
|
//#endregion
|
|
25
9
|
//#region src/client/errors.ts
|
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
let effect_ParseResult = require("effect/ParseResult");
|
|
2
2
|
//#region ../template/src/syntax.ts
|
|
3
|
-
/**
|
|
4
|
-
* What a variable looks like, defined once.
|
|
5
|
-
*
|
|
6
|
-
* The editor's atom node, the extractor and the renderer have to agree
|
|
7
|
-
* exactly: a name the editor draws as a chip but the renderer does not fill
|
|
8
|
-
* reaches the model as literal braces, and nobody notices until the output is
|
|
9
|
-
* wrong.
|
|
10
|
-
*/
|
|
11
3
|
const VARIABLE_PATTERN = String.raw`\{\{\s*([\w.-]+)\s*\}\}`;
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* They cannot be two passes: `{{{{name}}}}` contains `{{name}}` starting at
|
|
16
|
-
* its third brace, so a substitution pass run on its own would fill the very
|
|
17
|
-
* text the escape exists to protect. Reading both in one sweep is what keeps
|
|
18
|
-
* the extractor and the renderer agreeing on what counts as a variable.
|
|
19
|
-
*
|
|
20
|
-
* A fresh instance each call, because a global regular expression carries its
|
|
21
|
-
* own `lastIndex` and a shared one silently skips matches on a second pass.
|
|
22
|
-
*/
|
|
4
|
+
/** One sweep, escapes first: `{{{{name}}}}` contains `{{name}}` from its third
|
|
5
|
+
* brace, so a separate substitution pass would fill the escaped text. Fresh
|
|
6
|
+
* instance each call because a global regex carries its own `lastIndex`. */
|
|
23
7
|
const tokenMatcher = () => new RegExp(String.raw`(\{\{\{\{)|(\}\}\}\})|${VARIABLE_PATTERN}`, "g");
|
|
24
8
|
//#endregion
|
|
25
9
|
//#region src/client/errors.ts
|
|
@@ -29,9 +29,6 @@ declare const Forbidden_base: Schema.TaggedErrorClass<Forbidden, "Forbidden", {
|
|
|
29
29
|
} & {
|
|
30
30
|
message: typeof Schema.String;
|
|
31
31
|
}>;
|
|
32
|
-
/** Distinct from Unauthorized: the caller is who they say they are, and the
|
|
33
|
-
* answer is still no. Signing in again cannot help, so the client must not
|
|
34
|
-
* treat this as an expired session. */
|
|
35
32
|
declare class Forbidden extends Forbidden_base {}
|
|
36
33
|
//#endregion
|
|
37
34
|
export { Unauthorized as a, NotFound as i, Conflict as n, Forbidden as r, BadRequest as t };
|
|
@@ -29,9 +29,6 @@ declare const Forbidden_base: Schema.TaggedErrorClass<Forbidden, "Forbidden", {
|
|
|
29
29
|
} & {
|
|
30
30
|
message: typeof Schema.String;
|
|
31
31
|
}>;
|
|
32
|
-
/** Distinct from Unauthorized: the caller is who they say they are, and the
|
|
33
|
-
* answer is still no. Signing in again cannot help, so the client must not
|
|
34
|
-
* treat this as an expired session. */
|
|
35
32
|
declare class Forbidden extends Forbidden_base {}
|
|
36
33
|
//#endregion
|
|
37
34
|
export { Unauthorized as a, NotFound as i, Conflict as n, Forbidden as r, BadRequest as t };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
let effect = require("effect");
|
|
2
|
+
//#region ../schema/src/domain/harness.ts
|
|
3
|
+
const EvalHarness = effect.Schema.Literal("codex", "opencode", "pi", "fx", "claude", "gemini", "qwen", "cursor", "command");
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region ../schema/src/domain/eval-judges.ts
|
|
6
|
+
const text = effect.Schema.String.pipe(effect.Schema.minLength(1));
|
|
7
|
+
const EvalScore = effect.Schema.Number.pipe(effect.Schema.between(0, 1));
|
|
8
|
+
const fields = {
|
|
9
|
+
kind: effect.Schema.Literal("judge"),
|
|
10
|
+
name: text.pipe(effect.Schema.maxLength(100)),
|
|
11
|
+
model: text.pipe(effect.Schema.maxLength(200)),
|
|
12
|
+
rubric: text.pipe(effect.Schema.maxLength(32e3)),
|
|
13
|
+
expected: effect.Schema.optional(effect.Schema.String.pipe(effect.Schema.maxLength(32e3))),
|
|
14
|
+
choices: effect.Schema.Record({
|
|
15
|
+
key: text,
|
|
16
|
+
value: EvalScore
|
|
17
|
+
}).pipe(effect.Schema.filter((value) => Object.keys(value).length > 0 && Object.keys(value).length <= 20, { message: () => "A judge needs between 1 and 20 scored choices" })),
|
|
18
|
+
threshold: effect.Schema.optionalWith(EvalScore, { default: () => 1 }),
|
|
19
|
+
timeoutMs: effect.Schema.optionalWith(effect.Schema.Int.pipe(effect.Schema.between(1e3, 3e5)), { default: () => 12e4 })
|
|
20
|
+
};
|
|
21
|
+
const EvalJudge = effect.Schema.Union(effect.Schema.Struct({
|
|
22
|
+
...fields,
|
|
23
|
+
provider: effect.Schema.Literal("openai"),
|
|
24
|
+
harness: effect.Schema.optional(effect.Schema.Never)
|
|
25
|
+
}), effect.Schema.Struct({
|
|
26
|
+
...fields,
|
|
27
|
+
provider: effect.Schema.optional(effect.Schema.Never),
|
|
28
|
+
harness: effect.Schema.Literal(...EvalHarness.literals.filter((harness) => harness !== "command"))
|
|
29
|
+
}));
|
|
30
|
+
const EvalJudgment = effect.Schema.Struct({
|
|
31
|
+
name: effect.Schema.String,
|
|
32
|
+
model: effect.Schema.String,
|
|
33
|
+
evaluator: effect.Schema.String,
|
|
34
|
+
score: effect.Schema.NullOr(EvalScore),
|
|
35
|
+
choice: effect.Schema.NullOr(effect.Schema.String),
|
|
36
|
+
reason: effect.Schema.String,
|
|
37
|
+
threshold: EvalScore,
|
|
38
|
+
durationMs: effect.Schema.NonNegativeInt,
|
|
39
|
+
error: effect.Schema.NullOr(effect.Schema.String)
|
|
40
|
+
});
|
|
41
|
+
//#endregion
|
|
42
|
+
Object.defineProperty(exports, "EvalHarness", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function() {
|
|
45
|
+
return EvalHarness;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "EvalJudge", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function() {
|
|
51
|
+
return EvalJudge;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "EvalJudgment", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function() {
|
|
57
|
+
return EvalJudgment;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region ../schema/src/domain/harness.ts
|
|
3
|
+
const EvalHarness = Schema.Literal("codex", "opencode", "pi", "fx", "claude", "gemini", "qwen", "cursor", "command");
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region ../schema/src/domain/eval-judges.ts
|
|
6
|
+
const text = Schema.String.pipe(Schema.minLength(1));
|
|
7
|
+
const EvalScore = Schema.Number.pipe(Schema.between(0, 1));
|
|
8
|
+
const fields = {
|
|
9
|
+
kind: Schema.Literal("judge"),
|
|
10
|
+
name: text.pipe(Schema.maxLength(100)),
|
|
11
|
+
model: text.pipe(Schema.maxLength(200)),
|
|
12
|
+
rubric: text.pipe(Schema.maxLength(32e3)),
|
|
13
|
+
expected: Schema.optional(Schema.String.pipe(Schema.maxLength(32e3))),
|
|
14
|
+
choices: Schema.Record({
|
|
15
|
+
key: text,
|
|
16
|
+
value: EvalScore
|
|
17
|
+
}).pipe(Schema.filter((value) => Object.keys(value).length > 0 && Object.keys(value).length <= 20, { message: () => "A judge needs between 1 and 20 scored choices" })),
|
|
18
|
+
threshold: Schema.optionalWith(EvalScore, { default: () => 1 }),
|
|
19
|
+
timeoutMs: Schema.optionalWith(Schema.Int.pipe(Schema.between(1e3, 3e5)), { default: () => 12e4 })
|
|
20
|
+
};
|
|
21
|
+
const EvalJudge = Schema.Union(Schema.Struct({
|
|
22
|
+
...fields,
|
|
23
|
+
provider: Schema.Literal("openai"),
|
|
24
|
+
harness: Schema.optional(Schema.Never)
|
|
25
|
+
}), Schema.Struct({
|
|
26
|
+
...fields,
|
|
27
|
+
provider: Schema.optional(Schema.Never),
|
|
28
|
+
harness: Schema.Literal(...EvalHarness.literals.filter((harness) => harness !== "command"))
|
|
29
|
+
}));
|
|
30
|
+
const EvalJudgment = Schema.Struct({
|
|
31
|
+
name: Schema.String,
|
|
32
|
+
model: Schema.String,
|
|
33
|
+
evaluator: Schema.String,
|
|
34
|
+
score: Schema.NullOr(EvalScore),
|
|
35
|
+
choice: Schema.NullOr(Schema.String),
|
|
36
|
+
reason: Schema.String,
|
|
37
|
+
threshold: EvalScore,
|
|
38
|
+
durationMs: Schema.NonNegativeInt,
|
|
39
|
+
error: Schema.NullOr(Schema.String)
|
|
40
|
+
});
|
|
41
|
+
//#endregion
|
|
42
|
+
export { EvalJudgment as n, EvalHarness as r, EvalJudge as t };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region ../schema/src/domain/eval-judges.d.ts
|
|
3
|
+
declare const EvalJudge: Schema.Union<[Schema.Struct<{
|
|
4
|
+
provider: Schema.Literal<["openai"]>;
|
|
5
|
+
harness: Schema.optional<typeof Schema.Never>;
|
|
6
|
+
kind: Schema.Literal<["judge"]>;
|
|
7
|
+
name: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
8
|
+
model: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
9
|
+
rubric: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
10
|
+
expected: Schema.optional<Schema.filter<typeof Schema.String>>;
|
|
11
|
+
choices: Schema.filter<Schema.Record$<Schema.filter<typeof Schema.String>, Schema.filter<typeof Schema.Number>>>;
|
|
12
|
+
threshold: Schema.optionalWith<Schema.filter<typeof Schema.Number>, {
|
|
13
|
+
default: () => number;
|
|
14
|
+
}>;
|
|
15
|
+
timeoutMs: Schema.optionalWith<Schema.filter<typeof Schema.Int>, {
|
|
16
|
+
default: () => number;
|
|
17
|
+
}>;
|
|
18
|
+
}>, Schema.Struct<{
|
|
19
|
+
provider: Schema.optional<typeof Schema.Never>;
|
|
20
|
+
harness: Schema.SchemaClass<"codex" | "opencode" | "pi" | "fx" | "claude" | "gemini" | "qwen" | "cursor", "codex" | "opencode" | "pi" | "fx" | "claude" | "gemini" | "qwen" | "cursor", never>;
|
|
21
|
+
kind: Schema.Literal<["judge"]>;
|
|
22
|
+
name: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
23
|
+
model: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
24
|
+
rubric: Schema.filter<Schema.filter<typeof Schema.String>>;
|
|
25
|
+
expected: Schema.optional<Schema.filter<typeof Schema.String>>;
|
|
26
|
+
choices: Schema.filter<Schema.Record$<Schema.filter<typeof Schema.String>, Schema.filter<typeof Schema.Number>>>;
|
|
27
|
+
threshold: Schema.optionalWith<Schema.filter<typeof Schema.Number>, {
|
|
28
|
+
default: () => number;
|
|
29
|
+
}>;
|
|
30
|
+
timeoutMs: Schema.optionalWith<Schema.filter<typeof Schema.Int>, {
|
|
31
|
+
default: () => number;
|
|
32
|
+
}>;
|
|
33
|
+
}>]>;
|
|
34
|
+
type EvalJudge = typeof EvalJudge.Type;
|
|
35
|
+
declare const EvalJudgment: Schema.Struct<{
|
|
36
|
+
name: typeof Schema.String;
|
|
37
|
+
model: typeof Schema.String;
|
|
38
|
+
evaluator: typeof Schema.String;
|
|
39
|
+
score: Schema.NullOr<Schema.filter<typeof Schema.Number>>;
|
|
40
|
+
choice: Schema.NullOr<typeof Schema.String>;
|
|
41
|
+
reason: typeof Schema.String;
|
|
42
|
+
threshold: Schema.filter<typeof Schema.Number>;
|
|
43
|
+
durationMs: Schema.refine<number, typeof Schema.NonNegative>;
|
|
44
|
+
error: Schema.NullOr<typeof Schema.String>;
|
|
45
|
+
}>;
|
|
46
|
+
type EvalJudgment = typeof EvalJudgment.Type;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { EvalJudgment as n, EvalJudge as t };
|