Skip to content

Commit 8d18003

Browse files
committed
fix: address PR review feedback for configurable error & repetition limit
- Simplified conversion logic by removing Infinity conversion - Added validation for negative values in UI component - Removed unnecessary console logging in migration function - Added JSDoc comments for consecutiveMistakeLimit parameter - Improved test coverage for ToolRepetitionDetector behavior - Fixed UI issue where 0 was showing as 3 in ApiOptions
1 parent f8b4bf7 commit 8d18003

File tree

6 files changed

+64
-18
lines changed

6 files changed

+64
-18
lines changed

src/core/config/ProviderSettingsManager.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,6 @@ export class ProviderSettingsManager {
243243
for (const [name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
244244
if (apiConfig.consecutiveMistakeLimit == null) {
245245
apiConfig.consecutiveMistakeLimit = DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
246-
} else {
247-
console.log(
248-
`[ProviderSettingsManager] Profile ${name} already has consecutiveMistakeLimit: ${apiConfig.consecutiveMistakeLimit}`,
249-
)
250246
}
251247
}
252248
} catch (error) {

src/core/task/Task.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ export class Task extends EventEmitter<ClineEvents> {
256256
this.browserSession = new BrowserSession(provider.context)
257257
this.diffEnabled = enableDiff
258258
this.fuzzyMatchThreshold = fuzzyMatchThreshold
259-
this.consecutiveMistakeLimit = consecutiveMistakeLimit === 0 ? Infinity : (consecutiveMistakeLimit ?? 3)
259+
this.consecutiveMistakeLimit = consecutiveMistakeLimit ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
260260
this.providerRef = new WeakRef(provider)
261261
this.globalStoragePath = provider.context.globalStorageUri.fsPath
262262
this.diffViewProvider = new DiffViewProvider(this.cwd)
@@ -290,9 +290,7 @@ export class Task extends EventEmitter<ClineEvents> {
290290
})
291291
}
292292

293-
this.toolRepetitionDetector = new ToolRepetitionDetector(
294-
this.consecutiveMistakeLimit === Infinity ? 0 : this.consecutiveMistakeLimit,
295-
)
293+
this.toolRepetitionDetector = new ToolRepetitionDetector(this.consecutiveMistakeLimit)
296294

297295
onCreated?.(this)
298296

@@ -1162,7 +1160,7 @@ export class Task extends EventEmitter<ClineEvents> {
11621160
throw new Error(`[RooCode#recursivelyMakeRooRequests] task ${this.taskId}.${this.instanceId} aborted`)
11631161
}
11641162

1165-
if (this.consecutiveMistakeCount >= this.consecutiveMistakeLimit) {
1163+
if (this.consecutiveMistakeLimit > 0 && this.consecutiveMistakeCount >= this.consecutiveMistakeLimit) {
11661164
const { response, text, images } = await this.ask(
11671165
"mistake_limit_reached",
11681166
t("common:errors.mistake_limit_guidance"),

src/core/task/__tests__/Task.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ describe("Cline", () => {
343343
expect(cline.consecutiveMistakeLimit).toBe(5)
344344
})
345345

346-
it("should convert consecutiveMistakeLimit of 0 to Infinity", () => {
346+
it("should keep consecutiveMistakeLimit of 0 as 0 for unlimited", () => {
347347
const cline = new Task({
348348
provider: mockProvider,
349349
apiConfiguration: mockApiConfig,
@@ -352,10 +352,10 @@ describe("Cline", () => {
352352
startTask: false,
353353
})
354354

355-
expect(cline.consecutiveMistakeLimit).toBe(Infinity)
355+
expect(cline.consecutiveMistakeLimit).toBe(0)
356356
})
357357

358-
it("should pass correct value to ToolRepetitionDetector when limit is Infinity", () => {
358+
it("should pass 0 to ToolRepetitionDetector for unlimited mode", () => {
359359
const cline = new Task({
360360
provider: mockProvider,
361361
apiConfiguration: mockApiConfig,
@@ -364,10 +364,10 @@ describe("Cline", () => {
364364
startTask: false,
365365
})
366366

367-
// The toolRepetitionDetector should be initialized with 0 when limit is Infinity (unlimited)
367+
// The toolRepetitionDetector should be initialized with 0 for unlimited mode
368368
expect(cline.toolRepetitionDetector).toBeDefined()
369-
// We can't directly check the internal state, but we can verify the limit was converted
370-
expect(cline.consecutiveMistakeLimit).toBe(Infinity)
369+
// Verify the limit remains as 0
370+
expect(cline.consecutiveMistakeLimit).toBe(0)
371371
})
372372

373373
it("should pass consecutiveMistakeLimit to ToolRepetitionDetector", () => {

src/core/tools/__tests__/ToolRepetitionDetector.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,5 +312,50 @@ describe("ToolRepetitionDetector", () => {
312312
expect(result.askUser).toBeUndefined()
313313
}
314314
})
315+
316+
it("should handle different limits correctly", () => {
317+
// Test with limit of 5
318+
const detector5 = new ToolRepetitionDetector(5)
319+
const tool = createToolUse("tool", "tool-name")
320+
321+
// First 4 calls should be allowed
322+
for (let i = 0; i < 4; i++) {
323+
const result = detector5.check(tool)
324+
expect(result.allowExecution).toBe(true)
325+
expect(result.askUser).toBeUndefined()
326+
}
327+
328+
// 5th call should be blocked
329+
const result5 = detector5.check(tool)
330+
expect(result5.allowExecution).toBe(false)
331+
expect(result5.askUser).toBeDefined()
332+
expect(result5.askUser?.messageKey).toBe("mistake_limit_reached")
333+
})
334+
335+
it("should reset counter after blocking and allow new attempts", () => {
336+
const detector = new ToolRepetitionDetector(2)
337+
const tool = createToolUse("tool", "tool-name")
338+
339+
// First call allowed
340+
expect(detector.check(tool).allowExecution).toBe(true)
341+
342+
// Second call should block (limit is 2)
343+
const blocked = detector.check(tool)
344+
expect(blocked.allowExecution).toBe(false)
345+
346+
// After blocking, counter should reset and allow new attempts
347+
expect(detector.check(tool).allowExecution).toBe(true)
348+
})
349+
350+
it("should handle negative limits as 0 (unlimited)", () => {
351+
const detector = new ToolRepetitionDetector(-1)
352+
353+
// Should behave like unlimited
354+
for (let i = 0; i < 5; i++) {
355+
const result = detector.check(createToolUse("tool", "tool-name"))
356+
expect(result.allowExecution).toBe(true)
357+
expect(result.askUser).toBeUndefined()
358+
}
359+
})
315360
})
316361
})

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
66
import {
77
type ProviderName,
88
type ProviderSettings,
9+
DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
910
openRouterDefaultModelId,
1011
requestyDefaultModelId,
1112
glamaDefaultModelId,
@@ -549,7 +550,11 @@ const ApiOptions = ({
549550
onChange={(value) => setApiConfigurationField("rateLimitSeconds", value)}
550551
/>
551552
<ConsecutiveMistakeLimitControl
552-
value={apiConfiguration.consecutiveMistakeLimit ?? 3}
553+
value={
554+
apiConfiguration.consecutiveMistakeLimit !== undefined
555+
? apiConfiguration.consecutiveMistakeLimit
556+
: DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
557+
}
553558
onChange={(value) => setApiConfigurationField("consecutiveMistakeLimit", value)}
554559
/>
555560
</>

webview-ui/src/components/settings/ConsecutiveMistakeLimitControl.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export const ConsecutiveMistakeLimitControl: React.FC<ConsecutiveMistakeLimitCon
1313

1414
const handleValueChange = useCallback(
1515
(newValue: number) => {
16-
onChange(newValue)
16+
// Ensure value is not negative
17+
const validValue = Math.max(0, newValue)
18+
onChange(validValue)
1719
},
1820
[onChange],
1921
)
@@ -29,7 +31,7 @@ export const ConsecutiveMistakeLimitControl: React.FC<ConsecutiveMistakeLimitCon
2931
step={1}
3032
onValueChange={(newValue) => handleValueChange(newValue[0])}
3133
/>
32-
<span className="w-10">{value ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT}</span>
34+
<span className="w-10">{Math.max(0, value ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT)}</span>
3335
</div>
3436
<div className="text-sm text-vscode-descriptionForeground">
3537
{value === 0

0 commit comments

Comments
 (0)