diff --git a/webview-ui/src/components/chat/BrowserSessionRow.tsx b/webview-ui/src/components/chat/BrowserSessionRow.tsx index e9f6d09..0bf609d 100644 --- a/webview-ui/src/components/chat/BrowserSessionRow.tsx +++ b/webview-ui/src/components/chat/BrowserSessionRow.tsx @@ -1,11 +1,12 @@ import deepEqual from "fast-deep-equal" -import React, { memo, useEffect, useRef, useState } from "react" +import React, { memo, useEffect, useMemo, useRef, useState } from "react" import { useSize } from "react-use" import { BrowserActionResult, ClineMessage, ClineSayBrowserAction } from "../../../../src/shared/ExtensionMessage" import { vscode } from "../../utils/vscode" import CodeAccordian from "../common/CodeAccordian" import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock" import { ChatRowContent } from "./ChatRow" +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" interface BrowserSessionRowProps { messages: ClineMessage[] @@ -25,29 +26,134 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => { const { messages, isLast, onHeightChange } = props const prevHeightRef = useRef(0) - const [consoleLogsExpanded, setConsoleLogsExpanded] = useState(false) - const consoleLogs = "console logs\nhere\n..." + // Organize messages into pages with current state and next action + const pages = useMemo(() => { + const result: { + currentState: { + url?: string + screenshot?: string + messages: ClineMessage[] // messages up to and including the result + } + nextAction?: { + messages: ClineMessage[] // messages leading to next result + } + }[] = [] + + let currentStateMessages: ClineMessage[] = [] + let nextActionMessages: ClineMessage[] = [] + + messages.forEach((message) => { + if (message.ask === "browser_action_launch") { + // Start first page + currentStateMessages = [message] + } else if (message.say === "browser_action_result") { + // Complete current state + currentStateMessages.push(message) + const resultData = JSON.parse(message.text || "{}") as BrowserActionResult + + // Add page with current state and previous next actions + result.push({ + currentState: { + url: resultData.currentUrl, + screenshot: resultData.screenshot, + messages: [...currentStateMessages], + }, + nextAction: + nextActionMessages.length > 0 + ? { + messages: [...nextActionMessages], + } + : undefined, + }) + + // Reset for next page + currentStateMessages = [] + nextActionMessages = [] + } else if ( + message.say === "api_req_started" || + message.say === "text" || + message.say === "browser_action" + ) { + // These messages lead to the next result, so they should always go in nextActionMessages + nextActionMessages.push(message) + } else { + // Any other message types + currentStateMessages.push(message) + } + }) + + // Add incomplete page if exists + if (currentStateMessages.length > 0 || nextActionMessages.length > 0) { + result.push({ + currentState: { + messages: [...currentStateMessages], + }, + nextAction: + nextActionMessages.length > 0 + ? { + messages: [...nextActionMessages], + } + : undefined, + }) + } + + return result + }, [messages]) + + // Auto-advance to latest page + const [currentPageIndex, setCurrentPageIndex] = useState(0) + useEffect(() => { + setCurrentPageIndex(pages.length - 1) + }, [pages.length]) + + // Get initial URL from launch message + const initialUrl = useMemo(() => { + const launchMessage = messages.find((m) => m.ask === "browser_action_launch") + return launchMessage?.text || "" + }, [messages]) + + // Find the latest available URL and screenshot + const latestState = useMemo(() => { + for (let i = pages.length - 1; i >= 0; i--) { + const page = pages[i] + if (page.currentState.url || page.currentState.screenshot) { + return { + url: page.currentState.url, + screenshot: page.currentState.screenshot, + } + } + } + return { url: undefined, screenshot: undefined } + }, [pages]) + + const currentPage = pages[currentPageIndex] + const isLastPage = currentPageIndex === pages.length - 1 + + // Use latest state if we're on the last page and don't have a state yet + const displayState = isLastPage + ? { + url: currentPage?.currentState.url || latestState.url || initialUrl, + screenshot: currentPage?.currentState.screenshot || latestState.screenshot, + } + : { + url: currentPage?.currentState.url || initialUrl, + screenshot: currentPage?.currentState.screenshot, + } const [browserSessionRow, { height }] = useSize(