Fixed garbage collection of aborted tasks; handle if run from root directory then don’t read/write; fixed scroll to bottom; fix other small bugs

This commit is contained in:
Saoud Rizwan
2024-07-09 23:44:20 -04:00
parent 9867a6a597
commit 7170d2a2e8
8 changed files with 101 additions and 26 deletions

View File

@@ -256,7 +256,6 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
<CodeBlock
code={output}
language="shell-session"
path="src/components/WelcomeView.tsx/src/components/WelcomeView.tsx"
/>
</>
)}
@@ -295,19 +294,24 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
}
}
// we need to return null here instead of in getContent since that way would result in padding being applied
if (message.say === "api_req_finished") {
return null // Don't render anything for this message type
}
if (message.type === "ask" && message.ask === "completion_result" && message.text === "") {
return null // Don't render anything for this message type
}
return (
<div
style={{
padding: "10px 5px 10px 20px",
padding: "10px 20px 10px 20px",
}}>
{renderContent()}
{isExpanded && message.say === "api_req_started" && (
<div style={{ marginTop: "10px" }}>
<CodeBlock code={JSON.stringify(JSON.parse(message.text || "{}").request)} language="json" />
<CodeBlock code={JSON.stringify(JSON.parse(message.text || "{}").request, null, 2)} language="json" />
</div>
)}
</div>

View File

@@ -9,19 +9,20 @@ import { combineCommandSequences } from "../utilities/combineCommandSequences"
import { combineApiRequests } from "../utilities/combineApiRequests"
import TaskHeader from "./TaskHeader"
import { getApiMetrics } from "../utilities/getApiMetrics"
import { animateScroll as scroll } from "react-scroll"
interface ChatViewProps {
messages: ClaudeMessage[]
}
// maybe instead of storing state in App, just make chatview always show so dont conditionally load/unload? need to make sure messages are persisted (i remember seeing something about how webviews can be frozen in docs)
const ChatView = ({ messages }: ChatViewProps) => {
const task = messages.shift()
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages)), [messages])
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined
const task = messages.length > 0 ? messages[0] : undefined // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see ClaudeDev.abort)
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])
// has to be after api_req_finished are all reduced into api_req_started messages
const apiMetrics = useMemo(() => getApiMetrics(modifiedMessages), [modifiedMessages])
const [inputValue, setInputValue] = useState("")
const messagesEndRef = useRef<HTMLDivElement>(null)
const textAreaRef = useRef<HTMLTextAreaElement>(null)
const [textAreaHeight, setTextAreaHeight] = useState<number | undefined>(undefined)
const [textAreaDisabled, setTextAreaDisabled] = useState(false)
@@ -33,12 +34,12 @@ const ChatView = ({ messages }: ChatViewProps) => {
const [secondaryButtonText, setSecondaryButtonText] = useState<string | undefined>(undefined)
const scrollToBottom = (instant: boolean = false) => {
// https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
;(messagesEndRef.current as any)?.scrollIntoView({
behavior: instant ? "instant" : "smooth",
block: "nearest",
inline: "start",
})
const options = {
containerId: "chat-view-container",
duration: instant ? 0 : 500,
smooth: !instant,
}
scroll.scrollToBottom(options)
}
// scroll to bottom when new message is added
@@ -50,8 +51,13 @@ const ChatView = ({ messages }: ChatViewProps) => {
[modifiedMessages]
)
useEffect(() => {
scrollToBottom()
}, [visibleMessages.length])
const timer = setTimeout(() => {
scrollToBottom()
}, 0)
return () => {
clearTimeout(timer)
}
}, [visibleMessages])
useEffect(() => {
// if last message is an ask, show user ask UI
@@ -114,13 +120,23 @@ const ChatView = ({ messages }: ChatViewProps) => {
break
}
} else {
// this would get called after sending the first message, so we have to watch messages.length instead
// No messages, so user has to submit a task
// setTextAreaDisabled(false)
// setClaudeAsk(undefined)
// setPrimaryButtonText(undefined)
// setSecondaryButtonText(undefined)
}
}, [messages])
useEffect(() => {
if (messages.length === 0) {
setTextAreaDisabled(false)
setClaudeAsk(undefined)
setPrimaryButtonText(undefined)
setSecondaryButtonText(undefined)
}
}, [messages])
}, [messages.length])
const handleSendMessage = () => {
const text = inputValue.trim()
@@ -249,6 +265,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
/>
)}
<div
id="chat-view-container"
className="scrollable"
style={{
flexGrow: 1,
@@ -257,7 +274,6 @@ const ChatView = ({ messages }: ChatViewProps) => {
{modifiedMessages.map((message, index) => (
<ChatRow key={index} message={message} />
))}
<div style={{ float: "left", clear: "both" }} ref={messagesEndRef} />
</div>
{(primaryButtonText || secondaryButtonText) && (
<div style={{ display: "flex", padding: "10px 15px 0px 15px" }}>
@@ -282,7 +298,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
)}
</div>
)}
<div style={{ padding: "10px 15px" }}>
<div style={{ padding: "10px 15px", opacity: textAreaDisabled ? 0.7 : 1 }}>
<DynamicTextArea
ref={textAreaRef}
value={inputValue}
@@ -305,20 +321,24 @@ const ChatView = ({ messages }: ChatViewProps) => {
lineHeight: "var(--vscode-editor-line-height)",
resize: "none",
overflow: "hidden",
padding: "8px 40px 8px 8px",
padding: "8px 36px 8px 8px",
}}
/>
{textAreaHeight && (
<div
style={{
position: "absolute",
right: "18px",
right: "20px",
height: `${textAreaHeight}px`,
bottom: "12px",
display: "flex",
alignItems: "center",
}}>
<VSCodeButton disabled={textAreaDisabled} appearance="icon" aria-label="Send Message" onClick={handleSendMessage}>
<VSCodeButton
disabled={textAreaDisabled}
appearance="icon"
aria-label="Send Message"
onClick={handleSendMessage}>
<span className="codicon codicon-send"></span>
</VSCodeButton>
</div>

View File

@@ -89,7 +89,6 @@ const CodeBlock = ({ code, diff, language, path }: CodeBlockProps) => {
<div
style={{
borderRadius: "3px",
marginRight: "2px",
backgroundColor: backgroundColor,
overflow: "hidden", // This ensures the inner scrollable area doesn't overflow the rounded corners
}}>