import type { MessageId, ModelSelection, NodeId, OrchestrationV2AppThread, OrchestrationV2Actor, OrchestrationV2ConversationMessage, OrchestrationV2CreationSource, OrchestrationV2ProviderRef, OrchestrationV2Run, OrchestrationV2ThreadProjection, OrchestrationV2TurnItem, ProviderInstanceId, ProviderThreadId, ProviderTurnId, ThreadId, TurnItemId, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; function trimmed(value: string | null | undefined): string | undefined { const result = value?.trim(); return result && result.length > 0 ? result : undefined; } export function subagentThreadTitle(input: { readonly parentTitle: string; readonly title?: string | null; readonly prompt: string; readonly ordinal: number; }): string { const detail = trimmed(input.title) ?? trimmed(input.prompt); if (detail === undefined) { return `${input.parentTitle} subagent ${input.ordinal}`; } const clipped = detail.length > 72 ? `${detail.slice(0, 69)}...` : detail; return clipped; } export function makeSubagentChildThread(input: { readonly parentThread: OrchestrationV2AppThread; readonly childThreadId: ThreadId; readonly parentNodeId: NodeId; readonly activeProviderThreadId: ProviderThreadId | null; readonly providerInstanceId: ProviderInstanceId; readonly modelSelection: ModelSelection; readonly title: string; readonly now: DateTime.Utc; readonly createdBy: OrchestrationV2Actor; readonly creationSource: OrchestrationV2CreationSource; }): OrchestrationV2AppThread { return { ...input.parentThread, createdBy: input.createdBy, creationSource: input.creationSource, id: input.childThreadId, title: input.title, historyOrigin: undefined, providerInstanceId: input.providerInstanceId, modelSelection: input.modelSelection, activeProviderThreadId: input.activeProviderThreadId, lineage: { parentThreadId: input.parentThread.id, relationshipToParent: "subagent", rootThreadId: input.parentThread.lineage.rootThreadId, }, forkedFrom: { type: "node", nodeId: input.parentNodeId, }, createdAt: input.now, updatedAt: input.now, archivedAt: null, settledOverride: null, settledAt: null, snoozedUntil: null, snoozedAt: null, lastVisitedAt: null, deletedAt: null, }; } export function makeSubagentConversationArtifacts(input: { readonly messageId: MessageId; readonly turnItemId: TurnItemId; readonly threadId: ThreadId; readonly rootNodeId: NodeId; readonly providerThreadId: ProviderThreadId | null; readonly providerTurnId: ProviderTurnId | null; readonly nativeItemRef: OrchestrationV2ProviderRef | null; readonly role: "user" | "assistant"; readonly text: string; readonly ordinal: number; readonly now: DateTime.Utc; }): { readonly message: OrchestrationV2ConversationMessage; readonly turnItem: OrchestrationV2TurnItem; } { const message: OrchestrationV2ConversationMessage = { createdBy: "agent", creationSource: "provider", id: input.messageId, threadId: input.threadId, runId: null, nodeId: input.rootNodeId, role: input.role, text: input.text, attachments: [], streaming: false, createdAt: input.now, updatedAt: input.now, }; const base = { id: input.turnItemId, threadId: input.threadId, runId: null, nodeId: input.rootNodeId, providerThreadId: input.providerThreadId, providerTurnId: input.providerTurnId, nativeItemRef: input.nativeItemRef, parentItemId: null, ordinal: input.ordinal, status: "completed" as const, title: null, startedAt: input.now, completedAt: input.now, updatedAt: input.now, messageId: input.messageId, text: input.text, }; const turnItem: OrchestrationV2TurnItem = input.role === "user" ? { ...base, createdBy: "agent", creationSource: "provider", type: "user_message", inputIntent: "turn_start", attachments: [], } : { ...base, type: "assistant_message", streaming: false, }; return { message, turnItem }; } export function subagentResultForRun( projection: OrchestrationV2ThreadProjection, run: OrchestrationV2Run, ): { readonly text: string; readonly messageId: OrchestrationV2ConversationMessage["id"] | null; readonly turnItemId: OrchestrationV2TurnItem["id"] | null; } { const message = projection.messages .filter( (candidate) => candidate.runId === run.id && candidate.role === "assistant" && candidate.text.trim().length > 0, ) .toSorted( (left, right) => DateTime.toEpochMillis(right.updatedAt) - DateTime.toEpochMillis(left.updatedAt), )[0] ?? null; const turnItem = projection.turnItems .filter( ( candidate, ): candidate is Extract => candidate.runId === run.id && candidate.type === "assistant_message" && candidate.text.trim().length > 0, ) .toSorted((left, right) => right.ordinal - left.ordinal)[0] ?? null; const text = message?.text ?? turnItem?.text ?? (run.status === "completed" ? "Child task completed without an assistant result." : `Child task ended with status ${run.status}.`); return { text, messageId: message?.id ?? turnItem?.messageId ?? null, turnItemId: turnItem?.id ?? null, }; }