Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/types/src/codebase-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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(),
Expand Down
15 changes: 14 additions & 1 deletion src/services/code-index/config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

/**
Expand All @@ -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
Expand Down Expand Up @@ -66,6 +67,9 @@ export class CodeIndexConfigManager {
codebaseIndexSearchMinScore,
codebaseIndexSearchMaxResults,
} = codebaseIndexConfig

const codebaseIndexMaxBatchRetries = (codebaseIndexConfig as { codebaseIndexMaxBatchRetries?: number })
.codebaseIndexMaxBatchRetries

const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? ""
const qdrantApiKey = this.contextProxy?.getSecret("codeIndexQdrantApiKey") ?? ""
Expand All @@ -86,6 +90,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
Expand Down Expand Up @@ -541,4 +546,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
}
}
12 changes: 8 additions & 4 deletions src/services/code-index/processors/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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
}

/**
Expand Down Expand Up @@ -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 ---
Expand Down Expand Up @@ -450,15 +454,15 @@ 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))
}
}
}

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"
Expand All @@ -467,7 +471,7 @@ export class DirectoryScanner implements IDirectoryScanner {
onError(
new Error(
t("embeddings:scanner.failedToProcessBatchWithError", {
maxRetries: MAX_BATCH_RETRIES,
maxRetries: this.maxBatchRetries,
errorMessage,
}),
),
Expand Down
12 changes: 11 additions & 1 deletion src/services/code-index/service-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}

/**
Expand Down
48 changes: 48 additions & 0 deletions webview-ui/src/components/chat/CodeIndexPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ interface LocalCodeIndexSettings {
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
codebaseIndexSearchMaxResults?: number
codebaseIndexSearchMinScore?: number
codebaseIndexMaxBatchRetries?: number

// Bedrock-specific settings
codebaseIndexBedrockRegion?: string
Expand Down Expand Up @@ -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: "",
Expand Down Expand Up @@ -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: "",
Expand Down Expand Up @@ -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>
Expand Down
4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/ca/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/de/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions webview-ui/src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/es/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/fr/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/hi/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/id/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/it/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/ja/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/ko/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion webview-ui/src/i18n/locales/nl/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading