diff --git a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/MessageList/MessageList.tsx b/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/MessageList/MessageList.tsx deleted file mode 100644 index 22b51c0a92..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/MessageList/MessageList.tsx +++ /dev/null @@ -1,121 +0,0 @@ -"use client"; - -import { cn } from "@/lib/utils"; -import { ChatMessage } from "../ChatMessage/ChatMessage"; -import type { ChatMessageData } from "../ChatMessage/useChatMessage"; -import { StreamingMessage } from "../StreamingMessage/StreamingMessage"; -import { ThinkingMessage } from "../ThinkingMessage/ThinkingMessage"; -import { useMessageList } from "./useMessageList"; - -export interface MessageListProps { - messages: ChatMessageData[]; - streamingChunks?: string[]; - isStreaming?: boolean; - className?: string; - onStreamComplete?: () => void; - onSendMessage?: (content: string) => void; -} - -export function MessageList({ - messages, - streamingChunks = [], - isStreaming = false, - className, - onStreamComplete, - onSendMessage, -}: MessageListProps) { - const { messagesEndRef, messagesContainerRef } = useMessageList({ - messageCount: messages.length, - isStreaming, - }); - - return ( -
-
- {/* Render all persisted messages */} - {messages.map((message, index) => { - // Check if current message is an agent_output tool_response - // and if previous message is an assistant message - let agentOutput: ChatMessageData | undefined; - - if (message.type === "tool_response" && message.result) { - let parsedResult: Record | null = null; - try { - parsedResult = - typeof message.result === "string" - ? JSON.parse(message.result) - : (message.result as Record); - } catch { - parsedResult = null; - } - if (parsedResult?.type === "agent_output") { - const prevMessage = messages[index - 1]; - if ( - prevMessage && - prevMessage.type === "message" && - prevMessage.role === "assistant" - ) { - // This agent output will be rendered inside the previous assistant message - // Skip rendering this message separately - return null; - } - } - } - - // Check if next message is an agent_output tool_response to include in current assistant message - if (message.type === "message" && message.role === "assistant") { - const nextMessage = messages[index + 1]; - if ( - nextMessage && - nextMessage.type === "tool_response" && - nextMessage.result - ) { - let parsedResult: Record | null = null; - try { - parsedResult = - typeof nextMessage.result === "string" - ? JSON.parse(nextMessage.result) - : (nextMessage.result as Record); - } catch { - parsedResult = null; - } - if (parsedResult?.type === "agent_output") { - agentOutput = nextMessage; - } - } - } - - return ( - - ); - })} - - {/* Render thinking message when streaming but no chunks yet */} - {isStreaming && streamingChunks.length === 0 && } - - {/* Render streaming message if active */} - {isStreaming && streamingChunks.length > 0 && ( - - )} - - {/* Invisible div to scroll to */} -
-
-
- ); -} diff --git a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolCallMessage/ToolCallMessage.tsx b/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolCallMessage/ToolCallMessage.tsx deleted file mode 100644 index 97590ae0cf..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolCallMessage/ToolCallMessage.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Text } from "@/components/atoms/Text/Text"; -import { cn } from "@/lib/utils"; -import { WrenchIcon } from "@phosphor-icons/react"; -import { getToolActionPhrase } from "../../helpers"; - -export interface ToolCallMessageProps { - toolName: string; - className?: string; -} - -export function ToolCallMessage({ toolName, className }: ToolCallMessageProps) { - return ( -
- - - {getToolActionPhrase(toolName)}... - -
- ); -} diff --git a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolResponseMessage/ToolResponseMessage.tsx b/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolResponseMessage/ToolResponseMessage.tsx deleted file mode 100644 index b84204c3ff..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/chat/components/Chat/components/ToolResponseMessage/ToolResponseMessage.tsx +++ /dev/null @@ -1,260 +0,0 @@ -import { Text } from "@/components/atoms/Text/Text"; -import "@/components/contextual/OutputRenderers"; -import { - globalRegistry, - OutputItem, -} from "@/components/contextual/OutputRenderers"; -import { cn } from "@/lib/utils"; -import type { ToolResult } from "@/types/chat"; -import { WrenchIcon } from "@phosphor-icons/react"; -import { getToolActionPhrase } from "../../helpers"; - -export interface ToolResponseMessageProps { - toolName: string; - result?: ToolResult; - success?: boolean; - className?: string; -} - -export function ToolResponseMessage({ - toolName, - result, - success: _success = true, - className, -}: ToolResponseMessageProps) { - if (!result) { - return ( -
- - - {getToolActionPhrase(toolName)}... - -
- ); - } - - let parsedResult: Record | null = null; - try { - parsedResult = - typeof result === "string" - ? JSON.parse(result) - : (result as Record); - } catch { - parsedResult = null; - } - - if (parsedResult && typeof parsedResult === "object") { - const responseType = parsedResult.type as string | undefined; - - if (responseType === "agent_output") { - const execution = parsedResult.execution as - | { - outputs?: Record; - } - | null - | undefined; - const outputs = execution?.outputs || {}; - const message = parsedResult.message as string | undefined; - - return ( -
-
- - - {getToolActionPhrase(toolName)} - -
- {message && ( -
- - {message} - -
- )} - {Object.keys(outputs).length > 0 && ( -
- {Object.entries(outputs).map(([outputName, values]) => - values.map((value, index) => { - const renderer = globalRegistry.getRenderer(value); - if (renderer) { - return ( - - ); - } - return ( -
- - {outputName} - -
-                        {JSON.stringify(value, null, 2)}
-                      
-
- ); - }), - )} -
- )} -
- ); - } - - if (responseType === "block_output" && parsedResult.outputs) { - const outputs = parsedResult.outputs as Record; - - return ( -
-
- - - {getToolActionPhrase(toolName)} - -
-
- {Object.entries(outputs).map(([outputName, values]) => - values.map((value, index) => { - const renderer = globalRegistry.getRenderer(value); - if (renderer) { - return ( - - ); - } - return ( -
- - {outputName} - -
-                      {JSON.stringify(value, null, 2)}
-                    
-
- ); - }), - )} -
-
- ); - } - - // Handle other response types with a message field (e.g., understanding_updated) - if (parsedResult.message && typeof parsedResult.message === "string") { - // Format tool name from snake_case to Title Case - const formattedToolName = toolName - .split("_") - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" "); - - // Clean up message - remove incomplete user_name references - let cleanedMessage = parsedResult.message; - // Remove "Updated understanding with: user_name" pattern if user_name is just a placeholder - cleanedMessage = cleanedMessage.replace( - /Updated understanding with:\s*user_name\.?\s*/gi, - "", - ); - // Remove standalone user_name references - cleanedMessage = cleanedMessage.replace(/\buser_name\b\.?\s*/gi, ""); - cleanedMessage = cleanedMessage.trim(); - - // Only show message if it has content after cleaning - if (!cleanedMessage) { - return ( -
- - - {formattedToolName} - -
- ); - } - - return ( -
-
- - - {formattedToolName} - -
-
- - {cleanedMessage} - -
-
- ); - } - } - - const renderer = globalRegistry.getRenderer(result); - if (renderer) { - return ( -
-
- - - {getToolActionPhrase(toolName)} - -
- -
- ); - } - - return ( -
- - - {getToolActionPhrase(toolName)}... - -
- ); -} diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/components/CopilotShell/CopilotShell.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/components/CopilotShell/CopilotShell.tsx index 89580cb5db..ef95fe1980 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/components/CopilotShell/CopilotShell.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/components/CopilotShell/CopilotShell.tsx @@ -1,8 +1,9 @@ "use client"; +import { Skeleton } from "@/components/__legacy__/ui/skeleton"; import { Button } from "@/components/atoms/Button/Button"; -import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner"; import { Text } from "@/components/atoms/Text/Text"; +import { ChatLoader } from "@/components/contextual/Chat/components/ChatLoader/ChatLoader"; import { InfiniteList } from "@/components/molecules/InfiniteList/InfiniteList"; import { scrollbarStyles } from "@/components/styles/scrollbars"; import { NAVBAR_HEIGHT_PX } from "@/lib/constants"; @@ -35,15 +36,15 @@ export function CopilotShell({ children }: CopilotShellProps) { isReadyToShowContent, } = useCopilotShell(); - console.log(sessions) - function renderSessionsList() { - if (isLoading && sessions.length === 0) { + if (isLoading) { return ( -
- - Loading sessions... - +
+ {Array.from({ length: 5 }).map((_, i) => ( +
+ +
+ ))}
); } @@ -99,7 +100,7 @@ export function CopilotShell({ children }: CopilotShellProps) { style={{ height: `calc(100vh - ${NAVBAR_HEIGHT_PX}px)` }} > {!isMobile ? ( -