mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: add configurable max batch retries for scanner
This PR addresses Issue #10396 by adding a user-configurable setting for the maximum number of batch retries during codebase indexing. Changes: - Add batch retry constants to CODEBASE_INDEX_DEFAULTS (min: 1, max: 10, default: 3) - Add codebaseIndexMaxBatchRetries field to config schema - Update config-manager.ts to expose currentMaxBatchRetries getter - Update scanner.ts to accept and use configurable maxBatchRetries - Update service-factory.ts to pass configured value to DirectoryScanner - Add UI slider in Advanced Settings section of CodeIndexPopover - Add i18n translation strings for the new setting
This commit is contained in:
parent
6d8fa39319
commit
14a9ccfa87
6 changed files with 92 additions and 7 deletions
|
|
@ -12,6 +12,11 @@ export const CODEBASE_INDEX_DEFAULTS = {
|
|||
MAX_SEARCH_SCORE: 1,
|
||||
DEFAULT_SEARCH_MIN_SCORE: 0.4,
|
||||
SEARCH_SCORE_STEP: 0.05,
|
||||
// Batch retry settings
|
||||
MIN_BATCH_RETRIES: 1,
|
||||
MAX_BATCH_RETRIES: 10,
|
||||
DEFAULT_BATCH_RETRIES: 3,
|
||||
BATCH_RETRIES_STEP: 1,
|
||||
} as const
|
||||
|
||||
/**
|
||||
|
|
@ -42,6 +47,11 @@ export const codebaseIndexConfigSchema = z.object({
|
|||
.min(CODEBASE_INDEX_DEFAULTS.MIN_SEARCH_RESULTS)
|
||||
.max(CODEBASE_INDEX_DEFAULTS.MAX_SEARCH_RESULTS)
|
||||
.optional(),
|
||||
codebaseIndexMaxBatchRetries: z
|
||||
.number()
|
||||
.min(CODEBASE_INDEX_DEFAULTS.MIN_BATCH_RETRIES)
|
||||
.max(CODEBASE_INDEX_DEFAULTS.MAX_BATCH_RETRIES)
|
||||
.optional(),
|
||||
// OpenAI Compatible specific fields
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
|
||||
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { ApiHandlerOptions } from "../../shared/api"
|
|||
import { ContextProxy } from "../../core/config/ContextProxy"
|
||||
import { EmbedderProvider } from "./interfaces/manager"
|
||||
import { CodeIndexConfig, PreviousConfigSnapshot } from "./interfaces/config"
|
||||
import { DEFAULT_SEARCH_MIN_SCORE, DEFAULT_MAX_SEARCH_RESULTS } from "./constants"
|
||||
import { DEFAULT_SEARCH_MIN_SCORE, DEFAULT_MAX_SEARCH_RESULTS, MAX_BATCH_RETRIES } from "./constants"
|
||||
import { getDefaultModelId, getModelDimension, getModelScoreThreshold } from "../../shared/embeddingModels"
|
||||
|
||||
/**
|
||||
|
|
@ -26,6 +26,7 @@ export class CodeIndexConfigManager {
|
|||
private qdrantApiKey?: string
|
||||
private searchMinScore?: number
|
||||
private searchMaxResults?: number
|
||||
private maxBatchRetries?: number
|
||||
|
||||
constructor(private readonly contextProxy: ContextProxy) {
|
||||
// Initialize with current configuration to avoid false restart triggers
|
||||
|
|
@ -65,7 +66,8 @@ export class CodeIndexConfigManager {
|
|||
codebaseIndexEmbedderModelId,
|
||||
codebaseIndexSearchMinScore,
|
||||
codebaseIndexSearchMaxResults,
|
||||
} = codebaseIndexConfig
|
||||
codebaseIndexMaxBatchRetries,
|
||||
} = codebaseIndexConfig as any
|
||||
|
||||
const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? ""
|
||||
const qdrantApiKey = this.contextProxy?.getSecret("codeIndexQdrantApiKey") ?? ""
|
||||
|
|
@ -86,6 +88,7 @@ export class CodeIndexConfigManager {
|
|||
this.qdrantApiKey = qdrantApiKey ?? ""
|
||||
this.searchMinScore = codebaseIndexSearchMinScore
|
||||
this.searchMaxResults = codebaseIndexSearchMaxResults
|
||||
this.maxBatchRetries = codebaseIndexMaxBatchRetries
|
||||
|
||||
// Validate and set model dimension
|
||||
const rawDimension = codebaseIndexConfig.codebaseIndexEmbedderModelDimension
|
||||
|
|
@ -541,4 +544,12 @@ export class CodeIndexConfigManager {
|
|||
public get currentSearchMaxResults(): number {
|
||||
return this.searchMaxResults ?? DEFAULT_MAX_SEARCH_RESULTS
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured maximum batch retries for indexing.
|
||||
* Returns user setting if configured, otherwise returns default.
|
||||
*/
|
||||
public get currentMaxBatchRetries(): number {
|
||||
return this.maxBatchRetries ?? MAX_BATCH_RETRIES
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { Package } from "../../../shared/package"
|
|||
|
||||
export class DirectoryScanner implements IDirectoryScanner {
|
||||
private readonly batchSegmentThreshold: number
|
||||
private readonly maxBatchRetries: number
|
||||
|
||||
constructor(
|
||||
private readonly embedder: IEmbedder,
|
||||
|
|
@ -41,6 +42,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
private readonly cacheManager: CacheManager,
|
||||
private readonly ignoreInstance: Ignore,
|
||||
batchSegmentThreshold?: number,
|
||||
maxBatchRetries?: number,
|
||||
) {
|
||||
// Get the configurable batch size from VSCode settings, fallback to default
|
||||
// If not provided in constructor, try to get from VSCode settings
|
||||
|
|
@ -56,6 +58,8 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
this.batchSegmentThreshold = BATCH_SEGMENT_THRESHOLD
|
||||
}
|
||||
}
|
||||
// Set max batch retries from parameter or use default constant
|
||||
this.maxBatchRetries = maxBatchRetries ?? MAX_BATCH_RETRIES
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -360,7 +364,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
let success = false
|
||||
let lastError: Error | null = null
|
||||
|
||||
while (attempts < MAX_BATCH_RETRIES && !success) {
|
||||
while (attempts < this.maxBatchRetries && !success) {
|
||||
attempts++
|
||||
try {
|
||||
// --- Deletion Step ---
|
||||
|
|
@ -450,7 +454,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
batchSize: batchBlocks.length,
|
||||
})
|
||||
|
||||
if (attempts < MAX_BATCH_RETRIES) {
|
||||
if (attempts < this.maxBatchRetries) {
|
||||
const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempts - 1)
|
||||
await new Promise((resolve) => setTimeout(resolve, delay))
|
||||
}
|
||||
|
|
@ -458,7 +462,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
}
|
||||
|
||||
if (!success && lastError) {
|
||||
console.error(`[DirectoryScanner] Failed to process batch after ${MAX_BATCH_RETRIES} attempts`)
|
||||
console.error(`[DirectoryScanner] Failed to process batch after ${this.maxBatchRetries} attempts`)
|
||||
if (onError) {
|
||||
// Preserve the original error message from embedders which now have detailed i18n messages
|
||||
const errorMessage = lastError.message || "Unknown error"
|
||||
|
|
@ -467,7 +471,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|||
onError(
|
||||
new Error(
|
||||
t("embeddings:scanner.failedToProcessBatchWithError", {
|
||||
maxRetries: MAX_BATCH_RETRIES,
|
||||
maxRetries: this.maxBatchRetries,
|
||||
errorMessage,
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -186,7 +186,17 @@ export class CodeIndexServiceFactory {
|
|||
// In test environment, vscode.workspace might not be available
|
||||
batchSize = BATCH_SEGMENT_THRESHOLD
|
||||
}
|
||||
return new DirectoryScanner(embedder, vectorStore, parser, this.cacheManager, ignoreInstance, batchSize)
|
||||
// Get max batch retries from config manager
|
||||
const maxBatchRetries = this.configManager.currentMaxBatchRetries
|
||||
return new DirectoryScanner(
|
||||
embedder,
|
||||
vectorStore,
|
||||
parser,
|
||||
this.cacheManager,
|
||||
ignoreInstance,
|
||||
batchSize,
|
||||
maxBatchRetries,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ interface LocalCodeIndexSettings {
|
|||
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
|
||||
codebaseIndexSearchMaxResults?: number
|
||||
codebaseIndexSearchMinScore?: number
|
||||
codebaseIndexMaxBatchRetries?: number
|
||||
|
||||
// Bedrock-specific settings
|
||||
codebaseIndexBedrockRegion?: string
|
||||
|
|
@ -217,6 +218,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
codebaseIndexEmbedderModelDimension: undefined,
|
||||
codebaseIndexSearchMaxResults: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
|
||||
codebaseIndexSearchMinScore: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
|
||||
codebaseIndexMaxBatchRetries: CODEBASE_INDEX_DEFAULTS.DEFAULT_BATCH_RETRIES,
|
||||
codebaseIndexBedrockRegion: "",
|
||||
codebaseIndexBedrockProfile: "",
|
||||
codeIndexOpenAiKey: "",
|
||||
|
|
@ -256,6 +258,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
codebaseIndexConfig.codebaseIndexSearchMaxResults ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
|
||||
codebaseIndexSearchMinScore:
|
||||
codebaseIndexConfig.codebaseIndexSearchMinScore ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
|
||||
codebaseIndexMaxBatchRetries:
|
||||
codebaseIndexConfig.codebaseIndexMaxBatchRetries ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_BATCH_RETRIES,
|
||||
codebaseIndexBedrockRegion: codebaseIndexConfig.codebaseIndexBedrockRegion || "",
|
||||
codebaseIndexBedrockProfile: codebaseIndexConfig.codebaseIndexBedrockProfile || "",
|
||||
codeIndexOpenAiKey: "",
|
||||
|
|
@ -1589,6 +1593,50 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Maximum Batch Retries Slider */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.maxBatchRetriesLabel")}
|
||||
</label>
|
||||
<StandardTooltip
|
||||
content={t("settings:codeIndex.maxBatchRetriesDescription")}>
|
||||
<span className="codicon codicon-info text-xs text-vscode-descriptionForeground cursor-help" />
|
||||
</StandardTooltip>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Slider
|
||||
min={CODEBASE_INDEX_DEFAULTS.MIN_BATCH_RETRIES}
|
||||
max={CODEBASE_INDEX_DEFAULTS.MAX_BATCH_RETRIES}
|
||||
step={CODEBASE_INDEX_DEFAULTS.BATCH_RETRIES_STEP}
|
||||
value={[
|
||||
currentSettings.codebaseIndexMaxBatchRetries ??
|
||||
CODEBASE_INDEX_DEFAULTS.DEFAULT_BATCH_RETRIES,
|
||||
]}
|
||||
onValueChange={(values) =>
|
||||
updateSetting("codebaseIndexMaxBatchRetries", values[0])
|
||||
}
|
||||
className="flex-1"
|
||||
data-testid="max-batch-retries-slider"
|
||||
/>
|
||||
<span className="w-12 text-center">
|
||||
{currentSettings.codebaseIndexMaxBatchRetries ??
|
||||
CODEBASE_INDEX_DEFAULTS.DEFAULT_BATCH_RETRIES}
|
||||
</span>
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
title={t("settings:codeIndex.resetToDefault")}
|
||||
onClick={() =>
|
||||
updateSetting(
|
||||
"codebaseIndexMaxBatchRetries",
|
||||
CODEBASE_INDEX_DEFAULTS.DEFAULT_BATCH_RETRIES,
|
||||
)
|
||||
}>
|
||||
<span className="codicon codicon-discard" />
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@
|
|||
"searchMinScoreResetTooltip": "Reset to default value (0.4)",
|
||||
"searchMaxResultsLabel": "Maximum Search Results",
|
||||
"searchMaxResultsDescription": "Maximum number of search results to return when querying the codebase index. Higher values provide more context but may include less relevant results.",
|
||||
"maxBatchRetriesLabel": "Maximum Batch Retries",
|
||||
"maxBatchRetriesDescription": "Maximum number of retry attempts for failed batch operations during indexing. Higher values improve reliability on unstable connections but may delay error detection.",
|
||||
"resetToDefault": "Reset to default",
|
||||
"startIndexingButton": "Start Indexing",
|
||||
"clearIndexDataButton": "Clear Index Data",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue