1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertBaseProjection,
7 assertSemanticProjectionIntegrity,
8 assertTurnItemTypes,
9 assertUserMessagesInclude,
10 assertVisibleTurnItemsMirrorLocalTurnItems,
11 projectionFor,
12 TURN_INTERRUPT_PROMPT,
13} from "../shared.ts";
14
15export function assertTurnInterruptOutput(
16 result: OrchestratorV2ScenarioResult,
17 transcript: ProviderReplayTranscript,
18) {
19 assertBaseProjection({ result, transcript, runCount: 1, runStatuses: ["interrupted"] });
20
21 const projection = projectionFor(result, transcript.scenario);
22 assertSemanticProjectionIntegrity(projection);
23 assertVisibleTurnItemsMirrorLocalTurnItems(projection);
24 assertTurnItemTypes(projection, [
25 "user_message",
26 "run_interrupt_request",
27 "run_interrupt_result",
28 ]);
29 assertUserMessagesInclude(projection, [TURN_INTERRUPT_PROMPT]);
30 const interruptRequest = projection.turnItems.find(
31 (item) => item.type === "run_interrupt_request",
32 );
33 const interruptResult = projection.turnItems.find((item) => item.type === "run_interrupt_result");
34 assert.isDefined(interruptRequest);
35 assert.isDefined(interruptResult);
36 assert.equal(interruptRequest.status, "completed");
37 assert.equal(interruptResult.status, "interrupted");
38 assert.equal(interruptResult.parentItemId, interruptRequest.id);
39 assert.deepEqual(
40 projection.attempts.map((attempt) => attempt.status),
41 ["interrupted"],
42 );
43 assert.deepEqual(
44 projection.nodes.map((node) => node.status),
45 ["interrupted"],
46 );
47 assert.equal(projection.providerThreads[0]?.status, "idle");
48 assert.include(["interrupted", "cancelled"], projection.providerTurns[0]?.status);
49}