import type { ChatFileAttachment as ContractChatFileAttachment, ChatImageAttachment as ContractChatImageAttachment, ChatUnknownAttachment as ContractChatUnknownAttachment, OrchestrationCheckpointFile, OrchestrationCheckpointSummary, OrchestrationLatestTurn, OrchestrationMessage, OrchestrationProposedPlan, OrchestrationSession, ProjectScript as ContractProjectScript, ProviderInteractionMode, RuntimeMode, } from "@t3tools/contracts"; import type { EnvironmentProject, EnvironmentThread, EnvironmentThreadShell, } from "@t3tools/client-runtime/state/shell"; import { videoMimeType } from "@t3tools/shared/video"; export { videoMimeType } from "@t3tools/shared/video"; export type SessionPhase = "disconnected" | "connecting" | "ready" | "running"; export const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access"; export const DEFAULT_INTERACTION_MODE: ProviderInteractionMode = "default"; export const DEFAULT_THREAD_TERMINAL_HEIGHT = 280; export const DEFAULT_THREAD_TERMINAL_ID = "term-1"; export const MAX_TERMINALS_PER_GROUP = 4; export type ProjectScript = ContractProjectScript; export interface ThreadTerminalGroup { id: string; terminalIds: string[]; splitDirection?: "horizontal" | "vertical"; } export interface ChatImageAttachment extends ContractChatImageAttachment { readonly previewUrl?: string; } export interface ChatFileAttachment extends ContractChatFileAttachment { readonly previewUrl?: string; readonly downloadable?: boolean; } // Attachment types this build does not know pass through with the contract // shape. The UI renders them as inert rows so a newer server cannot crash an // older client. export type ChatUnknownAttachment = ContractChatUnknownAttachment; export type ChatAttachment = ChatImageAttachment | ChatFileAttachment | ChatUnknownAttachment; // The union has an open member (`type: string`), so a literal comparison does // not narrow. Use these guards wherever type-specific fields are read. export function isImageAttachment(attachment: ChatAttachment): attachment is ChatImageAttachment { return attachment.type === "image"; } export function isFileAttachment(attachment: ChatAttachment): attachment is ChatFileAttachment { return attachment.type === "file"; } export function isVideoAttachment(attachment: ChatFileAttachment): boolean { return videoMimeType(attachment) !== null; } export function isBrowserPreviewAttachment(attachment: ChatFileAttachment): boolean { const mimeType = attachment.mimeType.split(";", 1)[0]?.trim().toLowerCase(); return ( /\.(?:html?|pdf)$/i.test(attachment.name) || mimeType === "application/pdf" || mimeType === "text/html" ); } export interface ChatMessage extends Omit { readonly attachments?: ReadonlyArray | undefined; } export type ProposedPlan = OrchestrationProposedPlan; export type TurnDiffFileChange = OrchestrationCheckpointFile; export type TurnDiffSummary = OrchestrationCheckpointSummary; export type Project = EnvironmentProject; export type Thread = EnvironmentThread; export type ThreadShell = EnvironmentThreadShell; export interface ThreadTurnState { latestTurn: OrchestrationLatestTurn | null; } export type SidebarThreadSummary = EnvironmentThreadShell; export type ThreadSession = OrchestrationSession;