Compare commits

...

1 Commits

Author SHA1 Message Date
Cline Evaluation ba44bd696f Stop Chat mulit render 2025-07-02 16:50:30 -06:00
4 changed files with 164 additions and 17 deletions
+1
View File
@@ -0,0 +1 @@
nodejs 20.11.1
@@ -68,6 +68,13 @@ export async function sendStateUpdate(controllerId: string, state: any): Promise
},
false, // Not the last message
)
console.log(
"[SENDING stateJson follow up STATE]",
stateJson.length,
"bytes =",
(stateJson.length / 1024 / 1024).toFixed(2),
"MB",
)
console.log(`[DEBUG] sending followup state to controller ${controllerId}`, stateJson.length, "chars")
} catch (error) {
console.error(`Error sending state update to controller ${controllerId}:`, error)
@@ -116,6 +116,26 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
const prevHeightRef = useRef(0)
const [maxActionHeight, setMaxActionHeight] = useState(0)
const [consoleLogsExpanded, setConsoleLogsExpanded] = useState(false)
const [currentPageIndex, setCurrentPageIndex] = useState(0)
// Memoize callbacks
const handleConsoleLogsToggle = useCallback(() => {
setConsoleLogsExpanded((prev) => !prev)
}, [])
const handlePreviousPage = useCallback(() => {
setCurrentPageIndex((i) => i - 1)
}, [])
const handleNextPage = useCallback(() => {
setCurrentPageIndex((i) => i + 1)
}, [])
const handleScreenshotClick = useCallback((screenshot: string) => {
FileServiceClient.openImage(StringRequest.create({ value: screenshot })).catch((err) =>
console.error("Failed to open image:", err),
)
}, [])
const isLastApiReqInterrupted = useMemo(() => {
// Check if last api_req_started is cancelled
@@ -227,7 +247,6 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
}, [messages])
// Auto-advance to latest page
const [currentPageIndex, setCurrentPageIndex] = useState(0)
useEffect(() => {
setCurrentPageIndex(pages.length - 1)
}, [pages.length])
@@ -299,8 +318,8 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
onToggleExpand={props.onToggleExpand}
lastModifiedMessage={props.lastModifiedMessage}
isLast={props.isLast}
onSetQuote={props.onSetQuote}
setMaxActionHeight={setMaxActionHeight}
onSetQuote={onSetQuote}
/>
))}
{!isBrowsing && messages.some((m) => m.say === "browser_action_result") && currentPageIndex === 0 && (
@@ -407,11 +426,7 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
src={displayState.screenshot}
alt="Browser screenshot"
style={imgScreenshotStyle}
onClick={() =>
FileServiceClient.openImage(StringRequest.create({ value: displayState.screenshot })).catch(
(err) => console.error("Failed to open image:", err),
)
}
onClick={() => displayState.screenshot && handleScreenshotClick(displayState.screenshot)}
/>
) : (
<div style={noScreenshotContainerStyle}>
@@ -432,9 +447,7 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
<div style={consoleLogsContainerStyle}>
<div
onClick={() => {
setConsoleLogsExpanded(!consoleLogsExpanded)
}}
onClick={handleConsoleLogsToggle}
style={{
display: "flex",
alignItems: "center",
@@ -463,14 +476,10 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
Step {currentPageIndex + 1} of {pages.length}
</div>
<div style={paginationButtonGroupStyle}>
<VSCodeButton
disabled={currentPageIndex === 0 || isBrowsing}
onClick={() => setCurrentPageIndex((i) => i - 1)}>
<VSCodeButton disabled={currentPageIndex === 0 || isBrowsing} onClick={handlePreviousPage}>
Previous
</VSCodeButton>
<VSCodeButton
disabled={currentPageIndex === pages.length - 1 || isBrowsing}
onClick={() => setCurrentPageIndex((i) => i + 1)}>
<VSCodeButton disabled={currentPageIndex === pages.length - 1 || isBrowsing} onClick={handleNextPage}>
Next
</VSCodeButton>
</div>
@@ -516,7 +525,7 @@ const BrowserSessionRowContent = memo(
setMaxActionHeight(0)
}
onToggleExpand(message.ts)
}, [onToggleExpand, message.ts, setMaxActionHeight])
}, [onToggleExpand, message.ts, message.say, setMaxActionHeight])
if (message.ask === "browser_action_launch" || message.say === "browser_action_launch") {
return (
@@ -0,0 +1,130 @@
import React from "react"
import { AlertTriangle, Trash2 } from "lucide-react"
import { formatSize } from "@/utils/format"
import {
AlertDialog,
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogAction,
AlertDialogCancel,
} from "./AlertDialog"
interface TaskDeletionConfirmDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
onConfirm: () => void
taskCount: number
totalSize?: number
taskDetails?: {
date?: string
title?: string
}
variant: "single" | "multiple" | "all"
}
export function TaskDeletionConfirmDialog({
open,
onOpenChange,
onConfirm,
taskCount,
totalSize,
taskDetails,
variant,
}: TaskDeletionConfirmDialogProps) {
const handleConfirm = () => {
onConfirm()
onOpenChange(false)
}
const handleCancel = () => {
onOpenChange(false)
}
const getTitle = () => {
switch (variant) {
case "single":
return "Delete Task"
case "multiple":
return `Delete ${taskCount} Tasks`
case "all":
return "Delete All History"
default:
return "Delete Task"
}
}
const getDescription = () => {
switch (variant) {
case "single":
return `Are you sure you want to delete this task${
taskDetails?.date ? ` from ${taskDetails.date}` : ""
}? This will also delete all associated checkpoints and cannot be undone.`
case "multiple":
return `Are you sure you want to delete ${taskCount} selected tasks? This will free up ${
totalSize ? formatSize(totalSize) : "storage space"
} and delete all associated checkpoints. This action cannot be undone.`
case "all":
return `Are you sure you want to delete all task history? This will permanently remove all tasks, checkpoints, and conversation data${
totalSize ? ` (${formatSize(totalSize)})` : ""
}. This action cannot be undone.`
default:
return "This action cannot be undone."
}
}
const getConfirmText = () => {
switch (variant) {
case "single":
return "Delete Task"
case "multiple":
return `Delete ${taskCount} Tasks`
case "all":
return "Delete All History"
default:
return "Delete"
}
}
// Handle keyboard events
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Escape") {
handleCancel()
} else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
handleConfirm()
}
}
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent onKeyDown={handleKeyDown}>
<AlertDialogHeader>
<AlertDialogTitle>
<AlertTriangle className="w-5 h-5 text-[var(--vscode-errorForeground)]" />
{getTitle()}
</AlertDialogTitle>
<AlertDialogDescription>{getDescription()}</AlertDialogDescription>
{taskDetails?.title && variant === "single" && (
<div className="mt-3 p-3 bg-[var(--vscode-editor-inactiveSelectionBackground)] rounded border-l-4 border-[var(--vscode-errorForeground)]">
<div className="text-sm text-[var(--vscode-foreground)] font-medium">Task Preview:</div>
<div className="text-sm text-[var(--vscode-descriptionForeground)] mt-1 line-clamp-2">
{taskDetails.title}
</div>
</div>
)}
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={handleConfirm}
className="!bg-[#c42b2b] !border-[#c42b2b] !text-white hover:!bg-[#a82424] hover:!border-[#a82424] active:!bg-[#8f1f1f] active:!border-[#8f1f1f]">
<Trash2 className="w-4 h-4 mr-2" />
{getConfirmText()}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}