mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
feat: add user-configurable fuzzy match threshold setting
- Add fuzzyMatchThreshold to GlobalSettings schema (0-1 range, optional) - Update Task class to accept and pass threshold to MultiSearchReplaceDiffStrategy - Add UI slider control in ContextManagementSettings (80-100% range) - Add English translations for the new setting This allows users to adjust how strictly search content must match when editing files, addressing issues where models like gemini-2-flash-preview produce output with 89-96% similarity that fails with 100% exact match. Fixes #11087
This commit is contained in:
parent
b020f6be43
commit
27c47c05b6
6 changed files with 65 additions and 4 deletions
|
|
@ -101,6 +101,17 @@ export const globalSettingsSchema = z.object({
|
|||
alwaysAllowWriteOutsideWorkspace: z.boolean().optional(),
|
||||
alwaysAllowWriteProtected: z.boolean().optional(),
|
||||
writeDelayMs: z.number().min(0).optional(),
|
||||
/**
|
||||
* Fuzzy match threshold for diff operations.
|
||||
* Controls how strictly the search content must match the original file content.
|
||||
* Value between 0 and 1 where:
|
||||
* - 1.0 (100%) = exact match required (default)
|
||||
* - 0.9 (90%) = allows minor differences (recommended for some models)
|
||||
* - 0.8 (80%) = more lenient matching
|
||||
* Lower values allow more flexibility but may increase false positives.
|
||||
* @default 1.0
|
||||
*/
|
||||
fuzzyMatchThreshold: z.number().min(0).max(1).optional(),
|
||||
alwaysAllowBrowser: z.boolean().optional(),
|
||||
requestDelaySeconds: z.number().optional(),
|
||||
alwaysAllowMcp: z.boolean().optional(),
|
||||
|
|
|
|||
|
|
@ -159,6 +159,13 @@ export interface TaskOptions extends CreateTaskOptions {
|
|||
workspacePath?: string
|
||||
/** Initial status for the task's history item (e.g., "active" for child tasks) */
|
||||
initialStatus?: "active" | "delegated" | "completed"
|
||||
/**
|
||||
* Fuzzy match threshold for diff operations (0-1).
|
||||
* 1.0 = exact match required (default)
|
||||
* 0.9 = 90% similarity (recommended for some models)
|
||||
* @default 1.0
|
||||
*/
|
||||
fuzzyMatchThreshold?: number
|
||||
}
|
||||
|
||||
export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
||||
|
|
@ -565,6 +572,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
initialTodos,
|
||||
workspacePath,
|
||||
initialStatus,
|
||||
fuzzyMatchThreshold,
|
||||
}: TaskOptions) {
|
||||
super()
|
||||
|
||||
|
|
@ -683,8 +691,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
// Listen for provider profile changes to update parser state
|
||||
this.setupProviderProfileChangeListener(provider)
|
||||
|
||||
// Set up diff strategy
|
||||
this.diffStrategy = new MultiSearchReplaceDiffStrategy()
|
||||
// Set up diff strategy with optional fuzzy match threshold
|
||||
this.diffStrategy = new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
|
||||
|
||||
this.toolRepetitionDetector = new ToolRepetitionDetector(this.consecutiveMistakeLimit)
|
||||
|
||||
|
|
|
|||
|
|
@ -969,8 +969,15 @@ export class ClineProvider
|
|||
}
|
||||
}
|
||||
|
||||
const { apiConfiguration, enableCheckpoints, checkpointTimeout, experiments, cloudUserInfo, taskSyncEnabled } =
|
||||
await this.getState()
|
||||
const {
|
||||
apiConfiguration,
|
||||
enableCheckpoints,
|
||||
checkpointTimeout,
|
||||
experiments,
|
||||
cloudUserInfo,
|
||||
taskSyncEnabled,
|
||||
fuzzyMatchThreshold,
|
||||
} = await this.getState()
|
||||
|
||||
const task = new Task({
|
||||
provider: this,
|
||||
|
|
@ -980,6 +987,7 @@ export class ClineProvider
|
|||
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
|
||||
historyItem,
|
||||
experiments,
|
||||
fuzzyMatchThreshold,
|
||||
rootTask: historyItem.rootTask,
|
||||
parentTask: historyItem.parentTask,
|
||||
taskNumber: historyItem.number,
|
||||
|
|
@ -2877,6 +2885,7 @@ export class ClineProvider
|
|||
experiments,
|
||||
cloudUserInfo,
|
||||
remoteControlEnabled,
|
||||
fuzzyMatchThreshold,
|
||||
} = await this.getState()
|
||||
|
||||
// Single-open-task invariant: always enforce for user-initiated top-level tasks
|
||||
|
|
@ -2901,6 +2910,7 @@ export class ClineProvider
|
|||
task: text,
|
||||
images,
|
||||
experiments,
|
||||
fuzzyMatchThreshold,
|
||||
rootTask: this.clineStack.length > 0 ? this.clineStack[0] : undefined,
|
||||
parentTask,
|
||||
taskNumber: this.clineStack.length + 1,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
includeDiagnosticMessages?: boolean
|
||||
maxDiagnosticMessages?: number
|
||||
writeDelayMs: number
|
||||
fuzzyMatchThreshold?: number
|
||||
includeCurrentTime?: boolean
|
||||
includeCurrentCost?: boolean
|
||||
maxGitStatusFiles?: number
|
||||
|
|
@ -57,6 +58,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
| "includeDiagnosticMessages"
|
||||
| "maxDiagnosticMessages"
|
||||
| "writeDelayMs"
|
||||
| "fuzzyMatchThreshold"
|
||||
| "includeCurrentTime"
|
||||
| "includeCurrentCost"
|
||||
| "maxGitStatusFiles"
|
||||
|
|
@ -78,6 +80,7 @@ export const ContextManagementSettings = ({
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
writeDelayMs,
|
||||
fuzzyMatchThreshold,
|
||||
includeCurrentTime,
|
||||
includeCurrentCost,
|
||||
maxGitStatusFiles,
|
||||
|
|
@ -406,6 +409,29 @@ export const ContextManagementSettings = ({
|
|||
</div>
|
||||
</SearchableSetting>
|
||||
|
||||
<SearchableSetting
|
||||
settingId="context-fuzzy-match-threshold"
|
||||
section="contextManagement"
|
||||
label={t("settings:contextManagement.fuzzyMatchThreshold.label")}>
|
||||
<span className="block font-medium mb-1">
|
||||
{t("settings:contextManagement.fuzzyMatchThreshold.label")}
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<Slider
|
||||
min={80}
|
||||
max={100}
|
||||
step={1}
|
||||
value={[Math.round((fuzzyMatchThreshold ?? 1.0) * 100)]}
|
||||
onValueChange={([value]) => setCachedStateField("fuzzyMatchThreshold", value / 100)}
|
||||
data-testid="fuzzy-match-threshold-slider"
|
||||
/>
|
||||
<span className="w-12">{Math.round((fuzzyMatchThreshold ?? 1.0) * 100)}%</span>
|
||||
</div>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:contextManagement.fuzzyMatchThreshold.description")}
|
||||
</div>
|
||||
</SearchableSetting>
|
||||
|
||||
<SearchableSetting
|
||||
settingId="context-include-current-time"
|
||||
section="contextManagement"
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
terminalZshP10k,
|
||||
terminalZdotdir,
|
||||
writeDelayMs,
|
||||
fuzzyMatchThreshold,
|
||||
showRooIgnoredFiles,
|
||||
enableSubfolderRules,
|
||||
remoteBrowserEnabled,
|
||||
|
|
@ -857,6 +858,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
includeDiagnosticMessages={includeDiagnosticMessages}
|
||||
maxDiagnosticMessages={maxDiagnosticMessages}
|
||||
writeDelayMs={writeDelayMs}
|
||||
fuzzyMatchThreshold={fuzzyMatchThreshold}
|
||||
includeCurrentTime={includeCurrentTime}
|
||||
includeCurrentCost={includeCurrentCost}
|
||||
maxGitStatusFiles={maxGitStatusFiles}
|
||||
|
|
|
|||
|
|
@ -738,6 +738,10 @@
|
|||
"description": "Time to wait after file writes before proceeding, allowing diagnostic tools to process changes and detect issues."
|
||||
}
|
||||
},
|
||||
"fuzzyMatchThreshold": {
|
||||
"label": "Fuzzy match threshold for file edits",
|
||||
"description": "Controls how strictly the search content must match when editing files. Lower values allow more tolerance for minor formatting differences that some models produce. 100% requires exact match (default), 90% is recommended for models that produce slight variations."
|
||||
},
|
||||
"condensingThreshold": {
|
||||
"label": "Condensing Trigger Threshold",
|
||||
"selectProfile": "Configure threshold for profile",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue