lastlight-evals 0.1.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.
Files changed (41) hide show
  1. package/README.md +187 -0
  2. package/datasets/code-fix/instances.json +26 -0
  3. package/datasets/code-fix/repos/codefix__date-range-off-by-one/README.md +8 -0
  4. package/datasets/code-fix/repos/codefix__date-range-off-by-one/package.json +9 -0
  5. package/datasets/code-fix/repos/codefix__date-range-off-by-one/src/date-range.ts +25 -0
  6. package/datasets/code-fix/tests/codefix__date-range-off-by-one/date-range.test.ts +18 -0
  7. package/datasets/code-fix/tier.json +5 -0
  8. package/datasets/triage/instances.json +62 -0
  9. package/datasets/triage/tier.json +5 -0
  10. package/dist/bootstrap.js +46 -0
  11. package/dist/bootstrap.js.map +1 -0
  12. package/dist/discovery.js +100 -0
  13. package/dist/discovery.js.map +1 -0
  14. package/dist/env.js +109 -0
  15. package/dist/env.js.map +1 -0
  16. package/dist/fake-github.js +249 -0
  17. package/dist/fake-github.js.map +1 -0
  18. package/dist/grade.js +134 -0
  19. package/dist/grade.js.map +1 -0
  20. package/dist/html-report.js +325 -0
  21. package/dist/html-report.js.map +1 -0
  22. package/dist/init.js +122 -0
  23. package/dist/init.js.map +1 -0
  24. package/dist/mechanism.test.js +108 -0
  25. package/dist/mechanism.test.js.map +1 -0
  26. package/dist/metrics.js +86 -0
  27. package/dist/metrics.js.map +1 -0
  28. package/dist/paths.js +33 -0
  29. package/dist/paths.js.map +1 -0
  30. package/dist/report.js +137 -0
  31. package/dist/report.js.map +1 -0
  32. package/dist/run-instance.js +203 -0
  33. package/dist/run-instance.js.map +1 -0
  34. package/dist/run.js +476 -0
  35. package/dist/run.js.map +1 -0
  36. package/dist/schema.js +15 -0
  37. package/dist/schema.js.map +1 -0
  38. package/dist/seed.js +49 -0
  39. package/dist/seed.js.map +1 -0
  40. package/models.json +17 -0
  41. package/package.json +50 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Pull per-run token/cost/turn metrics out of the session jsonl the event
3
+ * shim writes (`src/engine/event-shim.ts`). Each phase emits one `result`
4
+ * envelope carrying `total_cost_usd` / `total_input_tokens` /
5
+ * `total_output_tokens`. We sum them across every jsonl under the run's
6
+ * sessions dir. Best-effort: missing files / lines just contribute zero.
7
+ */
8
+ import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ /**
11
+ * The in-process executor flushes its FINAL session envelope (the `result`
12
+ * line that carries cost/tokens) fire-and-forget (`void shim.flush()`), so it
13
+ * can land just after `runWorkflow` resolves. Wait for the jsonl tree to stop
14
+ * growing before reading metrics, so we don't miss it (and don't delete the
15
+ * workspace out from under the pending write).
16
+ */
17
+ export async function drainSessions(sessionsDir, maxMs = 4000, quietMs = 250) {
18
+ const sizeOf = () => {
19
+ const files = [];
20
+ walkJsonl(join(sessionsDir, "projects"), files);
21
+ return files.reduce((sum, f) => {
22
+ try {
23
+ return sum + statSync(f).size;
24
+ }
25
+ catch {
26
+ return sum;
27
+ }
28
+ }, 0);
29
+ };
30
+ const deadline = Date.now() + maxMs;
31
+ let last = -1;
32
+ let stableSince = Date.now();
33
+ while (Date.now() < deadline) {
34
+ const cur = sizeOf();
35
+ if (cur > 0 && cur === last) {
36
+ if (Date.now() - stableSince >= quietMs)
37
+ return;
38
+ }
39
+ else {
40
+ last = cur;
41
+ stableSince = Date.now();
42
+ }
43
+ await new Promise((r) => setTimeout(r, 80));
44
+ }
45
+ }
46
+ function walkJsonl(dir, out) {
47
+ if (!existsSync(dir))
48
+ return;
49
+ for (const name of readdirSync(dir, { withFileTypes: true })) {
50
+ const full = join(dir, name.name);
51
+ if (name.isDirectory())
52
+ walkJsonl(full, out);
53
+ else if (name.name.endsWith(".jsonl"))
54
+ out.push(full);
55
+ }
56
+ }
57
+ export function collectMetrics(sessionsDir) {
58
+ const files = [];
59
+ walkJsonl(join(sessionsDir, "projects"), files);
60
+ // Fallback: some shim configs write directly under sessionsDir.
61
+ walkJsonl(sessionsDir, files);
62
+ const seen = new Set();
63
+ const metrics = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
64
+ for (const file of files) {
65
+ if (seen.has(file))
66
+ continue;
67
+ seen.add(file);
68
+ for (const line of readFileSync(file, "utf8").split("\n")) {
69
+ if (!line.trim() || !line.includes('"result"'))
70
+ continue;
71
+ try {
72
+ const env = JSON.parse(line);
73
+ if (env.type !== "result")
74
+ continue;
75
+ metrics.inputTokens += env.total_input_tokens ?? 0;
76
+ metrics.outputTokens += env.total_output_tokens ?? 0;
77
+ metrics.costUsd += env.total_cost_usd ?? 0;
78
+ }
79
+ catch {
80
+ /* ignore malformed lines */
81
+ }
82
+ }
83
+ }
84
+ return metrics;
85
+ }
86
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
package/dist/paths.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Filesystem anchors for the eval package.
3
+ *
4
+ * Built-in assets (the shipped sample `datasets/` + `models.json`) live at the
5
+ * PACKAGE ROOT — one level above this file's dir, which is `src/` under tsx in
6
+ * dev and `dist/` when built+installed. Resolving relative to `import.meta.url`
7
+ * (not `process.cwd()`) keeps them findable no matter where the CLI is invoked
8
+ * from — including out of `node_modules/lastlight-evals/`.
9
+ *
10
+ * Run OUTPUT, by contrast, is written under the caller's cwd (an installed
11
+ * package dir is read-only), overridable via `LASTLIGHT_EVALS_OUT`.
12
+ */
13
+ import { dirname, resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ /** Package root: the dir holding `datasets/`, `models.json`, `package.json`. */
16
+ export function packageRoot() {
17
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..");
18
+ }
19
+ /** Shipped sample datasets root (`<pkg>/datasets`). */
20
+ export function builtinDatasetsRoot() {
21
+ return resolve(packageRoot(), "datasets");
22
+ }
23
+ /** Shipped default model registry (`<pkg>/models.json`). */
24
+ export function builtinModelsPath() {
25
+ return resolve(packageRoot(), "models.json");
26
+ }
27
+ /** Where scorecards/artifacts are written (cwd-relative, NOT the package dir). */
28
+ export function resultsRoot() {
29
+ return process.env.LASTLIGHT_EVALS_OUT
30
+ ? resolve(process.env.LASTLIGHT_EVALS_OUT)
31
+ : resolve(process.cwd(), "eval-results");
32
+ }
33
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,gFAAgF;AAChF,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAChE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AAC/C,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB;QACpC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC1C,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;AAC7C,CAAC"}
package/dist/report.js ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Scorecard rendering + SWE-bench-compatible artifacts.
3
+ *
4
+ * - A stdout table comparing models on resolved% / triage-correct% / tokens /
5
+ * cost / latency.
6
+ * - `scorecard.json` — the structured roll-up.
7
+ * - `predictions.jsonl` — SWE-bench predictions shape
8
+ * (`{ instance_id, model_name_or_path, model_patch }`), so the same artifact
9
+ * is consumable by SWE-bench's own harness.
10
+ */
11
+ import { mkdirSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ /**
14
+ * Fold N trials of ONE case (same model + instance) into a single result:
15
+ * - binary verdicts (behavioral / resolved) are WORST-case — true only if
16
+ * every non-errored trial passed (a reliability measure), with the pass
17
+ * count kept alongside for variance.
18
+ * - cost / tokens / latency are the MEAN across non-errored trials.
19
+ * A single trial is returned unchanged. If every trial errored, the aggregate
20
+ * carries that error.
21
+ */
22
+ export function aggregateTrials(trials) {
23
+ if (trials.length === 1)
24
+ return trials[0];
25
+ const base = trials[0];
26
+ const ok = trials.filter((t) => !t.error);
27
+ if (!ok.length) {
28
+ return { ...base, trials: 0, trialErrors: trials.length, error: base.error ?? "all trials errored" };
29
+ }
30
+ const mean = (xs) => (xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0);
31
+ const out = {
32
+ ...base,
33
+ error: undefined,
34
+ inputTokens: Math.round(mean(ok.map((t) => t.inputTokens))),
35
+ outputTokens: Math.round(mean(ok.map((t) => t.outputTokens))),
36
+ costUsd: mean(ok.map((t) => t.costUsd)),
37
+ durationMs: Math.round(mean(ok.map((t) => t.durationMs))),
38
+ githubMutations: Math.round(mean(ok.map((t) => t.githubMutations ?? 0))),
39
+ trials: ok.length,
40
+ trialErrors: trials.length - ok.length,
41
+ };
42
+ // behavioral: worst-case ok, checks AND'd by name, keep a failing detail.
43
+ if (ok.some((t) => t.behavioral)) {
44
+ const passes = ok.filter((t) => t.behavioral?.ok).length;
45
+ const names = [...new Set(ok.flatMap((t) => t.behavioral?.checks.map((c) => c.name) ?? []))];
46
+ const checks = names.map((name) => {
47
+ const perTrial = ok.map((t) => t.behavioral?.checks.find((c) => c.name === name));
48
+ const failing = perTrial.find((c) => c && !c.ok);
49
+ return { name, ok: perTrial.every((c) => c?.ok), detail: failing?.detail };
50
+ });
51
+ out.behavioral = { ok: passes === ok.length, checks };
52
+ out.behavioralPass = passes;
53
+ }
54
+ // resolved: worst-case; keep a failing trial's test breakdown + a patch.
55
+ if (ok.some((t) => t.resolved !== undefined)) {
56
+ const passes = ok.filter((t) => t.resolved).length;
57
+ const rep = ok.find((t) => !t.resolved) ?? ok[0];
58
+ out.resolved = passes === ok.length;
59
+ out.resolvedPass = passes;
60
+ out.failToPass = rep.failToPass;
61
+ out.passToPass = rep.passToPass;
62
+ out.model_patch = (ok.find((t) => t.resolved) ?? ok[0]).model_patch;
63
+ }
64
+ return out;
65
+ }
66
+ /** Per-model aggregation over a set of results (one tier or all of them). */
67
+ export function summarizeModels(results) {
68
+ const byModel = new Map();
69
+ for (const r of results) {
70
+ const list = byModel.get(r.model) ?? [];
71
+ list.push(r);
72
+ byModel.set(r.model, list);
73
+ }
74
+ const models = [];
75
+ for (const [model, list] of byModel) {
76
+ const codeFix = list.filter((r) => r.resolved !== undefined);
77
+ const behavioral = list.filter((r) => r.behavioral !== undefined && !r.error);
78
+ const durations = list.map((r) => r.durationMs).sort((a, b) => a - b);
79
+ models.push({
80
+ model,
81
+ total: list.length,
82
+ codeFixResolved: codeFix.filter((r) => r.resolved).length,
83
+ codeFixTotal: codeFix.length,
84
+ behavioralOk: behavioral.filter((r) => r.behavioral?.ok).length,
85
+ behavioralTotal: behavioral.length,
86
+ avgInputTokens: avg(list.map((r) => r.inputTokens)),
87
+ avgOutputTokens: avg(list.map((r) => r.outputTokens)),
88
+ totalCostUsd: list.reduce((s, r) => s + r.costUsd, 0),
89
+ p50DurationMs: durations[Math.floor(durations.length / 2)] ?? 0,
90
+ errors: list.filter((r) => r.error).length,
91
+ });
92
+ }
93
+ return models;
94
+ }
95
+ export function summarize(results) {
96
+ return { models: summarizeModels(results), results };
97
+ }
98
+ export function renderTable(card, labels = {}) {
99
+ const header = ["model", "code-fix", "behavioral", "in tok", "out tok", "cost $", "p50", "err"];
100
+ const rows = card.models.map((m) => [
101
+ labels[m.model] ?? m.model,
102
+ m.codeFixTotal ? `${m.codeFixResolved}/${m.codeFixTotal}` : "—",
103
+ m.behavioralTotal ? `${m.behavioralOk}/${m.behavioralTotal}` : "—",
104
+ String(Math.round(m.avgInputTokens)),
105
+ String(Math.round(m.avgOutputTokens)),
106
+ m.totalCostUsd.toFixed(4),
107
+ fmtMs(m.p50DurationMs),
108
+ String(m.errors),
109
+ ]);
110
+ return table([header, ...rows]);
111
+ }
112
+ export function writeArtifacts(dir, card) {
113
+ mkdirSync(dir, { recursive: true });
114
+ writeFileSync(join(dir, "scorecard.json"), JSON.stringify(card, null, 2));
115
+ const preds = card.results
116
+ .filter((r) => r.model_patch !== undefined)
117
+ .map((r) => JSON.stringify({ instance_id: r.instance_id, model_name_or_path: r.model, model_patch: r.model_patch ?? "" }))
118
+ .join("\n");
119
+ writeFileSync(join(dir, "predictions.jsonl"), preds ? preds + "\n" : "");
120
+ }
121
+ // ── helpers ─────────────────────────────────────────────────────────────────
122
+ function avg(xs) {
123
+ return xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0;
124
+ }
125
+ function fmtMs(ms) {
126
+ if (ms < 1000)
127
+ return `${ms}ms`;
128
+ const s = Math.round(ms / 1000);
129
+ return s < 60 ? `${s}s` : `${Math.floor(s / 60)}m${String(s % 60).padStart(2, "0")}`;
130
+ }
131
+ function table(rows) {
132
+ const widths = rows[0].map((_, i) => Math.max(...rows.map((r) => (r[i] ?? "").length)));
133
+ return rows
134
+ .map((r) => r.map((c, i) => (c ?? "").padEnd(widths[i])).join(" "))
135
+ .join("\n");
136
+ }
137
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Run ONE eval instance against the REAL production workflow with GitHub mocked.
3
+ *
4
+ * Flow:
5
+ * 1. Start the fake GitHub (seeded from the instance's issue fixtures).
6
+ * 2. (code-fix) Deterministically seed the workspace: fixture repo @ base
7
+ * commit + a local bare `origin` so `git push` works offline.
8
+ * 3. Load the REAL workflow YAML (build / issue-triage / …) via the loader.
9
+ * 4. runWorkflow with `sandbox: "none"`, `githubApiBaseUrl → fake GitHub`,
10
+ * and an EMPTY approvalConfig so gates never pause. No real GitHub creds.
11
+ * 5. Grade deterministically (execution + behavioral) and collect metrics.
12
+ *
13
+ * The only deviations from production are the ones we can't do unattended:
14
+ * approvals are skipped and GitHub is mocked. Prompts, skills, phases, and the
15
+ * agent loop are exactly what ships.
16
+ */
17
+ import { mkdtempSync, mkdirSync, rmSync, existsSync } from "node:fs";
18
+ import { execFileSync } from "node:child_process";
19
+ import { join } from "node:path";
20
+ import { tmpdir } from "node:os";
21
+ import { getWorkflow, runWorkflow } from "lastlight/evals";
22
+ import { startFakeGitHub } from "./fake-github.js";
23
+ import { seedWorkspace } from "./seed.js";
24
+ import { collectMetrics, drainSessions } from "./metrics.js";
25
+ import { gradeBehavioral, gradeExecution, gradeTriage } from "./grade.js";
26
+ const EVAL_ENV_KEYS = ["GITHUB_APP_ID", "GITHUB_APP_INSTALLATION_ID", "GITHUB_TOKEN", "GH_TOKEN", "GITHUB_API_URL"];
27
+ /**
28
+ * Install the eval's static-token GitHub env and return a restore fn:
29
+ * - unset the App creds so no real installation token is ever minted, and
30
+ * - set a dummy `GITHUB_TOKEN`/`GH_TOKEN` so the GitHub extension loads in
31
+ * static-token mode (its Octokit is pointed at the fake server via
32
+ * `githubApiBaseUrl`).
33
+ * Every eval run wants the SAME values, so the parallel batch installs this
34
+ * once up front (stable baseline) and each `runInstance` skips its own env work
35
+ * via `manageEnv: false`.
36
+ */
37
+ export function applyEvalEnv() {
38
+ const saved = snapshotEnv(EVAL_ENV_KEYS);
39
+ delete process.env.GITHUB_APP_ID;
40
+ delete process.env.GITHUB_APP_INSTALLATION_ID;
41
+ process.env.GITHUB_TOKEN = "eval-fake-token";
42
+ process.env.GH_TOKEN = "eval-fake-token";
43
+ return () => restoreEnv(saved);
44
+ }
45
+ function splitRepo(repo) {
46
+ const [owner, name] = repo.split("/");
47
+ return { owner: owner ?? "acme", name: name ?? "widget" };
48
+ }
49
+ export async function runInstance(inst, opts) {
50
+ const start = Date.now();
51
+ const { owner, name } = splitRepo(inst.repo);
52
+ const workflowName = inst.workflow ?? opts.defaultWorkflow ?? "issue-triage";
53
+ const isCodeFix = workflowName !== "issue-triage";
54
+ const stateDir = opts.stateDir ?? mkdtempSync(join(tmpdir(), "ll-eval-"));
55
+ const sessionsDir = join(stateDir, "agent-sessions");
56
+ // The shim appends per-phase jsonl under <sessionsDir>/projects/<slug>/ and
57
+ // does not create that parent recursively — pre-create it so token/cost
58
+ // metrics are captured (collectMetrics reads those jsonl files).
59
+ mkdirSync(join(sessionsDir, "projects"), { recursive: true });
60
+ const taskId = `${name}-${inst.issue?.number ?? 0}-${workflowName}-${slug(inst.instance_id)}`;
61
+ const issueNumber = inst.issue?.number ?? 1;
62
+ const branch = isCodeFix ? `lastlight/${slug(inst.instance_id)}` : "main";
63
+ // 1. Fake GitHub, seeded with the issue.
64
+ const fake = await startFakeGitHub({
65
+ owner,
66
+ repo: name,
67
+ issues: inst.issue ? [inst.issue] : [],
68
+ existingLabels: inst.issue?.labels ?? [],
69
+ });
70
+ // Static-token mode: no App creds (so no real mint), a dummy token so the
71
+ // GitHub extension loads, and point its Octokit at the fake. In a parallel
72
+ // batch the caller installs this once (manageEnv: false) so concurrent runs
73
+ // share one stable baseline instead of racing per-run env splices.
74
+ const restoreEvalEnv = opts.manageEnv === false ? () => { } : applyEvalEnv();
75
+ const result = {
76
+ instance_id: inst.instance_id,
77
+ model: opts.model,
78
+ workflowSucceeded: false,
79
+ inputTokens: 0,
80
+ outputTokens: 0,
81
+ costUsd: 0,
82
+ durationMs: 0,
83
+ phases: [],
84
+ };
85
+ try {
86
+ // 2. Seed the workspace for code-fix (triage needs no repo).
87
+ if (isCodeFix && opts.datasetDir) {
88
+ const fixtureDir = join(opts.datasetDir, "repos", inst.instance_id);
89
+ if (existsSync(fixtureDir)) {
90
+ seedWorkspace({ stateDir, taskId, fixtureDir, branch });
91
+ }
92
+ }
93
+ // 3. Real workflow definition + run context.
94
+ const def = getWorkflow(workflowName);
95
+ const ctx = {
96
+ owner,
97
+ repo: name,
98
+ issueNumber,
99
+ issueTitle: inst.issue?.title ?? inst.instance_id,
100
+ issueBody: inst.issue?.body ?? inst.problem_statement,
101
+ issueLabels: inst.issue?.labels ?? [],
102
+ commentBody: "",
103
+ sender: "eval",
104
+ branch,
105
+ taskId,
106
+ issueDir: `.lastlight/issue-${issueNumber}`,
107
+ bootstrapLabel: "lastlight:bootstrap",
108
+ // No prePopulateBranch → the runner never clones from GitHub; the agent
109
+ // works in the dir we seeded above (or an empty dir for triage).
110
+ };
111
+ const config = {
112
+ sandbox: "none",
113
+ stateDir,
114
+ sessionsDir,
115
+ model: opts.model,
116
+ githubApiBaseUrl: fake.url,
117
+ // Eval workflows shouldn't reach the network beyond the model + fake GH.
118
+ webSearch: false,
119
+ };
120
+ // 4. Run. Empty approvalConfig → every approval gate is disabled.
121
+ const wf = await runWorkflow(def, ctx, config, {}, undefined, undefined, {});
122
+ result.workflowSucceeded = wf.success;
123
+ result.phases = wf.phases.map((p) => ({ phase: p.phase, success: p.success }));
124
+ // A workflow-level failure (a phase erroring — provider auth/credit/rate
125
+ // errors, timeouts) is a RUN error, not a model "miss". Surface it so the
126
+ // scorecard counts it under errors instead of behavioral✗.
127
+ if (!wf.success) {
128
+ const failed = wf.phases.find((p) => !p.success && p.error);
129
+ result.error = failed?.error
130
+ ? `${failed.phase}: ${failed.error}`.slice(0, 300)
131
+ : "workflow failed";
132
+ }
133
+ // 5a. Behavioral grade (GitHub mutations).
134
+ const behavioralExpect = gradeBehavioral(inst.expect_github, fake, { issueNumber, branch });
135
+ const triage = gradeTriage(inst.triage_gold, fake, issueNumber);
136
+ result.behavioral = {
137
+ ok: behavioralExpect.ok && triage.ok,
138
+ checks: [...behavioralExpect.checks, ...triage.checks],
139
+ };
140
+ // 5b. Execution grade (code-fix only).
141
+ if (isCodeFix && (inst.FAIL_TO_PASS?.length || inst.test_patch)) {
142
+ const workDir = join(stateDir, "sandboxes", taskId);
143
+ const heldOutDir = opts.datasetDir ? join(opts.datasetDir, "tests", inst.instance_id) : undefined;
144
+ const exec = gradeExecution({
145
+ workDir,
146
+ heldOutDir,
147
+ testPatch: inst.test_patch,
148
+ failToPass: inst.FAIL_TO_PASS ?? [],
149
+ passToPass: inst.PASS_TO_PASS ?? [],
150
+ });
151
+ result.resolved = exec.resolved;
152
+ result.failToPass = exec.failToPass;
153
+ result.passToPass = exec.passToPass;
154
+ result.model_patch = gitDiff(workDir);
155
+ }
156
+ // 5c. Metrics. Drain the fire-and-forget session flush first so the final
157
+ // `result` envelope (cost/tokens) has landed before we read + clean up.
158
+ await drainSessions(sessionsDir);
159
+ const m = collectMetrics(sessionsDir);
160
+ result.inputTokens = m.inputTokens;
161
+ result.outputTokens = m.outputTokens;
162
+ result.costUsd = m.costUsd;
163
+ result.githubMutations = fake.calls.length;
164
+ }
165
+ catch (err) {
166
+ result.error = err instanceof Error ? err.message : String(err);
167
+ }
168
+ finally {
169
+ result.durationMs = Date.now() - start;
170
+ await fake.close();
171
+ restoreEvalEnv();
172
+ if (!opts.keepWorkspace && !opts.stateDir) {
173
+ rmSync(stateDir, { recursive: true, force: true });
174
+ }
175
+ }
176
+ return result;
177
+ }
178
+ function slug(s) {
179
+ return s.replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40);
180
+ }
181
+ function snapshotEnv(keys) {
182
+ const snap = {};
183
+ for (const k of keys)
184
+ snap[k] = process.env[k];
185
+ return snap;
186
+ }
187
+ function restoreEnv(snap) {
188
+ for (const [k, v] of Object.entries(snap)) {
189
+ if (v === undefined)
190
+ delete process.env[k];
191
+ else
192
+ process.env[k] = v;
193
+ }
194
+ }
195
+ function gitDiff(workDir) {
196
+ try {
197
+ return execFileSync("git", ["diff", "HEAD"], { cwd: workDir, stdio: ["ignore", "pipe", "ignore"] }).toString();
198
+ }
199
+ catch {
200
+ return undefined;
201
+ }
202
+ }
203
+ //# sourceMappingURL=run-instance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-instance.js","sourceRoot":"","sources":["../src/run-instance.ts"],"names":[],"mappings":"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"}