@tangle-network/agent-bench 0.8.32 → 0.9.0
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/CHANGELOG.md +9 -0
- package/HARNESS.md +9 -2
- package/dist/index.d.ts +27 -10
- package/dist/index.js +135 -38
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/scripts/verify-pier-agent.mts +1 -1
- package/scripts/verify-pier-recovery.mts +2 -1
- package/src/index.ts +1 -0
- package/src/pier-agent.test.mts +1 -1
- package/src/pier-agent.ts +3 -2
- package/src/pier-trial-controller.test.mts +7 -5
- package/src/pier-trial-controller.ts +2 -1
- package/src/run-benchmarks.test.mts +86 -4
- package/src/run-benchmarks.ts +128 -28
- package/src/sandbox-run.ts +2 -1
- package/src/swe-arena/activation.test.mts +1 -0
- package/src/swe-arena/briefing.test.mts +1 -0
- package/src/swe-arena/execution.test.mts +3 -2
- package/src/swe-arena/factory.test.mts +5 -3
- package/src/swe-arena/gepa-seat.test.mts +2 -0
- package/src/swe-arena/premeasured-from-cells.test.mts +1 -0
- package/src/swe-arena/proc.test.mts +3 -5
- package/src/swe-arena/proposer-fanout.test.mts +1 -0
- package/src/swe-arena/run-experiment.mts +2 -0
- package/src/swe-arena/scratch-worktree.test.mts +2 -1
- package/src/swe-bench-env.test.ts +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.34
|
|
4
|
+
|
|
5
|
+
The dependency range requires Knowledge 14.0.3 for the compatible Eval cohort.
|
|
6
|
+
|
|
7
|
+
## 0.8.33
|
|
8
|
+
|
|
9
|
+
Requires Eval `>=0.175.0 <0.176.0`, following Runtime 0.197.0.
|
|
10
|
+
No behavior change.
|
|
11
|
+
|
|
3
12
|
## 0.8.32
|
|
4
13
|
|
|
5
14
|
The dependency ranges now require Runtime 0.195.0, Eval 0.174, and Knowledge 14.
|
package/HARNESS.md
CHANGED
|
@@ -18,7 +18,7 @@ Use these labels literally. Do not promote one level into another in prose.
|
|
|
18
18
|
|
|
19
19
|
| Level | What it establishes | Canonical path |
|
|
20
20
|
|---|---|---|
|
|
21
|
-
| **contract proof** | packages install; identities, budgets, callbacks, resume, and receipts have the expected shape | root `pnpm verify:official-optimizers`, `pnpm verify:
|
|
21
|
+
| **contract proof** | packages install; identities, budgets, callbacks, resume, and receipts have the expected shape | root `pnpm verify:official-optimizers`, `pnpm verify:bench` |
|
|
22
22
|
| **evaluator proof** | the benchmark's own evaluator can distinguish known fail/pass artifacts in the exact environment | adapter preflight and gold/self-check |
|
|
23
23
|
| **reproduction proof** | an upstream method is run at a pinned revision on its claimed benchmark under a matched protocol | Discovery Lab reproduction manifest and runner |
|
|
24
24
|
| **value proof** | the integrated method beats the preregistered baseline on frozen evidence with uncertainty and complete cost accounting | Discovery Lab result receipt |
|
|
@@ -35,7 +35,6 @@ From the repository root:
|
|
|
35
35
|
```bash
|
|
36
36
|
pnpm verify:bench
|
|
37
37
|
pnpm verify:official-optimizers
|
|
38
|
-
pnpm verify:primeintellect
|
|
39
38
|
```
|
|
40
39
|
|
|
41
40
|
`verify:official-optimizers` exercises the official Optimize Anything bridge, engine identities, equal input budgets, resume compatibility, candidate callbacks, accounting, and package provenance. Its deterministic candidate improvement is deliberately a fixture. It does **not** reproduce the published GEPA or Omni benchmark numbers.
|
|
@@ -52,6 +51,14 @@ pnpm run run-benchmarks
|
|
|
52
51
|
|
|
53
52
|
Use `LOOP_ATTEMPTS=N` only when the benchmark's own visible feedback is allowed to enter later attempts. Hidden or gold material must remain outside the agent context.
|
|
54
53
|
|
|
54
|
+
`runBenchmarks()` returns each judged artifact, worker events, and observed usage in `perTask`.
|
|
55
|
+
Retry usage includes every attempt; missing receipts leave the measured subtotal explicitly incomplete.
|
|
56
|
+
Judge failures retain completed worker evidence.
|
|
57
|
+
Errors propagated by `close()` remain in `detail` beside the settled task outcome.
|
|
58
|
+
The current Runtime lineage suppresses sandbox deletion errors, so a returned result does not confirm resource deletion.
|
|
59
|
+
The caller's abort signal stops queued shots and reaches active sandbox turns.
|
|
60
|
+
`modelApiKey` supplies sandbox inference authorization separately from the `routerKey` used for sandbox control.
|
|
61
|
+
|
|
55
62
|
### Full-fidelity improvement fixture
|
|
56
63
|
|
|
57
64
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -8,8 +8,9 @@ import { FINAL_ANSWER_SENTINEL, RagAnswerScore, RagContext, answerScoreToBenchSc
|
|
|
8
8
|
import { createRagBenchAdapter } from "./benchmarks/ragbench.js";
|
|
9
9
|
import { SweBenchAdapterOptions, SweBenchArtifactCaptureContext, SweBenchCacheLevel, createSweBenchAdapter, scoreSweReport, sweEvaluationArgv, swePatchOutput } from "./benchmarks/swe-bench.js";
|
|
10
10
|
import { createT2RagBenchAdapter } from "./benchmarks/t2-ragbench.js";
|
|
11
|
-
import { AgentProfile, SandboxClient } from "@tangle-network/agent-runtime/kernel";
|
|
12
|
-
import {
|
|
11
|
+
import { AgentProfile, SandboxClient, sumSandboxUsage } from "@tangle-network/agent-runtime/kernel";
|
|
12
|
+
import { SandboxEvent } from "@tangle-network/sandbox";
|
|
13
|
+
import { AgentCandidateBenchmarkGraderPort, AgentCandidateExecutionClaimStore, AgentCandidateExecutorPort, AgentCandidateExecutorRequest, AgentCandidateExecutorStopRequest, AgentCandidateOutputArtifactPort, AgentCandidateRunFinalization, PreparedAgentCandidateExecution } from "@tangle-network/agent-runtime/candidate-execution";
|
|
13
14
|
import { TraceStore } from "@tangle-network/agent-eval";
|
|
14
15
|
//#region src/resolve-client.d.ts
|
|
15
16
|
interface ResolveBenchClientOptions {
|
|
@@ -47,8 +48,16 @@ interface BenchCell {
|
|
|
47
48
|
/** The agent under test. Defaults to a minimal `{ name, metadata.backendType }` profile. */
|
|
48
49
|
readonly profile?: AgentProfile;
|
|
49
50
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
51
|
+
/** A worker's artifact and observed execution evidence, before external grading. */
|
|
52
|
+
interface BenchShotResult {
|
|
53
|
+
readonly artifact: string;
|
|
54
|
+
readonly ok: boolean;
|
|
55
|
+
readonly detail?: string;
|
|
56
|
+
/** Provider observations, including explicit unknown counters. Omitted when the shot reports none. */
|
|
57
|
+
readonly usage?: ReturnType<typeof sumSandboxUsage>;
|
|
58
|
+
readonly events?: readonly SandboxEvent[];
|
|
59
|
+
}
|
|
60
|
+
/** Runs one (adapter, task, cell) shot. Defaults to `openSandboxRun`. */
|
|
52
61
|
type BenchShot = (input: {
|
|
53
62
|
readonly adapter: BenchmarkAdapter;
|
|
54
63
|
readonly task: BenchTask;
|
|
@@ -59,16 +68,15 @@ type BenchShot = (input: {
|
|
|
59
68
|
readonly attempt?: number;
|
|
60
69
|
readonly routerBaseUrl: string;
|
|
61
70
|
readonly routerKey: string;
|
|
71
|
+
/** Optional inference credential for the box; routerKey continues to authorize sandbox control. */
|
|
72
|
+
readonly modelApiKey?: string;
|
|
62
73
|
readonly bridgeUrl?: string;
|
|
63
74
|
readonly bridgeBearer?: string;
|
|
64
75
|
readonly sandboxBaseUrl?: string;
|
|
65
76
|
readonly timeoutMs?: number;
|
|
77
|
+
readonly signal?: AbortSignal;
|
|
66
78
|
readonly resolveClient?: typeof resolveBenchClient;
|
|
67
|
-
}) => Promise<
|
|
68
|
-
artifact: string;
|
|
69
|
-
ok: boolean;
|
|
70
|
-
detail?: string;
|
|
71
|
-
}>;
|
|
79
|
+
}) => Promise<BenchShotResult>;
|
|
72
80
|
interface RunBenchmarksOptions {
|
|
73
81
|
/** Registry keys (`resolveAdapter`) — the benchmark subset to run. */
|
|
74
82
|
readonly benchmarks: readonly string[];
|
|
@@ -76,6 +84,8 @@ interface RunBenchmarksOptions {
|
|
|
76
84
|
readonly cells: readonly BenchCell[];
|
|
77
85
|
readonly routerBaseUrl: string;
|
|
78
86
|
readonly routerKey: string;
|
|
87
|
+
/** Optional inference credential for the box; never used for sandbox creation or deletion. */
|
|
88
|
+
readonly modelApiKey?: string;
|
|
79
89
|
readonly bridgeUrl?: string;
|
|
80
90
|
readonly bridgeBearer?: string;
|
|
81
91
|
readonly sandboxBaseUrl?: string;
|
|
@@ -89,6 +99,8 @@ interface RunBenchmarksOptions {
|
|
|
89
99
|
readonly concurrency?: number;
|
|
90
100
|
/** Per-shot wall-clock (ms). */
|
|
91
101
|
readonly timeoutMs?: number;
|
|
102
|
+
/** Cancels active shots and prevents queued shots from starting. */
|
|
103
|
+
readonly signal?: AbortSignal;
|
|
92
104
|
/** Test seam: resolve the runtime transport. Defaults to `resolveBenchClient`. */
|
|
93
105
|
readonly resolveClient?: typeof resolveBenchClient;
|
|
94
106
|
/** Max attempts per (benchmark × cell × task). Default 1. Attempts after the first receive
|
|
@@ -115,6 +127,11 @@ interface BenchCellTaskResult {
|
|
|
115
127
|
readonly ok: boolean;
|
|
116
128
|
readonly detail?: string;
|
|
117
129
|
readonly wallMs: number;
|
|
130
|
+
/** Exact bytes given to the benchmark judge, retained even when judging fails. */
|
|
131
|
+
readonly artifact?: string;
|
|
132
|
+
readonly usage?: ReturnType<typeof sumSandboxUsage>;
|
|
133
|
+
/** Worker events only; benchmark grading remains outside this trace. */
|
|
134
|
+
readonly events?: readonly SandboxEvent[];
|
|
118
135
|
}
|
|
119
136
|
interface BenchLeaderboardRow {
|
|
120
137
|
readonly benchmark: string;
|
|
@@ -302,5 +319,5 @@ declare class FilePierCandidateTrialController implements PierCandidateTrialCont
|
|
|
302
319
|
//#region src/pier-result-grader.d.ts
|
|
303
320
|
declare function createPierResultGrader(descriptor: Pick<PierCandidateGraderPort, 'name' | 'version' | 'artifact'>): PierCandidateGraderPort;
|
|
304
321
|
//#endregion
|
|
305
|
-
export { ADAPTERS, type BenchCell, type BenchCellTaskResult, type BenchLeaderboardRow, type BenchScore, type BenchShot, type BenchTask, type BenchmarkAdapter, type ExecutePreparedPierCandidateOptions, FINAL_ANSWER_SENTINEL, FilePierCandidateTrialController, type FilePierCandidateTrialControllerOptions, type JudgeArtifactFileReceipt, type JudgeArtifactReceipt, type LoadOptions, type PierCandidateGraderPort, type PierCandidateOfficialResult, type PierCandidateProcessSpec, type PierCandidateTerminationAcknowledgement, type PierCandidateTrialController, type PierCandidateTrialHandle, type PierCandidateTrialIdentity, type PierCandidateTrialResult, type PierDockerConnection, type RagAnswerScore, type RagContext, type RunBenchmarksOptions, type RunBenchmarksReport, StagedJudgeError, type StagedPierCandidateExecution, type StagedRunCaptureSpec, type StagedRunSpec, type SweBenchAdapterOptions, type SweBenchArtifactCaptureContext, type SweBenchCacheLevel, answerScoreToBenchScore, contextBlock, contextsFrom, createCragAdapter, createNoMiraclAdapter, createOpenRagBenchAdapter, createPierCandidateRecoveryExecutor, createPierResultGrader, createRagBenchAdapter, createSweBenchAdapter, createT2RagBenchAdapter, executePreparedPierCandidate, normalizeAnswer, parseCitations, parseFinalAnswer, printBenchmarksReport, ragAnswerOutput, resolveAdapter, runBenchmarks, runStagedJudge, scoreAnswerArtifact, scoreSweReport, sweEvaluationArgv, swePatchOutput, tokenF1 };
|
|
322
|
+
export { ADAPTERS, type BenchCell, type BenchCellTaskResult, type BenchLeaderboardRow, type BenchScore, type BenchShot, type BenchShotResult, type BenchTask, type BenchmarkAdapter, type ExecutePreparedPierCandidateOptions, FINAL_ANSWER_SENTINEL, FilePierCandidateTrialController, type FilePierCandidateTrialControllerOptions, type JudgeArtifactFileReceipt, type JudgeArtifactReceipt, type LoadOptions, type PierCandidateGraderPort, type PierCandidateOfficialResult, type PierCandidateProcessSpec, type PierCandidateTerminationAcknowledgement, type PierCandidateTrialController, type PierCandidateTrialHandle, type PierCandidateTrialIdentity, type PierCandidateTrialResult, type PierDockerConnection, type RagAnswerScore, type RagContext, type RunBenchmarksOptions, type RunBenchmarksReport, StagedJudgeError, type StagedPierCandidateExecution, type StagedRunCaptureSpec, type StagedRunSpec, type SweBenchAdapterOptions, type SweBenchArtifactCaptureContext, type SweBenchCacheLevel, answerScoreToBenchScore, contextBlock, contextsFrom, createCragAdapter, createNoMiraclAdapter, createOpenRagBenchAdapter, createPierCandidateRecoveryExecutor, createPierResultGrader, createRagBenchAdapter, createSweBenchAdapter, createT2RagBenchAdapter, executePreparedPierCandidate, normalizeAnswer, parseCitations, parseFinalAnswer, printBenchmarksReport, ragAnswerOutput, resolveAdapter, runBenchmarks, runStagedJudge, scoreAnswerArtifact, scoreSweReport, sweEvaluationArgv, swePatchOutput, tokenF1 };
|
|
306
323
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -14,12 +14,11 @@ import { createHash } from "node:crypto";
|
|
|
14
14
|
import { accessSync, closeSync, constants, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
15
15
|
import { tmpdir } from "node:os";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { createExecutor, inlineSandboxClient, openSandboxRun, resolveSandboxClient } from "@tangle-network/agent-runtime/kernel";
|
|
17
|
+
import { SandboxRunAbortError, createExecutor, inlineSandboxClient, openSandboxRun, resolveSandboxClient, sumSandboxUsage } from "@tangle-network/agent-runtime/kernel";
|
|
18
18
|
import { Sandbox } from "@tangle-network/sandbox";
|
|
19
19
|
import assert from "node:assert/strict";
|
|
20
|
-
import { executePreparedAgentCandidate } from "@tangle-network/agent-runtime";
|
|
20
|
+
import { captureAgentCandidateWorkspaceFiles, executePreparedAgentCandidate } from "@tangle-network/agent-runtime/candidate-execution";
|
|
21
21
|
import { canonicalJson } from "@tangle-network/agent-eval";
|
|
22
|
-
import { captureAgentCandidateWorkspaceFiles } from "@tangle-network/agent-runtime/candidate-execution";
|
|
23
22
|
//#region src/refine-loop.ts
|
|
24
23
|
const defaultDecide = (history) => history[history.length - 1]?.verdict?.valid === true;
|
|
25
24
|
async function runRefineLoop(spec) {
|
|
@@ -253,7 +252,8 @@ function finalText(events) {
|
|
|
253
252
|
}
|
|
254
253
|
/** The default real-agent shot: one `openSandboxRun` over the cell's harness+model, deliverable
|
|
255
254
|
* extracted by the adapter's parser (or final text), abortable on `timeoutMs`. */
|
|
256
|
-
const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, routerKey, bridgeUrl, bridgeBearer, sandboxBaseUrl, timeoutMs, resolveClient }) => {
|
|
255
|
+
const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, routerKey, modelApiKey, bridgeUrl, bridgeBearer, sandboxBaseUrl, timeoutMs, signal, resolveClient }) => {
|
|
256
|
+
signal?.throwIfAborted();
|
|
257
257
|
const client = (resolveClient ?? resolveBenchClient)({
|
|
258
258
|
backend: cell.backend ?? "router",
|
|
259
259
|
routerBaseUrl,
|
|
@@ -292,7 +292,8 @@ const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, rou
|
|
|
292
292
|
model: {
|
|
293
293
|
provider: profileProvider,
|
|
294
294
|
model: cell.model,
|
|
295
|
-
baseUrl: routerBaseUrl
|
|
295
|
+
baseUrl: routerBaseUrl,
|
|
296
|
+
...modelApiKey === void 0 ? {} : { apiKey: modelApiKey }
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
}
|
|
@@ -305,7 +306,7 @@ const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, rou
|
|
|
305
306
|
const timer = timeoutMs ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
306
307
|
const runOptions = {
|
|
307
308
|
agentRun,
|
|
308
|
-
signal: controller.signal,
|
|
309
|
+
signal: signal ? AbortSignal.any([controller.signal, signal]) : controller.signal,
|
|
309
310
|
runId: `bench:${adapter.name}:${task.id}:${uniq}`,
|
|
310
311
|
scenarioId: task.id
|
|
311
312
|
};
|
|
@@ -319,9 +320,20 @@ const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, rou
|
|
|
319
320
|
});
|
|
320
321
|
if (sres.exitCode !== 0) throw new Error(`boxSetup failed (exit ${sres.exitCode}): ${(sres.stderr ?? "").slice(0, 200)}`);
|
|
321
322
|
};
|
|
322
|
-
|
|
323
|
+
let run;
|
|
324
|
+
let result = {
|
|
325
|
+
artifact: "",
|
|
326
|
+
ok: false
|
|
327
|
+
};
|
|
323
328
|
try {
|
|
329
|
+
run = await openSandboxRun(client, runOptions, deliverable);
|
|
324
330
|
const turn = await run.start(prompt ?? task.prompt);
|
|
331
|
+
result = {
|
|
332
|
+
artifact: "",
|
|
333
|
+
ok: false,
|
|
334
|
+
usage: sumSandboxUsage(turn.events),
|
|
335
|
+
events: turn.events
|
|
336
|
+
};
|
|
325
337
|
let artifact = (turn.out ?? "").trim();
|
|
326
338
|
let boxExtractError;
|
|
327
339
|
if (adapter.boxExtract) try {
|
|
@@ -358,21 +370,42 @@ const openSandboxShot = async ({ adapter, task, cell, prompt, routerBaseUrl, rou
|
|
|
358
370
|
} catch (err) {
|
|
359
371
|
boxExtractError = err instanceof Error ? err.message.slice(0, 160) : String(err);
|
|
360
372
|
}
|
|
361
|
-
const detail = turn.readError !== void 0 ? `read: ${turn.readError.slice(0, 160)}` : boxExtractError !== void 0 ? `boxExtract: ${boxExtractError}` : void 0;
|
|
373
|
+
const detail = !turn.outcome.success ? turn.outcome.error ?? `agent ended with status ${turn.outcome.status}` : turn.readError !== void 0 ? `read: ${turn.readError.slice(0, 160)}` : boxExtractError !== void 0 ? `boxExtract: ${boxExtractError}` : void 0;
|
|
362
374
|
if (process.env.BENCH_ARTIFACT_DIR) try {
|
|
363
375
|
mkdirSync(process.env.BENCH_ARTIFACT_DIR, { recursive: true });
|
|
364
376
|
const safe = `${adapter.name}_${task.id}_${uniq}`.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
365
377
|
writeFileSync(`${process.env.BENCH_ARTIFACT_DIR}/${safe}.patch`, artifact);
|
|
366
378
|
} catch {}
|
|
367
|
-
|
|
379
|
+
result = {
|
|
368
380
|
artifact,
|
|
369
|
-
ok: artifact.length > 0,
|
|
381
|
+
ok: turn.outcome.success && artifact.length > 0 && turn.readError === void 0 && boxExtractError === void 0,
|
|
382
|
+
usage: result.usage,
|
|
383
|
+
events: turn.events,
|
|
370
384
|
...detail ? { detail } : {}
|
|
371
385
|
};
|
|
386
|
+
} catch (err) {
|
|
387
|
+
result = {
|
|
388
|
+
...result,
|
|
389
|
+
ok: false,
|
|
390
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
391
|
+
...err instanceof SandboxRunAbortError ? {
|
|
392
|
+
usage: sumSandboxUsage(err.events),
|
|
393
|
+
events: err.events
|
|
394
|
+
} : {}
|
|
395
|
+
};
|
|
372
396
|
} finally {
|
|
373
397
|
if (timer) clearTimeout(timer);
|
|
374
|
-
|
|
398
|
+
try {
|
|
399
|
+
await run?.close();
|
|
400
|
+
} catch (err) {
|
|
401
|
+
const cleanup = `cleanup: ${err instanceof Error ? err.message : String(err)}`;
|
|
402
|
+
result = {
|
|
403
|
+
...result,
|
|
404
|
+
detail: combineDetails(result.detail, cleanup)
|
|
405
|
+
};
|
|
406
|
+
}
|
|
375
407
|
}
|
|
408
|
+
return result;
|
|
376
409
|
};
|
|
377
410
|
function parseMaybeJson(value) {
|
|
378
411
|
try {
|
|
@@ -426,30 +459,54 @@ function retryPrompt(task, history, scores) {
|
|
|
426
459
|
}
|
|
427
460
|
async function loopedShot(input, shot, attempts) {
|
|
428
461
|
const scores = /* @__PURE__ */ new Map();
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
462
|
+
const shots = /* @__PURE__ */ new Map();
|
|
463
|
+
let pendingShot = false;
|
|
464
|
+
let result;
|
|
465
|
+
try {
|
|
466
|
+
result = await runRefineLoop({
|
|
467
|
+
rounds: attempts,
|
|
468
|
+
prompt: (round, history) => round === 1 ? input.task.prompt : retryPrompt(input.task, history, scores),
|
|
469
|
+
runShot: async (prompt, round) => {
|
|
470
|
+
input.signal?.throwIfAborted();
|
|
471
|
+
pendingShot = true;
|
|
472
|
+
const out = await shot({
|
|
473
|
+
...input,
|
|
474
|
+
prompt,
|
|
475
|
+
attempt: round
|
|
476
|
+
});
|
|
477
|
+
shots.set(round, out);
|
|
478
|
+
pendingShot = false;
|
|
479
|
+
return {
|
|
480
|
+
artifact: out.artifact,
|
|
481
|
+
note: out.detail
|
|
482
|
+
};
|
|
483
|
+
},
|
|
484
|
+
judge: async (artifact, round) => {
|
|
485
|
+
const score = await input.adapter.judge(input.task, artifact);
|
|
486
|
+
scores.set(round, score);
|
|
487
|
+
const succeeded = shots.get(round)?.ok === true;
|
|
488
|
+
return {
|
|
489
|
+
valid: succeeded && score.resolved,
|
|
490
|
+
score: succeeded ? score.score : 0
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
} catch (err) {
|
|
495
|
+
const completed = [...shots.values()];
|
|
496
|
+
return {
|
|
497
|
+
artifact: completed.at(-1)?.artifact ?? "",
|
|
498
|
+
ok: false,
|
|
499
|
+
usage: combinedUsage(pendingShot ? [...completed, {
|
|
500
|
+
artifact: "",
|
|
501
|
+
ok: false
|
|
502
|
+
}] : completed),
|
|
503
|
+
events: completed.flatMap((shot) => shot.events ?? []),
|
|
504
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
452
507
|
const best = result.rounds.reduce((winner, candidate) => {
|
|
508
|
+
if (shots.get(candidate.round)?.ok !== true) return winner;
|
|
509
|
+
if (shots.get(winner.round)?.ok !== true) return candidate;
|
|
453
510
|
const a = scores.get(winner.round);
|
|
454
511
|
const b = scores.get(candidate.round);
|
|
455
512
|
if (!a) return candidate;
|
|
@@ -461,7 +518,9 @@ async function loopedShot(input, shot, attempts) {
|
|
|
461
518
|
const bestScore = scores.get(best.round);
|
|
462
519
|
return {
|
|
463
520
|
artifact: best.artifact,
|
|
464
|
-
ok: best.artifact.trim().length > 0,
|
|
521
|
+
ok: shots.get(best.round)?.ok === true && best.artifact.trim().length > 0,
|
|
522
|
+
usage: combinedUsage([...shots.values()]),
|
|
523
|
+
events: [...shots.values()].flatMap((shot) => shot.events ?? []),
|
|
465
524
|
detail: JSON.stringify({
|
|
466
525
|
mode: "refine-loop",
|
|
467
526
|
attempts: result.rounds.length,
|
|
@@ -477,6 +536,33 @@ async function loopedShot(input, shot, attempts) {
|
|
|
477
536
|
})
|
|
478
537
|
};
|
|
479
538
|
}
|
|
539
|
+
function combinedUsage(shots) {
|
|
540
|
+
const usage = {
|
|
541
|
+
input: 0,
|
|
542
|
+
output: 0,
|
|
543
|
+
costUsd: 0
|
|
544
|
+
};
|
|
545
|
+
let tokensKnown = shots.length > 0;
|
|
546
|
+
let usdKnown = shots.length > 0;
|
|
547
|
+
let estimate;
|
|
548
|
+
let unknownReason;
|
|
549
|
+
for (const shot of shots) {
|
|
550
|
+
usage.input += shot.usage?.input ?? 0;
|
|
551
|
+
usage.output += shot.usage?.output ?? 0;
|
|
552
|
+
usage.costUsd += shot.usage?.costUsd ?? 0;
|
|
553
|
+
tokensKnown &&= shot.usage !== void 0 && shot.usage.tokensKnown !== false;
|
|
554
|
+
usdKnown &&= shot.usage !== void 0 && shot.usage.usdKnown !== false;
|
|
555
|
+
unknownReason ??= shot.usage?.tokensUnknownReason;
|
|
556
|
+
if (shot.usage?.estimatedCostUsd !== void 0) estimate = (estimate ?? 0) + shot.usage.estimatedCostUsd;
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
...usage,
|
|
560
|
+
...tokensKnown ? {} : { tokensKnown: false },
|
|
561
|
+
...usdKnown ? {} : { usdKnown: false },
|
|
562
|
+
...estimate === void 0 ? {} : { estimatedCostUsd: estimate },
|
|
563
|
+
...unknownReason === void 0 ? {} : { tokensUnknownReason: unknownReason }
|
|
564
|
+
};
|
|
565
|
+
}
|
|
480
566
|
function combineDetails(runDetail, scoreDetail) {
|
|
481
567
|
if (runDetail && scoreDetail) return JSON.stringify({
|
|
482
568
|
run: parseMaybeJson(runDetail),
|
|
@@ -535,6 +621,7 @@ async function prepareBenchmarks(benchmarks, resolve, opts) {
|
|
|
535
621
|
};
|
|
536
622
|
}
|
|
537
623
|
async function runBenchmarks(opts) {
|
|
624
|
+
opts.signal?.throwIfAborted();
|
|
538
625
|
if (opts.benchmarks.length === 0) throw new Error("runBenchmarks: no benchmarks selected");
|
|
539
626
|
if (opts.cells.length === 0) throw new Error("runBenchmarks: no cells to run");
|
|
540
627
|
const reps = Math.max(1, opts.reps ?? 1);
|
|
@@ -553,20 +640,24 @@ async function runBenchmarks(opts) {
|
|
|
553
640
|
await runPool(jobs, Math.max(1, opts.concurrency ?? 4), async (job, index) => {
|
|
554
641
|
const startedAt = Date.now();
|
|
555
642
|
let result;
|
|
643
|
+
let out;
|
|
556
644
|
try {
|
|
645
|
+
opts.signal?.throwIfAborted();
|
|
557
646
|
const shotInput = {
|
|
558
647
|
adapter: job.adapter,
|
|
559
648
|
task: job.task,
|
|
560
649
|
cell: job.cell,
|
|
561
650
|
routerBaseUrl: opts.routerBaseUrl,
|
|
562
651
|
routerKey: opts.routerKey,
|
|
652
|
+
...opts.modelApiKey === void 0 ? {} : { modelApiKey: opts.modelApiKey },
|
|
563
653
|
...opts.bridgeUrl ? { bridgeUrl: opts.bridgeUrl } : {},
|
|
564
654
|
...opts.bridgeBearer ? { bridgeBearer: opts.bridgeBearer } : {},
|
|
565
655
|
...opts.sandboxBaseUrl ? { sandboxBaseUrl: opts.sandboxBaseUrl } : {},
|
|
566
656
|
...opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {},
|
|
657
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
567
658
|
...opts.resolveClient ? { resolveClient: opts.resolveClient } : {}
|
|
568
659
|
};
|
|
569
|
-
|
|
660
|
+
out = loopAttempts > 1 ? await loopedShot(shotInput, shot, loopAttempts) : await shot(shotInput);
|
|
570
661
|
const score = await job.adapter.judge(job.task, out.artifact);
|
|
571
662
|
result = {
|
|
572
663
|
benchmark: job.benchmark,
|
|
@@ -577,7 +668,10 @@ async function runBenchmarks(opts) {
|
|
|
577
668
|
score: out.ok ? score.score : 0,
|
|
578
669
|
ok: out.ok,
|
|
579
670
|
...out.detail ?? score.detail ? { detail: combineDetails(out.detail, score.detail) } : {},
|
|
580
|
-
wallMs: Date.now() - startedAt
|
|
671
|
+
wallMs: Date.now() - startedAt,
|
|
672
|
+
artifact: out.artifact,
|
|
673
|
+
...out.usage === void 0 ? {} : { usage: out.usage },
|
|
674
|
+
...out.events === void 0 ? {} : { events: out.events }
|
|
581
675
|
};
|
|
582
676
|
} catch (err) {
|
|
583
677
|
result = {
|
|
@@ -589,7 +683,10 @@ async function runBenchmarks(opts) {
|
|
|
589
683
|
score: 0,
|
|
590
684
|
ok: false,
|
|
591
685
|
detail: err instanceof Error ? err.message.slice(0, 200) : String(err),
|
|
592
|
-
wallMs: Date.now() - startedAt
|
|
686
|
+
wallMs: Date.now() - startedAt,
|
|
687
|
+
...out === void 0 ? {} : { artifact: out.artifact },
|
|
688
|
+
...out?.usage === void 0 ? {} : { usage: out.usage },
|
|
689
|
+
...out?.events === void 0 ? {} : { events: out.events }
|
|
593
690
|
};
|
|
594
691
|
}
|
|
595
692
|
perTask.push(result);
|