fix(coding-agent): record eval sessions after each test

This commit is contained in:
Christian Klotz 2026-07-30 02:05:43 +03:00
parent 2a2e677bed
commit 56e6a8a3fa
No known key found for this signature in database
5 changed files with 16 additions and 15 deletions

View file

@ -43,14 +43,12 @@ to each `describeEval(...)` suite:
import { expect } from "vitest";
import { describeEval } from "vitest-evals";
import { createPiCodingAgentHarness } from "./pi-harness.ts";
import { recordEvalSessionArtifact } from "./vitest-evals/artifacts.ts";
const harness = createPiCodingAgentHarness({ noTools: "all" });
describeEval("Pi smoke", { harness }, (it) => {
it("answers a factual question", async ({ run, task }) => {
it("answers a factual question", async ({ run }) => {
const result = await run("What is the capital of France? Reply with only the city name.");
await recordEvalSessionArtifact(task, result);
expect(result.output).toBe("Paris");
});
});
@ -111,7 +109,6 @@ Harnesses may differ by prompt, tools, skills, model, or any other Pi configurat
```ts
import { describe } from "vitest";
import { createJudge, describeEval } from "vitest-evals";
import { recordEvalSessionArtifact } from "./vitest-evals/artifacts.ts";
import { evalHarnessTable } from "./vitest-evals/harness-table.ts";
const TargetTaskJudge = createJudge<string, string>("TargetTaskJudge", ({ output }) => ({
@ -129,9 +126,8 @@ const harnessTable = evalHarnessTable(
describe.for(harnessTable)("$name repetition $repetition", ({ harness }) => {
describeEval("target skill effectiveness", { harness, judges: [TargetTaskJudge], judgeThreshold: null }, (it) => {
it("completes the target task", async ({ run, task }) => {
const result = await run("Complete the target task.");
await recordEvalSessionArtifact(task, result);
it("completes the target task", async ({ run }) => {
await run("Complete the target task.");
});
});
});
@ -141,9 +137,8 @@ Comparative suites should record correctness with deterministic or model-backed
This keeps a low score as an observation instead of making the Vitest invocation fail. Use hard assertions only for
suite invariants and infrastructure contracts. `expect.soft(...)` still fails the test and is not a scoring mechanism.
Record session attachments with the explicit Vitest `task` after `run(...)` returns. The Pi harness snapshots the native
session before deleting its temporary workspace, while `recordEvalSessionArtifact(...)` registers that snapshot through
Vitest's custom-artifact API.
The Pi harness snapshots native session JSONL before deleting its temporary workspace. An eval-only `afterEach` hook
registers that snapshot against the explicit Vitest test task before reporters run.
Harness names must be stable and unique within an eval set. The grouping key combines repetition and seed with a
non-empty string `input.id` when available, otherwise with a SHA-256 hash of strict canonical JSON input. Execution order

View file

@ -3,7 +3,7 @@ import { join } from "node:path";
import { describe, expect } from "vitest";
import { createJudge, describeEval } from "vitest-evals";
import { createPiCodingAgentHarness, type PiCodingAgentInput } from "./pi-harness.ts";
import { recordEvalSessionArtifact, recordEvalSourceArtifact } from "./vitest-evals/artifacts.ts";
import { recordEvalSourceArtifact } from "./vitest-evals/artifacts.ts";
import { evalHarnessTable } from "./vitest-evals/harness-table.ts";
type ExtensionAuthoringOutput = {
@ -125,7 +125,6 @@ describe.for(extensionHarnessTable)("$name", ({ harness }) => {
"Use the hello tool to greet Bob. Respond with exactly the tool's greeting and nothing else.",
},
]);
await recordEvalSessionArtifact(task, result);
if (result.output.extensionSource !== null) {
const runId = result.artifacts?.runId;
if (typeof runId !== "string") throw new Error("Pi eval run did not record a run ID.");

View file

@ -1,14 +1,12 @@
import { expect } from "vitest";
import { describeEval } from "vitest-evals";
import { createPiCodingAgentHarness } from "./pi-harness.ts";
import { recordEvalSessionArtifact } from "./vitest-evals/artifacts.ts";
const piCodingAgentHarness = createPiCodingAgentHarness({ noTools: "all" });
describeEval("Pi Coding Agent smoke", { harness: piCodingAgentHarness }, (it) => {
it("runs a basic prompt end to end", async ({ run, task }) => {
it("runs a basic prompt end to end", async ({ run }) => {
const result = await run("What's the capital of France? Respond with only the city name.");
await recordEvalSessionArtifact(task, result);
expect(result.output.trim()).toBe("Paris");
expect(result.errors).toEqual([]);

View file

@ -0,0 +1,8 @@
import { afterEach } from "vitest";
import type {} from "vitest-evals";
import { recordEvalSessionArtifact } from "./artifacts.ts";
afterEach(async ({ task }) => {
const run = task.meta.harness?.run;
if (run) await recordEvalSessionArtifact(task, run);
});

View file

@ -10,6 +10,7 @@ export default mergeConfig(
include: ["src/**/*.eval.ts"],
testTimeout: 120000,
hookTimeout: 30000,
setupFiles: ["./src/vitest-evals/setup.ts"],
reporters: ["vitest-evals/reporter", "./src/vitest-evals/reporter.ts"],
},
resolve: {