1import {
2 formatSubagentDisplayTitle,
3 subagentDetailPreview,
4} from "@t3tools/client-runtime/state/subagent-display";
5import { isActiveSubagentStatus } from "@t3tools/client-runtime/state/subagentRuntime";
6import type { OrchestrationV2Subagent } from "@t3tools/contracts";
7
8const PROMPT_TITLE_LIMIT = 80;
9
10export type SubagentRowTone = "working" | "completed" | "failed" | "stopped";
11
12export interface SubagentRowPresentation {
13 readonly title: string;
14 /** Live agents lead with progress; settled ones lead with what came out. */
15 readonly detail: string | null;
16 readonly statusLabel: string;
17 readonly tone: SubagentRowTone;
18 readonly live: boolean;
19 /** Provider-native tasks have no thread of their own to open. */
20 readonly canOpenThread: boolean;
21}
22
23function rowTitle(subagent: Pick<OrchestrationV2Subagent, "title" | "prompt">): string {
24 const title = subagent.title?.trim();
25 if (title) return formatSubagentDisplayTitle(title);
26 const prompt = subagent.prompt.trim();
27 if (prompt.length === 0) return "Subagent";
28 return prompt.length > PROMPT_TITLE_LIMIT
29 ? `${prompt.slice(0, PROMPT_TITLE_LIMIT - 3)}...`
30 : prompt;
31}
32
33function rowTone(status: OrchestrationV2Subagent["status"]): SubagentRowTone {
34 if (isActiveSubagentStatus(status)) return "working";
35 if (status === "completed") return "completed";
36 if (status === "failed") return "failed";
37 return "stopped";
38}
39
40function rowStatusLabel(status: OrchestrationV2Subagent["status"]): string {
41 switch (status) {
42 case "pending":
43 case "running":
44 return "Working";
45 case "waiting":
46 return "Waiting";
47 case "idle":
48 return "Idle";
49 case "completed":
50 return "Completed";
51 case "failed":
52 return "Failed";
53 case "cancelled":
54 return "Cancelled";
55 case "interrupted":
56 return "Interrupted";
57 }
58}
59
60export function resolveSubagentRowPresentation(
61 subagent: Pick<
62 OrchestrationV2Subagent,
63 "title" | "prompt" | "status" | "progress" | "result" | "childThreadId"
64 >,
65): SubagentRowPresentation {
66 const live = isActiveSubagentStatus(subagent.status);
67 return {
68 title: rowTitle(subagent),
69 detail: subagentDetailPreview(subagent),
70 statusLabel: rowStatusLabel(subagent.status),
71 tone: rowTone(subagent.status),
72 live,
73 canOpenThread: subagent.childThreadId !== null,
74 };
75}