import { useMemo, type ReactNode } from 'react' import { cn } from '../../lib/utils' import { MarkdownBody } from '../markdown' import { ReasoningStep } from '../reasoning-step' import { StreamingMarkdownBlock } from '../streaming-markdown-block' import { ImageGenerating as ImageGeneratingBase } from '../image-generating' import { useResponseContext } from './context' import type { ResponseThinkingProps, ResponseStepsProps, ResponseStepProps, ResponseContentProps, ResponseImageGeneratingProps, ResponseDefaultLayoutProps, } from './types' // ===== Response.Thinking ===== export function ResponseThinking({ className }: ResponseThinkingProps) { const ctx = useResponseContext() const effectiveShowThink = ctx.simulate ? ctx.showThink : ctx.phase === 'thinking' || ctx.phase === 'streaming' if (!effectiveShowThink) return null return {ctx.thinkingIndicator} } ResponseThinking.displayName = 'ResponseThinking' // ===== Response.Steps ===== export function ResponseSteps({ className, children }: ResponseStepsProps) { return
{children}
} ResponseSteps.displayName = 'ResponseSteps' // ===== Response.Step ===== export function ResponseStepComponent({ step, status = 'completed' }: ResponseStepProps) { return ( ) } ResponseStepComponent.displayName = 'ResponseStep' // ===== Response.Content ===== export function ResponseContent({ markdown, streaming = false, onStreamComplete, className, }: ResponseContentProps) { const ctx = useResponseContext() const content = markdown ?? ctx.finalMarkdown if (streaming) { return (
) } return (
{content}
) } ResponseContent.displayName = 'ResponseContent' // ===== Response.ImageGenerating ===== export function ResponseImageGenerating({ width = '320px', height = '240px', className, }: ResponseImageGeneratingProps) { return } ResponseImageGenerating.displayName = 'ResponseImageGenerating' // ===== Response.DefaultLayout ===== export function ResponseDefaultLayout({ className }: ResponseDefaultLayoutProps) { const ctx = useResponseContext() // 模拟模式:流式渲染 - useMemo 必须在条件语句前调用 const contentElements = useMemo(() => { if (!ctx.simulate) return [] const el: ReactNode[] = [] const upTo = Math.min(ctx.visibleIndex, ctx.blocks.length - 1) let lastVisibleComposerIndex = -1 for (let j = 0; j <= upTo; j++) { if (ctx.blocks[j]?.type === 'composer') lastVisibleComposerIndex = j } for (let i = 0; i <= upTo; i++) { const b = ctx.blocks[i] if (!b) continue if (b.type === 'think') { if (i === ctx.visibleIndex) { el.push({ctx.thinkingIndicator}) } continue } if (b.type === 'composer' && b.step) { const inProgress = i === lastVisibleComposerIndex && !ctx.isSimDone el.push( ) } if (b.type === 'md' && b.md) { el.push(
{ ctx.setVisibleIndex((v) => Math.min(v + 1, ctx.blocks.length)) if (i + 1 >= ctx.blocks.length) ctx.onSimulateComplete?.() }} />
) } } return el }, [ctx]) // 静态内容元素(非模拟模式) const staticElements = useMemo(() => { if (ctx.simulate) return [] const staticEl: ReactNode[] = [] for (let i = 0; i < ctx.blocks.length; i++) { const b = ctx.blocks[i] if (!b) continue if (b.type === 'composer' && b.step) { staticEl.push( ) } if (b.type === 'md' && b.md) { staticEl.push(
{b.md}
) } } return staticEl }, [ctx]) // imageGenerating 阶段 if (ctx.phase === 'imageGenerating') { return (
) } // 非模拟模式:静态渲染 if (!ctx.simulate) { return (
{staticElements}
{(ctx.phase === 'thinking' || ctx.phase === 'streaming') && ctx.thinkingIndicator}
) } // 模拟模式 return (
{contentElements}
) } ResponseDefaultLayout.displayName = 'ResponseDefaultLayout'