import { AIMessage, ToolMessage } from "@langchain/langgraph-sdk"; import { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { ChevronDown, ChevronUp } from "lucide-react"; function isComplexValue(value: any): boolean { return Array.isArray(value) || (typeof value === "object" && value !== null); } export function ToolCalls({ toolCalls, }: { toolCalls: AIMessage["tool_calls"]; }) { if (!toolCalls || toolCalls.length === 0) return null; return (
{toolCalls.map((tc, idx) => { const args = tc.args as Record; if (!tc.args || Object.keys(args).length === 0) return null; return (

{tc.name} {tc.id && ( {tc.id} )}

{Object.entries(args).map(([key, value], argIdx) => ( ))}
{key} {isComplexValue(value) ? ( {JSON.stringify(value, null, 2)} ) : ( String(value) )}
); })}
); } export function ToolResult({ message }: { message: ToolMessage }) { const [isExpanded, setIsExpanded] = useState(false); let parsedContent: any; let isJsonContent = false; try { if (typeof message.content === "string") { parsedContent = JSON.parse(message.content); isJsonContent = true; } } catch { // Content is not JSON, use as is parsedContent = message.content; } const contentStr = isJsonContent ? JSON.stringify(parsedContent, null, 2) : String(message.content); const contentLines = contentStr.split("\n"); const shouldTruncate = contentLines.length > 4 || contentStr.length > 500; const displayedContent = shouldTruncate && !isExpanded ? contentStr.length > 500 ? contentStr.slice(0, 500) + "..." : contentLines.slice(0, 4).join("\n") + "\n..." : contentStr; return (
{message.name ? (

Tool Result:{" "} {message.name}

) : (

Tool Result

)} {message.tool_call_id && ( {message.tool_call_id} )}
{isJsonContent ? ( {(Array.isArray(parsedContent) ? isExpanded ? parsedContent : parsedContent.slice(0, 5) : Object.entries(parsedContent) ).map((item, argIdx) => { const [key, value] = Array.isArray(parsedContent) ? [argIdx, item] : [item[0], item[1]]; return ( ); })}
{key} {isComplexValue(value) ? ( {JSON.stringify(value, null, 2)} ) : ( String(value) )}
) : ( {displayedContent} )}
{((shouldTruncate && !isJsonContent) || (isJsonContent && Array.isArray(parsedContent) && parsedContent.length > 5)) && ( setIsExpanded(!isExpanded)} className="w-full py-2 flex items-center justify-center border-t-[1px] border-gray-200 text-gray-500 hover:text-gray-600 hover:bg-gray-50 transition-all ease-in-out duration-200 cursor-pointer" initial={{ scale: 1 }} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > {isExpanded ? : } )}
); }