/** * * Copyright 2023-2025 InspectorRAGet Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **/ import cx from 'classnames'; import Balancer from 'react-wrap-balancer'; import { useState, useEffect, useRef } from 'react'; import { CodeSnippet } from '@carbon/react'; import { Message, ToolCall, ToolMessage, AssistantMessage } from '@/src/types'; import Avatar from '@/src/components/avatar/Avatar'; import DocumentsViewer from '@/src/components/documents-viewer/DocumentsViewer'; import classes from './ChatLine.module.scss'; // =================================================================================== // TYPES // =================================================================================== interface ChatLineProps { messageId: string; message: Message; latestResponse?: boolean; onSelection?: Function; focused?: boolean; } // =================================================================================== // RENDER FUNCTIONS // =================================================================================== function Tool({ tool }: { tool: ToolCall }) { return (
Tool ID: {tool.id}  {tool.function.name ? ({tool.function.name}) : null} {tool.function.arguments ? ( {JSON.stringify(tool.function.arguments, null, 2)} ) : null}
); } function ToolResponse({ messageId, message, onSelection, }: { messageId: string; message: ToolMessage; onSelection?: Function; }) { // Step 1: Initialize state and necessary variables const [documentIndex, setDocumentIndex] = useState(0); // Step 2: Render return (
Tool Call ID: {message.tool_call_id}  {message.name ? ({message.name}) : null} {message.type === 'documents' && Array.isArray(message.content) ? ( ) : message.type === 'json' ? ( {JSON.stringify(message.content, null, 2)} ) : ( { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].content`, ); } }} onMouseUp={() => { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].content`, ); } }} > {typeof message.content === 'string' ? message.content.split('\n').map((line, i) => ( {line}
)) : message.content}
)}
); } function AssistantResponse({ messageId, message, onSelection, }: { messageId: string; message: AssistantMessage; onSelection?: Function; }) { return (
{message.content ? ( { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].content`, ); } }} onMouseUp={() => { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].content`, ); } }} > {message.content.split('\n').map((line, i) => ( {line}
))}
) : null} {message.tool_calls ? message.tool_calls.map((tool, toolIdx) => { return ( ); }) : null}
); } // =================================================================================== // MAIN FUNCTIONS // =================================================================================== export default function ChatLine({ messageId, message, latestResponse, onSelection, focused, }: ChatLineProps) { // Step 1: Initialize state and necessary variables const anchorRef = useRef(null); // Step 2: Run effects // Step 2.a: Scroll into view useEffect(() => { if (anchorRef.current && focused) { anchorRef.current.scrollIntoView({ behavior: 'smooth', block: message.role === 'user' ? 'start' : 'center', inline: 'center', }); } }, [focused, message.role]); // Step 3: Render // Step 3.a: Return "null" if message is undefined if (!message) { return null; } // Step 3.b: Render chat line return (
{message.role === 'system' || message.role === 'developer' || message.role === 'user' ? ( { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].text`, ); } }} onMouseUp={() => { if (onSelection) { onSelection( `messages[${messageId.split('--').slice(-1)[0]}].text`, ); } }} > {message.content.split('\n').map((line, i) => ( {line}
))}
) : message.role === 'tool' ? ( //@ts-ignore ) : ( )}
); }