import { useMemo } from 'react' import { extractAssistantOutputTargets } from '../../lib/assistantOutputTargets' import { previewFsUrl } from '../../lib/handlePreviewLink' import { getServerBaseUrl } from '../../lib/desktopRuntime' type GalleryVideo = { src: string name: string } type Props = { text: string /** * Required to build a `/preview-fs//...` URL. When absent (e.g. * tool-log usage) nothing renders — relative workspace videos can't be served * without a session, and we deliberately keep media out of tool logs. */ sessionId?: string workDir?: string | null } /** * Renders AI-output video paths (mp4/webm/mov/m4v) inline, mirroring * {@link InlineImageGallery}. Only relative workspace paths are surfaced (via the * sandboxed target extractor + `/preview-fs`); videos are large so we use a * vertical stack, `preload="metadata"`, and never autoplay. */ export function InlineVideoGallery({ text, sessionId, workDir }: Props) { const videos = useMemo(() => { if (!sessionId) { return [] } const base = getServerBaseUrl() const targets = extractAssistantOutputTargets(text, { workDir }).filter( (target) => target.kind === 'video', ) const seenSrc = new Set() const result: GalleryVideo[] = [] for (const target of targets) { const relPath = target.normalizedPath ?? target.href const src = previewFsUrl(base, sessionId, relPath) if (seenSrc.has(src)) { continue } seenSrc.add(src) result.push({ src, name: relPath.split('/').pop() ?? '' }) } return result }, [sessionId, text, workDir]) if (videos.length === 0) return null return (
{videos.map((video) => (
))}
) }