1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertAssistantTextIncludes,
7 assertBaseProjection,
8 assertSemanticProjectionIntegrity,
9 assertUserMessagesInclude,
10 assertVisibleTurnItemsMirrorLocalTurnItems,
11 OPENCODE2_COMPACTION_FIRST_PROMPT,
12 OPENCODE2_COMPACTION_RECALL_PROMPT,
13 projectionFor,
14} from "../shared.ts";
15
16/**
17 * `/compact` runs `session.compact`: OpenCode queues a compaction item and
18 * summarizes in its own execution, which ends the `/compact` turn. The next
19 * turn answers from the summary.
20 */
21export function assertOpenCode2CompactionOutput(
22 result: OrchestratorV2ScenarioResult,
23 transcript: ProviderReplayTranscript,
24) {
25 assertBaseProjection({
26 result,
27 transcript,
28 runCount: 3,
29 runStatuses: ["completed", "completed", "completed"],
30 });
31 const projection = projectionFor(result, transcript.scenario);
32 assertSemanticProjectionIntegrity(projection);
33 assertVisibleTurnItemsMirrorLocalTurnItems(projection);
34 assertUserMessagesInclude(projection, [
35 OPENCODE2_COMPACTION_FIRST_PROMPT,
36 "/compact",
37 OPENCODE2_COMPACTION_RECALL_PROMPT,
38 ]);
39
40 const compactRun = projection.runs[1];
41 const compactions = projection.turnItems.filter((item) => item.type === "compaction");
42 assert.lengthOf(compactions, 1);
43 const [compaction] = compactions;
44 assert.equal(compaction?.runId, compactRun?.id);
45 assert.equal(compaction?.status, "completed");
46 assert.equal(compaction?.title, "Context compacted");
47 // The summary OpenCode carries forward is `compaction.ended`'s full text.
48 assert.include(compaction?.type === "compaction" ? compaction.summary : "", "PAPAYA");
49 assert.include(compaction?.type === "compaction" ? compaction.summary : "", "## Objective");
50 // The `/compact` run shows no assistant reply; the recall run answers from the summary.
51 assert.isUndefined(
52 projection.turnItems.find(
53 (item) => item.type === "assistant_message" && item.runId === compactRun?.id,
54 ),
55 );
56 assertAssistantTextIncludes(projection, "PAPAYA");
57 assert.deepEqual(
58 projection.providerTurns.map((turn) => turn.status),
59 ["completed", "completed", "completed"],
60 );
61}