| 1 | import { assert } from "@effect/vitest"; |
| 2 | import type { ProviderReplayTranscript } from "@t3tools/contracts"; |
| 3 | |
| 4 | import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts"; |
| 5 | import { assertMultiTurnOutput } from "./codex_output.ts"; |
| 6 | import { projectionFor } from "../shared.ts"; |
| 7 | |
| 8 | function isReplayFrameWithType( |
| 9 | frame: unknown, |
| 10 | type: string, |
| 11 | ): frame is { readonly type: string; readonly options?: Record<string, unknown> } { |
| 12 | return ( |
| 13 | typeof frame === "object" && |
| 14 | frame !== null && |
| 15 | "type" in frame && |
| 16 | (frame as { readonly type?: unknown }).type === type |
| 17 | ); |
| 18 | } |
| 19 | |
| 20 | export function assertMultiTurnClaudeOutput( |
| 21 | result: OrchestratorV2ScenarioResult, |
| 22 | transcript: ProviderReplayTranscript, |
| 23 | ) { |
| 24 | assertMultiTurnOutput(result, transcript); |
| 25 | |
| 26 | const projection = projectionFor(result, transcript.scenario); |
| 27 | assert.lengthOf(projection.providerThreads, 1); |
| 28 | const providerThread = projection.providerThreads[0]; |
| 29 | assert.isDefined(providerThread); |
| 30 | assert.isNotNull(providerThread.nativeThreadRef); |
| 31 | assert.deepEqual( |
| 32 | projection.runs.map((run) => run.providerThreadId), |
| 33 | projection.runs.map(() => providerThread.id), |
| 34 | ); |
| 35 | |
| 36 | const outboundFrames = transcript.entries.flatMap((entry) => |
| 37 | entry.type === "expect_outbound" ? [entry.frame] : [], |
| 38 | ); |
| 39 | const queryOpenFrames = outboundFrames.filter((frame) => |
| 40 | isReplayFrameWithType(frame, "query.open"), |
| 41 | ); |
| 42 | const promptOfferFrames = outboundFrames.filter((frame) => |
| 43 | isReplayFrameWithType(frame, "prompt.offer"), |
| 44 | ); |
| 45 | |
| 46 | assert.lengthOf(promptOfferFrames, 2); |
| 47 | if (transcript.scenario === "multi_turn_restart") { |
| 48 | assert.lengthOf(queryOpenFrames, 2); |
| 49 | assert.isString(queryOpenFrames[1]?.options?.resume); |
| 50 | } else { |
| 51 | assert.lengthOf(queryOpenFrames, 1); |
| 52 | } |
| 53 | } |