1import type {
2 OrchestrationV2Run,
3 OrchestrationV2RunAttempt,
4 OrchestrationV2TurnItem,
5 OrchestrationV2UserMessageInputIntent,
6} from "@t3tools/contracts";
7
8type TimelineRun = Pick<OrchestrationV2Run, "id" | "status">;
9type TimelineRunAttempt = Pick<OrchestrationV2RunAttempt, "runId" | "rootNodeId" | "status">;
10type TimelineTurnItem = Pick<OrchestrationV2TurnItem, "type" | "runId" | "nodeId"> & {
11 readonly inputIntent?: OrchestrationV2UserMessageInputIntent;
12};
13
14function isOrchestrationV2SupersededInterrupt(input: {
15 readonly item: TimelineTurnItem;
16 readonly attempts: ReadonlyArray<TimelineRunAttempt>;
17 readonly items: ReadonlyArray<TimelineTurnItem>;
18}): boolean {
19 const { item } = input;
20 if (item.type !== "run_interrupt_result" || item.runId === null || item.nodeId === null) {
21 return false;
22 }
23
24 const isSuperseded = input.attempts.some(
25 (attempt) =>
26 attempt.runId === item.runId &&
27 attempt.rootNodeId === item.nodeId &&
28 attempt.status === "superseded",
29 );
30 if (!isSuperseded) {
31 return false;
32 }
33
34 // Show paired stop-then-steer results; hide legacy plain-steer results without matching requests.
35 const hasMatchingRequest = input.items.some(
36 (candidate) => candidate.type === "run_interrupt_request" && candidate.runId === item.runId,
37 );
38 return !hasMatchingRequest;
39}
40
41export function isOrchestrationV2TurnItemVisible(input: {
42 readonly item: TimelineTurnItem;
43 readonly runs: ReadonlyArray<TimelineRun>;
44 readonly attempts: ReadonlyArray<TimelineRunAttempt>;
45 readonly items: ReadonlyArray<TimelineTurnItem>;
46}): boolean {
47 const { item } = input;
48 if (
49 item.runId !== null &&
50 input.runs.some((run) => run.id === item.runId && run.status === "rolled_back")
51 ) {
52 return false;
53 }
54
55 // A steer can return to the queue before delivery. Keep its retained item out
56 // of conversation history until its run starts; cancelled queued inputs stay hidden.
57 if (
58 item.type === "user_message" &&
59 item.inputIntent === "queued_turn" &&
60 item.runId !== null &&
61 input.runs.some(
62 (run) => run.id === item.runId && (run.status === "queued" || run.status === "cancelled"),
63 )
64 ) {
65 return false;
66 }
67
68 return !isOrchestrationV2SupersededInterrupt({
69 item,
70 attempts: input.attempts,
71 items: input.items,
72 });
73}
74
75export function createOrchestrationV2TurnItemVisibility(input: {
76 readonly runs: ReadonlyArray<TimelineRun>;
77 readonly attempts: ReadonlyArray<TimelineRunAttempt>;
78 readonly items: ReadonlyArray<TimelineTurnItem>;
79}): (item: TimelineTurnItem) => boolean {
80 const statuses = new Map<TimelineRun["id"], TimelineRun["status"]>();
81 for (const run of input.runs) {
82 if (run.status === "rolled_back" || run.status === "cancelled" || run.status === "queued")
83 statuses.set(run.id, run.status);
84 else statuses.delete(run.id);
85 }
86 const supersededRoots = new Map<
87 TimelineRunAttempt["runId"],
88 Set<TimelineRunAttempt["rootNodeId"]>
89 >();
90 for (const attempt of input.attempts) {
91 if (attempt.status !== "superseded") continue;
92 let roots = supersededRoots.get(attempt.runId);
93 if (roots === undefined) supersededRoots.set(attempt.runId, (roots = new Set()));
94 roots.add(attempt.rootNodeId);
95 }
96 if (statuses.size === 0 && supersededRoots.size === 0) return () => true;
97 const interruptRuns = new Set<TimelineTurnItem["runId"]>();
98 if (supersededRoots.size > 0) {
99 for (const item of input.items) {
100 if (item.type === "run_interrupt_request") interruptRuns.add(item.runId);
101 }
102 }
103 return (item) => {
104 const status = item.runId === null ? undefined : statuses.get(item.runId);
105 if (status === "rolled_back") return false;
106 if (
107 (status === "queued" || status === "cancelled") &&
108 item.type === "user_message" &&
109 item.inputIntent === "queued_turn"
110 )
111 return false;
112 return !(
113 item.type === "run_interrupt_result" &&
114 item.runId !== null &&
115 item.nodeId !== null &&
116 supersededRoots.get(item.runId)?.has(item.nodeId) === true &&
117 !interruptRuns.has(item.runId)
118 );
119 };
120}