import { ScrollToBottom, StickyToBottomContent } from "@/utils/scroll-utils"; import { Message } from "@langchain/langgraph-sdk"; import { getMessageContentString } from "@open-swe/shared/messages"; import { useState } from "react"; import { StickToBottom } from "use-stick-to-bottom"; import { TooltipIconButton } from "../ui/tooltip-icon-button"; import { AnimatePresence, motion } from "framer-motion"; import { Bot, Copy, CopyCheck, ArrowUp, User, AlertCircle } from "lucide-react"; import { Textarea } from "../ui/textarea"; import { Button } from "../ui/button"; import { isAIMessageSDK } from "@/lib/langchain-messages"; import { BasicMarkdownText } from "../thread/markdown-text"; import { ErrorState } from "./types"; import { CollapsibleAlert } from "./collapsible-alert"; import { Loader2 } from "lucide-react"; import { parsePartialJson } from "@langchain/core/output_parsers"; function MessageCopyButton({ content }: { content: string }) { const [copied, setCopied] = useState(false); const handleCopy = (e: React.MouseEvent) => { e.stopPropagation(); navigator.clipboard.writeText(content); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return ( handleCopy(e)} variant="ghost" tooltip="Copy content" className="size-6 p-1" > {copied ? ( ) : ( )} ); } interface ManagerChatProps { messages: Message[]; chatInput: string; setChatInput: (input: string) => void; handleSendMessage: () => void; isLoading: boolean; cancelRun: () => void; errorState?: ErrorState | null; githubUser?: { login: string; avatar_url: string; html_url: string; name: string | null; email: string | null; }; } function extractResponseFromMessage(message: Message): string { if (!isAIMessageSDK(message)) { return getMessageContentString(message.content); } if ( Array.isArray(message.content) && ["input_json_delta", "tool_use"].includes( message.content[0].type as string, ) && "input" in message.content[0] && message.content[0].input ) { try { const parsedJson = parsePartialJson(message.content[0].input as string); if (parsedJson.response) { return parsedJson.response; } } catch { // no-op } } const toolCall = message.tool_calls?.[0]; const response = toolCall?.args?.response; if (!toolCall || !response) { return getMessageContentString(message.content); } return response; } function LoadingMessageDots() { return (
); } export function ManagerChat({ messages, chatInput, setChatInput, handleSendMessage, isLoading, cancelRun, errorState, githubUser, }: ManagerChatProps) { return (
{messages.map((message) => { const messageContentString = extractResponseFromMessage(message); return (
{message.type === "human" ? ( githubUser?.avatar_url ? (
{githubUser.login}
) : (
) ) : (
)}
{message.type === "human" ? githubUser?.login || "You" : "Open SWE"}
{messageContentString ? ( {messageContentString} ) : ( )}
); })} {errorState ? ( } /> ) : null} } footer={
} />