anpord 0.1.13 → 0.1.17

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 (70) hide show
  1. package/README.md +1 -1
  2. package/dist/api-context.cjs +18 -0
  3. package/dist/api-context.d.cts +8 -0
  4. package/dist/api-context.d.mts +8 -0
  5. package/dist/api-context.mjs +17 -0
  6. package/dist/api-mocks-BXZmPUwV.d.cts +101 -0
  7. package/dist/api-mocks-BXZmPUwV.d.mts +101 -0
  8. package/dist/api-mocks-CuVw86Qw.cjs +68 -0
  9. package/dist/api-mocks-wNUnpzJf.mjs +33 -0
  10. package/dist/api-runtime.cjs +4 -0
  11. package/dist/api-runtime.d.cts +13 -0
  12. package/dist/api-runtime.d.mts +13 -0
  13. package/dist/api-runtime.mjs +2 -0
  14. package/dist/api.cjs +5 -0
  15. package/dist/api.d.cts +4 -0
  16. package/dist/api.d.mts +4 -0
  17. package/dist/api.mjs +2 -0
  18. package/dist/bin.cjs +8 -8
  19. package/dist/bin.mjs +6 -6
  20. package/dist/cli-runtime.cjs +9 -26
  21. package/dist/cli-runtime.mjs +5 -22
  22. package/dist/{client-BirFO3jz.d.cts → client-BVoIRPot.d.cts} +1082 -1082
  23. package/dist/{client-BfdjFtlV.mjs → client-DE3YNtWc.mjs} +3 -90
  24. package/dist/{client-C-P2I00z.cjs → client-DziJjMFh.cjs} +4 -91
  25. package/dist/{client-BgRs8JvW.d.mts → client-_OgJhHpJ.d.mts} +1083 -1083
  26. package/dist/{compiler-D96wI7UP.mjs → compiler-C62ss3a4.mjs} +161 -61
  27. package/dist/{compiler-uwb1pkdK.cjs → compiler-CYwJNlT4.cjs} +202 -72
  28. package/dist/config.cjs +1 -1
  29. package/dist/config.d.cts +1 -1
  30. package/dist/config.d.mts +1 -1
  31. package/dist/config.mjs +1 -1
  32. package/dist/define-NZvmQuIv.d.cts +34 -0
  33. package/dist/define-NZvmQuIv.d.mts +34 -0
  34. package/dist/{eval-judges-DPPUftbh.d.cts → eval-judges-0FkhUOIB.d.cts} +2 -2
  35. package/dist/{eval-judges-DPPUftbh.d.mts → eval-judges-0FkhUOIB.d.mts} +2 -2
  36. package/dist/{eval-judges-BkmiVLLq.cjs → eval-judges-1zF4PVqV.cjs} +1 -1
  37. package/dist/{eval-judges-CwTvTq7N.mjs → eval-judges-Bee_ABJt.mjs} +1 -1
  38. package/dist/{eval-validations-_MlnQ_uv.cjs → eval-validations-BdlPhudg.cjs} +8 -2
  39. package/dist/{eval-validations-BRdoZrTQ.mjs → eval-validations-BvX9dkYh.mjs} +3 -3
  40. package/dist/eval.cjs +4 -1
  41. package/dist/eval.d.cts +275 -25
  42. package/dist/eval.d.mts +275 -25
  43. package/dist/eval.mjs +2 -2
  44. package/dist/{evals-B6aT3xgH.d.cts → evals-CFxc4IrF.d.cts} +124 -124
  45. package/dist/{evals-B6aT3xgH.d.mts → evals-CFxc4IrF.d.mts} +124 -124
  46. package/dist/{evals-DouMsrsM.cjs → evals-api-CqhPZCr5.cjs} +104 -73
  47. package/dist/{evals-Dcc_x6jW.mjs → evals-api-CsdU741J.mjs} +96 -5
  48. package/dist/index.cjs +8 -8
  49. package/dist/index.d.cts +12 -8
  50. package/dist/index.d.mts +13 -9
  51. package/dist/index.mjs +7 -7
  52. package/dist/mcp-runtime.cjs +9 -18
  53. package/dist/mcp-runtime.mjs +5 -14
  54. package/dist/mock-journal-Bnaozlx4.cjs +39 -0
  55. package/dist/mock-journal-rbsXfDRs.mjs +22 -0
  56. package/dist/runtime-CXcsGvwP.cjs +292 -0
  57. package/dist/runtime-DDUrsAI-.mjs +269 -0
  58. package/dist/source.d.cts +1 -1
  59. package/dist/source.d.mts +1 -1
  60. package/dist/{types-Codjaq-o.d.mts → types-BjQf9IIi.d.mts} +21 -11
  61. package/dist/{types-ISsteq95.d.cts → types-C2nRDJ95.d.cts} +20 -10
  62. package/dist/validator-runtime.cjs +6 -1
  63. package/dist/validator-runtime.d.cts +1 -1
  64. package/dist/validator-runtime.d.mts +1 -1
  65. package/dist/validator-runtime.mjs +6 -1
  66. package/dist/validators.cjs +1 -1
  67. package/dist/validators.d.cts +1 -1
  68. package/dist/validators.d.mts +1 -1
  69. package/dist/validators.mjs +1 -1
  70. package/package.json +21 -1
@@ -1,10 +1,11 @@
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
- import { t as EvalJudge } from "./eval-judges-CwTvTq7N.mjs";
1
+ import { t as EvalJudge } from "./eval-judges-Bee_ABJt.mjs";
2
+ import { r as API_PROGRAM } from "./api-mocks-wNUnpzJf.mjs";
3
+ import { a as EvalValidator, c as PROFILE_LIMITS, d as EvalSourceFiles, l as ProfilePath, n as PublicStartEvalRequest, o as EnvName, s as HarnessProfile, u as profileFitsHarness } from "./evals-api-CsdU741J.mjs";
3
4
  import { a as parseRepo, i as cloneUrlOf, r as repo } from "./source-Fg1h2VNn.mjs";
4
5
  import { Config, Data, Effect, Option, Schema } from "effect";
6
+ import { mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
5
7
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
8
  import { existsSync, realpathSync } from "node:fs";
7
- import { mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
8
9
  import { fileURLToPath, pathToFileURL } from "node:url";
9
10
  import { build } from "esbuild";
10
11
  import { gzipSync } from "node:zlib";
@@ -47,11 +48,29 @@ const sourceFiles = (map, entry) => {
47
48
  };
48
49
  //#endregion
49
50
  //#region src/evals/eval-bundle.ts
50
- const authoringExports = ["export const defineEval = value => value;", `export { empty, files, repo } from "./source";`].join("\n");
51
+ const authoringExports = ["export const defineEval = (first, second) => typeof first === 'string' ? second : first;", `export { empty, files, repo } from "./source";`].join("\n");
51
52
  const authoringDir = dirname(fileURLToPath(import.meta.url));
52
53
  const ANPORD_MODULE = /^anpord$/;
53
54
  const ANY_MODULE = /.*/;
54
55
  const localModules = [
56
+ {
57
+ built: "api.mjs",
58
+ filter: /^anpord\/api$/,
59
+ namespace: "anpord-api-authoring",
60
+ source: "../mock-api/index.ts"
61
+ },
62
+ {
63
+ built: "api-runtime.mjs",
64
+ filter: /^anpord\/api\/runtime$/,
65
+ namespace: "anpord-api-runtime",
66
+ source: "../mock-api/runtime.ts"
67
+ },
68
+ {
69
+ built: "api-context.mjs",
70
+ filter: /^anpord\/api\/context$/,
71
+ namespace: "anpord-api-context",
72
+ source: "../mock-api/context.ts"
73
+ },
55
74
  {
56
75
  built: "validator-runtime.mjs",
57
76
  filter: /^anpord\/validators\/runtime$/,
@@ -128,6 +147,7 @@ const bundle = (contents, entry, options = {}) => Effect.tryPromise({
128
147
  try: () => build({
129
148
  absWorkingDir: process.cwd(),
130
149
  bundle: true,
150
+ banner: { js: "import { createRequire as anpordCreateRequire } from \"node:module\"; const require = anpordCreateRequire(import.meta.url);" },
131
151
  format: "esm",
132
152
  metafile: true,
133
153
  minify: options.minify,
@@ -158,36 +178,6 @@ const bundle = (contents, entry, options = {}) => Effect.tryPromise({
158
178
  catch: (cause) => new Error(`Could not compile ${entry}`, { cause })
159
179
  });
160
180
  //#endregion
161
- //#region src/evals/case-modules.ts
162
- const realOrGiven = (path) => {
163
- try {
164
- return realpathSync.native(path);
165
- } catch {
166
- return path;
167
- }
168
- };
169
- const sameFile = (one, other) => one === other || realOrGiven(one) === realOrGiven(other);
170
- const exportingModule = (entry, inputs, name) => Effect.gen(function* () {
171
- const pattern = new RegExp(`\\bexport\\s+(?:async\\s+)?(?:const|function)\\s+${name}\\b`);
172
- const matches = yield* Effect.filter(inputs.filter((path) => !(sameFile(path, entry) || path.includes(`${sep}node_modules${sep}`))), (path) => Effect.tryPromise(() => readFile(path, "utf8")).pipe(Effect.map((source) => pattern.test(source)), Effect.orElseSucceed(() => false)), { concurrency: 8 });
173
- if (matches.length !== 1) return yield* Effect.fail(/* @__PURE__ */ new Error(`${name} must be one named function or const export from a separate TypeScript file`));
174
- return matches[0];
175
- });
176
- const bundledCaseModule = (entry, inputs, name, wrap) => Effect.gen(function* () {
177
- const module = yield* exportingModule(entry, inputs, name);
178
- const { source } = yield* bundle(wrap(module, name), entry);
179
- return {
180
- name,
181
- source
182
- };
183
- });
184
- //#endregion
185
- //#region src/evals/profile-compose.ts
186
- const appendInstall = (profile, command) => ({
187
- ...profile,
188
- install: profile.install ? `${profile.install} && ${command}` : command
189
- });
190
- //#endregion
191
181
  //#region src/evals/program-package.ts
192
182
  const CHUNK_SIZE = 9e4;
193
183
  const packageProgram = (root, entry, source) => {
@@ -197,18 +187,20 @@ const packageProgram = (root, entry, source) => {
197
187
  const loader = `#!/usr/bin/env node\nimport{readFile,writeFile}from"node:fs/promises";import{gunzipSync}from"node:zlib";const root=new URL("./",import.meta.url),names=${JSON.stringify(names)},data=(await Promise.all(names.map(name=>readFile(new URL(name,root),"utf8")))).join(""),runtime=new URL("runtime.mjs",root);await writeFile(runtime,gunzipSync(Buffer.from(data,"base64")));await import(runtime.href);`;
198
188
  return {
199
189
  entry: `${root}/${entry}`,
200
- files: Object.fromEntries([[`${root}/${entry}`, loader], ...names.map((name, index) => [`${root}/${name}`, chunks[index]])])
190
+ files: Object.fromEntries([[`${root}/${entry}`, loader], ...chunks.map((chunk, index) => [`${root}/${index}.txt`, chunk])])
201
191
  };
202
192
  };
203
193
  //#endregion
204
194
  //#region src/evals/runner-source.ts
205
- const validatorCaseEntry = (entry, index, names = []) => `import definition from ${JSON.stringify(entry)};
195
+ const importsDefinition = ({ entry, exportName }) => exportName === null ? `import definition from ${JSON.stringify(entry)};` : `import { ${exportName} as definition } from ${JSON.stringify(entry)};`;
196
+ const validatorCaseEntry = (ref, index, names = []) => `${importsDefinition(ref)}
206
197
  import { runValidators } from "anpord/validators/runtime";
207
198
  const selected = definition.cases[${index}].validate;
208
199
  const names = ${JSON.stringify(names)};
209
200
  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
201
  await runValidators(checks, definition.captureValidation !== false);`;
211
202
  const prepareRuntime = `
203
+ import { apiContext } from "anpord/api/context";
212
204
  import { access, readFile } from "node:fs/promises";
213
205
  import { spawn } from "node:child_process";
214
206
 
@@ -236,6 +228,7 @@ const exec = (file, args = [], options = {}) => new Promise((resolve, reject) =>
236
228
  });
237
229
 
238
230
  const context = {
231
+ api: apiContext,
239
232
  cached: process.env.ANPORD_CACHE_RESTORED === "1",
240
233
  exec,
241
234
  exists: path => access(path).then(() => true, () => false),
@@ -252,25 +245,88 @@ try {
252
245
  }
253
246
  `;
254
247
  const prepareEntry = (module, name) => `import { ${name} as setup } from ${JSON.stringify(module)};\n${prepareRuntime}`;
255
- const definitionEntry = (entry) => `import definition from ${JSON.stringify(entry)}; export default definition;`;
256
- const mcpEntry = (entry, index) => `import definition from ${JSON.stringify(entry)};
248
+ const definitionEntry = (ref) => `${importsDefinition(ref)} export default definition;`;
249
+ const mcpEntry = (ref, index) => `${importsDefinition(ref)}
257
250
  import { runMcpServer } from "anpord/mcp/runtime";
258
251
  const server = definition.mcp?.[${index}];
259
252
  if (server === undefined) throw new Error("MCP server ${index} is missing");
260
253
  runMcpServer(server);`;
261
- const cliEntry = (entry, index) => `import { fileURLToPath } from "node:url";
262
- import definition from ${JSON.stringify(entry)};
254
+ const cliEntry = (ref, index) => `import { fileURLToPath } from "node:url";
255
+ ${importsDefinition(ref)}
263
256
  import { runCli } from "anpord/cli/runtime";
264
257
  const cli = definition.cli?.[${index}];
265
258
  if (cli === undefined) throw new Error("CLI ${index} is missing");
266
259
  await runCli(cli, fileURLToPath(new URL("../../cli-calls.jsonl", import.meta.url)));`;
267
260
  //#endregion
261
+ //#region src/evals/api-profile.ts
262
+ const compileApis = (ref, definitions) => Effect.gen(function* () {
263
+ if (definitions.length === 0) return {};
264
+ const names = definitions.map(({ name }) => name);
265
+ if (new Set(names).size !== names.length) return yield* Effect.fail(/* @__PURE__ */ new Error("Duplicate API mock name"));
266
+ const { source } = yield* bundle(`${importsDefinition(ref)}
267
+ import { runApiServers } from "anpord/api/runtime";
268
+ runApiServers(definition.api ?? []);`, ref.entry, { minify: true });
269
+ const program = packageProgram("workspace/.anpord/api", "server.mjs", source);
270
+ return {
271
+ ...program.files,
272
+ [API_PROGRAM]: JSON.stringify({ entry: program.entry.slice(10) })
273
+ };
274
+ });
275
+ const withApis = (task, files) => {
276
+ if (Object.keys(files).length === 0) return task;
277
+ const profile = task.profile ?? {
278
+ name: "anpord-api",
279
+ files: {}
280
+ };
281
+ for (const path of Object.keys(files)) if (profile.files[path] !== void 0) throw new Error(`Profile file ${path} is reserved for API mocks`);
282
+ return {
283
+ ...task,
284
+ profile: {
285
+ ...profile,
286
+ files: {
287
+ ...profile.files,
288
+ ...files
289
+ }
290
+ }
291
+ };
292
+ };
293
+ //#endregion
294
+ //#region src/evals/case-modules.ts
295
+ const realOrGiven = (path) => {
296
+ try {
297
+ return realpathSync.native(path);
298
+ } catch {
299
+ return path;
300
+ }
301
+ };
302
+ const sameFile = (one, other) => one === other || realOrGiven(one) === realOrGiven(other);
303
+ const exportingModule = (entry, inputs, name) => Effect.gen(function* () {
304
+ const pattern = new RegExp(`\\bexport\\s+(?:async\\s+)?(?:const|function)\\s+${name}\\b`);
305
+ const matches = yield* Effect.filter(inputs.filter((path) => !(sameFile(path, entry) || path.includes(`${sep}node_modules${sep}`))), (path) => Effect.tryPromise(() => readFile(path, "utf8")).pipe(Effect.map((source) => pattern.test(source)), Effect.orElseSucceed(() => false)), { concurrency: 8 });
306
+ if (matches.length !== 1) return yield* Effect.fail(/* @__PURE__ */ new Error(`${name} must be one named function or const export from a separate TypeScript file`));
307
+ return matches[0];
308
+ });
309
+ const bundledCaseModule = (entry, inputs, name, wrap) => Effect.gen(function* () {
310
+ const module = yield* exportingModule(entry, inputs, name);
311
+ const { source } = yield* bundle(wrap(module, name), entry, { minify: true });
312
+ return {
313
+ name,
314
+ source
315
+ };
316
+ });
317
+ //#endregion
318
+ //#region src/evals/profile-compose.ts
319
+ const appendInstall = (profile, command) => ({
320
+ ...profile,
321
+ install: profile.install ? `${profile.install} && ${command}` : command
322
+ });
323
+ //#endregion
268
324
  //#region src/evals/cli-profile.ts
269
- const compileClis = (entry, definitions) => Effect.gen(function* () {
325
+ const compileClis = (ref, definitions) => Effect.gen(function* () {
270
326
  const paths = definitions.map(({ path }) => path);
271
327
  const duplicate = paths.find((path, index) => paths.indexOf(path) !== index);
272
328
  if (duplicate !== void 0) return yield* Effect.fail(/* @__PURE__ */ new Error(`Duplicate CLI: ${duplicate}`));
273
- return yield* Effect.forEach(definitions, (definition, index) => bundle(cliEntry(entry, index), entry, { minify: true }).pipe(Effect.map(({ source }) => ({
329
+ return yield* Effect.forEach(definitions, (definition, index) => bundle(cliEntry(ref, index), ref.entry, { minify: true }).pipe(Effect.map(({ source }) => ({
274
330
  ...packageProgram(`workspace/.anpord/cli/${index}`, "cli.mjs", source),
275
331
  path: definition.path
276
332
  }))), { concurrency: 4 });
@@ -300,7 +356,7 @@ const withClis = (task, clis) => {
300
356
  };
301
357
  //#endregion
302
358
  //#region src/evals/compile-validator.ts
303
- const compileValidator = (entry, subject, caseIndex, captureSource, captureValidation = true) => Effect.gen(function* () {
359
+ const compileValidator = (ref, subject, caseIndex, captureSource, captureValidation = true) => Effect.gen(function* () {
304
360
  if (subject.validate === void 0) return null;
305
361
  const validations = Array.isArray(subject.validate) ? subject.validate : [subject.validate];
306
362
  if (validations.length === 0 || validations.length > 20) return yield* Effect.fail(/* @__PURE__ */ new Error("Use between 1 and 20 validators"));
@@ -311,7 +367,7 @@ const compileValidator = (entry, subject, caseIndex, captureSource, captureValid
311
367
  name: value.name || `Validator ${index + 1}`
312
368
  }] : []);
313
369
  const hasCode = manifest.length > 0;
314
- const compiled = yield* bundle(hasCode ? validatorCaseEntry(entry, caseIndex, manifest) : definitionEntry(entry), entry, {
370
+ const compiled = yield* bundle(hasCode ? validatorCaseEntry(ref, caseIndex, manifest) : definitionEntry(ref), ref.entry, {
315
371
  minify: true,
316
372
  captureSource
317
373
  });
@@ -334,7 +390,7 @@ const compileValidator = (entry, subject, caseIndex, captureSource, captureValid
334
390
  });
335
391
  //#endregion
336
392
  //#region src/evals/definition-loader.ts
337
- const loadDefinition = (entry) => bundle(definitionEntry(entry), entry).pipe(Effect.flatMap(({ inputs, source }) => Effect.acquireUseRelease(Effect.tryPromise(() => mkdtemp(join(tmpdir(), "anpord-eval-"))), (directory) => Effect.tryPromise({
393
+ const loadDefinition = (ref) => bundle(definitionEntry(ref), ref.entry).pipe(Effect.flatMap(({ inputs, source }) => Effect.acquireUseRelease(Effect.tryPromise(() => mkdtemp(join(tmpdir(), "anpord-eval-"))), (directory) => Effect.tryPromise({
338
394
  try: async () => {
339
395
  const output = join(directory, "definition.mjs");
340
396
  await writeFile(output, source);
@@ -343,7 +399,7 @@ const loadDefinition = (entry) => bundle(definitionEntry(entry), entry).pipe(Eff
343
399
  inputs
344
400
  };
345
401
  },
346
- catch: (cause) => new Error(`Could not load ${entry}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause })
402
+ catch: (cause) => new Error(`Could not load ${ref.entry}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause })
347
403
  }), (directory) => Effect.promise(() => rm(directory, {
348
404
  force: true,
349
405
  recursive: true
@@ -391,6 +447,39 @@ const localRepo = (cwd) => Effect.gen(function* () {
391
447
  });
392
448
  }).pipe(Effect.withSpan("Eval.localRepo"));
393
449
  //#endregion
450
+ //#region src/evals/define.ts
451
+ const SOURCE_URL = Symbol.for("anpord.sourceUrl");
452
+ function defineEval(first, second) {
453
+ if (typeof first !== "string") return first;
454
+ return Object.defineProperty(second, SOURCE_URL, {
455
+ enumerable: false,
456
+ value: first
457
+ });
458
+ }
459
+ const sourceUrlOf = (definition) => definition[SOURCE_URL];
460
+ //#endregion
461
+ //#region src/evals/locate.ts
462
+ const HINT = "Pass import.meta.url as the first argument to defineEval, or compile by path.";
463
+ const exportHolding = async (entry, definition) => {
464
+ const module = await import(entry);
465
+ if (module.default === definition) return null;
466
+ const named = Object.keys(module).find((key) => module[key] === definition);
467
+ if (named === void 0) throw new Error(`The definition passed is not exported from ${entry}. ${HINT}`);
468
+ return named;
469
+ };
470
+ const locate = (definition) => Effect.gen(function* () {
471
+ const url = sourceUrlOf(definition);
472
+ if (url === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error(`This eval does not know where it was written. ${HINT}`));
473
+ const exportName = yield* Effect.tryPromise({
474
+ catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
475
+ try: () => exportHolding(url, definition)
476
+ });
477
+ return {
478
+ entry: fileURLToPath(url),
479
+ exportName
480
+ };
481
+ });
482
+ //#endregion
394
483
  //#region src/evals/mcp-harness.ts
395
484
  const Entries = Schema.Record({
396
485
  key: Schema.String,
@@ -491,11 +580,11 @@ const applyMcpHarness = (harness, profile, servers) => {
491
580
  };
492
581
  //#endregion
493
582
  //#region src/evals/mcp-profile.ts
494
- const compileMcpServers = (entry, definitions) => Effect.gen(function* () {
583
+ const compileMcpServers = (ref, definitions) => Effect.gen(function* () {
495
584
  const names = definitions.map(({ name }) => name);
496
585
  const duplicate = names.find((name, index) => names.indexOf(name) !== index);
497
586
  if (duplicate !== void 0) return yield* Effect.fail(/* @__PURE__ */ new Error(`Duplicate MCP server: ${duplicate}`));
498
- return yield* Effect.forEach(definitions, (definition, index) => bundle(mcpEntry(entry, index), entry, { minify: true }).pipe(Effect.map(({ source }) => ({
587
+ return yield* Effect.forEach(definitions, (definition, index) => bundle(mcpEntry(ref, index), ref.entry, { minify: true }).pipe(Effect.map(({ source }) => ({
499
588
  ...packageProgram(`workspace/.anpord/mcp/${index}`, "server.mjs", source),
500
589
  name: definition.name
501
590
  }))), { concurrency: 4 });
@@ -708,7 +797,7 @@ const profileTask = (entry, task) => Effect.gen(function* () {
708
797
  }).pipe(Effect.withSpan("Eval.profileTask", { attributes: { profile: task.harness.profile.name } }));
709
798
  //#endregion
710
799
  //#region src/evals/compiler.ts
711
- const taskOf = (entry, task, clis, mcp) => Effect.gen(function* () {
800
+ const taskOf = (entry, task, clis, mcp, apis) => Effect.gen(function* () {
712
801
  const compiled = typeof task.harness === "string" ? {
713
802
  harness: task.harness,
714
803
  model: task.model,
@@ -717,7 +806,7 @@ const taskOf = (entry, task, clis, mcp) => Effect.gen(function* () {
717
806
  ...task,
718
807
  harness: task.harness
719
808
  });
720
- return yield* Effect.try(() => withClis(withMcpServers(compiled, mcp), clis));
809
+ return yield* Effect.try(() => withApis(withClis(withMcpServers(compiled, mcp), clis), apis));
721
810
  });
722
811
  const sourceFor = (definition, subject, fallback) => {
723
812
  const source = subject.source ?? definition.source;
@@ -727,17 +816,21 @@ const sourceFor = (definition, subject, fallback) => {
727
816
  onSome: (source) => ({ source })
728
817
  });
729
818
  };
730
- const compileEvalEffect = (path) => Effect.gen(function* () {
731
- const entry = resolve(path);
732
- const loaded = yield* loadDefinition(entry);
819
+ const compileRefEffect = (ref) => Effect.gen(function* () {
820
+ const entry = ref.entry;
821
+ const loaded = yield* loadDefinition(ref);
733
822
  const definition = loaded.definition;
734
- if (!isDefinition(definition)) return yield* Effect.fail(/* @__PURE__ */ new Error(`${entry} must default export defineEval({ ... })`));
735
- const clis = yield* compileClis(entry, definition.cli ?? []);
736
- const mcp = yield* compileMcpServers(entry, definition.mcp ?? []);
823
+ if (!isDefinition(definition)) {
824
+ const named = ref.exportName === null ? "default export" : `export ${ref.exportName}`;
825
+ return yield* Effect.fail(/* @__PURE__ */ new Error(`${entry} must ${named} defineEval({ ... })`));
826
+ }
827
+ const clis = yield* compileClis(ref, definition.cli ?? []);
828
+ const mcp = yield* compileMcpServers(ref, definition.mcp ?? []);
829
+ const apis = yield* compileApis(ref, definition.api ?? []);
737
830
  const fallback = definition.source === void 0 && definition.cases.some((subject) => subject.source === void 0) ? yield* localRepo(dirname(entry)) : Option.none();
738
831
  const cases = yield* Effect.forEach(definition.cases, (subject, caseIndex) => Effect.gen(function* () {
739
832
  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`));
740
- const validator = yield* compileValidator(entry, subject, caseIndex, definition.captureSource !== false, definition.captureValidation !== false);
833
+ const validator = yield* compileValidator(ref, subject, caseIndex, definition.captureSource !== false, definition.captureValidation !== false);
741
834
  const prepare = typeof subject.prepare === "function" ? yield* bundledCaseModule(entry, loaded.inputs, subject.prepare.name || `${subject.name}-prepare`, prepareEntry) : null;
742
835
  return {
743
836
  ...subject.cache === void 0 ? {} : { cache: subject.cache },
@@ -749,15 +842,22 @@ const compileEvalEffect = (path) => Effect.gen(function* () {
749
842
  verify: subject.verify ?? null
750
843
  };
751
844
  }), { concurrency: 4 });
752
- const tasks = yield* Effect.forEach(definition.tasks, (task) => taskOf(entry, task, clis, mcp), { concurrency: 4 });
753
- return {
845
+ const tasks = yield* Effect.forEach(definition.tasks, (task) => taskOf(entry, task, clis, mcp, apis), { concurrency: 4 });
846
+ return yield* Schema.decodeUnknown(PublicStartEvalRequest)({
754
847
  cases,
755
848
  name: definition.name,
756
849
  prompt: definition.prompt,
757
850
  tasks,
758
851
  trials: definition.trials
759
- };
852
+ });
760
853
  }).pipe(Effect.withSpan("Eval.compile"));
854
+ const compileDefinitionEffect = (definition) => Effect.flatMap(locate(definition), compileRefEffect);
855
+ const compileDefinition = (definition) => Effect.runPromise(compileDefinitionEffect(definition));
856
+ const refOfPath = (path) => ({
857
+ entry: resolve(path),
858
+ exportName: null
859
+ });
860
+ const compileEvalEffect = (path) => compileRefEffect(refOfPath(path));
761
861
  const compileEval = (path) => Effect.runPromise(compileEvalEffect(path));
762
862
  //#endregion
763
- export { compileEvalEffect as n, compileEval as t };
863
+ export { compileRefEffect as a, compileEvalEffect as i, compileDefinitionEffect as n, defineEval as o, compileEval as r, sourceUrlOf as s, compileDefinition as t };