feat: Add configurable error & repetition limit with unified control (#5654) (#5752)

Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com>
This commit is contained in:
Murilo Pires 2025-07-15 19:25:43 -03:00 committed by GitHub
parent 5557d77a96
commit 93f88b45b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 369 additions and 5 deletions

View file

@ -53,12 +53,18 @@ export type ProviderSettingsEntry = z.infer<typeof providerSettingsEntrySchema>
* ProviderSettings
*/
/**
* Default value for consecutive mistake limit
*/
export const DEFAULT_CONSECUTIVE_MISTAKE_LIMIT = 3
const baseProviderSettingsSchema = z.object({
includeMaxTokens: z.boolean().optional(),
diffEnabled: z.boolean().optional(),
fuzzyMatchThreshold: z.number().optional(),
modelTemperature: z.number().nullish(),
rateLimitSeconds: z.number().optional(),
consecutiveMistakeLimit: z.number().min(0).optional(),
// Model reasoning.
enableReasoningEffort: z.boolean().optional(),

View file

@ -5,6 +5,7 @@ import {
type ProviderSettingsEntry,
providerSettingsSchema,
providerSettingsSchemaDiscriminated,
DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
} from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
@ -26,6 +27,7 @@ export const providerProfilesSchema = z.object({
rateLimitSecondsMigrated: z.boolean().optional(),
diffSettingsMigrated: z.boolean().optional(),
openAiHeadersMigrated: z.boolean().optional(),
consecutiveMistakeLimitMigrated: z.boolean().optional(),
})
.optional(),
})
@ -48,6 +50,7 @@ export class ProviderSettingsManager {
rateLimitSecondsMigrated: true, // Mark as migrated on fresh installs
diffSettingsMigrated: true, // Mark as migrated on fresh installs
openAiHeadersMigrated: true, // Mark as migrated on fresh installs
consecutiveMistakeLimitMigrated: true, // Mark as migrated on fresh installs
},
}
@ -113,6 +116,7 @@ export class ProviderSettingsManager {
rateLimitSecondsMigrated: false,
diffSettingsMigrated: false,
openAiHeadersMigrated: false,
consecutiveMistakeLimitMigrated: false,
} // Initialize with default values
isDirty = true
}
@ -135,6 +139,12 @@ export class ProviderSettingsManager {
isDirty = true
}
if (!providerProfiles.migrations.consecutiveMistakeLimitMigrated) {
await this.migrateConsecutiveMistakeLimit(providerProfiles)
providerProfiles.migrations.consecutiveMistakeLimitMigrated = true
isDirty = true
}
if (isDirty) {
await this.store(providerProfiles)
}
@ -228,6 +238,18 @@ export class ProviderSettingsManager {
}
}
private async migrateConsecutiveMistakeLimit(providerProfiles: ProviderProfiles) {
try {
for (const [name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
if (apiConfig.consecutiveMistakeLimit == null) {
apiConfig.consecutiveMistakeLimit = DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
}
}
} catch (error) {
console.error(`[MigrateConsecutiveMistakeLimit] Failed to migrate consecutive mistake limit:`, error)
}
}
/**
* List all available configs with metadata.
*/

View file

@ -66,6 +66,7 @@ describe("ProviderSettingsManager", () => {
rateLimitSecondsMigrated: true,
diffSettingsMigrated: true,
openAiHeadersMigrated: true,
consecutiveMistakeLimitMigrated: true,
},
}),
)
@ -144,6 +145,47 @@ describe("ProviderSettingsManager", () => {
expect(storedConfig.apiConfigs.existing.rateLimitSeconds).toEqual(43)
})
it("should call migrateConsecutiveMistakeLimit if it has not done so already", async () => {
mockSecrets.get.mockResolvedValue(
JSON.stringify({
currentApiConfigName: "default",
apiConfigs: {
default: {
config: {},
id: "default",
consecutiveMistakeLimit: undefined,
},
test: {
apiProvider: "anthropic",
consecutiveMistakeLimit: undefined,
},
existing: {
apiProvider: "anthropic",
// this should not really be possible, unless someone has loaded a hand edited config,
// but we don't overwrite so we'll check that
consecutiveMistakeLimit: 5,
},
},
migrations: {
rateLimitSecondsMigrated: true,
diffSettingsMigrated: true,
openAiHeadersMigrated: true,
consecutiveMistakeLimitMigrated: false,
},
}),
)
await providerSettingsManager.initialize()
// Get the last call to store, which should contain the migrated config
const calls = mockSecrets.store.mock.calls
const storedConfig = JSON.parse(calls[calls.length - 1][1])
expect(storedConfig.apiConfigs.default.consecutiveMistakeLimit).toEqual(3)
expect(storedConfig.apiConfigs.test.consecutiveMistakeLimit).toEqual(3)
expect(storedConfig.apiConfigs.existing.consecutiveMistakeLimit).toEqual(5)
expect(storedConfig.migrations.consecutiveMistakeLimitMigrated).toEqual(true)
})
it("should throw error if secrets storage fails", async () => {
mockSecrets.get.mockRejectedValue(new Error("Storage failed"))

View file

@ -18,6 +18,7 @@ import {
type ClineMessage,
type ClineSay,
type ToolProgressStatus,
DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
type HistoryItem,
TelemetryEventName,
TodoItem,
@ -216,7 +217,7 @@ export class Task extends EventEmitter<ClineEvents> {
enableDiff = false,
enableCheckpoints = true,
fuzzyMatchThreshold = 1.0,
consecutiveMistakeLimit = 3,
consecutiveMistakeLimit = DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
task,
images,
historyItem,
@ -255,7 +256,7 @@ export class Task extends EventEmitter<ClineEvents> {
this.browserSession = new BrowserSession(provider.context)
this.diffEnabled = enableDiff
this.fuzzyMatchThreshold = fuzzyMatchThreshold
this.consecutiveMistakeLimit = consecutiveMistakeLimit
this.consecutiveMistakeLimit = consecutiveMistakeLimit ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
this.providerRef = new WeakRef(provider)
this.globalStoragePath = provider.context.globalStorageUri.fsPath
this.diffViewProvider = new DiffViewProvider(this.cwd)
@ -1159,7 +1160,7 @@ export class Task extends EventEmitter<ClineEvents> {
throw new Error(`[RooCode#recursivelyMakeRooRequests] task ${this.taskId}.${this.instanceId} aborted`)
}
if (this.consecutiveMistakeCount >= this.consecutiveMistakeLimit) {
if (this.consecutiveMistakeLimit > 0 && this.consecutiveMistakeCount >= this.consecutiveMistakeLimit) {
const { response, text, images } = await this.ask(
"mistake_limit_reached",
t("common:errors.mistake_limit_guidance"),

View file

@ -320,6 +320,70 @@ describe("Cline", () => {
expect(cline.diffStrategy).toBeDefined()
})
it("should use default consecutiveMistakeLimit when not provided", () => {
const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
task: "test task",
startTask: false,
})
expect(cline.consecutiveMistakeLimit).toBe(3)
})
it("should respect provided consecutiveMistakeLimit", () => {
const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
consecutiveMistakeLimit: 5,
task: "test task",
startTask: false,
})
expect(cline.consecutiveMistakeLimit).toBe(5)
})
it("should keep consecutiveMistakeLimit of 0 as 0 for unlimited", () => {
const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
consecutiveMistakeLimit: 0,
task: "test task",
startTask: false,
})
expect(cline.consecutiveMistakeLimit).toBe(0)
})
it("should pass 0 to ToolRepetitionDetector for unlimited mode", () => {
const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
consecutiveMistakeLimit: 0,
task: "test task",
startTask: false,
})
// The toolRepetitionDetector should be initialized with 0 for unlimited mode
expect(cline.toolRepetitionDetector).toBeDefined()
// Verify the limit remains as 0
expect(cline.consecutiveMistakeLimit).toBe(0)
})
it("should pass consecutiveMistakeLimit to ToolRepetitionDetector", () => {
const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
consecutiveMistakeLimit: 5,
task: "test task",
startTask: false,
})
// The toolRepetitionDetector should be initialized with the same limit
expect(cline.toolRepetitionDetector).toBeDefined()
expect(cline.consecutiveMistakeLimit).toBe(5)
})
it("should require either task or historyItem", () => {
expect(() => {
new Task({ provider: mockProvider, apiConfiguration: mockApiConfig })

View file

@ -43,8 +43,11 @@ export class ToolRepetitionDetector {
this.previousToolCallJson = currentToolCallJson
}
// Check if limit is reached
if (this.consecutiveIdenticalToolCallCount >= this.consecutiveIdenticalToolCallLimit) {
// Check if limit is reached (0 means unlimited)
if (
this.consecutiveIdenticalToolCallLimit > 0 &&
this.consecutiveIdenticalToolCallCount >= this.consecutiveIdenticalToolCallLimit
) {
// Reset counters to allow recovery if user guides the AI past this point
this.consecutiveIdenticalToolCallCount = 0
this.previousToolCallJson = null

View file

@ -301,5 +301,61 @@ describe("ToolRepetitionDetector", () => {
expect(result3.allowExecution).toBe(false)
expect(result3.askUser).toBeDefined()
})
it("should never block when limit is 0 (unlimited)", () => {
const detector = new ToolRepetitionDetector(0)
// Try many identical calls
for (let i = 0; i < 10; i++) {
const result = detector.check(createToolUse("tool", "tool-name"))
expect(result.allowExecution).toBe(true)
expect(result.askUser).toBeUndefined()
}
})
it("should handle different limits correctly", () => {
// Test with limit of 5
const detector5 = new ToolRepetitionDetector(5)
const tool = createToolUse("tool", "tool-name")
// First 4 calls should be allowed
for (let i = 0; i < 4; i++) {
const result = detector5.check(tool)
expect(result.allowExecution).toBe(true)
expect(result.askUser).toBeUndefined()
}
// 5th call should be blocked
const result5 = detector5.check(tool)
expect(result5.allowExecution).toBe(false)
expect(result5.askUser).toBeDefined()
expect(result5.askUser?.messageKey).toBe("mistake_limit_reached")
})
it("should reset counter after blocking and allow new attempts", () => {
const detector = new ToolRepetitionDetector(2)
const tool = createToolUse("tool", "tool-name")
// First call allowed
expect(detector.check(tool).allowExecution).toBe(true)
// Second call should block (limit is 2)
const blocked = detector.check(tool)
expect(blocked.allowExecution).toBe(false)
// After blocking, counter should reset and allow new attempts
expect(detector.check(tool).allowExecution).toBe(true)
})
it("should handle negative limits as 0 (unlimited)", () => {
const detector = new ToolRepetitionDetector(-1)
// Should behave like unlimited
for (let i = 0; i < 5; i++) {
const result = detector.check(createToolUse("tool", "tool-name"))
expect(result.allowExecution).toBe(true)
expect(result.askUser).toBeUndefined()
}
})
})
})

View file

@ -553,6 +553,7 @@ export class ClineProvider
enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
task,
images,
experiments,
@ -589,6 +590,7 @@ export class ClineProvider
enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
historyItem,
experiments,
rootTask: historyItem.rootTask,

View file

@ -6,6 +6,7 @@ import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import {
type ProviderName,
type ProviderSettings,
DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
openRouterDefaultModelId,
requestyDefaultModelId,
glamaDefaultModelId,
@ -64,6 +65,7 @@ import { ThinkingBudget } from "./ThinkingBudget"
import { DiffSettingsControl } from "./DiffSettingsControl"
import { TemperatureControl } from "./TemperatureControl"
import { RateLimitSecondsControl } from "./RateLimitSecondsControl"
import { ConsecutiveMistakeLimitControl } from "./ConsecutiveMistakeLimitControl"
import { BedrockCustomArn } from "./providers/BedrockCustomArn"
import { buildDocLink } from "@src/utils/docLinks"
@ -547,6 +549,14 @@ const ApiOptions = ({
value={apiConfiguration.rateLimitSeconds || 0}
onChange={(value) => setApiConfigurationField("rateLimitSeconds", value)}
/>
<ConsecutiveMistakeLimitControl
value={
apiConfiguration.consecutiveMistakeLimit !== undefined
? apiConfiguration.consecutiveMistakeLimit
: DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
}
onChange={(value) => setApiConfigurationField("consecutiveMistakeLimit", value)}
/>
</>
)}
</div>

View file

@ -0,0 +1,50 @@
import React, { useCallback } from "react"
import { Slider } from "@/components/ui"
import { useAppTranslation } from "@/i18n/TranslationContext"
import { DEFAULT_CONSECUTIVE_MISTAKE_LIMIT } from "@roo-code/types"
interface ConsecutiveMistakeLimitControlProps {
value: number
onChange: (value: number) => void
}
export const ConsecutiveMistakeLimitControl: React.FC<ConsecutiveMistakeLimitControlProps> = ({ value, onChange }) => {
const { t } = useAppTranslation()
const handleValueChange = useCallback(
(newValue: number) => {
// Ensure value is not negative
const validValue = Math.max(0, newValue)
onChange(validValue)
},
[onChange],
)
return (
<div className="flex flex-col gap-1">
<label className="block font-medium mb-1">{t("settings:providers.consecutiveMistakeLimit.label")}</label>
<div className="flex items-center gap-2">
<Slider
value={[value ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT]}
min={0}
max={10}
step={1}
onValueChange={(newValue) => handleValueChange(newValue[0])}
/>
<span className="w-10">{Math.max(0, value ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT)}</span>
</div>
<div className="text-sm text-vscode-descriptionForeground">
{value === 0
? t("settings:providers.consecutiveMistakeLimit.unlimitedDescription")
: t("settings:providers.consecutiveMistakeLimit.description", {
value: value ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT,
})}
</div>
{value === 0 && (
<div className="text-sm text-vscode-errorForeground mt-1">
{t("settings:providers.consecutiveMistakeLimit.warning")}
</div>
)}
</div>
)
}

View file

@ -367,6 +367,12 @@
"label": "Límit de freqüència",
"description": "Temps mínim entre sol·licituds d'API."
},
"consecutiveMistakeLimit": {
"label": "Límit d'errors i repeticions",
"description": "Nombre d'errors consecutius o accions repetides abans de mostrar el diàleg 'En Roo està tenint problemes'",
"unlimitedDescription": "Reintents il·limitats habilitats (procediment automàtic). El diàleg no apareixerà mai.",
"warning": "⚠️ Establir a 0 permet reintents il·limitats que poden consumir un ús significatiu de l'API"
},
"reasoningEffort": {
"label": "Esforç de raonament del model",
"high": "Alt",

View file

@ -367,6 +367,12 @@
"label": "Ratenbegrenzung",
"description": "Minimale Zeit zwischen API-Anfragen."
},
"consecutiveMistakeLimit": {
"label": "Fehler- & Wiederholungslimit",
"description": "Anzahl aufeinanderfolgender Fehler oder wiederholter Aktionen, bevor der Dialog 'Roo hat Probleme' angezeigt wird",
"unlimitedDescription": "Unbegrenzte Wiederholungen aktiviert (automatisches Fortfahren). Der Dialog wird niemals angezeigt.",
"warning": "⚠️ Das Setzen auf 0 erlaubt unbegrenzte Wiederholungen, was zu erheblichem API-Verbrauch führen kann"
},
"reasoningEffort": {
"label": "Modell-Denkaufwand",
"high": "Hoch",

View file

@ -367,6 +367,12 @@
"label": "Rate limit",
"description": "Minimum time between API requests."
},
"consecutiveMistakeLimit": {
"label": "Error & Repetition Limit",
"description": "Number of consecutive errors or repeated actions before showing 'Roo is having trouble' dialog",
"unlimitedDescription": "Unlimited retries enabled (auto-proceed). The dialog will never appear.",
"warning": "⚠️ Setting to 0 allows unlimited retries which may consume significant API usage"
},
"reasoningEffort": {
"label": "Model Reasoning Effort",
"high": "High",

View file

@ -367,6 +367,12 @@
"label": "Límite de tasa",
"description": "Tiempo mínimo entre solicitudes de API."
},
"consecutiveMistakeLimit": {
"label": "Límite de errores y repeticiones",
"description": "Número de errores consecutivos o acciones repetidas antes de mostrar el diálogo 'Roo está teniendo problemas'",
"unlimitedDescription": "Reintentos ilimitados habilitados (proceder automáticamente). El diálogo nunca aparecerá.",
"warning": "⚠️ Establecer en 0 permite reintentos ilimitados que pueden consumir un uso significativo de la API"
},
"reasoningEffort": {
"label": "Esfuerzo de razonamiento del modelo",
"high": "Alto",

View file

@ -367,6 +367,12 @@
"label": "Limite de débit",
"description": "Temps minimum entre les requêtes API."
},
"consecutiveMistakeLimit": {
"label": "Limite d'erreurs et de répétitions",
"description": "Nombre d'erreurs consécutives ou d'actions répétées avant d'afficher la boîte de dialogue 'Roo a des difficultés'",
"unlimitedDescription": "Réessais illimités activés (poursuite automatique). La boîte de dialogue n'apparaîtra jamais.",
"warning": "⚠️ Mettre à 0 autorise des réessais illimités, ce qui peut consommer une utilisation importante de l'API"
},
"reasoningEffort": {
"label": "Effort de raisonnement du modèle",
"high": "Élevé",

View file

@ -367,6 +367,12 @@
"label": "दर सीमा",
"description": "API अनुरोधों के बीच न्यूनतम समय।"
},
"consecutiveMistakeLimit": {
"label": "त्रुटि और पुनरावृत्ति सीमा",
"description": "'रू को समस्या हो रही है' संवाद दिखाने से पहले लगातार त्रुटियों या दोहराए गए कार्यों की संख्या",
"unlimitedDescription": "असीमित पुनः प्रयास सक्षम (स्वतः आगे बढ़ें)। संवाद कभी नहीं दिखाई देगा।",
"warning": "⚠️ 0 पर सेट करने से असीमित पुनः प्रयास की अनुमति मिलती है जिससे महत्वपूर्ण एपीआई उपयोग हो सकता है"
},
"reasoningEffort": {
"label": "मॉडल तर्क प्रयास",
"high": "उच्च",

View file

@ -371,6 +371,12 @@
"label": "Rate limit",
"description": "Waktu minimum antara permintaan API."
},
"consecutiveMistakeLimit": {
"label": "Batas Kesalahan & Pengulangan",
"description": "Jumlah kesalahan berturut-turut atau tindakan berulang sebelum menampilkan dialog 'Roo mengalami masalah'",
"unlimitedDescription": "Percobaan ulang tak terbatas diaktifkan (lanjut otomatis). Dialog tidak akan pernah muncul.",
"warning": "⚠️ Mengatur ke 0 memungkinkan percobaan ulang tak terbatas yang dapat menghabiskan penggunaan API yang signifikan"
},
"reasoningEffort": {
"label": "Upaya Reasoning Model",
"high": "Tinggi",

View file

@ -367,6 +367,12 @@
"label": "Limite di frequenza",
"description": "Tempo minimo tra le richieste API."
},
"consecutiveMistakeLimit": {
"label": "Limite di errori e ripetizioni",
"description": "Numero di errori consecutivi o azioni ripetute prima di mostrare la finestra di dialogo 'Roo sta riscontrando problemi'",
"unlimitedDescription": "Tentativi illimitati abilitati (procedi automaticamente). La finestra di dialogo non verrà mai visualizzata.",
"warning": "⚠️ L'impostazione a 0 consente tentativi illimitati che possono consumare un notevole utilizzo dell'API"
},
"reasoningEffort": {
"label": "Sforzo di ragionamento del modello",
"high": "Alto",

View file

@ -367,6 +367,12 @@
"label": "レート制限",
"description": "APIリクエスト間の最小時間。"
},
"consecutiveMistakeLimit": {
"label": "エラーと繰り返しの制限",
"description": "「Rooが問題を抱えています」ダイアログを表示するまでの連続エラーまたは繰り返しアクションの数",
"unlimitedDescription": "無制限のリトライが有効です(自動進行)。ダイアログは表示されません。",
"warning": "⚠️ 0に設定すると無制限のリトライが可能になり、API使用量が大幅に増加する可能性があります"
},
"reasoningEffort": {
"label": "モデル推論の労力",
"high": "高",

View file

@ -367,6 +367,12 @@
"label": "속도 제한",
"description": "API 요청 간 최소 시간."
},
"consecutiveMistakeLimit": {
"label": "오류 및 반복 제한",
"description": "'Roo에 문제가 발생했습니다' 대화 상자를 표시하기 전의 연속 오류 또는 반복 작업 수",
"unlimitedDescription": "무제한 재시도 활성화 (자동 진행). 대화 상자가 나타나지 않습니다.",
"warning": "⚠️ 0으로 설정하면 무제한 재시도가 허용되어 상당한 API 사용량이 발생할 수 있습니다"
},
"reasoningEffort": {
"label": "모델 추론 노력",
"high": "높음",

View file

@ -367,6 +367,12 @@
"label": "Snelheidslimiet",
"description": "Minimale tijd tussen API-verzoeken."
},
"consecutiveMistakeLimit": {
"label": "Fout- & Herhalingslimiet",
"description": "Aantal opeenvolgende fouten of herhaalde acties voordat het dialoogvenster 'Roo ondervindt problemen' wordt weergegeven",
"unlimitedDescription": "Onbeperkt aantal nieuwe pogingen ingeschakeld (automatisch doorgaan). Het dialoogvenster zal nooit verschijnen.",
"warning": "⚠️ Instellen op 0 staat onbeperkte nieuwe pogingen toe, wat aanzienlijk API-gebruik kan verbruiken"
},
"reasoningEffort": {
"label": "Model redeneervermogen",
"high": "Hoog",

View file

@ -367,6 +367,12 @@
"label": "Limit szybkości",
"description": "Minimalny czas między żądaniami API."
},
"consecutiveMistakeLimit": {
"label": "Limit błędów i powtórzeń",
"description": "Liczba kolejnych błędów lub powtórzonych akcji przed wyświetleniem okna dialogowego 'Roo ma problemy'",
"unlimitedDescription": "Włączono nieograniczone próby (automatyczne kontynuowanie). Okno dialogowe nigdy się nie pojawi.",
"warning": "⚠️ Ustawienie na 0 pozwala na nieograniczone próby, co może zużyć znaczną ilość API"
},
"reasoningEffort": {
"label": "Wysiłek rozumowania modelu",
"high": "Wysoki",

View file

@ -367,6 +367,12 @@
"label": "Limite de taxa",
"description": "Tempo mínimo entre requisições de API."
},
"consecutiveMistakeLimit": {
"label": "Limite de Erros e Repetições",
"description": "Número de erros consecutivos ou ações repetidas antes de exibir o diálogo 'Roo está com problemas'",
"unlimitedDescription": "Tentativas ilimitadas ativadas (prosseguimento automático). O diálogo nunca aparecerá.",
"warning": "⚠️ Definir como 0 permite tentativas ilimitadas, o que pode consumir um uso significativo da API"
},
"reasoningEffort": {
"label": "Esforço de raciocínio do modelo",
"high": "Alto",

View file

@ -367,6 +367,12 @@
"label": "Лимит скорости",
"description": "Минимальное время между запросами к API."
},
"consecutiveMistakeLimit": {
"label": "Лимит ошибок и повторений",
"description": "Количество последовательных ошибок или повторных действий перед показом диалогового окна 'У Roo возникли проблемы'",
"unlimitedDescription": "Включены неограниченные повторные попытки (автоматическое продолжение). Диалоговое окно никогда не появится.",
"warning": "⚠️ Установка значения 0 разрешает неограниченные повторные попытки, что может значительно увеличить использование API"
},
"reasoningEffort": {
"label": "Усилия по рассуждению модели",
"high": "Высокие",

View file

@ -367,6 +367,12 @@
"label": "Hız sınırı",
"description": "API istekleri arasındaki minimum süre."
},
"consecutiveMistakeLimit": {
"label": "Hata ve Tekrar Limiti",
"description": "'Roo sorun yaşıyor' iletişim kutusunu göstermeden önceki ardışık hata veya tekrarlanan eylem sayısı",
"unlimitedDescription": "Sınırsız yeniden deneme etkin (otomatik devam et). Diyalog asla görünmeyecek.",
"warning": "⚠️ 0'a ayarlamak, önemli API kullanımına neden olabilecek sınırsız yeniden denemeye izin verir"
},
"reasoningEffort": {
"label": "Model Akıl Yürütme Çabası",
"high": "Yüksek",

View file

@ -367,6 +367,12 @@
"label": "Giới hạn tốc độ",
"description": "Thời gian tối thiểu giữa các yêu cầu API."
},
"consecutiveMistakeLimit": {
"label": "Giới hạn lỗi và lặp lại",
"description": "Số lỗi liên tiếp hoặc hành động lặp lại trước khi hiển thị hộp thoại 'Roo đang gặp sự cố'",
"unlimitedDescription": "Đã bật thử lại không giới hạn (tự động tiếp tục). Hộp thoại sẽ không bao giờ xuất hiện.",
"warning": "⚠️ Đặt thành 0 cho phép thử lại không giới hạn, điều này có thể tiêu tốn mức sử dụng API đáng kể"
},
"reasoningEffort": {
"label": "Nỗ lực suy luận của mô hình",
"high": "Cao",

View file

@ -367,6 +367,12 @@
"label": "API 请求频率限制",
"description": "设置API请求的最小间隔时间"
},
"consecutiveMistakeLimit": {
"label": "错误和重复限制",
"description": "在显示“Roo遇到问题”对话框前允许的连续错误或重复操作次数",
"unlimitedDescription": "已启用无限重试(自动继续)。对话框将永远不会出现。",
"warning": "⚠️ 设置为 0 允许无限重试,这可能会消耗大量 API 使用量"
},
"reasoningEffort": {
"label": "模型推理强度",
"high": "高",

View file

@ -367,6 +367,12 @@
"label": "速率限制",
"description": "API 請求間的最短時間"
},
"consecutiveMistakeLimit": {
"label": "錯誤和重複限制",
"description": "在顯示「Roo 遇到問題」對話方塊前允許的連續錯誤或重複操作次數",
"unlimitedDescription": "已啟用無限重試(自動繼續)。對話方塊將永遠不會出現。",
"warning": "⚠️ 設定為 0 允許無限重試,這可能會消耗大量 API 使用量"
},
"reasoningEffort": {
"label": "模型推理強度",
"high": "高",