import { useState } from 'react'; import type { ReactNode } from 'react'; import { ChevronRight, Wrench } from 'lucide-react'; import type { Message, ToolCall } from '@/api/types'; import { sessionEvents } from '@/hooks/sessionEvents'; interface Props { message?: Message; toolCall?: ToolCall; } // Same regex/heuristic as MessageBubble: paths ending in `.ext` with at // least one `/`. Linkifies file paths emitted by tools like grep / find_files // so they're clickable. const PATH_REGEX = /([a-zA-Z0-9._/-]+\.[a-zA-Z0-9]+)/g; function linkifyOutput(text: string): ReactNode[] { const out: ReactNode[] = []; let lastIdx = 0; let idx = 0; for (const match of text.matchAll(PATH_REGEX)) { const matchedText = match[0]; const start = match.index ?? 0; if (!matchedText.includes('/')) continue; if (start > lastIdx) out.push(text.slice(lastIdx, start)); out.push( ); lastIdx = start + matchedText.length; idx += 1; } if (lastIdx < text.length) out.push(text.slice(lastIdx)); return out.length > 0 ? out : [text]; } export function ToolCallCard({ message, toolCall }: Props) { const [open, setOpen] = useState(false); const tc = toolCall ?? message?.tool_calls?.[0]; const result = message?.tool_results; const name = tc?.name ?? 'tool'; const args = tc?.args ?? {}; const error = result?.error; const output = result?.output; const truncated = result?.truncated; return (
{error}
) : output !== undefined ? (
{linkifyOutput(
typeof output === 'string'
? output
: JSON.stringify(output, null, 2)
)}
) : (