Add configurable delay after auto-writes to allow diagnostics to catch up

This commit is contained in:
Matt Rubens
2024-12-26 09:46:50 -08:00
parent 6126cdf254
commit 03707d5dcc
9 changed files with 91 additions and 6 deletions

View File

@@ -37,7 +37,7 @@ interface ChatViewProps {
export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryView }: ChatViewProps) => {
const { version, clineMessages: messages, taskHistory, apiConfiguration, mcpServers, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, allowedCommands } = useExtensionState()
const { version, clineMessages: messages, taskHistory, apiConfiguration, mcpServers, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, allowedCommands, writeDelayMs } = useExtensionState()
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
const task = useMemo(() => messages.at(0), [messages]) // 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 Cline.abort)
@@ -831,10 +831,17 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// Only proceed if we have an ask and buttons are enabled
if (!clineAsk || !enableButtons) return
if (isAutoApproved(lastMessage)) {
handlePrimaryButtonClick()
const autoApprove = async () => {
if (isAutoApproved(lastMessage)) {
// Add delay for write operations
if (alwaysAllowWrite && isWriteToolAction(lastMessage)) {
await new Promise(resolve => setTimeout(resolve, writeDelayMs))
}
handlePrimaryButtonClick()
}
}
}, [clineAsk, enableButtons, handlePrimaryButtonClick, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, messages, allowedCommands, mcpServers, isAutoApproved, lastMessage])
autoApprove()
}, [clineAsk, enableButtons, handlePrimaryButtonClick, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, messages, allowedCommands, mcpServers, isAutoApproved, lastMessage, writeDelayMs, isWriteToolAction])
return (
<div

View File

@@ -42,6 +42,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
setFuzzyMatchThreshold,
preferredLanguage,
setPreferredLanguage,
writeDelayMs,
setWriteDelayMs,
} = useExtensionState()
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined)
@@ -70,6 +72,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
vscode.postMessage({ type: "browserLargeViewport", bool: browserLargeViewport })
vscode.postMessage({ type: "fuzzyMatchThreshold", value: fuzzyMatchThreshold ?? 1.0 })
vscode.postMessage({ type: "preferredLanguage", text: preferredLanguage })
vscode.postMessage({ type: "writeDelayMs", value: writeDelayMs })
onDone()
}
}
@@ -277,6 +280,31 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
Automatically create and edit files without requiring approval
</p>
{alwaysAllowWrite && (
<div style={{ marginTop: 10 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<input
type="range"
min="0"
max="5000"
step="100"
value={writeDelayMs}
onChange={(e) => setWriteDelayMs(parseInt(e.target.value))}
style={{
flex: 1,
accentColor: 'var(--vscode-button-background)',
height: '2px'
}}
/>
<span style={{ minWidth: '45px', textAlign: 'left' }}>
{writeDelayMs}ms
</span>
</div>
<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
Delay after writes to allow diagnostics to detect potential problems
</p>
</div>
)}
</div>
<div style={{ marginBottom: 5 }}>

View File

@@ -35,6 +35,7 @@ export interface ExtensionStateContextType extends ExtensionState {
setFuzzyMatchThreshold: (value: number) => void
preferredLanguage: string
setPreferredLanguage: (value: string) => void
setWriteDelayMs: (value: number) => void
}
const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@@ -51,6 +52,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
diffEnabled: false,
fuzzyMatchThreshold: 1.0,
preferredLanguage: 'English',
writeDelayMs: 1000,
})
const [didHydrateState, setDidHydrateState] = useState(false)
const [showWelcome, setShowWelcome] = useState(false)
@@ -139,6 +141,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
filePaths,
soundVolume: state.soundVolume,
fuzzyMatchThreshold: state.fuzzyMatchThreshold,
writeDelayMs: state.writeDelayMs,
setApiConfiguration: (value) => setState((prevState) => ({
...prevState,
apiConfiguration: value
@@ -157,6 +160,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setBrowserLargeViewport: (value) => setState((prevState) => ({ ...prevState, browserLargeViewport: value })),
setFuzzyMatchThreshold: (value) => setState((prevState) => ({ ...prevState, fuzzyMatchThreshold: value })),
setPreferredLanguage: (value) => setState((prevState) => ({ ...prevState, preferredLanguage: value })),
setWriteDelayMs: (value) => setState((prevState) => ({ ...prevState, writeDelayMs: value })),
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>