Remove max requests per task settings option

This commit is contained in:
Saoud Rizwan
2024-09-01 01:41:43 -04:00
parent fdcec81814
commit ba4caf4f00
11 changed files with 6 additions and 147 deletions

View File

@@ -18,7 +18,6 @@ import { ApiConfiguration } from "./shared/api"
import { ClaudeRequestResult } from "./shared/ClaudeRequestResult" import { ClaudeRequestResult } from "./shared/ClaudeRequestResult"
import { combineApiRequests } from "./shared/combineApiRequests" import { combineApiRequests } from "./shared/combineApiRequests"
import { combineCommandSequences } from "./shared/combineCommandSequences" import { combineCommandSequences } from "./shared/combineCommandSequences"
import { DEFAULT_MAX_REQUESTS_PER_TASK } from "./shared/Constants"
import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "./shared/ExtensionMessage" import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "./shared/ExtensionMessage"
import { getApiMetrics } from "./shared/getApiMetrics" import { getApiMetrics } from "./shared/getApiMetrics"
import { HistoryItem } from "./shared/HistoryItem" import { HistoryItem } from "./shared/HistoryItem"
@@ -250,10 +249,8 @@ type UserContent = Array<
export class ClaudeDev { export class ClaudeDev {
readonly taskId: string readonly taskId: string
private api: ApiHandler private api: ApiHandler
private maxRequestsPerTask: number
private customInstructions?: string private customInstructions?: string
private alwaysAllowReadOnly: boolean private alwaysAllowReadOnly: boolean
private requestCount = 0
apiConversationHistory: Anthropic.MessageParam[] = [] apiConversationHistory: Anthropic.MessageParam[] = []
claudeMessages: ClaudeMessage[] = [] claudeMessages: ClaudeMessage[] = []
private askResponse?: ClaudeAskResponse private askResponse?: ClaudeAskResponse
@@ -268,7 +265,6 @@ export class ClaudeDev {
constructor( constructor(
provider: ClaudeDevProvider, provider: ClaudeDevProvider,
apiConfiguration: ApiConfiguration, apiConfiguration: ApiConfiguration,
maxRequestsPerTask?: number,
customInstructions?: string, customInstructions?: string,
alwaysAllowReadOnly?: boolean, alwaysAllowReadOnly?: boolean,
task?: string, task?: string,
@@ -277,7 +273,6 @@ export class ClaudeDev {
) { ) {
this.providerRef = new WeakRef(provider) this.providerRef = new WeakRef(provider)
this.api = buildApiHandler(apiConfiguration) this.api = buildApiHandler(apiConfiguration)
this.maxRequestsPerTask = maxRequestsPerTask ?? DEFAULT_MAX_REQUESTS_PER_TASK
this.customInstructions = customInstructions this.customInstructions = customInstructions
this.alwaysAllowReadOnly = alwaysAllowReadOnly ?? false this.alwaysAllowReadOnly = alwaysAllowReadOnly ?? false
@@ -296,10 +291,6 @@ export class ClaudeDev {
this.api = buildApiHandler(apiConfiguration) this.api = buildApiHandler(apiConfiguration)
} }
updateMaxRequestsPerTask(maxRequestsPerTask: number | undefined) {
this.maxRequestsPerTask = maxRequestsPerTask ?? DEFAULT_MAX_REQUESTS_PER_TASK
}
updateCustomInstructions(customInstructions: string | undefined) { updateCustomInstructions(customInstructions: string | undefined) {
this.customInstructions = customInstructions this.customInstructions = customInstructions
} }
@@ -1395,27 +1386,6 @@ ${this.customInstructions.trim()}
} }
await this.addToApiConversationHistory({ role: "user", content: userContent }) await this.addToApiConversationHistory({ role: "user", content: userContent })
if (this.requestCount >= this.maxRequestsPerTask) {
const { response } = await this.ask(
"request_limit_reached",
`Claude Dev has reached the maximum number of requests for this task. Would you like to reset the count and allow him to proceed?`
)
if (response === "yesButtonTapped") {
this.requestCount = 0
} else {
await this.addToApiConversationHistory({
role: "assistant",
content: [
{
type: "text",
text: "Failure: I have reached the request limit for this task. Do you have a new task for me?",
},
],
})
return { didEndLoop: true, inputTokens: 0, outputTokens: 0 }
}
}
if (!this.shouldSkipNextApiReqStartedMessage) { if (!this.shouldSkipNextApiReqStartedMessage) {
await this.say( await this.say(
@@ -1430,7 +1400,6 @@ ${this.customInstructions.trim()}
} }
try { try {
const response = await this.attemptApiRequest() const response = await this.attemptApiRequest()
this.requestCount++
if (this.abort) { if (this.abort) {
throw new Error("ClaudeDev instance aborted") throw new Error("ClaudeDev instance aborted")

View File

@@ -22,7 +22,6 @@ type GlobalStateKey =
| "awsRegion" | "awsRegion"
| "vertexProjectId" | "vertexProjectId"
| "vertexRegion" | "vertexRegion"
| "maxRequestsPerTask"
| "lastShownAnnouncementId" | "lastShownAnnouncementId"
| "customInstructions" | "customInstructions"
| "alwaysAllowReadOnly" | "alwaysAllowReadOnly"
@@ -166,11 +165,10 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
async initClaudeDevWithTask(task?: string, images?: string[]) { async initClaudeDevWithTask(task?: string, images?: string[]) {
await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one
const { maxRequestsPerTask, apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState() const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState()
this.claudeDev = new ClaudeDev( this.claudeDev = new ClaudeDev(
this, this,
apiConfiguration, apiConfiguration,
maxRequestsPerTask,
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
task, task,
@@ -180,11 +178,10 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
async initClaudeDevWithHistoryItem(historyItem: HistoryItem) { async initClaudeDevWithHistoryItem(historyItem: HistoryItem) {
await this.clearTask() await this.clearTask()
const { maxRequestsPerTask, apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState() const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState()
this.claudeDev = new ClaudeDev( this.claudeDev = new ClaudeDev(
this, this,
apiConfiguration, apiConfiguration,
maxRequestsPerTask,
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
undefined, undefined,
@@ -329,18 +326,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
} }
await this.postStateToWebview() await this.postStateToWebview()
break break
case "maxRequestsPerTask":
let result: number | undefined = undefined
if (message.text && message.text.trim()) {
const num = Number(message.text)
if (!isNaN(num)) {
result = num
}
}
await this.updateGlobalState("maxRequestsPerTask", result)
this.claudeDev?.updateMaxRequestsPerTask(result)
await this.postStateToWebview()
break
case "customInstructions": case "customInstructions":
// User may be clearing the field // User may be clearing the field
await this.updateGlobalState("customInstructions", message.text || undefined) await this.updateGlobalState("customInstructions", message.text || undefined)
@@ -489,7 +474,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
async getStateToPostToWebview() { async getStateToPostToWebview() {
const { const {
apiConfiguration, apiConfiguration,
maxRequestsPerTask,
lastShownAnnouncementId, lastShownAnnouncementId,
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
@@ -498,7 +482,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
return { return {
version: this.context.extension?.packageJSON?.version ?? "", version: this.context.extension?.packageJSON?.version ?? "",
apiConfiguration, apiConfiguration,
maxRequestsPerTask,
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
themeName: vscode.workspace.getConfiguration("workbench").get<string>("colorTheme"), themeName: vscode.workspace.getConfiguration("workbench").get<string>("colorTheme"),
@@ -606,7 +589,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
awsRegion, awsRegion,
vertexProjectId, vertexProjectId,
vertexRegion, vertexRegion,
maxRequestsPerTask,
lastShownAnnouncementId, lastShownAnnouncementId,
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
@@ -621,7 +603,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
this.getGlobalState("awsRegion") as Promise<string | undefined>, this.getGlobalState("awsRegion") as Promise<string | undefined>,
this.getGlobalState("vertexProjectId") as Promise<string | undefined>, this.getGlobalState("vertexProjectId") as Promise<string | undefined>,
this.getGlobalState("vertexRegion") as Promise<string | undefined>, this.getGlobalState("vertexRegion") as Promise<string | undefined>,
this.getGlobalState("maxRequestsPerTask") as Promise<number | undefined>,
this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>, this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>,
this.getGlobalState("customInstructions") as Promise<string | undefined>, this.getGlobalState("customInstructions") as Promise<string | undefined>,
this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>, this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>,
@@ -654,7 +635,6 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
vertexProjectId, vertexProjectId,
vertexRegion, vertexRegion,
}, },
maxRequestsPerTask,
lastShownAnnouncementId, lastShownAnnouncementId,
customInstructions, customInstructions,
alwaysAllowReadOnly: alwaysAllowReadOnly ?? false, alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,

View File

@@ -1 +0,0 @@
export const DEFAULT_MAX_REQUESTS_PER_TASK = 20

View File

@@ -15,7 +15,6 @@ export interface ExtensionMessage {
export interface ExtensionState { export interface ExtensionState {
version: string version: string
apiConfiguration?: ApiConfiguration apiConfiguration?: ApiConfiguration
maxRequestsPerTask?: number
customInstructions?: string customInstructions?: string
alwaysAllowReadOnly?: boolean alwaysAllowReadOnly?: boolean
themeName?: string themeName?: string
@@ -35,7 +34,6 @@ export interface ClaudeMessage {
} }
export type ClaudeAsk = export type ClaudeAsk =
| "request_limit_reached"
| "followup" | "followup"
| "command" | "command"
| "command_output" | "command_output"

View File

@@ -3,7 +3,6 @@ import { ApiConfiguration, ApiProvider } from "./api"
export interface WebviewMessage { export interface WebviewMessage {
type: type:
| "apiConfiguration" | "apiConfiguration"
| "maxRequestsPerTask"
| "customInstructions" | "customInstructions"
| "alwaysAllowReadOnly" | "alwaysAllowReadOnly"
| "webviewDidLaunch" | "webviewDidLaunch"

View File

@@ -57,13 +57,6 @@ const ChatRow: React.FC<ChatRowProps> = ({
) )
switch (type) { switch (type) {
case "request_limit_reached":
return [
<span
className="codicon codicon-error"
style={{ color: errorColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: errorColor, fontWeight: "bold" }}>Max Requests Reached</span>,
]
case "error": case "error":
return [ return [
<span <span
@@ -410,16 +403,6 @@ const ChatRow: React.FC<ChatRowProps> = ({
switch (message.ask) { switch (message.ask) {
case "tool": case "tool":
return renderTool(message, headerStyle) return renderTool(message, headerStyle)
case "request_limit_reached":
return (
<>
<div style={headerStyle}>
{icon}
{title}
</div>
<p style={{ ...pStyle, color: "var(--vscode-errorForeground)" }}>{message.text}</p>
</>
)
case "command": case "command":
const splitMessage = (text: string) => { const splitMessage = (text: string) => {
const outputIndex = text.indexOf(COMMAND_OUTPUT_STRING) const outputIndex = text.indexOf(COMMAND_OUTPUT_STRING)

View File

@@ -95,13 +95,6 @@ const ChatView = ({
switch (lastMessage.type) { switch (lastMessage.type) {
case "ask": case "ask":
switch (lastMessage.ask) { switch (lastMessage.ask) {
case "request_limit_reached":
setTextAreaDisabled(true)
setClaudeAsk("request_limit_reached")
setEnableButtons(true)
setPrimaryButtonText("Proceed")
setSecondaryButtonText("Start New Task")
break
case "api_req_failed": case "api_req_failed":
setTextAreaDisabled(true) setTextAreaDisabled(true)
setClaudeAsk("api_req_failed") setClaudeAsk("api_req_failed")
@@ -257,7 +250,6 @@ const ChatView = ({
*/ */
const handlePrimaryButtonClick = () => { const handlePrimaryButtonClick = () => {
switch (claudeAsk) { switch (claudeAsk) {
case "request_limit_reached":
case "api_req_failed": case "api_req_failed":
case "command": case "command":
case "command_output": case "command_output":
@@ -280,7 +272,6 @@ const ChatView = ({
const handleSecondaryButtonClick = () => { const handleSecondaryButtonClick = () => {
switch (claudeAsk) { switch (claudeAsk) {
case "request_limit_reached":
case "api_req_failed": case "api_req_failed":
startNewTask() startNewTask()
break break

View File

@@ -2,12 +2,11 @@ import {
VSCodeButton, VSCodeButton,
VSCodeCheckbox, VSCodeCheckbox,
VSCodeLink, VSCodeLink,
VSCodeTextArea, VSCodeTextArea
VSCodeTextField,
} from "@vscode/webview-ui-toolkit/react" } from "@vscode/webview-ui-toolkit/react"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { useExtensionState } from "../context/ExtensionStateContext" import { useExtensionState } from "../context/ExtensionStateContext"
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate" import { validateApiConfiguration } from "../utils/validate"
import { vscode } from "../utils/vscode" import { vscode } from "../utils/vscode"
import ApiOptions from "./ApiOptions" import ApiOptions from "./ApiOptions"
@@ -21,28 +20,20 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
const { const {
apiConfiguration, apiConfiguration,
version, version,
maxRequestsPerTask,
customInstructions, customInstructions,
setCustomInstructions, setCustomInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
setAlwaysAllowReadOnly, setAlwaysAllowReadOnly,
} = useExtensionState() } = useExtensionState()
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined) const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
const [maxRequestsErrorMessage, setMaxRequestsErrorMessage] = useState<string | undefined>(undefined)
const [maxRequestsPerTaskString, setMaxRequestsPerTaskString] = useState<string>(
maxRequestsPerTask?.toString() || ""
)
const handleSubmit = () => { const handleSubmit = () => {
const apiValidationResult = validateApiConfiguration(apiConfiguration) const apiValidationResult = validateApiConfiguration(apiConfiguration)
const maxRequestsValidationResult = validateMaxRequestsPerTask(maxRequestsPerTaskString)
setApiErrorMessage(apiValidationResult) setApiErrorMessage(apiValidationResult)
setMaxRequestsErrorMessage(maxRequestsValidationResult)
if (!apiValidationResult && !maxRequestsValidationResult) { if (!apiValidationResult) {
vscode.postMessage({ type: "apiConfiguration", apiConfiguration }) vscode.postMessage({ type: "apiConfiguration", apiConfiguration })
vscode.postMessage({ type: "maxRequestsPerTask", text: maxRequestsPerTaskString })
vscode.postMessage({ type: "customInstructions", text: customInstructions }) vscode.postMessage({ type: "customInstructions", text: customInstructions })
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly }) vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
onDone() onDone()
@@ -53,10 +44,6 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
setApiErrorMessage(undefined) setApiErrorMessage(undefined)
}, [apiConfiguration]) }, [apiConfiguration])
useEffect(() => {
setMaxRequestsErrorMessage(undefined)
}, [maxRequestsPerTask])
// validate as soon as the component is mounted // validate as soon as the component is mounted
/* /*
useEffect will use stale values of variables if they are not included in the dependency array. so trying to use useEffect with a dependency array of only one value for example will use any other variables' old values. In most cases you don't want this, and should opt to use react-use hooks. useEffect will use stale values of variables if they are not included in the dependency array. so trying to use useEffect with a dependency array of only one value for example will use any other variables' old values. In most cases you don't want this, and should opt to use react-use hooks.
@@ -141,35 +128,6 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
</p> </p>
</div> </div>
<div>
<VSCodeTextField
value={maxRequestsPerTaskString}
style={{ width: "100%" }}
placeholder="20"
onInput={(e: any) => setMaxRequestsPerTaskString(e.target?.value ?? "")}>
<span style={{ fontWeight: "500" }}>Maximum # Requests Per Task</span>
</VSCodeTextField>
<p
style={{
fontSize: "12px",
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
If Claude Dev reaches this limit, it will pause and ask for your permission before making
additional requests.
</p>
{maxRequestsErrorMessage && (
<p
style={{
fontSize: "12px",
marginTop: "5px",
color: "var(--vscode-errorForeground)",
}}>
{maxRequestsErrorMessage}
</p>
)}
</div>
{IS_DEV && ( {IS_DEV && (
<> <>
<div style={{ marginTop: "10px", marginBottom: "4px" }}>Debug</div> <div style={{ marginTop: "10px", marginBottom: "4px" }}>Debug</div>

View File

@@ -8,7 +8,6 @@ interface ExtensionStateContextType extends ExtensionState {
didHydrateState: boolean didHydrateState: boolean
showWelcome: boolean showWelcome: boolean
setApiConfiguration: (config: ApiConfiguration) => void setApiConfiguration: (config: ApiConfiguration) => void
setMaxRequestsPerTask: (value?: number) => void
setCustomInstructions: (value?: string) => void setCustomInstructions: (value?: string) => void
setAlwaysAllowReadOnly: (value: boolean) => void setAlwaysAllowReadOnly: (value: boolean) => void
setShowAnnouncement: (value: boolean) => void setShowAnnouncement: (value: boolean) => void
@@ -52,7 +51,6 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
didHydrateState, didHydrateState,
showWelcome, showWelcome,
setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })), setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })),
setMaxRequestsPerTask: (value) => setState((prevState) => ({ ...prevState, maxRequestsPerTask: value })),
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })), setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })), setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })), setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),

View File

@@ -204,12 +204,6 @@ export const mockMessages: ClaudeMessage[] = [
say: "text", say: "text",
text: "Great! The tests for the TodoList component have passed. All functionalities, including the new delete feature, are working as expected.", text: "Great! The tests for the TodoList component have passed. All functionalities, including the new delete feature, are working as expected.",
}, },
{
ts: Date.now() - 2200000,
type: "ask",
ask: "request_limit_reached",
text: "You've reached the maximum number of requests for this task. Would you like to continue or start a new task?",
},
{ {
ts: Date.now() - 2100000, ts: Date.now() - 2100000,
type: "say", type: "say",

View File

@@ -26,14 +26,4 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
} }
} }
return undefined return undefined
} }
export function validateMaxRequestsPerTask(maxRequestsPerTask?: string): string | undefined {
if (maxRequestsPerTask && maxRequestsPerTask.trim()) {
const num = Number(maxRequestsPerTask)
if (isNaN(num) || num < 3 || num > 100) {
return "Maximum requests must be between 3 and 100"
}
}
return undefined
}