1import {
2 ORCHESTRATION_V2_WORKSPACE_PREPARATION_FAILURE_CODE,
3 RunId,
4 ThreadId,
5 TurnItemId,
6 type OrchestrationV2Run,
7 type OrchestrationV2TurnItem,
8} from "@t3tools/contracts";
9import * as DateTime from "effect/DateTime";
10import { describe, expect, it } from "vite-plus/test";
11
12import {
13 turnItemIsWorkspacePreparation,
14 workspacePreparationRetryRunIds,
15} from "./turnItemPresentation.ts";
16
17function command(input: string): OrchestrationV2TurnItem {
18 const now = DateTime.makeUnsafe("2026-08-03T00:00:00.000Z");
19 return {
20 id: TurnItemId.make("item-command"),
21 threadId: ThreadId.make("thread-1"),
22 runId: RunId.make("run-1"),
23 nodeId: null,
24 providerThreadId: null,
25 providerTurnId: null,
26 nativeItemRef: null,
27 parentItemId: null,
28 ordinal: 1,
29 status: "completed",
30 title: "Workspace ready",
31 startedAt: now,
32 completedAt: now,
33 updatedAt: now,
34 type: "command_execution",
35 input,
36 output: "Workspace preparation completed.",
37 exitCode: 0,
38 };
39}
40
41function preparationFailure(
42 status: OrchestrationV2TurnItem["status"],
43 code: string | null = ORCHESTRATION_V2_WORKSPACE_PREPARATION_FAILURE_CODE,
44): OrchestrationV2TurnItem {
45 const {
46 input: _input,
47 output: _output,
48 exitCode: _exitCode,
49 ...base
50 } = command("") as Extract<OrchestrationV2TurnItem, { type: "command_execution" }>;
51 return {
52 ...base,
53 id: TurnItemId.make("item-error"),
54 status,
55 title: "Workspace preparation failed",
56 type: "error",
57 failure: { class: "validation_error", message: "fetch failed", code, retryable: false },
58 };
59}
60
61const worktree = { type: "worktree", baseRef: "main" } as const;
62function run(
63 status: OrchestrationV2Run["status"],
64 workspacePreparation?: typeof worktree,
65): Pick<OrchestrationV2Run, "id" | "status" | "workspacePreparation"> {
66 return {
67 id: RunId.make("run-1"),
68 status,
69 ...(workspacePreparation === undefined ? {} : { workspacePreparation }),
70 };
71}
72
73describe("turnItemIsWorkspacePreparation", () => {
74 it("hides a preparation failure only once a retry cancelled it", () => {
75 expect(turnItemIsWorkspacePreparation(preparationFailure("failed"))).toBe(false);
76 expect(turnItemIsWorkspacePreparation(preparationFailure("cancelled"))).toBe(true);
77 expect(turnItemIsWorkspacePreparation(preparationFailure("cancelled", null))).toBe(false);
78 });
79});
80
81describe("workspacePreparationRetryRunIds", () => {
82 it("offers a retry while the run still ends in its failed preparation", () => {
83 const failure = [preparationFailure("failed")];
84 expect([...workspacePreparationRetryRunIds([run("failed", worktree)], failure)]).toEqual([
85 RunId.make("run-1"),
86 ]);
87 expect(workspacePreparationRetryRunIds([run("preparing", worktree)], failure).size).toBe(0);
88 expect(workspacePreparationRetryRunIds([run("failed")], failure).size).toBe(0);
89 expect(
90 workspacePreparationRetryRunIds(
91 [run("failed", worktree)],
92 [preparationFailure("failed", "provider_crashed")],
93 ).size,
94 ).toBe(0);
95 });
96});