"use client"; import { v4 as uuidv4 } from "uuid"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { ArrowLeft, GitBranch, Terminal, Clock } from "lucide-react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ThreadSwitcher } from "./thread-switcher"; import { ThreadDisplayInfo } from "./types"; import { useStream } from "@langchain/langgraph-sdk/react"; import { ManagerGraphState } from "@open-swe/shared/open-swe/manager/types"; import { PlannerGraphState } from "@open-swe/shared/open-swe/planner/types"; import { GraphState } from "@open-swe/shared/open-swe/types"; import { ActionsRenderer } from "./actions-renderer"; import { ThemeToggle } from "../theme-toggle"; import { HumanMessage } from "@langchain/core/messages"; import { DO_NOT_RENDER_ID_PREFIX, PROGRAMMER_GRAPH_ID, PLANNER_GRAPH_ID, } from "@open-swe/shared/constants"; import { StickToBottom } from "use-stick-to-bottom"; import { StickyToBottomContent, ScrollToBottom, } from "../../utils/scroll-utils"; import { ManagerChat } from "./manager-chat"; interface ThreadViewProps { stream: ReturnType>; displayThread: ThreadDisplayInfo; allDisplayThreads: ThreadDisplayInfo[]; onBackToHome: () => void; } export function ThreadView({ stream, displayThread, allDisplayThreads, onBackToHome, }: ThreadViewProps) { const [chatInput, setChatInput] = useState(""); const [selectedTab, setSelectedTab] = useState<"planner" | "programmer">( "planner", ); const plannerThreadId = stream.values?.plannerSession?.threadId; const plannerRunId = stream.values?.plannerSession?.runId; const [programmerSession, setProgrammerSession] = useState(); const handleSendMessage = () => { if (chatInput.trim()) { const newHumanMessage = new HumanMessage({ id: uuidv4(), content: chatInput, }); stream.submit( { messages: [newHumanMessage], }, { streamResumable: true, optimisticValues: (prev) => ({ ...prev, messages: [...(prev.messages ?? []), newHumanMessage], }), }, ); setChatInput(""); } }; const filteredMessages = stream.messages.filter((message) => { return !message.id?.startsWith(DO_NOT_RENDER_ID_PREFIX); }); return (
{/* Header */}
{displayThread.title} {displayThread.repository && ( <> • {displayThread.repository} )}
{/* Main Content - Split Layout */}
{/* Right Side - Actions & Plan */}
setSelectedTab(value as "planner" | "programmer") } > Planner Programmer {plannerThreadId && plannerRunId && ( graphId={PLANNER_GRAPH_ID} threadId={plannerThreadId} runId={plannerRunId} setProgrammerSession={setProgrammerSession} programmerSession={programmerSession} setSelectedTab={setSelectedTab} /> )} {!(plannerThreadId && plannerRunId) && (
No planner session
)}
{programmerSession && ( graphId={PROGRAMMER_GRAPH_ID} threadId={programmerSession.threadId} runId={programmerSession.runId} /> )} {!programmerSession && (
No programmer session
)}
} footer={
} />
); }