import { useEffect, useMemo, useState } from 'react' import { IconCheck, IconCopy } from '@tabler/icons-react' import { cn } from '@/client/lib/cn' import type { ToolCall } from '@/lib/types' import { Button } from '@/client/components/ui/button' import { CodeBlock } from './CodeBlock' import { detectOutput } from './detect' type ToolOutputProps = { call: ToolCall; output: string; isError: boolean } const PRE = 'max-h-[280px] overflow-auto px-3 py-2.5 font-mono text-xs leading-relaxed' // Renders a tool result, choosing a view from `detectOutput`: a syntax- // highlighted code/json block (with a raw ↔ formatted switch), or plain text. export function ToolOutput({ call, output, isError }: ToolOutputProps) { const [raw, setRaw] = useState(false) // Detection runs JSON.parse/stringify — memoize so toggling raw/json (or any // re-render) doesn't re-detect. Errors always render as plain red text. const view = useMemo( () => (isError ? ({ kind: 'plain' } as const) : detectOutput(call, output)), [call, output, isError] ) if (view.kind === 'plain') { return (
{output || '(empty)'}
{output || '(empty)'}
) : (