import type { ContentPart, UnifiedMessage } from "./types"; export function textOf(parts: ContentPart[] | undefined | null): string { if (!parts) return ""; return parts .filter((p): p is Extract => p.type === "text") .map((p) => p.text) .join(""); } export function hasImages(messages: UnifiedMessage[]): boolean { return messages.some((m) => m.content.some((p) => p.type === "image")); } export function hasFiles(messages: UnifiedMessage[]): boolean { return messages.some((m) => m.content.some((p) => p.type === "file")); } export const IMAGE_MIME = new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]); export const TEXT_LIKE_MIME = new Set([ "text/plain", "text/markdown", "text/csv", "application/json", "text/html", "text/xml", "application/xml", "text/x-python", "text/javascript", "application/javascript", "text/typescript", "application/typescript", "text/x-c", "text/x-java", "text/x-go", "text/x-rust", "text/x-sh", "application/x-yaml", "text/yaml", ]); export function isTextLike(mime: string, name?: string): boolean { if (TEXT_LIKE_MIME.has(mime) || mime.startsWith("text/")) return true; if (name && /\.(md|txt|csv|json|ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php|c|cc|cpp|h|hpp|cs|sh|zsh|yaml|yml|toml|ini|sql|html|css|scss|xml|r|jl|lua|m|scala|dart|tex)$/i.test(name)) return true; return false; } /** Fallback for providers that don't accept text files natively: inline the file content. */ export function inlineTextFile(name: string, base64: string): string { const text = Buffer.from(base64, "base64").toString("utf8"); return `\n${text}\n`; }