Skip to content

Commit 69af5d7

Browse files
committed
feat(evals): record and replay judge transcripts
Fixtures now store the judge model and judge turns alongside the task turns, so replay reproduces a judged pass/fail instead of skipping the judge. A live trial that failed only its judge check can no longer replay green. - replay.ts: ReplayFixture gains judgeModel/judgeTurns - live test records judge turns when EVAL_RECORD=1 - replay test supplies the recorded judge when the scenario has a rubric - replay.test.ts round-trips judge turns (verified: a failing recorded verdict fails the replay)
1 parent 8bf9c01 commit 69af5d7

4 files changed

Lines changed: 24 additions & 1 deletion

File tree

‎apps/sim/evals/agent-tool-use/agent-tool-use.live.test.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,20 @@ describe.skipIf(!LIVE)('agent tool-use eval suite (live DeepSeek)', () => {
6262
'$id: $name',
6363
async (scenario) => {
6464
const base = createDeepSeekLiveCompletion(MODEL)
65-
const judgeCompletion = scenario.judge ? createDeepSeekLiveCompletion(JUDGE_MODEL) : undefined
65+
const judgeBase = scenario.judge ? createDeepSeekLiveCompletion(JUDGE_MODEL) : undefined
6666
const results: AgentToolUseResult[] = []
6767

6868
for (let trial = 0; trial < TRIALS; trial++) {
6969
const recordedTurns: ChatCompletionChunk[][] = []
70+
const recordedJudgeTurns: ChatCompletionChunk[][] = []
7071
const completion =
7172
RECORD && trial === 0
7273
? createRecordingCompletion(base, (turn) => recordedTurns.push(turn))
7374
: base
75+
const judgeCompletion =
76+
judgeBase && RECORD && trial === 0
77+
? createRecordingCompletion(judgeBase, (turn) => recordedJudgeTurns.push(turn))
78+
: judgeBase
7479

7580
results.push(
7681
await runScenario(scenario, {
@@ -96,6 +101,7 @@ describe.skipIf(!LIVE)('agent tool-use eval suite (live DeepSeek)', () => {
96101
model: MODEL,
97102
recordedAt: new Date().toISOString(),
98103
turns: recordedTurns,
104+
...(judgeBase ? { judgeModel: JUDGE_MODEL, judgeTurns: recordedJudgeTurns } : {}),
99105
})
100106
}
101107
}

‎apps/sim/evals/agent-tool-use/agent-tool-use.replay.test.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ describe.skipIf(replayCases.length === 0)('agent tool-use replay suite', () => {
4242
mode: 'live',
4343
model: fixture.model,
4444
providerName: 'Replay',
45+
...(scenario.judge && fixture.judgeTurns
46+
? {
47+
judge: {
48+
completion: createReplayCompletion(fixture.judgeTurns),
49+
model: fixture.judgeModel ?? 'replay-judge',
50+
rubric: scenario.judge,
51+
},
52+
}
53+
: {}),
4554
})
4655

4756
const failed = result.checks.filter((entry) => !entry.passed)

‎apps/sim/evals/agent-tool-use/replay.test.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ describe('replay primitives', () => {
7676
model: 'deepseek-chat',
7777
recordedAt: '2026-01-01T00:00:00.000Z',
7878
turns: [[chunk('a')]],
79+
judgeModel: 'deepseek-chat',
80+
judgeTurns: [[chunk('judge')]],
7981
})
8082

8183
expect(existsSync(replayFixturePath(directory, 'single-tool-lookup'))).toBe(true)
@@ -84,8 +86,10 @@ describe('replay primitives', () => {
8486
expect(fixtures[0]).toMatchObject({
8587
scenarioId: 'single-tool-lookup',
8688
model: 'deepseek-chat',
89+
judgeModel: 'deepseek-chat',
8790
})
8891
expect(fixtures[0].turns).toEqual([[chunk('a')]])
92+
expect(fixtures[0].judgeTurns).toEqual([[chunk('judge')]])
8993
} finally {
9094
rmSync(directory, { recursive: true, force: true })
9195
}

‎apps/sim/evals/agent-tool-use/replay.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ export interface ReplayFixture {
1818
recordedAt: string
1919
/** One entry per model call; each holds the chunks that call streamed. */
2020
turns: ChatCompletionChunk[][]
21+
/** Judge model, present when the scenario was judged during recording. */
22+
judgeModel?: string
23+
/** Judge calls, so replay reproduces a judged pass/fail instead of skipping it. */
24+
judgeTurns?: ChatCompletionChunk[][]
2125
}
2226

2327
export function replayFixturePath(directory: string, scenarioId: string): string {

0 commit comments

Comments
 (0)