conversational-assistant/components/tool-call.tsx (163 lines of code) (raw):

import React from 'react' import { FunctionCallItem, Item } from '@/lib/assistant' import { getComponent } from '@/lib/components-mapping' import { ChevronRight, Code, LoaderCircle, X, Zap } from 'lucide-react' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { coy } from 'react-syntax-highlighter/dist/esm/styles/prism' import { toolDisplayMap } from '@/config/ui/tool-results' interface FunctionCallProps { functionCall: FunctionCallItem previousItem: Item } const ApiCallCell: React.FC<FunctionCallProps> = ({ functionCall, previousItem }) => { const [showDetails, setShowDetails] = React.useState(false) const toggleShowDetails = () => { setShowDetails(!showDetails) } return ( <div className="flex flex-col bg-white rounded-[16px] w-[70%] relative my-3"> <div> {previousItem.type === 'function_call' ? ( <div className="absolute -top-16 pt-1.5 z-0 left-5"> <div className="w-1 h-14 bg-gray-500 bg-opacity-50"></div> </div> ) : null} <div className="flex flex-col text-sm overflow-x-hidden rounded-[16px] z-10"> <div className="font-semibold p-3 pl-4 text-gray-700 rounded-b-none flex justify-between"> <div className="flex items-center"> <Zap size={16} /> <span className="ml-2"> {functionCall.name .split('_') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' ')} </span> </div> <span className={`mt-0.5 transform text-gray-500 cursor-pointer transition-transform duration-300 ${ showDetails ? 'rotate-90' : 'rotate-0' }`} onClick={toggleShowDetails} > <ChevronRight size={16} /> </span> </div> {showDetails && ( <div> <div className="max-h-72 overflow-y-scroll text-xs border-b-[1.5px]"> <SyntaxHighlighter customStyle={{ backgroundColor: '#fff', padding: '8px', paddingLeft: '4px', borderRadius: '0.5rem', borderTopLeftRadius: 0, borderTopRightRadius: 0, marginTop: 0, marginBottom: 0 }} language="json" style={coy} > {JSON.stringify(functionCall.parsedArguments, null, 2)} </SyntaxHighlighter> </div> <div className="max-h-96 overflow-y-scroll min-h-20 rounded-lg rounded-t-none"> {functionCall.output ? ( <SyntaxHighlighter customStyle={{ backgroundColor: '#fff', padding: '8px', paddingLeft: '4px', borderRadius: '0.5rem', marginTop: 0, borderTopLeftRadius: 0, borderTopRightRadius: 0 }} language="json" style={coy} > {JSON.stringify(JSON.parse(functionCall.output), null, 2)} </SyntaxHighlighter> ) : null} </div> </div> )} </div> </div> </div> ) } const ToolCall: React.FC<FunctionCallProps> = ({ functionCall, previousItem }: FunctionCallProps) => { const [showJSON, setShowJSON] = React.useState(false) const toggleShowJSON = () => { setShowJSON(!showJSON) } return ( <div className="flex justify-start pt-8"> {(() => { if (functionCall.name === 'generate_ui') { return ( <div className="w-full relative my-2"> <div className="absolute right-2 -top-6 z-10" onClick={toggleShowJSON} > {showJSON ? ( <X size={20} className="cursor-pointer text-neutral-900 hover:text-neutral-700" /> ) : ( <Code size={20} className="cursor-pointer text-neutral-900 hover:text-neutral-700" /> )} </div> <div className={`text-xs max-h-[500px] font-mono overflow-x-scroll h-full overflow-y-scroll rounded-xl ${ showJSON ? '' : 'hidden' }`} > <SyntaxHighlighter language="json" style={coy} customStyle={{ borderRadius: '0.75rem', paddingTop: '16px', paddingBottom: '16px', marginTop: 0 }} > {JSON.stringify(functionCall.parsedArguments, null, 2)} </SyntaxHighlighter> </div> <div className={`${showJSON ? 'hidden' : ''}`}> {getComponent(functionCall.parsedArguments.component) ?? null} </div> </div> ) } else if (functionCall.name in toolDisplayMap) { const ToolComponent = toolDisplayMap[functionCall.name as keyof typeof toolDisplayMap] return <ToolComponent /> } else { return ( <ApiCallCell functionCall={functionCall} previousItem={previousItem} /> ) } })()} </div> ) } export default ToolCall