@tangle-network/agent-eval 0.143.0 → 0.144.1

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 (79) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +21 -8
  3. package/dist/analyst/index.d.ts +82 -17
  4. package/dist/analyst/index.d.ts.map +1 -1
  5. package/dist/analyst/index.js +4 -4
  6. package/dist/{benchmark-command-CSddvlq7.js → benchmark-command-95Zqd1e8.js} +333 -111
  7. package/dist/benchmark-command-95Zqd1e8.js.map +1 -0
  8. package/dist/benchmarks/index.d.ts +1 -1
  9. package/dist/benchmarks/index.js +1 -1
  10. package/dist/{benchmarks-Dg0B56tK.js → benchmarks-CRT4ScEA.js} +4 -4
  11. package/dist/{benchmarks-Dg0B56tK.js.map → benchmarks-CRT4ScEA.js.map} +1 -1
  12. package/dist/campaign/index.d.ts +4 -3
  13. package/dist/campaign/index.js +4 -4
  14. package/dist/{campaign-C7ZGiZYG.js → campaign-CefP3fPS.js} +12 -10
  15. package/dist/campaign-CefP3fPS.js.map +1 -0
  16. package/dist/cli.js +2 -2
  17. package/dist/contract/index.d.ts +1 -1
  18. package/dist/contract/index.js +3 -3
  19. package/dist/{default-registry-BupFSXSN.js → default-registry-SOyHB6qG.js} +3 -3
  20. package/dist/{default-registry-BupFSXSN.js.map → default-registry-SOyHB6qG.js.map} +1 -1
  21. package/dist/{dspy-rlm-engine-CJ4sN8Wx.js → dspy-rlm-engine-BR7TtB0o.js} +69 -31
  22. package/dist/dspy-rlm-engine-BR7TtB0o.js.map +1 -0
  23. package/dist/{eval-campaign-YdkpWWoT.js → eval-campaign-lI7wB9DH.js} +2 -2
  24. package/dist/{eval-campaign-YdkpWWoT.js.map → eval-campaign-lI7wB9DH.js.map} +1 -1
  25. package/dist/external-optimizer-contracts-CdmX2K2S.d.ts +165 -0
  26. package/dist/external-optimizer-contracts-CdmX2K2S.d.ts.map +1 -0
  27. package/dist/{index-BKjcUH13.d.ts → index-BZUe-ODI.d.ts} +41 -5
  28. package/dist/index-BZUe-ODI.d.ts.map +1 -0
  29. package/dist/{index-DY83M1WL.d.ts → index-BrpxwELi.d.ts} +9 -8
  30. package/dist/{index-DY83M1WL.d.ts.map → index-BrpxwELi.d.ts.map} +1 -1
  31. package/dist/{index-CaOjqCli.d.ts → index-DRI1DU5z.d.ts} +3 -3
  32. package/dist/{index-CaOjqCli.d.ts.map → index-DRI1DU5z.d.ts.map} +1 -1
  33. package/dist/index.d.ts +7 -7
  34. package/dist/index.js +12 -11
  35. package/dist/index.js.map +1 -1
  36. package/dist/{integrity-hruKe6oe.js → integrity-DY6tIbl0.js} +48 -18
  37. package/dist/integrity-DY6tIbl0.js.map +1 -0
  38. package/dist/{llm-client-B3WXSH5Y.js → llm-client-D3EoChAU.js} +7 -7
  39. package/dist/llm-client-D3EoChAU.js.map +1 -0
  40. package/dist/openapi.json +1 -1
  41. package/dist/rl.js +1 -1
  42. package/dist/{semantic-concept-judge-DJQtFr95.js → semantic-concept-judge-l8Lb3Kqz.js} +2 -2
  43. package/dist/{semantic-concept-judge-DJQtFr95.js.map → semantic-concept-judge-l8Lb3Kqz.js.map} +1 -1
  44. package/dist/{server-Cu4M3NSO.js → server-Df00sdwz.js} +3 -3
  45. package/dist/{server-Cu4M3NSO.js.map → server-Df00sdwz.js.map} +1 -1
  46. package/dist/single-run-lock-B-cFnnNn.js +1799 -0
  47. package/dist/single-run-lock-B-cFnnNn.js.map +1 -0
  48. package/dist/{skill-usage-CRqaHi0R.d.ts → skill-usage-3vUWdZ9n.d.ts} +24 -5
  49. package/dist/skill-usage-3vUWdZ9n.d.ts.map +1 -0
  50. package/dist/{skillopt-optimization-method-Di8Xkalt.js → skillopt-optimization-method-DA5mJmFE.js} +225 -347
  51. package/dist/skillopt-optimization-method-DA5mJmFE.js.map +1 -0
  52. package/dist/{skillopt-optimization-method-CwRvi-rL.d.ts → skillopt-optimization-method-DNniakI5.d.ts} +47 -9
  53. package/dist/skillopt-optimization-method-DNniakI5.d.ts.map +1 -0
  54. package/dist/supervisor-run/index.d.ts +3 -3
  55. package/dist/supervisor-run/index.js +3 -3
  56. package/dist/{supervisor-run-BEns49Nx.js → supervisor-run-DiyQVczd.js} +301 -25
  57. package/dist/supervisor-run-DiyQVczd.js.map +1 -0
  58. package/dist/types-BjMFz88h.d.ts.map +1 -1
  59. package/dist/{types-Dea6tiVI.d.ts → types-yLK8gXE9.d.ts} +15 -2
  60. package/dist/types-yLK8gXE9.d.ts.map +1 -0
  61. package/dist/wire/index.js +1 -1
  62. package/docs/campaign-proposers.md +11 -7
  63. package/docs/trace-analysis.md +43 -32
  64. package/package.json +1 -1
  65. package/dist/benchmark-command-CSddvlq7.js.map +0 -1
  66. package/dist/campaign-C7ZGiZYG.js.map +0 -1
  67. package/dist/dspy-rlm-engine-CJ4sN8Wx.js.map +0 -1
  68. package/dist/external-optimizer-contracts-nb7c_WAR.d.ts +0 -42
  69. package/dist/external-optimizer-contracts-nb7c_WAR.d.ts.map +0 -1
  70. package/dist/index-BKjcUH13.d.ts.map +0 -1
  71. package/dist/integrity-hruKe6oe.js.map +0 -1
  72. package/dist/llm-client-B3WXSH5Y.js.map +0 -1
  73. package/dist/single-run-lock-Do-8vBIJ.js +0 -1049
  74. package/dist/single-run-lock-Do-8vBIJ.js.map +0 -1
  75. package/dist/skill-usage-CRqaHi0R.d.ts.map +0 -1
  76. package/dist/skillopt-optimization-method-CwRvi-rL.d.ts.map +0 -1
  77. package/dist/skillopt-optimization-method-Di8Xkalt.js.map +0 -1
  78. package/dist/supervisor-run-BEns49Nx.js.map +0 -1
  79. package/dist/types-Dea6tiVI.d.ts.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { c as ValidationError, t as AgentEvalError } from "./errors-D-LKuDhb.js";
2
2
  import { s as resolveModelPricing } from "./metrics-C9YY1OcL.js";
3
3
  import { a as CostLedgerPersistenceError, i as CostLedger, n as CostCallConflictError, o as CostReceiptCaptureError, r as CostCeilingReachedError, s as CostReservationExceededError, t as CostAccountingIncompleteError } from "./cost-ledger-DMFxsLKr.js";
4
- import { c as callLlmJson, f as maximumChargeForLlmRequest, l as costReceiptFromLlm, r as LlmResponseError, t as LlmCallError, u as costReceiptFromLlmError } from "./llm-client-B3WXSH5Y.js";
4
+ import { c as callLlmJson, r as LlmResponseError, t as LlmCallError } from "./llm-client-D3EoChAU.js";
5
5
  import { O as evidenceRefsFromRawFinding, h as TRACE_ANALYSIS_LIMITS, i as runTraceAnalyst } from "./kind-factory-Bvwe3pup.js";
6
6
  import { o as makeFinding, r as usageReceiptFromCostLedger } from "./usage-receipt-CgxMEBZq.js";
7
7
  import { i as hashCanonical, r as canonicalString } from "./canonical-D011XM8r.js";
8
- import { n as createRunCostLedger, r as fsCampaignStorage, t as acquireSingleRunLock } from "./single-run-lock-Do-8vBIJ.js";
9
- import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-CJ4sN8Wx.js";
8
+ import { M as resolveExternalOptimizerProcessLimits, f as runWithCleanup, n as createRunCostLedger, p as startExternalOptimizerModelProxy, r as fsCampaignStorage, t as acquireSingleRunLock } from "./single-run-lock-B-cFnnNn.js";
9
+ import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-BR7TtB0o.js";
10
10
  import { c as writeLedgerFileAtomically, s as withLedgerFileLock } from "./ledger-core-Dxz0Rkwa.js";
11
11
  import { E as pairedBootstrap } from "./statistics-ByxzSiOM.js";
12
12
  import { i as otlpTextToTraceAnalysisStore, r as createOtlpBufferTraceStore, t as DEFAULT_MAX_TRACE_FILE_BYTES } from "./store-otlp-D4I90_vR.js";
@@ -19,6 +19,7 @@ import { createHash, randomUUID } from "node:crypto";
19
19
  import { link, lstat, mkdir, open, readFile, readdir, realpath, stat, unlink } from "node:fs/promises";
20
20
  import { arch, platform } from "node:os";
21
21
  import { TextDecoder as TextDecoder$1 } from "node:util";
22
+ import { pathToFileURL } from "node:url";
22
23
  //#region src/analyst/benchmark-dataset-utils.ts
23
24
  function normalizeBenchmarkLabel(value) {
24
25
  const normalized = nonEmpty$1(value, "benchmark label").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -1070,8 +1071,34 @@ const artifactSchema = z.strictObject({
1070
1071
  concurrency: positiveInteger$1,
1071
1072
  rlmSamples: positiveInteger$1.optional(),
1072
1073
  model: nonEmptyString,
1074
+ modelOwnerCallRef: nonEmptyString.optional(),
1073
1075
  maxOutputTokens: positiveInteger$1,
1076
+ maxReasoningTokens: nonNegativeInteger.optional(),
1077
+ maxModelRequestBytes: positiveInteger$1.optional(),
1078
+ maxModelResponseBytes: positiveInteger$1.optional(),
1079
+ modelRequestTimeoutMs: positiveInteger$1.optional(),
1074
1080
  timeoutMs: positiveInteger$1,
1081
+ pricing: z.strictObject({
1082
+ inputUsdPerMillion: nonNegativeNumber,
1083
+ cachedInputUsdPerMillion: nonNegativeNumber.optional(),
1084
+ cacheWriteUsdPerMillion: nonNegativeNumber.optional(),
1085
+ outputUsdPerMillion: nonNegativeNumber
1086
+ }).optional(),
1087
+ recursiveLimits: z.strictObject({
1088
+ maxIterations: positiveInteger$1,
1089
+ maxLlmCalls: positiveInteger$1,
1090
+ maxToolCalls: positiveInteger$1,
1091
+ maxOutputChars: positiveInteger$1,
1092
+ maxModelRequests: positiveInteger$1.nullable(),
1093
+ traceToolRequestBytes: positiveInteger$1,
1094
+ traceToolResponseBytes: positiveInteger$1,
1095
+ traceToolTimeoutMs: positiveInteger$1
1096
+ }).optional(),
1097
+ processLimits: z.strictObject({
1098
+ maxInputBytes: positiveInteger$1,
1099
+ maxResultBytes: positiveInteger$1,
1100
+ maxOutputChars: positiveInteger$1
1101
+ }).optional(),
1075
1102
  maxCostUsd: nonNegativeNumber,
1076
1103
  maxArtifactBytes: positiveInteger$1,
1077
1104
  analystProtocolSha256: sha256,
@@ -1173,7 +1200,7 @@ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES = Object.freeze([
1173
1200
  "package.json",
1174
1201
  "pnpm-lock.yaml"
1175
1202
  ]);
1176
- const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "2867725e505a600f4f1f9d934fb797f5fb94a71c906577d05009aecc254f85f3";
1203
+ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "044bf5b84d7902c43e627dd302dad22332f8787aa5ae70b72f52fbf9db667d93";
1177
1204
  /** The published benchmark evidence was produced at this package version, by
1178
1205
  * the retired one-shot direct runner, before trace analysts moved to the
1179
1206
  * recursive DSPy RLM engine. Both evidence digests below are historical facts
@@ -1228,9 +1255,11 @@ const ANALYST_BENCHMARK_IMPLEMENTATION_FILES = Object.freeze([
1228
1255
  "src/analyst/trace-tool-callback.ts",
1229
1256
  "src/analyst/types.ts",
1230
1257
  "src/analyst/usage-receipt.ts",
1258
+ "src/campaign/external-optimizer-callback.ts",
1231
1259
  "src/campaign/external-optimizer-contracts.ts",
1232
1260
  "src/campaign/external-optimizer-http.ts",
1233
1261
  "src/campaign/external-optimizer-model-proxy.ts",
1262
+ "src/campaign/external-optimizer-process.ts",
1234
1263
  "src/campaign/external-optimizer-resources.ts",
1235
1264
  "src/campaign/external-optimizer-subprocess.ts",
1236
1265
  "src/campaign/search-ledger-errors.ts",
@@ -1267,9 +1296,10 @@ const ANALYST_BENCHMARK_IMPLEMENTATION_FILES = Object.freeze([
1267
1296
  "src/trace-analyst/types.ts",
1268
1297
  "src/trace/attribute-vocabulary.ts",
1269
1298
  "src/trace/otlp-attributes.ts",
1270
- "src/trace/raw-provider-sink.ts"
1299
+ "src/trace/raw-provider-sink.ts",
1300
+ "src/verdict-cache.ts"
1271
1301
  ]);
1272
- const ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 = "b8b6d4f7a01f8341a0565159806f93ff9ca71c88322e63e4e52a86eed2c1d9c7";
1302
+ const ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 = "d317d9e7593ddc13f22a4a1e3d62d2fa1e4591395ef3984a0c7585a75794cf8d";
1273
1303
  function analystBenchmarkImplementationDigest() {
1274
1304
  return ANALYST_BENCHMARK_IMPLEMENTATION_SHA256;
1275
1305
  }
@@ -2327,6 +2357,7 @@ async function prepareOutputLockPath(outDir) {
2327
2357
  return `${directory}.lock`;
2328
2358
  }
2329
2359
  function createRunIdentity(config, prepared) {
2360
+ const model = commandModelIdentity(config.model);
2330
2361
  const caseDefinitions = prepared.cases.map((testCase) => ({
2331
2362
  id: testCase.id,
2332
2363
  clusterId: testCase.clusterId,
@@ -2343,8 +2374,7 @@ function createRunIdentity(config, prepared) {
2343
2374
  datasetSplit: config.split,
2344
2375
  model: {
2345
2376
  id: config.model.model,
2346
- maxOutputTokens: config.model.maxOutputTokens,
2347
- timeoutMs: config.model.timeoutMs
2377
+ ...model
2348
2378
  },
2349
2379
  limit: config.limit,
2350
2380
  seed: config.seed,
@@ -2369,6 +2399,36 @@ function createRunIdentity(config, prepared) {
2369
2399
  }
2370
2400
  };
2371
2401
  }
2402
+ function commandModelIdentity(config) {
2403
+ const catalogPricing = resolveModelPricing(config.model);
2404
+ const pricing = config.pricing ?? (catalogPricing ? {
2405
+ inputUsdPerMillion: catalogPricing.input * 1e3,
2406
+ outputUsdPerMillion: catalogPricing.output * 1e3
2407
+ } : void 0);
2408
+ if (!pricing) throw new Error(`benchmark model '${config.model}' has no recorded pricing`);
2409
+ const recursive = config.dspyRlm;
2410
+ return {
2411
+ ownerCallRef: config.callRef,
2412
+ maxOutputTokens: config.maxOutputTokens,
2413
+ maxReasoningTokens: config.maxReasoningTokens ?? config.maxOutputTokens * 4,
2414
+ maxRequestBytes: config.maxModelRequestBytes ?? 16 * 1024 * 1024,
2415
+ maxResponseBytes: config.maxModelResponseBytes ?? 4 * 1024 * 1024,
2416
+ requestTimeoutMs: config.modelRequestTimeoutMs ?? config.timeoutMs,
2417
+ timeoutMs: config.timeoutMs,
2418
+ pricing: { ...pricing },
2419
+ recursiveLimits: {
2420
+ maxIterations: recursive?.maxIterations ?? 14,
2421
+ maxLlmCalls: recursive?.maxLlmCalls ?? 8,
2422
+ maxToolCalls: recursive?.maxToolCalls ?? 80,
2423
+ maxOutputChars: recursive?.maxOutputChars ?? 8e3,
2424
+ maxModelRequests: recursive?.maxModelRequests ?? null,
2425
+ traceToolRequestBytes: recursive?.traceToolRequestBytes ?? 1e6,
2426
+ traceToolResponseBytes: recursive?.traceToolResponseBytes ?? 4e6,
2427
+ traceToolTimeoutMs: recursive?.traceToolTimeoutMs ?? 6e4
2428
+ },
2429
+ processLimits: resolveExternalOptimizerProcessLimits(recursive?.runner?.limits)
2430
+ };
2431
+ }
2372
2432
  function createLocalRunReceipt(config, paths) {
2373
2433
  return {
2374
2434
  kind: "agent-eval/analyst-benchmark-local-run",
@@ -2377,8 +2437,7 @@ function createLocalRunReceipt(config, paths) {
2377
2437
  traceDir: resolve(config.traceDir),
2378
2438
  ...config.artifactDir ? { artifactDir: resolve(config.artifactDir) } : {},
2379
2439
  outputDir: paths.directory,
2380
- baseUrl: config.model.baseUrl,
2381
- apiKeyEnvironment: config.apiKeyEnv
2440
+ modelOwnerModule: config.modelOwnerModule
2382
2441
  },
2383
2442
  command: config.command,
2384
2443
  environment: {
@@ -2450,7 +2509,7 @@ async function readAndValidateResumeFiles(paths, currentIdentity, currentIdentit
2450
2509
  runIdentitySha256: currentIdentitySha256,
2451
2510
  localIdentitySha256: currentLocalIdentitySha256
2452
2511
  };
2453
- if (digestCanonical(value.local) !== currentLocalIdentitySha256 || canonicalJson(value.local) !== canonicalJson(localReceiptInput.local)) throw new Error("benchmark local paths or endpoint do not match the requested resume");
2512
+ if (digestCanonical(value.local) !== currentLocalIdentitySha256 || canonicalJson(value.local) !== canonicalJson(localReceiptInput.local)) throw new Error("benchmark local paths or model-owner module do not match the requested resume");
2454
2513
  if (localReceiptContent !== `${JSON.stringify(expectedLocalReceipt, null, 2)}\n`) throw new Error(`benchmark local run receipt does not exactly match: ${paths.localReceipt}`);
2455
2514
  if (await readRegularFile(paths.initializationComplete, "benchmark initialization marker") !== renderInitializationComplete(manifest)) throw new Error(`benchmark initialization marker does not match the run manifest: ${paths.initializationComplete}`);
2456
2515
  return manifest;
@@ -2996,8 +3055,16 @@ function assertCompletedArtifactMatchesRun(artifact, manifest, observations, pre
2996
3055
  concurrency: config.concurrency,
2997
3056
  ...config.rlmSamples === void 0 ? {} : { rlmSamples: config.rlmSamples },
2998
3057
  model: config.model.id,
3058
+ modelOwnerCallRef: config.model.ownerCallRef,
2999
3059
  maxOutputTokens: config.model.maxOutputTokens,
3060
+ maxReasoningTokens: config.model.maxReasoningTokens,
3061
+ maxModelRequestBytes: config.model.maxRequestBytes,
3062
+ maxModelResponseBytes: config.model.maxResponseBytes,
3063
+ modelRequestTimeoutMs: config.model.requestTimeoutMs,
3000
3064
  timeoutMs: config.model.timeoutMs,
3065
+ pricing: config.model.pricing,
3066
+ recursiveLimits: config.model.recursiveLimits,
3067
+ processLimits: config.model.processLimits,
3001
3068
  maxCostUsd: config.maxCostUsd,
3002
3069
  maxArtifactBytes: config.maxArtifactBytes,
3003
3070
  analystProtocolSha256: config.analystProtocolSha256,
@@ -3014,7 +3081,7 @@ function assertCompletedArtifactMatchesRun(artifact, manifest, observations, pre
3014
3081
  id: expectedDatasetId,
3015
3082
  revision: config.datasetRevision,
3016
3083
  split: config.datasetSplit
3017
- }) || provenance.caseCount !== inputs.selectedCaseIds.length || canonicalJson(provenance.runnerIds) !== canonicalJson(config.runnerIds) || provenance.repetitions !== config.repetitions || provenance.maxConcurrency !== Math.min(config.concurrency, expectedCount) || provenance.runnerOrderSeed !== config.seed || provenance.metadata?.model !== config.model.id || provenance.metadata?.rlmSamples !== config.rlmSamples || provenance.metadata?.outputAdapter !== expectedOutputAdapter || provenance.metadata?.caseSelection !== prepared.selection.method || provenance.metadata?.caseSelectionSeed !== config.seed || provenance.metadata?.selectionStratified !== prepared.selection.stratified || provenance.metadata?.protocolSha256 !== config.analystProtocolSha256 || provenance.metadata?.implementationSha256 !== config.implementationSha256 || provenance.metadata?.dependencyLockSha256 !== config.dependencyLockSha256 || provenance.metadata?.populationRepresentativenessProven !== false) throw new Error("completed benchmark result provenance does not match the run manifest");
3084
+ }) || provenance.caseCount !== inputs.selectedCaseIds.length || canonicalJson(provenance.runnerIds) !== canonicalJson(config.runnerIds) || provenance.repetitions !== config.repetitions || provenance.maxConcurrency !== Math.min(config.concurrency, expectedCount) || provenance.runnerOrderSeed !== config.seed || provenance.metadata?.model !== config.model.id || provenance.metadata?.modelOwnerCallRef !== config.model.ownerCallRef || provenance.metadata?.rlmSamples !== config.rlmSamples || provenance.metadata?.outputAdapter !== expectedOutputAdapter || provenance.metadata?.caseSelection !== prepared.selection.method || provenance.metadata?.caseSelectionSeed !== config.seed || provenance.metadata?.selectionStratified !== prepared.selection.stratified || provenance.metadata?.protocolSha256 !== config.analystProtocolSha256 || provenance.metadata?.implementationSha256 !== config.implementationSha256 || provenance.metadata?.dependencyLockSha256 !== config.dependencyLockSha256 || provenance.metadata?.populationRepresentativenessProven !== false) throw new Error("completed benchmark result provenance does not match the run manifest");
3018
3085
  const expectedSummaries = config.runnerIds.map((runnerId) => summarizeAnalystBenchmarkRunner(runnerId, observations.filter((observation) => observation.runnerId === runnerId)));
3019
3086
  if (canonicalJson(artifact.result.summaries) !== canonicalJson(expectedSummaries)) throw new Error("completed benchmark summaries do not match durable observations");
3020
3087
  const expectedComparisons = [compareAnalystRunners(artifact.result, {
@@ -3520,10 +3587,17 @@ function fileContext() {
3520
3587
  function createPublicBenchmarkDirectRunner(dataset, config) {
3521
3588
  if (config.instructionsOverride) throw new Error("the direct runner executes only the stock protocol; an instructions override requires the dspy-rlm runner");
3522
3589
  const model = requiredString(config.model, "model");
3523
- const baseUrl = requiredString(config.baseUrl, "baseUrl");
3524
- const apiKey = requiredString(config.apiKey, "apiKey");
3590
+ const callRef = requiredString(config.callRef, "callRef");
3591
+ if (typeof config.call !== "function") throw new TypeError("call must be a function");
3592
+ if (typeof config.recordExecution !== "function") throw new TypeError("recordExecution must be a function");
3525
3593
  const maxOutputTokens = positiveSafeInteger(config.maxOutputTokens, "maxOutputTokens");
3526
3594
  const timeoutMs = positiveSafeInteger(config.timeoutMs, "timeoutMs");
3595
+ const maxReasoningTokens = config.maxReasoningTokens ?? maxOutputTokens * 4;
3596
+ const maxModelRequestBytes = config.maxModelRequestBytes ?? 16 * 1024 * 1024;
3597
+ const maxModelResponseBytes = config.maxModelResponseBytes ?? 4 * 1024 * 1024;
3598
+ const modelRequestTimeoutMs = config.modelRequestTimeoutMs ?? timeoutMs;
3599
+ const pricing = config.pricing ?? pricingForModel$1(model);
3600
+ const maxCostUsd = config.maxCostUsdPerAnalysis ?? 1;
3527
3601
  const costLedger = config.costLedger ?? new CostLedger();
3528
3602
  const durability = config.durability ? {
3529
3603
  runIdentitySha256: requiredString(config.durability.runIdentitySha256, "durability.runIdentitySha256"),
@@ -3531,15 +3605,6 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3531
3605
  } : void 0;
3532
3606
  const actor = dataset === "agentrx" ? "agentrx-root-cause-localizer" : "codetracebench-step-localizer";
3533
3607
  const outputAdapter = dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block";
3534
- const llmOptions = {
3535
- baseUrl,
3536
- apiKey,
3537
- maximumAttempts: 1,
3538
- jsonSchemaTransport: "json-object",
3539
- jsonPayloadMode: "exact",
3540
- thinking: "disabled",
3541
- ...config.fetchImpl ? { fetch: config.fetchImpl } : {}
3542
- };
3543
3608
  return {
3544
3609
  id: "direct",
3545
3610
  async analyze(input, context) {
@@ -3557,7 +3622,8 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3557
3622
  let modelMetadata = {
3558
3623
  analysisMode: "direct-baseline",
3559
3624
  outputAdapter,
3560
- protocolSha256: publicBenchmarkProtocolSha256(dataset)
3625
+ protocolSha256: publicBenchmarkProtocolSha256(dataset),
3626
+ callRef
3561
3627
  };
3562
3628
  try {
3563
3629
  if (!input.traceStore) throw new Error(`${dataset} model runner requires a trace store`);
@@ -3575,7 +3641,7 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3575
3641
  jsonMode: true,
3576
3642
  thinking: "disabled",
3577
3643
  maxTokens: maxOutputTokens,
3578
- timeoutMs
3644
+ timeoutMs: modelRequestTimeoutMs
3579
3645
  };
3580
3646
  const cacheIdentity = durability ? {
3581
3647
  runIdentitySha256: durability.runIdentitySha256,
@@ -3614,26 +3680,51 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3614
3680
  };
3615
3681
  } else {
3616
3682
  assertNoSettledResponseWithoutCache(costLedger, callId);
3617
- let completedResult;
3618
- const paid = await costLedger.runPaidCall({
3619
- ...callId ? { callId } : {},
3620
- channel: "analyst",
3621
- phase: "analyst.public-benchmark",
3622
- actor,
3623
- model,
3624
- signal: context.signal,
3625
- maximumCharge: maximumChargeForLlmRequest(request, llmOptions),
3626
- tags: costTags,
3627
- execute: async (signal, providerCallId) => {
3683
+ const providerCallId = callId ?? `analyst-benchmark-${randomUUID()}`;
3684
+ let modelProxy;
3685
+ const completed = await runWithCleanup({
3686
+ label: "public benchmark direct model resources",
3687
+ run: async () => {
3688
+ modelProxy = await startExternalOptimizerModelProxy({
3689
+ call: config.call,
3690
+ callRef,
3691
+ recordExecution: config.recordExecution,
3692
+ model,
3693
+ budget: {
3694
+ maxCostUsd,
3695
+ maxRequests: 1,
3696
+ maxRequestBytes: maxModelRequestBytes,
3697
+ maxResponseBytes: maxModelResponseBytes,
3698
+ maxOutputTokensPerRequest: maxOutputTokens,
3699
+ maxReasoningTokensPerRequest: maxReasoningTokens,
3700
+ pricing,
3701
+ requestTimeoutMs: modelRequestTimeoutMs
3702
+ },
3703
+ costLedger,
3704
+ channel: "analyst",
3705
+ phase: "analyst.public-benchmark",
3706
+ actor,
3707
+ tags: costTags,
3708
+ callId: providerCallId,
3709
+ ...context.signal ? { signal: context.signal } : {}
3710
+ });
3711
+ const llmOptions = {
3712
+ baseUrl: modelProxy.baseUrl,
3713
+ apiKey: modelProxy.apiKey,
3714
+ maximumAttempts: 1,
3715
+ jsonSchemaTransport: "json-object",
3716
+ jsonPayloadMode: "exact",
3717
+ thinking: "disabled"
3718
+ };
3628
3719
  try {
3629
3720
  const completed = await callLlmJson(request, {
3630
3721
  ...llmOptions,
3631
- signal,
3722
+ ...context.signal ? { signal: context.signal } : {},
3632
3723
  idempotencyKey: providerCallId
3633
3724
  });
3634
- completedResult = completed.result;
3635
3725
  const response = parsePublicBenchmarkModelResponse(dataset, completed.value);
3636
3726
  const responseProducedAt = (/* @__PURE__ */ new Date()).toISOString();
3727
+ const receipt = requiredSettledReceipt(costLedger, providerCallId);
3637
3728
  if (cacheIdentity) writePublicBenchmarkResponseCache(durability.responseCacheDir, {
3638
3729
  kind: "agent-eval/public-benchmark-model-response",
3639
3730
  ...cacheIdentity,
@@ -3646,42 +3737,49 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3646
3737
  finishReason: completed.result.finishReason ?? null,
3647
3738
  producedAt: responseProducedAt
3648
3739
  },
3649
- receipt: costReceiptFromLlm(completed.result)
3740
+ receipt: cacheReceiptInput(receipt)
3650
3741
  });
3742
+ modelProxy.assertExecutionComplete();
3651
3743
  return {
3652
3744
  ...completed,
3653
3745
  response,
3654
- producedAt: responseProducedAt
3746
+ producedAt: responseProducedAt,
3747
+ receipt
3655
3748
  };
3656
3749
  } catch (error) {
3657
- if (cacheIdentity) writePublicBenchmarkResponseCache(durability.responseCacheDir, {
3658
- kind: "agent-eval/public-benchmark-model-response",
3659
- ...cacheIdentity,
3660
- callId: providerCallId,
3661
- status: "failed",
3662
- error: publicBenchmarkError(error, [apiKey]),
3663
- receipt: receiptForProviderFailure(error, completedResult, model)
3664
- });
3750
+ const controlFailure = modelProxy.failures().find(isPaidCallControlError$1);
3751
+ if (controlFailure) throw controlFailure;
3752
+ const receipt = settledReceipt(costLedger, providerCallId);
3753
+ if (cacheIdentity) {
3754
+ if (receipt) writePublicBenchmarkResponseCache(durability.responseCacheDir, {
3755
+ kind: "agent-eval/public-benchmark-model-response",
3756
+ ...cacheIdentity,
3757
+ callId: providerCallId,
3758
+ status: "failed",
3759
+ error: publicBenchmarkError(error, []),
3760
+ receipt: cacheReceiptInput(receipt)
3761
+ });
3762
+ }
3665
3763
  throw error;
3666
3764
  }
3667
3765
  },
3668
- receipt: ({ result }) => costReceiptFromLlm(result),
3669
- receiptFromError: (error) => receiptForProviderFailure(error, completedResult, model)
3766
+ cleanup: async () => {
3767
+ await modelProxy?.close();
3768
+ }
3670
3769
  });
3671
- if (!paid.succeeded) throw paid.error;
3672
- const response = paid.value.response;
3770
+ const response = completed.response;
3673
3771
  rawPredictions = response.findings;
3674
3772
  rejectedBlocks = response.rejectedBlocks;
3675
- providerModel = paid.value.result.model;
3676
- producedAt = paid.value.producedAt;
3773
+ providerModel = completed.result.model;
3774
+ producedAt = completed.producedAt;
3677
3775
  modelMetadata = {
3678
3776
  ...modelMetadata,
3679
3777
  responseSource: "provider",
3680
3778
  report: response.report,
3681
- providerModel: paid.value.result.model,
3682
- providerDurationMs: paid.value.result.durationMs,
3683
- finishReason: paid.value.result.finishReason ?? null,
3684
- cost: costReceiptMetadata(paid.receipt)
3779
+ providerModel: completed.result.model,
3780
+ providerDurationMs: completed.result.durationMs,
3781
+ finishReason: completed.result.finishReason ?? null,
3782
+ cost: costReceiptMetadata(completed.receipt)
3685
3783
  };
3686
3784
  }
3687
3785
  const converted = await publicBenchmarkPredictionsToFindings({
@@ -3725,7 +3823,7 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3725
3823
  channel: "analyst",
3726
3824
  tags: costTags
3727
3825
  }),
3728
- error: publicBenchmarkError(error, [apiKey]),
3826
+ error: publicBenchmarkError(error, []),
3729
3827
  metadata: {
3730
3828
  ...modelMetadata,
3731
3829
  rawPredictions,
@@ -3759,18 +3857,48 @@ function assertCacheReceiptMatches(cached, receipt) {
3759
3857
  function isPaidCallControlError$1(error) {
3760
3858
  return error instanceof CostAccountingIncompleteError || error instanceof CostCallConflictError || error instanceof CostCeilingReachedError || error instanceof CostLedgerPersistenceError || error instanceof CostReceiptCaptureError || error instanceof CostReservationExceededError;
3761
3859
  }
3762
- function receiptForProviderFailure(error, completedResult, model) {
3763
- if (completedResult) return costReceiptFromLlm(completedResult);
3764
- if (error instanceof Error) {
3765
- const captured = costReceiptFromLlmError(error);
3766
- if (captured) return captured;
3767
- }
3860
+ function settledReceipt(costLedger, callId) {
3861
+ return costLedger.list().find((receipt) => receipt.callId === callId);
3862
+ }
3863
+ function requiredSettledReceipt(costLedger, callId) {
3864
+ const receipt = settledReceipt(costLedger, callId);
3865
+ if (!receipt) throw new CostAccountingIncompleteError(`caller-owned model call '${callId}' produced no cost receipt`);
3866
+ return receipt;
3867
+ }
3868
+ function cacheReceiptInput(receipt) {
3869
+ const usage = {
3870
+ model: receipt.model,
3871
+ inputTokens: receipt.inputTokens,
3872
+ outputTokens: receipt.outputTokens,
3873
+ ...receipt.reasoningTokens === void 0 ? {} : { reasoningTokens: receipt.reasoningTokens },
3874
+ ...receipt.cachedTokens === void 0 ? {} : { cachedTokens: receipt.cachedTokens },
3875
+ ...receipt.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: receipt.cacheWriteTokens },
3876
+ ...receipt.usageUnknown === void 0 ? {} : { usageUnknown: receipt.usageUnknown }
3877
+ };
3878
+ if (receipt.costUnknown) return {
3879
+ ...usage,
3880
+ costUnknown: true
3881
+ };
3882
+ if (receipt.actualCostUsd !== void 0) return {
3883
+ ...usage,
3884
+ actualCostUsd: receipt.actualCostUsd
3885
+ };
3886
+ if (receipt.estimatedCostUsd !== void 0) return {
3887
+ ...usage,
3888
+ estimatedCostUsd: receipt.estimatedCostUsd
3889
+ };
3890
+ if (receipt.pricing) return {
3891
+ ...usage,
3892
+ customTokenPricing: {
3893
+ inputUsdPerMillion: receipt.pricing.inputUsdPerThousand * 1e3,
3894
+ ...receipt.pricing.cachedInputUsdPerThousand === void 0 ? {} : { cachedInputUsdPerMillion: receipt.pricing.cachedInputUsdPerThousand * 1e3 },
3895
+ ...receipt.pricing.cacheWriteUsdPerThousand === void 0 ? {} : { cacheWriteUsdPerMillion: receipt.pricing.cacheWriteUsdPerThousand * 1e3 },
3896
+ outputUsdPerMillion: receipt.pricing.outputUsdPerThousand * 1e3
3897
+ }
3898
+ };
3768
3899
  return {
3769
- model,
3770
- inputTokens: 0,
3771
- outputTokens: 0,
3772
- costUnknown: true,
3773
- usageUnknown: true
3900
+ ...usage,
3901
+ estimatedCostUsd: receipt.costUsd
3774
3902
  };
3775
3903
  }
3776
3904
  function costReceiptMetadata(receipt) {
@@ -3792,6 +3920,14 @@ function costReceiptMetadata(receipt) {
3792
3920
  estimatedCostUsd: null
3793
3921
  };
3794
3922
  }
3923
+ function pricingForModel$1(model) {
3924
+ const pricing = resolveModelPricing(model);
3925
+ if (!pricing) throw new Error(`no pricing is configured for '${model}'; provide PublicAnalystBenchmarkModelConfig.pricing`);
3926
+ return {
3927
+ inputUsdPerMillion: pricing.input * 1e3,
3928
+ outputUsdPerMillion: pricing.output * 1e3
3929
+ };
3930
+ }
3795
3931
  const ModelSeveritySchema = z.enum([
3796
3932
  "critical",
3797
3933
  "high",
@@ -4111,13 +4247,24 @@ function createPublicBenchmarkRlmRunner(dataset, config) {
4111
4247
  };
4112
4248
  const pricing = config.pricing ?? pricingForModel(config.model);
4113
4249
  const engine = createDspyRlmTraceEngine({
4114
- baseUrl: config.baseUrl,
4115
- apiKey: config.apiKey,
4250
+ call: config.call,
4251
+ callRef: config.callRef,
4252
+ recordExecution: config.recordExecution,
4116
4253
  model: config.model,
4117
4254
  maxOutputTokens: config.maxOutputTokens,
4118
4255
  timeoutMs: config.timeoutMs,
4119
4256
  maxCostUsd: config.maxCostUsdPerAnalysis ?? 1,
4120
4257
  pricing,
4258
+ ...config.maxReasoningTokens === void 0 ? {} : { maxReasoningTokens: config.maxReasoningTokens },
4259
+ ...config.maxModelRequestBytes === void 0 ? {} : { maxModelRequestBytes: config.maxModelRequestBytes },
4260
+ ...config.maxModelResponseBytes === void 0 ? {} : { maxModelResponseBytes: config.maxModelResponseBytes },
4261
+ ...config.modelRequestTimeoutMs === void 0 ? {} : { modelRequestTimeoutMs: config.modelRequestTimeoutMs },
4262
+ ...config.dspyRlm?.maxModelRequests === void 0 ? {} : { maxModelRequests: config.dspyRlm.maxModelRequests },
4263
+ ...config.dspyRlm?.traceToolRequestBytes === void 0 && config.dspyRlm?.traceToolResponseBytes === void 0 ? {} : { traceToolLimits: {
4264
+ ...config.dspyRlm?.traceToolRequestBytes === void 0 ? {} : { maxRequestBytes: config.dspyRlm.traceToolRequestBytes },
4265
+ ...config.dspyRlm?.traceToolResponseBytes === void 0 ? {} : { maxResponseBytes: config.dspyRlm.traceToolResponseBytes }
4266
+ } },
4267
+ ...config.dspyRlm?.traceToolTimeoutMs === void 0 ? {} : { traceToolTimeoutMs: config.dspyRlm.traceToolTimeoutMs },
4121
4268
  ...config.dspyRlm?.runner ? { runner: config.dspyRlm.runner } : {}
4122
4269
  });
4123
4270
  const instructions = config.instructionsOverride?.text ?? publicBenchmarkRlmInstructions(dataset);
@@ -4328,7 +4475,7 @@ function createPublicBenchmarkRlmRunner(dataset, config) {
4328
4475
  return {
4329
4476
  findings: [],
4330
4477
  usage,
4331
- error: publicBenchmarkError(error, [config.apiKey]),
4478
+ error: publicBenchmarkError(error, []),
4332
4479
  metadata: {
4333
4480
  analysisMode: "recursive",
4334
4481
  engine: "dspy-rlm",
@@ -4786,7 +4933,7 @@ async function runAnalystBenchmarkCommand(argv, env = process.env, dependencies
4786
4933
  process.stdout.write(`${ANALYST_BENCHMARK_HELP}\n`);
4787
4934
  return 0;
4788
4935
  }
4789
- const config = parseCommandConfig(argv, env);
4936
+ const config = await parseCommandConfig(argv, env, dependencies);
4790
4937
  const outputLock = acquireSingleRunLock({ lockPath: await prepareOutputLockPath(config.outDir) });
4791
4938
  try {
4792
4939
  return await executeAnalystBenchmarkCommand(config, dependencies);
@@ -4869,6 +5016,7 @@ async function executeAnalystBenchmarkCommand(config, dependencies) {
4869
5016
  },
4870
5017
  metadata: {
4871
5018
  model: config.model.model,
5019
+ modelOwnerCallRef: config.model.callRef,
4872
5020
  rlmSamples: config.rlmSamples,
4873
5021
  outputAdapter: config.dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block",
4874
5022
  caseSelection: prepared.selection.method,
@@ -4920,8 +5068,16 @@ async function executeAnalystBenchmarkCommand(config, dependencies) {
4920
5068
  concurrency: config.concurrency,
4921
5069
  rlmSamples: config.rlmSamples,
4922
5070
  model: config.model.model,
4923
- maxOutputTokens: config.model.maxOutputTokens,
4924
- timeoutMs: config.model.timeoutMs,
5071
+ modelOwnerCallRef: manifest.identity.config.model.ownerCallRef,
5072
+ maxOutputTokens: manifest.identity.config.model.maxOutputTokens,
5073
+ maxReasoningTokens: manifest.identity.config.model.maxReasoningTokens,
5074
+ maxModelRequestBytes: manifest.identity.config.model.maxRequestBytes,
5075
+ maxModelResponseBytes: manifest.identity.config.model.maxResponseBytes,
5076
+ modelRequestTimeoutMs: manifest.identity.config.model.requestTimeoutMs,
5077
+ timeoutMs: manifest.identity.config.model.timeoutMs,
5078
+ pricing: manifest.identity.config.model.pricing,
5079
+ recursiveLimits: manifest.identity.config.model.recursiveLimits,
5080
+ processLimits: manifest.identity.config.model.processLimits,
4925
5081
  maxCostUsd: config.maxCostUsd,
4926
5082
  maxArtifactBytes: config.maxArtifactBytes,
4927
5083
  analystProtocolSha256: effectiveAnalystProtocolSha256(config.dataset, config.model.instructionsOverride),
@@ -4988,16 +5144,15 @@ Run the recursive DSPy trace analyst against public AgentRx or CodeTraceBench la
4988
5144
  Required:
4989
5145
  --dataset agentrx|codetracebench
4990
5146
  --analyst dspy-rlm|direct Scored analyst. Default: dspy-rlm.
4991
- 'direct' is the retired one-shot runner that
4992
- produced the published evidence.
5147
+ 'direct' is the one-shot comparison arm.
4993
5148
  --labels <dataset.json|dataset.jsonl>
4994
5149
  --trace-dir <one-trace-per-file OTLP JSONL directory>
4995
5150
  --artifact-dir <extracted artifact root> Required for CodeTraceBench
4996
5151
  --out <new output directory>
4997
5152
  --revision <full 40- or 64-character hex digest>
4998
5153
  --split <dataset split>
4999
- --base-url <OpenAI-compatible /v1 URL>
5000
- --api-key-env <environment variable containing the bearer>
5154
+ --model-owner-module <module> Module exporting createModelExecutionOwner;
5155
+ the owner keeps provider credentials and policy
5001
5156
  --model <provider model id>
5002
5157
  --limit <positive case count>
5003
5158
 
@@ -5015,6 +5170,22 @@ Controls:
5015
5170
  protocol to the override text, and
5016
5171
  result.json records instructionsOverrideSha256.
5017
5172
  --max-output-tokens <positive> Model output limit per call. Default: 16384
5173
+ --max-reasoning-tokens <integer> Reasoning-token limit per call. Default: 65536
5174
+ --max-model-requests <positive> Caller-owned model calls per analysis.
5175
+ Default: max iterations + model calls + 1
5176
+ --max-model-request-bytes <positive> Default: 16777216
5177
+ --max-model-response-bytes <positive> Default: 4194304
5178
+ --model-request-timeout-ms <positive> Default: --timeout-ms
5179
+ --max-iterations <positive> Recursive iterations per analysis. Default: 14
5180
+ --max-llm-calls <positive> DSPy model calls per analysis. Default: 8
5181
+ --max-tool-calls <positive> Trace-tool calls per analysis. Default: 80
5182
+ --max-analysis-output-chars <positive> Default: 8000
5183
+ --trace-tool-request-bytes <positive> Default: 1000000
5184
+ --trace-tool-response-bytes <positive> Default: 4000000
5185
+ --trace-tool-timeout-ms <positive> Default: 60000
5186
+ --max-process-input-bytes <positive> Default: 67108864
5187
+ --max-process-result-bytes <positive> Default: 4194304
5188
+ --max-process-output-chars <positive> Default: 64000
5018
5189
  --python <executable> Python with agent-eval-rpc[dspy]. Default: python
5019
5190
  --timeout-ms <positive> Model analyst deadline per case. Default: 300000
5020
5191
  --max-cost-usd <positive> Run-wide spend limit. Default: 5
@@ -5024,20 +5195,15 @@ Writes result.json with every observation, metric, usage field, error, compariso
5024
5195
  input digest, artifact digest, case distribution, selected case id, and explicit
5025
5196
  unknown cost. Limited deterministic-hash subsets are marked non-representative.
5026
5197
  Completed observations are fsynced to observations.jsonl. Shareable output is in
5027
- result.json and report.md. Machine-local paths, endpoint, and command are isolated
5028
- in run.local.json.
5029
- The key is read from the named environment variable and is never written.`;
5030
- function parseCommandConfig(argv, env) {
5198
+ result.json and report.md. Machine-local paths, execution-owner module, and command
5199
+ are isolated in run.local.json. Provider credentials never enter this command.`;
5200
+ async function parseCommandConfig(argv, env, dependencies) {
5031
5201
  const flags = parseFlags(argv);
5032
5202
  assertKnownFlags(flags);
5033
5203
  const dataset = requiredFlag(flags, "dataset");
5034
5204
  if (dataset !== "agentrx" && dataset !== "codetracebench") throw new Error("--dataset must be 'agentrx' or 'codetracebench'");
5035
5205
  const artifactDir = flags.get("artifact-dir")?.trim();
5036
5206
  if (dataset === "codetracebench" && !artifactDir) throw new Error("--artifact-dir is required for CodeTraceBench");
5037
- const apiKeyEnv = requiredFlag(flags, "api-key-env");
5038
- if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(apiKeyEnv)) throw new Error("--api-key-env must be a valid environment variable name");
5039
- const apiKey = env[apiKeyEnv]?.trim();
5040
- if (!apiKey) throw new Error(`--api-key-env points to an empty or missing variable: ${apiKeyEnv}`);
5041
5207
  const maxCostUsd = positiveFiniteFlag(flags, "max-cost-usd", 5);
5042
5208
  const python = flags.get("python")?.trim();
5043
5209
  const analyst = flags.get("analyst")?.trim() ?? "dspy-rlm";
@@ -5048,6 +5214,16 @@ function parseCommandConfig(argv, env) {
5048
5214
  if (instructionsFile && analyst !== "dspy-rlm") throw new Error("--instructions-file requires --analyst dspy-rlm");
5049
5215
  const instructionsOverride = instructionsFile ? readAnalystInstructionsOverride(instructionsFile) : void 0;
5050
5216
  if (rlmSamples > 1 && dataset !== "codetracebench") throw new Error("--rlm-samples above 1 requires --dataset codetracebench; step-level consensus is defined on its block grammar");
5217
+ const model = requiredFlag(flags, "model");
5218
+ const modelOwnerModule = requiredFlag(flags, "model-owner-module");
5219
+ const owner = await (dependencies.loadModelExecutionOwner ?? loadModelExecutionOwner)(modelOwnerModule, {
5220
+ model,
5221
+ environment: Object.freeze({ ...env })
5222
+ });
5223
+ assertModelExecutionOwner(owner);
5224
+ const pricing = owner.pricing ?? benchmarkModelPricing(model);
5225
+ const maxOutputTokens = positiveFlag(flags, "max-output-tokens", 16384);
5226
+ const timeoutMs = positiveFlag(flags, "timeout-ms", 3e5);
5051
5227
  return {
5052
5228
  dataset,
5053
5229
  analyst,
@@ -5058,15 +5234,36 @@ function parseCommandConfig(argv, env) {
5058
5234
  revision: immutableRevision(requiredFlag(flags, "revision")),
5059
5235
  split: requiredFlag(flags, "split"),
5060
5236
  model: {
5061
- baseUrl: openAiCompatibleBaseUrl(requiredFlag(flags, "base-url")),
5062
- apiKey,
5063
- model: requiredFlag(flags, "model"),
5064
- maxOutputTokens: positiveFlag(flags, "max-output-tokens", 16384),
5065
- timeoutMs: positiveFlag(flags, "timeout-ms", 3e5),
5237
+ call: owner.call,
5238
+ callRef: owner.callRef,
5239
+ recordExecution: owner.recordExecution,
5240
+ model,
5241
+ maxOutputTokens,
5242
+ timeoutMs,
5243
+ maxReasoningTokens: nonNegativeFlag(flags, "max-reasoning-tokens", maxOutputTokens * 4),
5244
+ maxModelRequestBytes: positiveFlag(flags, "max-model-request-bytes", 16 * 1024 * 1024),
5245
+ maxModelResponseBytes: positiveFlag(flags, "max-model-response-bytes", 4 * 1024 * 1024),
5246
+ modelRequestTimeoutMs: positiveFlag(flags, "model-request-timeout-ms", timeoutMs),
5247
+ pricing,
5066
5248
  maxCostUsdPerAnalysis: maxCostUsd,
5067
5249
  ...instructionsOverride ? { instructionsOverride } : {},
5068
5250
  dspyRlm: {
5069
- ...python ? { runner: { command: python } } : {},
5251
+ runner: {
5252
+ ...python ? { command: python } : {},
5253
+ limits: {
5254
+ maxInputBytes: positiveFlag(flags, "max-process-input-bytes", 64 * 1024 * 1024),
5255
+ maxResultBytes: positiveFlag(flags, "max-process-result-bytes", 4 * 1024 * 1024),
5256
+ maxOutputChars: positiveFlag(flags, "max-process-output-chars", 64e3)
5257
+ }
5258
+ },
5259
+ maxIterations: positiveFlag(flags, "max-iterations", 14),
5260
+ maxLlmCalls: positiveFlag(flags, "max-llm-calls", 8),
5261
+ maxToolCalls: positiveFlag(flags, "max-tool-calls", 80),
5262
+ maxOutputChars: positiveFlag(flags, "max-analysis-output-chars", 8e3),
5263
+ ...flags.has("max-model-requests") ? { maxModelRequests: positiveFlag(flags, "max-model-requests") } : {},
5264
+ traceToolRequestBytes: positiveFlag(flags, "trace-tool-request-bytes", 1e6),
5265
+ traceToolResponseBytes: positiveFlag(flags, "trace-tool-response-bytes", 4e6),
5266
+ traceToolTimeoutMs: positiveFlag(flags, "trace-tool-timeout-ms", 6e4),
5070
5267
  samples: rlmSamples
5071
5268
  }
5072
5269
  },
@@ -5077,7 +5274,7 @@ function parseCommandConfig(argv, env) {
5077
5274
  rlmSamples,
5078
5275
  maxCostUsd,
5079
5276
  maxArtifactBytes: positiveFlag(flags, "max-artifact-bytes", DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES),
5080
- apiKeyEnv,
5277
+ modelOwnerModule,
5081
5278
  command: `agent-eval analyst-benchmark ${argv.filter((argument) => argument !== "--resume").map(shellQuote).join(" ")}`,
5082
5279
  resume: flags.has("resume")
5083
5280
  };
@@ -5113,8 +5310,7 @@ const KNOWN_FLAGS = /* @__PURE__ */ new Set([
5113
5310
  "out",
5114
5311
  "revision",
5115
5312
  "split",
5116
- "base-url",
5117
- "api-key-env",
5313
+ "model-owner-module",
5118
5314
  "model",
5119
5315
  "limit",
5120
5316
  "seed",
@@ -5123,6 +5319,21 @@ const KNOWN_FLAGS = /* @__PURE__ */ new Set([
5123
5319
  "rlm-samples",
5124
5320
  "instructions-file",
5125
5321
  "max-output-tokens",
5322
+ "max-reasoning-tokens",
5323
+ "max-model-requests",
5324
+ "max-model-request-bytes",
5325
+ "max-model-response-bytes",
5326
+ "model-request-timeout-ms",
5327
+ "max-iterations",
5328
+ "max-llm-calls",
5329
+ "max-tool-calls",
5330
+ "max-analysis-output-chars",
5331
+ "trace-tool-request-bytes",
5332
+ "trace-tool-response-bytes",
5333
+ "trace-tool-timeout-ms",
5334
+ "max-process-input-bytes",
5335
+ "max-process-result-bytes",
5336
+ "max-process-output-chars",
5126
5337
  "python",
5127
5338
  "timeout-ms",
5128
5339
  "max-cost-usd",
@@ -5152,6 +5363,13 @@ function integerFlag(flags, name, defaultValue) {
5152
5363
  if (!Number.isSafeInteger(value)) throw new Error(`--${name} must be a safe integer`);
5153
5364
  return value;
5154
5365
  }
5366
+ function nonNegativeFlag(flags, name, defaultValue) {
5367
+ const raw = flags.get(name);
5368
+ if (raw === void 0) return defaultValue;
5369
+ const value = Number(raw);
5370
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error(`--${name} must be a non-negative safe integer`);
5371
+ return value;
5372
+ }
5155
5373
  function positiveFiniteFlag(flags, name, defaultValue) {
5156
5374
  const raw = flags.get(name);
5157
5375
  if (raw === void 0) return defaultValue;
@@ -5159,20 +5377,24 @@ function positiveFiniteFlag(flags, name, defaultValue) {
5159
5377
  if (!Number.isFinite(value) || value <= 0) throw new Error(`--${name} must be a positive finite number`);
5160
5378
  return value;
5161
5379
  }
5162
- function openAiCompatibleBaseUrl(value) {
5163
- let parsed;
5164
- try {
5165
- parsed = new URL(value);
5166
- } catch {
5167
- throw new Error("--base-url must be an absolute HTTP or HTTPS URL");
5168
- }
5169
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.search || parsed.hash) throw new Error("--base-url must use HTTP or HTTPS without credentials, query, or fragment");
5170
- if (parsed.protocol === "http:" && !isLoopbackHost(parsed.hostname)) throw new Error("--base-url must use HTTPS unless the endpoint is on the local machine");
5171
- return value;
5380
+ async function loadModelExecutionOwner(moduleRef, context) {
5381
+ const imported = await (moduleRef.startsWith(".") || moduleRef.startsWith("/") ? import(pathToFileURL(resolve(moduleRef)).href) : import(moduleRef));
5382
+ if (typeof imported.createModelExecutionOwner !== "function") throw new Error(`${moduleRef} must export createModelExecutionOwner({ model, environment })`);
5383
+ return imported.createModelExecutionOwner(context);
5384
+ }
5385
+ function assertModelExecutionOwner(value) {
5386
+ if (!value || typeof value !== "object") throw new Error("createModelExecutionOwner must return an object");
5387
+ if (typeof value.call !== "function") throw new Error("model execution owner call must be a function");
5388
+ if (typeof value.callRef !== "string" || !value.callRef.trim() || value.callRef !== value.callRef.trim()) throw new Error("model execution owner callRef must be trimmed and non-empty");
5389
+ if (typeof value.recordExecution !== "function") throw new Error("model execution owner recordExecution must be a function");
5172
5390
  }
5173
- function isLoopbackHost(hostname) {
5174
- const normalized = hostname.toLowerCase();
5175
- return normalized === "localhost" || normalized === "[::1]" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
5391
+ function benchmarkModelPricing(model) {
5392
+ const pricing = resolveModelPricing(model);
5393
+ if (!pricing) throw new Error(`model execution owner must supply pricing for uncatalogued model '${model}'`);
5394
+ return {
5395
+ inputUsdPerMillion: pricing.input * 1e3,
5396
+ outputUsdPerMillion: pricing.output * 1e3
5397
+ };
5176
5398
  }
5177
5399
  function immutableRevision(value) {
5178
5400
  if (!/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(value)) throw new Error("--revision must be a full 40- or 64-character hexadecimal digest");
@@ -5247,4 +5469,4 @@ function shellQuote(value) {
5247
5469
  //#endregion
5248
5470
  export { normalizeAgentRxCategory as $, parseVerificationOutcome as A, analystBenchmarkDependencyLockDigest as B, MAX_INCORRECT_BLOCK_STEPS as C, DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES as D, publicBenchmarkSystemPrompt as E, ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256 as F, ANALYST_BENCHMARK_OBSERVATIONS_FILE as G, ANALYST_BENCHMARK_COST_LEDGER_FILE as H, ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION as I, summarizeAgentRxCalibration as J, AGENT_RX_UPSTREAM_REVISION as K, ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM as L, ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES as M, ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 as N, appendVerificationArtifactsToOtlp as O, ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256 as P, agentRxPredictionsToFindings as Q, ANALYST_BENCHMARK_IMPLEMENTATION_FILES as R, MAX_INCORRECT_BLOCKS as S, publicBenchmarkRlmInstructions as T, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE as U, analystBenchmarkImplementationDigest as V, ANALYST_BENCHMARK_MANIFEST_FILE as W, codeTracerPredictionsToFindings as X, codeTraceBenchCase as Y, agentRxBenchmarkCase as Z, compareAnalystRunners as _, preparePublicAnalystBenchmark as a, readAnalystInstructionsOverride as b, selectPublicBenchmarkRows as c, adaptPublicBenchmarkFindings as d, roundAgentRxStep as et, emptyPublicBenchmarkRunner as f, summarizeCodeTraceCalibration as g, renderCodeTraceCalibrationMarkdown as h, loadPublicBenchmarkRows as i, ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM as j, loadCodeTraceVerificationArtifacts as k, createPublicBenchmarkRlmRunner as l, readAnalystBenchmarkArtifact as m, runAnalystBenchmarkCommand as n, publicBenchmarkDistributions as o, expandCodeTraceFailureBlocks as p, renderAgentRxCalibrationMarkdown as q, renderAnalystBenchmarkMarkdown as r, publicBenchmarkSelectionReport as s, ANALYST_BENCHMARK_HELP as t, normalizeBenchmarkLabel as tt, createPublicBenchmarkDirectRunner as u, analystInstructionsOverrideFromText as v, publicBenchmarkProtocolSha256 as w, CODE_TRACE_BENCH_ANALYST_PROMPT as x, effectiveAnalystProtocolSha256 as y, ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 as z };
5249
5471
 
5250
- //# sourceMappingURL=benchmark-command-CSddvlq7.js.map
5472
+ //# sourceMappingURL=benchmark-command-95Zqd1e8.js.map