1import {
2 NodeId,
3 ProviderDriverKind,
4 ProviderInstanceId,
5 ProviderSessionId,
6 ProviderThreadId,
7 ProviderTurnId,
8 RunAttemptId,
9 RunId,
10 RuntimeRequestId,
11 TurnItemId,
12 type OrchestrationV2TurnItem,
13} from "@t3tools/contracts";
14import * as DateTime from "effect/DateTime";
15import { describe, expect, it } from "vite-plus/test";
16
17import { v2Projection, v2ThreadId } from "./orchestrationV2TestFixtures.ts";
18import { EMPTY_V2_ITEM_SUPPORT, resolveV2ItemSupport, v2ItemSupportEqual } from "./itemSupport.ts";
19
20const now = DateTime.makeUnsafe("2026-06-20T00:00:00.000Z");
21const runId = RunId.make("run-1");
22const nodeId = NodeId.make("node-1");
23const itemId = TurnItemId.make("item-1");
24const requestId = RuntimeRequestId.make("request-1");
25const providerInstanceId = ProviderInstanceId.make("codex");
26const providerThreadId = ProviderThreadId.make("provider-thread-1");
27const providerTurnId = ProviderTurnId.make("provider-turn-1");
28
29const commandItem: OrchestrationV2TurnItem = {
30 id: itemId,
31 threadId: v2ThreadId,
32 runId,
33 nodeId,
34 providerThreadId,
35 providerTurnId,
36 nativeItemRef: null,
37 parentItemId: null,
38 ordinal: 0,
39 status: "running",
40 title: null,
41 startedAt: now,
42 completedAt: null,
43 updatedAt: now,
44 type: "command_execution",
45 input: "vp check",
46};
47
48describe("resolveV2ItemSupport", () => {
49 it("retains identity while linking a turn item to its execution and provider entities", () => {
50 const run = {
51 id: runId,
52 threadId: v2ThreadId,
53 ordinal: 1,
54 providerInstanceId,
55 modelSelection: { instanceId: providerInstanceId, model: "gpt-5.4" },
56 providerThreadId,
57 userMessageId: "message-1" as never,
58 rootNodeId: nodeId,
59 activeAttemptId: RunAttemptId.make("attempt-2"),
60 status: "running" as const,
61 requestedAt: now,
62 startedAt: now,
63 completedAt: null,
64 checkpointId: null,
65 contextHandoffId: null,
66 };
67 const attempts = [
68 {
69 id: RunAttemptId.make("attempt-1"),
70 runId,
71 attemptOrdinal: 1,
72 rootNodeId: nodeId,
73 providerInstanceId,
74 providerThreadId,
75 providerTurnId,
76 reason: "initial" as const,
77 status: "superseded" as const,
78 startedAt: now,
79 completedAt: now,
80 },
81 {
82 id: RunAttemptId.make("attempt-2"),
83 runId,
84 attemptOrdinal: 2,
85 rootNodeId: nodeId,
86 providerInstanceId,
87 providerThreadId,
88 providerTurnId,
89 reason: "steering_restart" as const,
90 status: "running" as const,
91 startedAt: now,
92 completedAt: null,
93 },
94 ];
95 const node = {
96 id: nodeId,
97 threadId: v2ThreadId,
98 runId,
99 parentNodeId: null,
100 rootNodeId: nodeId,
101 kind: "tool_call" as const,
102 status: "running" as const,
103 countsForRun: true,
104 providerThreadId,
105 providerTurnId,
106 nativeItemRef: null,
107 runtimeRequestId: requestId,
108 checkpointScopeId: null,
109 startedAt: now,
110 completedAt: null,
111 };
112 const providerThread = {
113 id: providerThreadId,
114 driver: ProviderDriverKind.make("codex"),
115 providerInstanceId,
116 providerSessionId: null,
117 appThreadId: v2ThreadId,
118 ownerNodeId: nodeId,
119 nativeThreadRef: null,
120 nativeConversationHeadRef: null,
121 status: "active" as const,
122 firstRunOrdinal: 1,
123 lastRunOrdinal: 1,
124 handoffIds: [],
125 forkedFrom: null,
126 createdAt: now,
127 updatedAt: now,
128 };
129 const providerTurn = {
130 id: providerTurnId,
131 providerThreadId,
132 nodeId,
133 runAttemptId: attempts[1]!.id,
134 nativeTurnRef: null,
135 ordinal: 1,
136 status: "running" as const,
137 startedAt: now,
138 completedAt: null,
139 };
140 const runtimeRequest = {
141 id: requestId,
142 nodeId,
143 providerTurnId,
144 nativeRequestRef: null,
145 kind: "dynamic_tool_call" as const,
146 status: "pending" as const,
147 responseCapability: {
148 type: "live" as const,
149 providerSessionId: ProviderSessionId.make("session-1"),
150 },
151 createdAt: now,
152 resolvedAt: null,
153 };
154 const projection = {
155 ...v2Projection,
156 runs: [run],
157 attempts,
158 nodes: [node],
159 providerThreads: [providerThread],
160 providerTurns: [providerTurn],
161 runtimeRequests: [runtimeRequest],
162 turnItems: [commandItem],
163 };
164
165 const support = resolveV2ItemSupport(projection, itemId);
166 expect(support.item).toBe(commandItem);
167 expect(support.run).toBe(run);
168 expect(support.attempts).toEqual(attempts);
169 expect(support.attempts[0]).toBe(attempts[0]);
170 expect(support.node).toBe(node);
171 expect(support.providerThread).toBe(providerThread);
172 expect(support.providerTurn).toBe(providerTurn);
173 expect(support.runtimeRequest).toBe(runtimeRequest);
174 });
175
176 it("resolves synthetic items from the authoritative visible sequence", () => {
177 const projection = {
178 ...v2Projection,
179 visibleTurnItems: [
180 {
181 position: 0,
182 visibility: "synthetic" as const,
183 sourceThreadId: v2ThreadId,
184 sourceItemId: itemId,
185 item: commandItem,
186 },
187 ],
188 };
189 expect(resolveV2ItemSupport(projection, itemId).item).toBe(commandItem);
190 });
191
192 it("returns the stable empty support for unknown items", () => {
193 expect(resolveV2ItemSupport(v2Projection, itemId)).toBe(EMPTY_V2_ITEM_SUPPORT);
194 });
195
196 it("compares support structurally while retaining entity identity semantics", () => {
197 expect(v2ItemSupportEqual(EMPTY_V2_ITEM_SUPPORT, { ...EMPTY_V2_ITEM_SUPPORT })).toBe(true);
198 expect(
199 v2ItemSupportEqual(EMPTY_V2_ITEM_SUPPORT, {
200 ...EMPTY_V2_ITEM_SUPPORT,
201 attempts: [{ id: "attempt" } as never],
202 }),
203 ).toBe(false);
204 });
205});